我尝试将一个有变化的分支恢复到与它的上游分支相同。这些变化都是本地的,并且已经被推送到github,所以git reset
和git rebase
都不是真正可行的,因为它们改变了历史,这对于已经被推送到github的分支来说是一件坏事。
我也尝试过git merge
的各种策略,但没有一个撤消本地更改,即如果我添加了一个文件,合并可能会使其他文件回到行中,但我仍然有上游没有的文件。
我可以在上游创建一个新的分支,但是我真的很想一个合并,在修订历史方面应用所有的更改来获取我的分支,并使其再次与上游相同,这样我就可以安全地推送更改而不破坏历史。有这样的命令或命令系列吗?
9条答案
按热度按时间aiazj4mn1#
您可以使用**自定义合并驱动“keepTheirs”**将上游分支合并到
dev
分支:请参阅“需要
git merge -s theirs
-但我知道它不存在”。在您的例子中,只需要一个
.gitattributes
,以及一个keepTheirs
脚本,如下所示:git merge --strategy=theirs
模拟#1显示为合并,上游为第一个父节点。
Jefromi在评论中提到了
merge -s ours
,通过合并上游(或从上游开始的临时分支)的工作,然后将分支快进到合并的结果:这样做的好处是将上游祖先记录为第一个父分支,因此合并意味着“吸收这个过时的主题分支”,而不是“销毁这个主题分支并用上游替换它”。
2023年更新:例如,如果你想让
main
准确地反映dev
是什么:(Edit 2011年):
此工作流已在此blog post by the OP中报告:
为什么我又想要这个?
只要我的repo与公共版本无关,这一切都很好,但因为现在我希望能够与其他团队成员和外部贡献者在WIP上进行校对,我想确保我的公共分支对于其他人来说是可靠的,可以从分支中提取,即不再对我推到远程备份的东西进行rebase和重置,因为它现在在GitHub上并且是公共的。
所以剩下的就是我该怎么做了。
99%的情况下,我的副本会进入上游母版,所以我想在大部分时间里工作我的母版并推进到上游。
但是每隔一段时间,我在
wip
中的内容就会被进入上游的内容无效,我将放弃我的wip
的一部分。此时,我希望将master恢复到与upstream同步,但不破坏我的公开推送master上的任何提交点。即,我希望与upstream合并,最终合并的变更集使我的副本与upstream相同。
这就是
git merge --strategy=theirs
应该做的。git merge --strategy=theirs
模拟#2显示为合并,我们的作为第一个父。
(由jcwenger提出)
git merge --strategy=theirs
模拟#3blog post mentions:
有时候你确实想这么做,并不是因为你的历史中有“垃圾”,而是也许是因为你想改变公共存储库中的开发基线,而在公共存储库中应该避免rebase。
git merge --strategy=theirs
模拟#4(same博客文章)
或者,如果你想保持本地上游分支的快速转发,一个潜在的妥协是理解对于sid/unstable,上游分支可以不时地被重置/重定基(基于上游项目端最终不受你控制的事件)。
这不是什么大问题,使用这个假设意味着很容易将本地上游分支保持在只进行快进更新的状态。
git merge --strategy=theirs
模拟#5(由Barak A. Pearlmutter提出):
git merge --strategy=theirs
模拟#6(由同一个Michael Gebetsroither提出):
Michael Gebetsroither插话,声称我在“作弊”;),并给出了另一个使用较低级别的管道命令的解决方案:
(it如果git only命令不可能实现,那就不是git,git中的所有diff/patch/apply都不是真实的的解决方案;).
git merge --strategy=theirs
模拟#7必要的步骤可以描述为:
1.用upstream替换你的工作树
1.将更改应用于索引
1.将上游添加为第二个父级
1.提交
命令
git read-tree
用不同的树覆盖索引,完成了第二步,并有标志来更新工作树,完成了第一步。在提交时,git使用.git/MERGE_HEAD中的SHA1作为第二个父节点,因此我们可以填充它来创建合并提交。因此,这可以通过以下方式完成:qacovj5a2#
你现在可以很容易地做到这一点:
这会使您的本地存储库与源同步,并保留历史记录。
1tuwyuhd3#
听起来你只需要做:
如果没有要向上游推送的更改,而你只是想让上游分支成为你的当前分支,这将做到这一点。在本地做这件事并没有害处但是你将丢失任何尚未推送到master的本地更改**。
**实际上,如果你在本地提交了它们,这些更改仍然存在,因为提交仍然会在你的
git reflog
中,通常至少30天。qhhrdooz4#
git merge -s theirs ref-to-be-merged
的另一个模拟:双重复位的替代方案是应用反向补丁:
5ssjco0h5#
还有一种方法,几乎没有管道命令的帮助-恕我直言,最直接的。说你想模仿“他们的”2分支情况:
这会合并任意数量的head(在上面的例子中为2),使用其中一个head的tree(在上面的例子中bar,提供'their' tree),忽略任何diff/file问题(commit-tree是低级命令,所以它不关心这些)。注意head可以是1(所以相当于cherry-pick with“their”)。
请注意,首先指定哪个父头会影响一些东西(例如,请参阅git-log命令的--first-parent)-因此请记住这一点。
除了git-show,任何能够输出树和提交哈希的东西都可以使用-无论是用来解析的(cat-file,rev-list,...)。你可以使用git commit --amend来交互地美化提交消息。
5uzkadbs6#
严厉的,但地狱,什么可能出错?
cp -r .git /tmp
git checkout y
rm -rf .git && cp -r /tmp/.git
。yqyhoc1h7#
切换到远程上游分支并执行
git merge
,合并策略设置为ours
。所有的历史仍然存在,但是你会有一个额外的合并提交。这里重要的是从你想要的版本开始,并将
ours
与github实际所在的分支合并。mctunoxg8#
使用git reset BACKWARDS!
你可以用
git reset
使一个分支看起来像任何其他的提交,但是你必须以一种迂回的方式来做。要使提交
<old>
上的分支看起来像提交<new>
,可以执行以下操作以使
<new>
成为工作树的内容。那就做吧
将分支更改回原始提交**,但将工作树保留在**
<new>
状态。然后,您可以添加并提交更改,以使您的分支与
<new>
提交的内容完全匹配。从
<old>
状态转移到<new>
状态,需要执行git reset
from<new>
to<old>
,这是违反直觉的。然而,使用--mixed
选项,工作树留在<new>
,分支指针设置为<old>
,因此当提交更改时,分支看起来像我们想要的那样。警告
不要忘记你的提交,例如,在执行
git reset --hard <new>
时忘记<old>
是什么。zpf6vheq9#
我扮演了这些角色:
从分支中获取,硬重置,然后从他们的分支中递归,然后强制推送到分支
风险自负