Git pull在提交日志中导致多余的“合并分支”消息


110

我正在与另一个开发人员合作进行一个项目,我们正在使用Github作为我们的远程仓库。我在Mac上使用git 1.7.7.3,他在Windows上使用git 1.7.6。

这是发生了什么

  1. 我们中的一个人(我们称他为开发人员A,但无论是哪个人都没关系)将一组提交推送到GitHub。
  2. 另一个(开发人员B)进行一些本地提交。
  3. B做一个git pull
  4. B做一个git push
  5. 查看提交历史记录日志,我看到github.com:foo/bar的Merge分支“ master”

随着时间的推移,提交日志中会散布“合并分支”消息,并且还将开发人员B显示为开发人员A所做的提交更改。我们发现防止此问题的唯一方法是git pull --rebase在第3步中进行操作,但我不知道重新定基会带来哪些副作用。这是我第一次从事多开发人员git repo的工作,所以这只是正常现象吗?关于如何解决这个问题有什么想法?


2
您可以在不合并的情况下查看日志git log --no-merges
wjandrea

Answers:


88

您看到的提交非常好。一个pull有效的运行git fetch,然后git merge所以当你运行一个合并通常发生git pull

可以使用重定基础而不是合并的替代方法,但是通常应该避免这种情况。变基使您可以保留线性历史记录,但也可以删除有关最初发生的分支的任何信息。这也将导致当前分支的历史记录被重写,从而重新创建目标分支(在您的情况下为远程)中未包含的所有提交。由于重新创建的提交是不同的提交,因此与其他开发人员一起进行开发时会引起很多混乱,尤其是当人们在重写之前已经检出了部分提交时(例如使用功能分支)。因此,根据经验,永远不要重写任何已经推送的提交。

您看到的提交将合并两个(或多个)分支。拥有一个不执行其他任何操作然后合并多个分支的提交就很好了。实际上,当您有一个合并提交,它可以在查看历史记录时合并分支,因此非常清楚。与重新定级相比,合并还使您可以有效地查看原始历史记录,包括合并的实际分支。

因此,长话短说:是的,拥有合并提交是完全可以的,您不必担心它们。


2
很好的答案。我自己尝试了rebase样式,因为在一些开源项目贡献准则中建议使用rebase样式,这给我带来了问题。团队中的新成员也是如此。我认为rebase选项不适用于一整天一起工作的团队,但对于具有主要贡献者和仅提交补丁的其他贡献者的项目是正确的。那些应该在发出拉取请求之前很好地获取主存储库并根据其更改重新存储。
Meligy 2012年

2
@sTodorov如果没有新的更改,则pull的fetch-part将什么都不做,但是合并仍在执行。因此,如果您当前的本地分支不是最新的,它将把新更改合并到您的分支中。并且如果它不能进行快速合并(如果您有不同的提交),那么它将创建一个合并提交。

28
这个答案使OP所描述的使用rebase看起来很危险,但事实并非如此。在第3步重新设置基准不会重写整个历史记录。通过在新HEAD(最新推送到该分支的提交)上重新应用,仅重写尚未推送的本地提交。这样可以防止无关的合并提交,并且没有其他副作用。
bob esponja 2014年

1
@bobesponja重写不在拉出的远程分支上的所有提交。这可以包括来自其他分支的已发布提交,例如具有功能分支的提交,其他人以前可能已经访问过。因此,是的,在不考虑要重新设置基础的情况下进行重新设置有些危险。

1
@bobesponja是的,如果您要过早发布功能分支(因为其他人正在处理它,或者只是作为备份),则不应重新设置它的基础,因为其他人可能已经获取了它。就像您自己说的那样,然后进行基础调整违反了我在回答中所述的基础调整准则。但是,如果您不发布提交,那么如果您愿意并且不介意线性历史记录,则可以使用重新基准化。但这取决于您的工作方式,因此通常的答案是避免使用它,除非它确实安全。顺便说一句。我修改了答案,因此如果问题得以解决,请删除您的否决表。

48

由于我的理解,图表和结论不正确,因此该答案已被修改。


git pull导致合并提交,因为git正在合并。可以通过将分支设置为使用rebase而不是merge来更改此设置。使用rebase而不是在pull上合并将为共享存储库提供更线性的历史记录。另一方面,合并提交显示了分支上的并行开发工作。

