一般来说,merge步骤是将远程跟踪分支合并到master还是当前分支?
这两个是相同的:master 是您当前的分支。远程跟踪分支是origin/master。
(其中origin只是用于远程的默认名称,不是任何特殊的Git“关键字”,master是默认分支。实际名称可能因实际情况而异。)
rebase 或 merge 操作的目标(产生的更改将去向)是当前分支。
如果你试图做一些像checkout origin/master 这样愚蠢的事情来试图使跟踪分支成为当前状态,Git 会与你作斗争。
所以,合并的目标是master。问题是,合并了什么?如果你拉一些新的上游材料,你最终可能会遇到(例如)这种情况:
YOURS (master)
*
\ UPSTREAM (origin/master)
* *
\ /
* <--- "git merge-base master origin/master"
|
*
master 和 origin/master 已经分道扬镳,分别有 2 个和 1 个新的提交。
使用git rebase,YOURS 下的两个本地提交会在上游重写:
YOURS (master)
* <-- rewritten: SHA changes
\
ghost of YOURS * <-- rewritten: SHA changes
* ---- * \
\ * UPSTREAM (origin/master)
\ /
*
|
现在的情况是“本地分支master 领先origin/master 2 个提交”。您已准备好(尝试)git push。
您的原始未重写提交仍然存在(在 ASCII 图中用“您的幽灵”表示)。它们在git reflog 中被引用。当它们从那里过期或被手动清除时,它们就会变成垃圾,最终被垃圾收集。
使用git merge,您可以执行其他操作:您的更改将与origin/master 合并,并创建一个具有两个父级的新提交:
* YOURS-merged (master)
/ \
YOURS / \
* |
\ | UPSTREAM (origin/master)
* *
\ /
* <--- "git merge-base master origin/master"
|
*
现在您的 master 比 origin/master 领先 1 个提交。如果您现在成功推送,远程存储库的master 也将呈现上述形状,双父提交沿一条路径进行更改,而先前的上游提交沿另一条路径提交。没有“你的幽灵”:你的更改从未被重写。
为什么合并是“快进合并”?
快进合并或变基发生在两种情况下。一是origin/master没有任何并行变化:
YOURS (master)
*
\
*
\
* UPSTREAM (origin/master)
|
*
在上述情况下,无需做任何事情:一切都是最新的,并且您领先 origin/master 两次提交。因此,这不是“快进任何东西”; git merge 或 git rebase 根本不会做任何事情。如果您对这些提交感到满意,可以尝试git push。
真正的快进场景发生在您没有任何本地更改时:
* UPSTREAM (origin/master)
/
YOURS (master) *
|
*
在这种情况下,如果您执行git rebase 或git merge,那么默认情况下,您的master HEAD 指针只是“向前滑动”以指向与origin/master 相同的提交,这张幻灯片是“快进”:
YOURS (master) * UPSTREAM (origin/master)
/
* <- master slid forward from here
|
*
“快进”术语可能是指只有HEAD 指针移动(以及重写本地文件系统树以匹配)的想法。无需编写或重写新的提交。
在不同的场景中不可能进行快进(除非您丢弃本地更改)。必须产生一个新的合并提交,或者一个 rebase 必须重写一些更改。在这些操作之前,不存在任何 master 可以向前滑动的提交。
有些人以某种方式使用 Git,他们希望所有本地工作的提交都被合并。当上游没有新的工作要合并时,您可以强制 Git 使用 git merge --no-ff 进行合并提交(无快进)。从这个开始:
YOURS (master)
*
\
*
\
* UPSTREAM (origin/master)
|
*
你会得到这样的东西:
----* YOURS-merge (master)
YOURS / |
* |
\ |
* |
\ |
* UPSTREAM (origin/master)
|
*
想法是,在历史的主线路径中,两个变化似乎浓缩为一个步骤。可以关注另一个父级以查看具有多个提交的详细沿袭。
为什么引用说“您的本地跟踪分支”而不是当前分支?
这是一个错误。涉及的所有分支都是本地的(在您的存储库中)。有工作分支(如master)和它的远程跟踪分支(如origin/master)。两者都是本地的。
您工作的分支不称为跟踪分支;它不跟踪任何东西。
某些本地分支未与远程跟踪分支配对。没有远程的仓库中的所有分支(例如 git init 新创建的东西)都是纯本地的。除非推送到远程仓库,否则任何本地创建的分支都是纯本地的。
远程跟踪分支是与本地分支配对的类似分支的对象。它跟踪上游正在做什么。每次您执行git fetch 时,它都可能被重写以指向一些不同的提交。本地分支不受影响。两者可能会出现分歧,这可以通过 rebase 或 merge 来解决。当您执行git push 时,本地分支会更新上游存储库中的实际远程。当此操作成功(未被远程端拒绝)时,本地跟踪分支也会更新为指向同一提交,因此它们保持同步。
一般情况下,纯本地操作不会改变origin/master:它会跟踪远程repo中对应分支的状态。