使用 `git format-patch`、`git am` 和 `git pull` 后出现的 Git 历史记录中的重复提交问题

4

我在我的电脑上编写代码,并拥有几个计算节点。

为了保持我的程序同步,我决定使用git。以前,我使用它的单向模式将更改从PC“推下”到计算节点。然而,不时会遇到一些与计算节点特定的小错误,并在现场进行修复。这比在PC上编写并提交可能或可能未修复所有问题的更改要容易测试和开发。

我决定使用git实用程序将更改发送回“主”代码库。

我编写了一个修复程序。在计算笔记本上提交了它,使用git format-patch origin。将补丁发送到我的电脑并使用git am应用它。到此为止,一切看起来都很好。

但是,在计算节点上使用git pull时,它再次从origin拉出带有补丁的提交,并且git log显示具有相同注释和作者的两个提交。

我使用的命令有误,还是我的工作流程有缺陷?或者这是可以接受的?(但是我觉得这不好看)。

我在两种情况下都使用master分支。

git pull计算节点:

commit 68710f82ddb2b2f191a9c29f088423853032a851  <--- git pull enforced merge
Merge: ce19df4 609b82b
Author: luk32 <luk32@computing.node>
Date:   Fri Dec 13 20:39:28 2013 +0100

    Merge branch 'master' of PC:~/projects/_cmake

commit 609b82bc96f88da956869cec2953e8621cbdcd93  <--- 2nd git pull after git am
Author: luk32 <luk32@computing.node>
Date:   Fri Dec 13 20:35:23 2013 +0100

    Changed to worki with MathGL version 2. Broken version 1 compatibility!

commit ce19df4760519eaf42269461f7bdcf94b65bdc48  <--- on-site fix
Author: luk32 <luk32@computing.node>
Date:   Fri Dec 13 20:35:23 2013 +0100

    Changed to worki with MathGL version 2. Broken version 1 compatibility!

commit ccc5b8a1854e4ca4089cf4c0945baff990288557  <--- after previous git pull
Author: lukas <luk32@PC>
Date:   Mon Jan 16 10:33:11 2012 +0100

    skeleton changed to introduce project stacks

在电脑上运行git log命令看起来很好:
commit 609b82bc96f88da956869cec2953e8621cbdcd93
Author: luk32 <luk32@computring.node>
Date:   Fri Dec 13 20:35:23 2013 +0100

    Changed to worki with MathGL version 2. Broken version 1 compatibility!

commit ccc5b8a1854e4ca4089cf4c0945baff990288557
Author: lukasz kucharski <luk32@PC>
Date:   Mon Jan 16 10:33:11 2012 +0100

    skeleton changed to introduce project stacks

编辑: 计算.节点: 〜/项目/_cmake$ git log --装饰--图形--单行主人

*   68710f8 (HEAD, master) Merge branch 'master' of PC:~/projects/_cmake
|\  
| * 609b82b (origin/master, origin/HEAD) Changed to work with MathGL version 2. Broken version 1 compatibility!
| * ccc5b8a skeleton changed to introduce project stacks
* | ce19df4 Changed to work with MathGL version 2. Broken version 1 compatibility!
|/  
* 35d2eaa (origin/pushee) added eigen3 find module
* 39f4937 small bugfixes and slight changes in the reporting of what's going on

请包含 git log --decorate --graph --oneline master 相关部分。 - Peter Lundgren
@PeterLundgren 已添加。我并不是一个Git专家。正如大家所看到的,更多的细节指出对我来说具有更多的教育价值。 - luk32
2个回答

5

在你将补丁应用到origin之后,在运行git pull之前,你的历史记录如下:

  * 609b82b (origin/master, origin/HEAD) Changed to work with MathGL version 2. Broken version 1 compatibility!
  * ccc5b8a skeleton changed to introduce project stacks
* | ce19df4 (HEAD, master) Changed to work with MathGL version 2. Broken version 1 compatibility!
|/
* 35d2eaa (origin/pushee) added eigen3 find module
* 39f4937 small bugfixes and slight changes in the reporting of what's going on

您的第一个提交 ce19df4,其父提交为 35d2eaa。当您应用补丁时,您创建了第二个提交 609b82b,其父提交为 ccc5b8a。因为它们有不同的父提交,所以它们是 不同的 提交,并具有不同的哈希值。提交的身份是以下内容的集合:
  • 存储库的快照(由于仓库现在包含来自 ccc5b8a 的更改,因此在第二个提交中不同)。
  • 提交消息、作者、时间(相同,因为您使用了 format-patcham)。
  • 父提交(在第二个提交中不同)。
