Git 恢复错误合并后恢复丢失的更改
我对Git比较陌生,在误解了一篇帮助文章后犯了一个(愚蠢的)错误,我不知道如何使用Git完全修复这个问题,而不是手动重新引入对目标分支的更改Git 恢复错误合并后恢复丢失的更改,git,git-merge,git-revert,Git,Git Merge,Git Revert,我对Git比较陌生,在误解了一篇帮助文章后犯了一个(愚蠢的)错误,我不知道如何使用Git完全修复这个问题,而不是手动重新引入对目标分支的更改 S---sc1---sc2---sc3-----sc4----M4---R1---M5---sc5 \ \ / / T1-------------------M2---M3--------R2 \ \ / F---fc1---fc2---M1
S---sc1---sc2---sc3-----sc4----M4---R1---M5---sc5
\ \ / /
T1-------------------M2---M3--------R2
\ \ /
F---fc1---fc2---M1
一些注释:S
是此场景中的主要分支,T1
是从S
提取的团队分支,F
是从T1
提取的我的功能分支
我已经设置了自动合并,因此当提交到T1
分支时,它们将通过连续集成运行,然后自动合并到S
。T1
分支中有一个文件与另一个团队成员提交的S
存在合并冲突,因此我决定在完成F
的工作后修复该问题
我将T1
合并到F
(M1
),然后将F
合并到T1
(M2
)。考虑到我过去遇到的合并冲突解决方案不符合我的预期的问题,我想我应该尝试一些新方法:只将S
中的冲突文件合并到T1
,解决那里的合并冲突,从合并中删除所有其他文件,然后允许连续集成将所有内容合并到S
我在未提交的情况下启动了从S
到T1
(M3
)的合并,解决了冲突,从合并中删除了其他(~200)个文件,然后提交。这将自动合并到S
(M4
)
我立刻注意到,排除这些约200个文件似乎已经完全消除了更改,这相当于两个团队大约一个月的工作量。我(错误地)认为最好的做法是迅速行动,在我的错误进入其他任何人的本地回购之前,恢复合并提交M4
和M3
。我首先还原了M4
(R1
),提交后,我还原了M3
(R2
)。我认为这是一个正确的顺序,因为我不确定当自动合并开始时,另一种方式是否会带来问题。最后,R2
被提交并自动合并到S
(M5
)
这解决了所有其他人的更改都被删除的问题,但是我在F
中的所有更改以及最初存在合并冲突的文件都从s
中删除了。我能够将单个文件的更改直接提交到s
(sc5
),但是F
中的更改要复杂得多。它们仍然生活在T1
中,但由于它们是作为R1
的一部分从S
还原的,所以我不能将它们重新提交
我花了一天的大部分时间试图找出如何最好地将这些更改升级到S
,但是git-rebase
和git-cherry-pick
似乎不能满足我的需要,尽管我很清楚我在这方面可能是错的。如果任何比我更擅长Git的人能提出至少一个起点,那将是令人惊讶的。谢谢
编辑:从图表中删除无用/混乱的点<由于我试图用M3
解决合并冲突,code>M2在S
之前未自动合并
编辑2:在阅读了torek的精彩解释后,我开始尝试重新基址。我忘记了在F
的历史中,我多次将T1
分支合并到F
分支中,因为该功能分支跨越了多少时间。这意味着有很多很多合并冲突需要解决
在torek对此的回应中,我尝试了合并挤压。我最初的想法是,我需要将新分支从合并挤压合并到T1
分支,然后将T1
分支合并到S
,但我遇到了同样的问题,它没有看到更改。我认为这是因为更改已经存在于T1
中,所以它基本上只是将相同的、先前还原的更改反馈回S
,而S不需要这些更改
编辑3:多亏了torek非常详细的解释(非常感谢!),我将完成合并挤压,然后在解决冲突后将其结果合并到S
分支。这相当长,所以请随意跳过您已经知道的部分(或者一直滚动到最后)。每个部分都有设置信息,在后面的部分中解释正在发生的事情或我们正在做的事情
y型钻头简介
首先,让我以我喜欢的方式重新绘制此图(我认为这是一种局部图,但它包含我们需要的关键提交):
S0--sc1---sc2---sc3-----sc4----M4---R1---M5---sc5 <-- branch-S
\ \ / /
T0-------------o----M2---M3--------R2 <---- branch-T1
\ \ /
F0--fc1---fc2---M1 <------------------- branch-F
其他合并是由软件进行的,只有在没有冲突时才会发生。R
提交是从运行开始的:
git checkout <branch>
git revert -m 1 <hash ID of some M commit>
在这里,我们需要提到Git的索引。该索引最好描述为Git构建下一次提交的位置。它最初包含当前提交中保存的每个文件(此处C
):签出此提交,用提交C
中的文件填充索引和工作树。名称master
指向此提交,名称HEAD
附加到名称master
然后修改工作树中的文件,使用git add
将它们复制回索引中,如果需要,使用git add
将新文件复制到索引中,然后运行git commit
。通过将这些索引副本冻结到快照中来进行新的提交。git然后添加快照元数据您的姓名和电子邮件、日志m以及当前提交的哈希ID,以便新提交指向现有提交。结果是:
git checkout <branch>
git revert -m 1 <hash ID of some M commit>
A--B--C <-- master (HEAD)
A--B--C <-- master (HEAD)
\
D
A--B--C--D <-- master (HEAD)
o--...--L <-- mainline (HEAD)
/
...--o--*
\
o--...--R <-- feature
git diff --find-renames <hash-of-*> <hash-of-L> # what we changed
git diff --find-renames <hash-of-*> <hash-of-R> # what they changed
o--...--L
/ \
...--o--* M <-- mainline (HEAD)
\ /
o--...--R <-- feature
...--sc4----M4---R1
\ /
...--M2---M3--------R2
T0-------------o <-- branch-T1
\
F0--fc1---fc2 <--- branch-F (HEAD)
T0-------------o <-- branch-T1
\ \
F0--fc1---fc2---M1 <--- branch-F (HEAD)
T0-------------o----M2 <-- branch-T1 (HEAD)
\ \ /
F0--fc1---fc2---M1 <--- branch-F
git checkout branch-T1
git merge branch-S
S0--sc1---sc2---sc3-----sc4 <-- branch-S
\
T0-------------o----M2 <-- branch-T1 (HEAD)
\ \ /
F0--fc1---fc2---M1 <-- branch-F
git checkout branch-S
git merge --no-ff branch-T1
S0--sc1---sc2---sc3-----sc4----M4 <-- branch-S
\ \ /
T0-------------o----M2---M3 <-- branch-T1
\ \ /
F0--fc1---fc2---M1 <-- branch-F
git diff <hash-of-sc4> <hash-of-R1>
T0 <-- revised-F (HEAD)
\
F0--fc1--fc2--M1 <-- branch-F
T0-----....
\
F0--fc1--fc2--M1 <-- branch-F, revised-F (HEAD)
git checkout -b revised-F <hash of T0> # for merge --squash method
git checkout -b revised-f branch-F^1 # for rebase -f method
git merge --squash branch-F
fc1--fc2--M1 <-- branch-F
/
F0-------------F3 <-- revised-F (HEAD)
git rebase -f <hash-of-T0>
F0'-fc1'-fc2' <-- revised-F (HEAD)
/
T0-----....
\
F0--fc1--fc2--M1 <-- branch-F
S0--sc1---sc2---sc3-----sc4----M4---R1---M5---sc5 <-- branch-S
\ \ / /
T0-----o-------o----M2---M3--------R2 <---- branch-T1
\ \ \ /
F0--fc1-o-fc2---M1 <--------------- branch-F
S0--sc1---sc2---sc3-----sc4----M4---R1---M5---sc5 <-- branch-S
\ \ / /
T0-----o-------o----M2---M3--------R2 <---- branch-T1
\ \ \ /
F0--fc1-o-fc2---M1 <--------------- branch-F
\
---------------------------------F3 <-- revised-F
git checkout branch-T1
git merge revised-F
git merge-base --all branch-T1 revised-F
S0--sc1---sc2---sc3-----sc4----M4---R1---M5---sc5 <-- branch-S
\ \ / /
T0-----o-------o----M2---M3--------R2-----M6 <---- branch-T1
\ \ \ / /
F0--fc1-o-fc2---M1 <-- branch-F /
\ /
---------------------------------F3 <-- revised-F
S0--sc1---sc2---sc3-----sc4----M4---R1---M5---sc5 <-- branch-S
\ \ / /
T0-----o-------o----M2---M3--------R2 <---- branch-T1
\ \ \ /
F0--fc1-o-fc2---M1 <--------------- branch-F
\
---------------------------------F3 <-- revised-F
S0--sc1---sc2---sc3-----sc4----M4---R1---M5---sc5----M6 <-- branch-S
\ \ / / /
T0-----o-------o----M2---M3--------R2 <------ / -- branch-T1
\ \ \ / /
F0--fc1-o-fc2---M1 <-- branch-F /
\ /
---------------------------------------F3 <-- revised-F
git merge-base --all branch-S revised-F