GitHub合并分支'master'

45

使用svn多年后,我尝试使用Git和Github。我似乎已经掌握了基础知识,但有一项让我感到困惑。

  • UserA对FileA进行更改并推送到远程服务器(GitHub)

  • UserB更改了FileB。他首先从远程服务器拉取,然后将自己的更改推送到FileB到远程服务器

  • Github提交历史记录显示了来自UserA和UserB的推送

  • 然而,在提交历史记录中还有一个名为“Merge branch 'master' of https://github.com/xxx/yyy'的来自UserB的附加条目。在Github中查看差异显示它是FileA中UserA所做更改的精确副本。

为什么会显示这个重复 - UserA对FileA的推送和Merge branch master条目是完全相同的...第二个对我来说似乎是多余的。

1个回答

73

git 中存储的每个版本(“提交”)都形成一个图形,通常有助于从该图中思考你在 git 中所做的操作。

当用户A开始时,假设只创建了两个提交,我们将它们称为PQ

P--Q (master)

然后他修改了FileA,暂存该更改并创建一个提交以表示源代码的新状态 - 假设该提交名为R。它有一个父提交,即提交Q

P--Q--R (master)
成功推送后,GitHub存储库的提交记录图看起来与之前相同。 UserB 的历史记录也是相同的。
P--Q (master)

... 但是他创建了一个不同的提交版本,比如称为S,其中包含他修改过的FileB文件:

P--Q--S (master)

UserB试图将内容推送到GitHub,但推送被拒绝 - 如果不"强制"推送,你无法更新远程分支,除非你所推送的版本包含该远程分支中所有历史记录。因此,UserB从GitHub拉取了代码。拉取实际上包括两个步骤:获取和合并。获取会更新origin/master,这类似于来自远程仓库originmaster分支状态的缓存。(这是"远程跟踪分支"的一个示例。)

P--Q--S (master)
    \
      R (origin/master)

这张图中的历史记录已经分叉了,所以合并尝试通过创建一个合并提交(比如 M),将两个历史记录统一起来,并希望代表来自两个分支的更改:

P--Q--S--M (master)
    \   /
     \ /
      R (origin/master)
当GitHub向您展示代表提交所引入的更改的差异时,在只有一个父提交的情况下,很容易进行差异比较 - 它只需要从那个版本开始进行差异比较。然而,在像M这样具有多个父级的提交中,它必须选择一个父级来显示与之进行差异比较。这就解释了为什么合并提交M所显示的差异可能看起来与SR中的一个相同。在Git中,提交是通过源树的确切状态来定义的,而不是得到该状态的更改。

2
这是否意味着,如果UserB在拉取FileA的更改后才修改并推送FileB,则不会创建合并分支'master'?如果是的话,那我就明白了。 - JonoB
是的,如果用户B在创建引入文件B更改的提交之前进行了拉取操作,就不会有合并提交 - 它就像创建具有单个父项的任何其他提交一样。 - Mark Longair
4
值得注意的是,(a) 许多人使用 git pull --rebase 使历史线性化 - 在获取(fetching)后,它会尝试重新应用任何不在 origin/master 中的提交。 (b) 如果您尝试合并到当前分支的提交已经包含了当前分支的历史记录,则默认情况下Git不会创建合并提交 - 它只会将您的分支"快进"到正在合并的分支状态。 - Mark Longair
13
我们使用git config --global branch.autosetuprebase always命令将远程分支设置为自动执行git pull --rebase操作。可以通过git config branch.<branch>.rebase true来单独设置某个分支。这样可以防止引入额外的合并提交,使历史记录更加一致和规律。 - Bill Door

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