缺失的git提交

5

在工作中,经常会出现有人意外地将某些内容提交到主分支而不是目标特性分支的情况,然后这个人试图解决它,却发现更改突然消失了。我已经四处搜寻,但找不到任何文件可以阐明为什么会发生这种情况,或者如何解决。

以下是重现步骤:

$ git init
$ echo hello world > testfile
$ git add testfile
$ git commit -m 'init'
$ git branch A
$ echo abc >> testfile
$ git commit -am 'append abc'
$ git revert HEAD --no-edit
$ git checkout A
$ echo fff > secondfile
$ git add secondfile
$ git commit -m 'Add second file'
$ git cherry-pick master^

此时 Git 历史记录如下:

$ git log --oneline --all --graph --decorate
* ac6f9b4 (HEAD -> A) append abc
* 54be952 Add second file
| * 9ba1f16 (master) Revert "append abc"
| * ef7c8d6 append abc
|/  
* 65a885d init

现在请看当我将分支A变基到主分支上时会发生什么:

$ git rebase master
$ git log --oneline --all --graph --decorate
* 9d08739 (HEAD -> A) Add second file
* 9ba1f16 (master) Revert "append abc"
* ef7c8d6 append abc
* 65a885d init

在A分支的最前端有一次提交,提交号为ac6f9b4,它发生了什么?它去哪里了?为什么没有重新应用?

尽管这只是一个小例子,仅缺少一个提交,但有时我们会丢失长时间提交链中间的多个提交,它们似乎就像隐形一样 :(


顺便提一下,我知道Github至少允许您限制对主分支的直接推送,并要求使用PR。 - noahnu
1个回答

4
重新定位不会重新应用已经在新基础中应用的提交——这里是你的 append abc 更改。它已经在主分支历史记录中了。这通常是正确的,Git也不会做出任何评论。当然,在后续撤销操作时至少值得一提。要查看任何需要重新定位的内容是否已经是新基础历史记录的一部分(这里是master),
git log --oneline --cherry ...master

请查找标记为=的提交。这些是主分支中与您的分支匹配的提交; 变基不会重新应用它们。将master...交换为...master以查看本地等效项。

如果您想要一个有效的盲目变基,可以首先进行如下操作:

git checkout -B A master
git cherry-pick ..A@{1}      # < added the very important `..` by edit

这只是把A移到主分支上,然后挑选出你留下的所有内容。为了忽略合并(你应该这样做),在挑选时添加--no-merges,结果证明当你请求一系列的cherry-pick时,它会直接将整个集合传递给git rev-list,因此你可以直接使用该机制:

git cherry-pick --no-merges ..A@{1}  # just learned now that cherry-pick takes this

我喜欢你的帖子,git log 命令非常有用,虽然它不能主动解决问题,但在确定和验证可能出错的地方方面非常有帮助。我也喜欢你的 cherry pick,我不知道那个技巧,然而,cherry-pick 也并不能完全解决问题,因为你不能(正如我刚刚发现的)cherry-pick 合并。因此,在我的真实案例中,命令只完成了一半;( - Born2Smile
毫无疑问,你将得到应有的荣誉。同时,努力追求最普遍的解决方案也没有什么坏处,你不同意吗?此外,为了日后阅读此内容的人们,我可以手动挑选合并。我也可以重新设置基础并使用 git log 命令识别和重新挑选缺失的提交。但是,Git 是聪明的,并且被许多人使用,肯定有一个命令会做正确的事情,如果指出这一点能够激发解决问题的想法,那对我们和所有之后的人都更好。 :) - Born2Smile
好的,但你提到的唯一新事物是合并 - rebase 也忽略了它们,你只是在寻找 git cherry-pick $(git rev-list --no-merges ..A@{1}) 吗? - jthill
嗯...不对,那是按相反的顺序应用提交。然而,试图从造成的混乱中恢复,我发现当你解决了一个问题时,你可以使用 git cherry-pick --continue 继续进行 cherry-pick。所以考虑到这一点,你最初的建议似乎完美地解决了这个问题。它不保留分支和合并,但它确实保留了两侧的提交,总体来说就像 rebase 一样,除了不会丢弃提交。所以我非常感谢你,并为没有立即认识到你的解决方案的天才而道歉 :) - Born2Smile
cherrypick --no-merges 太棒了!!这正是我希望我们能发现的那种棒极了。如果我有额外的大拇指,我会给你的!再次感谢。 - Born2Smile
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接