例如,两个人在同一个分支上工作。分支开始于:

...->C1

第一个人完成工作并推送到分支:

...->C1->C2

第二个人完成了他们的工作并想要推送,但是不能,因为他们需要更新。第二人称的本地存储库如下所示:

...->C1->C3

如果拉取设置为合并,则第二个人存储库将看起来像。

...->C1->C3->M1
      \      /
       ->C2->

其中M1是合并提交。这个新的分支历史将被推送到仓库中。如果相反,则将pull设置为对本地存储库进行重设,如下所示:

...->C1->C2->C3

没有合并提交。历史变得更加线性。

两种选择都反映了分支的历史。git允许您选择喜欢的历史记录。

确实在某些地方,重新设置可能会导致远程分支机构出现问题。这不是其中一种情况。我们更喜欢使用rebase,因为它简化了已经很复杂的分支历史记录,并显示了相对于共享存储库的历史记录版本。

您可以设置branch.autosetuprebase = always来让git自动将远程分支建立为rebase而不是master。

git config --global branch.autosetuprebase always

此设置使git自动为每个远程分支创建配置设置:

branch.<branchname>.rebase=true

您可以为已设置的远程分支机构自行设置。

git config branch.<branchname>.rebase true

我要感谢@LaurensHolst对我之前的发言提出质疑和追求。我当然已经了解了更多有关git如何与pull和merge提交一起工作的知识。

有关合并的提交,你可以阅读更多的信息为一个项目贡献ProGit图书。在私人小团队部分显示合并的提交。


7
“使用重载而不是在合并时进行合并可以为共享存储库提供正确的历史记录。使用合并提供了错误的历史记录。” —支持这个相当大胆的声明的理由是什么?合并的历史记录不可能是“虚假历史记录”。这是对事物发生顺序的准确描述。您通过重新基准进行的操作实际上是在更改历史记录,以创建一个稍微线性的版本。您为了美观而牺牲了准确性。也许您更喜欢做某事,但绝不更真实。
劳伦斯·霍尔斯特

2
使用rebase而不是merge并不会牺牲准确性。我们使用--no-ff进行合并,因此美观不是必需的。准确性是一种愿望。变基提供了这种准确性。
比尔

2
重新记录的历史记录如何更准确?您没有弄清楚,我也不知道会怎样。
劳伦斯·霍尔斯特

1
历史记录反映了共享存储库中提交的时间。一天1,共享存储库看到提交C2。在第2天,共享存储库看到提交C3。如果C3早于C2,那么时间的反映将是不正确的。C3不在C2之前。所做的所有修改工作是重新组织本地存储库上的提交,以正确反映共享存储库显示的历史记录。
Bill Door

6
您的问题使我重新审视了对合并提交的理解。我的图不正确。我正在修改讨论。我的结论也不正确。重新设置和合并的历史记录同样正确。您可以自己选择。
Bill Door

11

你可以做:

git pull --rebase

但是,这总是将您的更改放在合作者的基础上。但是您不会收到任何污染合并消息。


9

实际上,对此有一个简单得多的答案。只需让开发人员B在提交之前进行拉动即可。这将防止这些合并提交,因为它们是由您在本地存储库中尝试与远程存储库上的提交历史记录合并的本地存储库中的历史记录引起的。如果您在进行拉取时收到一条消息,说“更改将被覆盖”,则表示您都触摸了同一文件,因此:

git stash
git pull
git stash pop

那么您可以解决任何合并冲突(如果有)。


最为烦人和焦虑的正是合并冲突。我宁可避免这种情况
绿色的

1
@Green如果您担心合并冲突,那么即使git pull也不例外。
Zoso

除了一次忘记stash之前pull。Ugh git要求我一直处于游戏的顶端。
linuxNoob

git pull --rebase无论如何,都需要在本地更改之前集成远程更改。
vonbrand

7

进行git pull将插入“合并分支”消息,这就是它的作用。通过执行git pull,您已将远程分支合并到本地分支。

当您执行git pull并存在冲突时,git日志会将冲突文件的更新显示为来自解决冲突的用户。我认为这是因为解决冲突的人重新提交了文件。

据我所知,这只是git的工作方式,没有办法解决。

重新设定基准会破坏git历史记录,因此您将无法查看何时发生合并。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.