git pull、git fetch+merge和git rebase之间的区别

4
我对git pull, git fetch + git mergegit rebase之间的区别感到困惑。它们似乎都有相同的功能,那么特别是在提交日志方面,它们之间有什么区别呢?
如果远程分支和本地分支都有更改,那么在这三种情况下谁的提交将首先出现?

“谁的提交会先出现” - 听起来像是一个实验! - Sergio Tulentsev
那似乎是 http://learngitbranching.js.org/ 的任务。 - VonC
合并 vs. 变基 - Alexan
1
可能是What is the difference between 'git pull' and 'git fetch'?的重复问题。 - Andrew C
@AndrewC,我不同意这是一个重复的问题,他更关注了解后的影响,尽管问题可以缩小范围,关注最终结果(如何影响提交日志和本地/远程存储库提交历史记录)。 - LightCC
3个回答

3
正如你在问题中暗示的那样,最令人困惑的部分是理解本地存储库与远程存储库之间的影响,以及所有其他人与远程存储库一起工作时的部分影响。首先,就像其他答案所指出的那样,“git pull”与“git fetch”+“git merge”是完全相同的。这两个命令从您本地存储库从远程拉取/获取+合并的角度来看。这发生在您在远程上本地检出的相同分支到本地的该分支。我将首先讨论这些,然后是压缩和重置基础。
Git Pull / Git Fetch + Git Merge 假设您已经在本地检出了“master”,您将从远程获取“master”(除非您对这些命令使用了更高级的语法或标志)。让我们将远程分支称为“origin/master”。
从“origin/master”获取意味着您要获取“origin/master”的新提交,并更新您的本地跟踪引用以匹配远程上实际存在的“master”。如果“master”在本地和远程之间分歧,则将有一个从您的主分支分支出的提交,直到它们达到“origin/master”的当前位置。您尚未推送的最近提交将位于可能不同的本地“master”分支上。
然后,在合并发生时,您基本上要求将“origin/master”合并到本地的“master”分支中。如果您执行普通的合并命令,则会在本地的“master”分支上生成一个新的提交,该提交将从“origin/master”中获取所有最近的更改,并将其合并到本地的“master”分支中。如果存在冲突,则需要先解决它们,然后再提交。但是,如果您尚未在本地提交任何内容,则合并可以快进到新的“origin/master”位置,而无需做其他任何事情(您的“master”只会跳转到匹配“origin/master”的新位置)。
此时,如果在其他人推送任何内容到远程之前推送,则您的新合并提交将与您的单独提交一起推送(它们看起来像一个未命名的分支),以及原始远程提交和一个新的合并提交。
那么压缩呢? 虽然您确实询问了这个问题,但是如果您使用--squash进行合并,则会添加合并提交,但删除其他本地提交,因此历史记录中不会有额外的未命名分支。有些人喜欢这样做,因为它更加“清洁”,而其他人则喜欢看到所有历史记录(即代码分叉以及在合并提交中确切地汇总了什么)。
重置基础
当你使用rebase时,基本上是将所有本地提交记录重放到远程主分支上,这样它们就不会显示为一个单独的分支。这样可以保持本地历史记录的完整性,而不显示代码分歧,有些人认为这样更加"干净"。这与该历史记录是否重要无关。
如果在你获取之后,其他人进行了提交,那么你的推送将失败。你可以使用--force选项,但这样会完全覆盖他们的提交,因此通常被视为不好的做法,因为这会给其他人带来各种问题。在这种情况下,如果每个人都同意他的提交应该先进行,那么你需要重新进行这个过程(如果没有冲突,那么这很快、很容易),但一般来说,团队需要对这种情况制定政策,通常使用拉取请求和审核来管理推送,以便更有序地进行操作,一旦团队足够大。
还有一种思考方式,就是将你的本地主分支视为远程的一个独立分支 - 这基本上是Git的观点。实际上,在我看来,除非你准备将某些东西合并到远程分支,否则最好始终在自己的独立分支中工作。Git使得拥有一个独立分支变得如此容易、快速和无痛,这就是我所做的。

1

我建议使用谷歌搜索一下。 git pull = 先执行git fetch,再执行git merge。当你谷歌搜索git pull时,第一个结果是:https://git-scm.com/docs/git-pull:

在默认模式下,git pull是git fetch后面跟着 git merge FETCH_HEAD的缩写。

git rebase 完全不同,与远程无关。同样,通过谷歌可以解决你的问题,但简短的图形说明如下:当你处于分支A上,并在其之上进行rebase操作时,它与处于A上并将B合并到其内是不同的:

c1-c2-c3<-A
 \-c4-c5<-B

变成
c1-c4-c5-c2-c3<-A
       ^
       B

我们所做的是将A上的不同提交应用到B之上,基本上删除了分支结构。永远不会有像"合并提交"这样的"变基提交"。这与远程无关,除了git pull --rebase会获取并在远程的基础上重新进行变基,而不是将远程的内容合并到本地提交中。再次提醒,可以参考google.com或git-scm.com/docs。

0

来自git文档

git pull 将远程仓库的更改合并到当前分支中。在默认模式下,git pullgit fetchgit merge FETCH_HEAD 的缩写

rebase 可以重新应用提交到另一个基础提示之上。

所以你可以在执行了fetch操作后使用git rebase FETCH_HEAD

所以如果你有

(*) <-- HEAD
 |
(*) <-- commit B
 \   (*) <-- origin/master
  \  /
   (*) <-- commit A

如果您使用rebase,Git将会将您的HEAD回退到提交A,并按日期顺序应用所有提交。
如果您使用merge,Git将合并两个分支为一个单一的分支,并将您的提交应用于origin/head的顶部。

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