【发布时间】:2017-04-30 13:01:15
【问题描述】:
让我们这么说:
- 我们有一个 master 分支,其中一位同事意外添加了一系列本应属于新功能的提交(我们称之为
A B C)。 - 我发现了这一点,我告诉他将这些提交移到一个新分支,但保留其他不相关的提交,这些提交稍后在 master 中完成。我把我问的这个问题发给他,并告诉他按照回复:git: how to move a branch's root two commits back
- 几天后,当新功能分支准备就绪时,我将其合并到 master 中。
- 解决合并中的所有冲突后,我提交更改...
- ...我发现那些第一次提交(
A B C)已经消失了。 - 我问我的同事,他说“他认为”他使用链接中提到的方法移动了这些更改(基本上:检查最后一个常见的提交,然后使用
git cherry-pick只选择我们后来想要),但他记不清了。 - 我检查了 repo 的历史记录,
A B C在功能分支中,一开始。它们看起来像是从 master 成功迁移过来的。
鉴于上述情况,谁能解释为什么 git 会丢失这些更改? (我个人的理论是 git 以某种方式“记住”了我们已经撤消的提交 A B C,所以当它们来自新功能分支时,git 决定不合并它们。编辑:抱歉,如果这个解释听起来太像“神奇的想法” ",但我不知所措。如果它是正确的,我欢迎任何尝试用更专业的术语来解释这个解释。
很抱歉无法提供更多细节,但我没有亲自在 repo 中进行这些更改,因此无法提供所做操作的确切细节。
编辑:好的,按照这里的建议,我让我的同事在他的机器上执行git reflog,所以我将结果粘贴到这里。回到我之前的(链接的)问题,我们有这样一棵树:
A - B - C - D - E - F master
\
\- G - H new feature branch
我们想将 B 和 C 移至新功能分支。
所以,他发给我的git reflog 就在这里。提交 5acb457 将对应于上图中的“提交 A”:
4629c88 HEAD@{59}: commit: blah
f93f3d3 HEAD@{60}: commit: blah
57b0ea7 HEAD@{61}: checkout: moving from master to feature_branch
4b39fbf HEAD@{62}: commit: Added bugfix F again
4fa21f2 HEAD@{63}: commit: undid checkouts that were in the wrong branch
1c8b2f9 HEAD@{64}: reset: moving to origin/master
5acb457 HEAD@{65}: checkout: moving from 5acb4576eca4b44e0a7574eea19cca067c039dc5 to master
5acb457 HEAD@{66}: checkout: moving from master to 5acb4576eca4b44e0a7574eea19cca067c039dc5
1c8b2f9 HEAD@{67}: checkout: moving from 1c8b2f9bf54ca1d80472c08f3ce7d9028a757985 to master
1c8b2f9 HEAD@{68}: rebase: checkout master
5acb457 HEAD@{69}: checkout: moving from master to 5acb4576eca4b44e0a7574eea19cca067c039dc5
1c8b2f9 HEAD@{70}: checkout: moving from 5acb4576eca4b44e0a7574eea19cca067c039dc5 to master
5acb457 HEAD@{71}: checkout: moving from master to 5acb4576eca4b44e0a7574eea19cca067c039dc5
1c8b2f9 HEAD@{72}: merge origin/master: Fast-forward
5acb457 HEAD@{73}: checkout: moving from master to master
5acb457 HEAD@{74}: checkout: moving from 5acb4576eca4b44e0a7574eea19cca067c039dc5 to master
5acb457 HEAD@{75}: checkout: moving from undo_branch to 5acb4576eca4b44e0a7574eea19cca067c039dc5
5acb457 HEAD@{76}: checkout: moving from master to undo_branch
1c8b2f9 HEAD@{77}: checkout: moving from undo_branch to master
525dbce HEAD@{78}: cherry-pick: Bugfix F
a1a5028 HEAD@{79}: cherry-pick: Bugfix E
32f8968 HEAD@{80}: cherry-pick: Feature C
8b003cb HEAD@{81}: cherry-pick: Feature B
5acb457 HEAD@{82}: checkout: moving from 5acb4576eca4b44e0a7574eea19cca067c039dc5 to undo_branch
5acb457 HEAD@{83}: checkout: moving from master to 5acb4576eca4b44e0a7574eea19cca067c039dc5
1c8b2f9 HEAD@{84}: checkout: moving from 1c8b2f9bf54ca1d80472c08f3ce7d9028a757985 to master
1c8b2f9 HEAD@{85}: pull origin HEAD:master: Fast-forward
5acb457 HEAD@{86}: checkout: moving from master to 5acb4576eca4b44e0a7574eea19cca067c039dc5
5acb457 HEAD@{87}: reset: moving to 5acb4576eca4b44e0a7574eea19cca067c039dc5
1c8b2f9 HEAD@{88}: merge origin/master: Fast-forward
5acb457 HEAD@{89}: reset: moving to 5acb4576eca4b44e0a7574eea19cca067c039dc5
1c8b2f9 HEAD@{90}: checkout: moving from 5acb4576eca4b44e0a7574eea19cca067c039dc5 to master
5acb457 HEAD@{91}: checkout: moving from master to 5acb4576eca4b44e0a7574eea19cca067c039dc5
1c8b2f9 HEAD@{92}: merge origin/master: Merge made by the 'recursive' strategy.
7b912cd HEAD@{93}: checkout: moving from 7b912cdf33843d28dd4a7b28b37b5edbe11cf3b9 to master
7b912cd HEAD@{94}: cherry-pick: Bugfix F
df7a9cd HEAD@{95}: cherry-pick: Bugfix E
d4d0e41 HEAD@{96}: cherry-pick: Feature C
701c8cc HEAD@{97}: cherry-pick: Feature B
5acb457 HEAD@{98}: checkout: moving from master to 5acb4576eca4b44e0a7574eea19cca067c039dc5
22ecc3a HEAD@{99}: checkout: moving from 5acb4576eca4b44e0a7574eea19cca067c039dc5 to master
5acb457 HEAD@{100}: checkout: moving from master to 5acb4576eca4b44e0a7574eea19cca067c039dc5
22ecc3a HEAD@{101}: commit: bugfix E
3b568bc HEAD@{102}: checkout: moving from feature_branch to master
57b0ea7 HEAD@{103}: commit: blah
152c5b9 HEAD@{104}: checkout: moving from master to feature_branch
3b568bc HEAD@{105}: commit: bugfix D
fe3bbce HEAD@{106}: checkout: moving from feature_branch to master
152c5b9 HEAD@{107}: commit: blah
2318ebc HEAD@{108}: commit: blah
cc5ea32 HEAD@{109}: commit: blah
a5c2303 HEAD@{110}: commit: blah
544a99a HEAD@{111}: commit: blah
299f86a HEAD@{112}: commit: Feature G
fe3bbce HEAD@{113}: checkout: moving from master to feature_branch
fe3bbce HEAD@{114}: commit: Feature C
3852e71 HEAD@{115}: commit: Feature B
5acb457 HEAD@{116}: merge origin/master: Fast-forward
任何人都可以理解这 4 个连续的 cherry-picks 吗?我怀疑他并没有真正做git cherry-pick master~3 的事情,尤其是~3 部分(当我第一次看到它时,这确实让我很生气)。
【问题讨论】:
-
当然,最明显和最可能的原因仅仅是您的同事按照说明从 master 中删除了 A B C,但忘记在特性分支上提交它们,或者可能确实在特性分支上提交它们但从未推那个?
git reflog在您同事的机器上的功能分支上应该会告诉您是否是这种情况......但如果是这样,那么您也不应该在功能分支中使用 A B C 。如果你还有 feature 分支,你能检查一下吗? -
正如@hvd 建议的那样,您可以通过
git reflog审查丢失的提交。这为您提供了带有提交哈希的提交历史记录。然后找到引用您想要获取的提交的行。 -
好的,您已经验证提交是功能分支的一部分。那挺好的。您是否还可以检查内容是否是功能分支的一部分(并且没有被后来的某些提交意外恢复)?也就是说,检查特性分支,看看是否一切正常。
-
所以你主要关心的是第(3)项,最终的合并结果。合并结果的历史记录中有哪些提交根本不重要,除非它们与您在
git checkout合并提交时获得的树有什么关系? -
我之所以问,是因为每当您“更改”提交时,提交的 ID 都会更改(因为您永远无法更改任何提交——您会得到新的副本) .这会影响所有底层细节,但不会影响最终的合并结果:合并结果取决于三个输入(一旦有更多时间,我将在答案中描述)。
标签: git version-control rebase