那么,git pull 是什么?我不会向新的 Git 用户介绍 pull,因为这很困惑人。它取决于您所在的分支,并且只有在设置为跟踪分支时才起作用(master 可能已经是,但您的其他分支可能没有除非您自己设置)。它有两个功能:
  • 获取远程更改(与 git fetch 相同)。
  • 尝试将远程分支与当前分支合并(与 git merge 相同)。只有在本地分支设置为跟踪分支时,它才知道要尝试合并哪个分支。
合并 是令人困惑的。它尝试做快进式合并(在此处了解更多),但无法这样做。因此,它会创建一个合并提交,其中一个父提交是您的本地分支,另一个父提交是远程分支,您将得到以下结果:
*   68710f8 (HEAD, master) Merge branch 'master' of PC:~/projects/_cmake
|\
| * 609b82b (origin/master, origin/HEAD) Changed to work with MathGL version 2. Broken version 1 compatibility!
| * ccc5b8a skeleton changed to introduce project stacks
* | ce19df4 Changed to work with MathGL version 2. Broken version 1 compatibility!
|/
* 35d2eaa (origin/pushee) added eigen3 find module
* 39f4937 small bugfixes and slight changes in the reporting of what's going on

虽然对于git merge来说这是一个合理的操作,但这并不是你想要的。谁在乎你最初是针对35d2eaa提交的?你只想让master指向与origin/master相同的提交。现在你可以通过以下方式实现:

git checkout master
git stash # If you have any uncommitted changes
git reset --hard origin/master
git stash pop

然后您的历史记录将会像您想要的那样显示。
* 609b82b (HEAD, master, origin/master, origin/HEAD) Changed to work with MathGL version 2. Broken version 1 compatibility!
* ccc5b8a skeleton changed to introduce project stacks
* 35d2eaa (origin/pushee) added eigen3 find module
* 39f4937 small bugfixes and slight changes in the reporting of what's going on

感谢非常详细的解释。我希望我能+2给你,只是为了表达我的感激=)所以在执行git format-patch之前,我可以尝试git pull。我会拉取ccc5b8a,然后补丁会将其作为父补丁。我理解得对吗?但这似乎不太可靠。请问您认为合适的工作流程是什么?patch am pull back 和 hard-reset 看起来有些奇怪/粗暴,但最终结果似乎还可以。也许比pull回来更合适的是某种合并,因为合并不容易出错? - luk32
git pull --rebase 应该是您想要的。 - skorgon
skorgon 是正确的,git pull --rebase 会做你想要的事情。我建议使用 git fetch 然后根据是否需要合并提交,使用 git merge --no-ffgit rebase。我发现这种方式更容易教授。当你完全理解其影响时,可以再次使用 git pull - Peter Lundgren

1
当通过补丁上游时,该行为是正确的和预期的。你本地做的提交ID和从上游拉取的提交ID应该不同。这看起来有点奇怪,但它正确地反映了历史,正如你在历史的图形视图中所看到的。更改已在每个分支上引入,并且不会从任何一个分支中删除。合并从不更改现有历史,只是向你的分支添加更多内容。 如果你想避免提交“重复”,你必须改为使用基于'git rebase'的流程,而不是将上游合并到你的开发分支中。
作为额外的参考,我找到了这篇博客文章,解释了合并与变基,也触及了补丁问题:http://blog.experimentalworks.net/2009/03/merge-vs-rebase-a-deep-dive-into-the-mysteries-of-revision-control/

这很奇怪,因为 diff 很相似。就像两次应用相同的补丁。你能否提供一个 git rebase 工作流的简单示例,并讲解其缺点?或者告诉如何通过不同的方式上传到上游分支?也许你是指通过 push?最终,我想避免双重提交,因为它们看起来很奇怪,有点污染了历史记录。 - luk32
关键是提交ID,当您应用补丁时,与使用合并真正合并整个分支时不同。当您变基时,实质上是重写您的分支(更改您正在变基的更改的所有提交ID)。它获取您的本地更改并将其应用于当前上游分支(或任何其他fwiw)之上。如果已经在上游中,则变基会检测到差异相同并丢弃您的本地更改。我认为我上面添加的链接很好地解释了合并与变基的工作原理。 - skorgon

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