关于git pull的merge / rebase步骤的困惑 [英] Confusions about the merge/rebase step of git pull
问题描述
在第二步中的第二步中, pull操作,Git执行
合并(默认)或rebase操作。
关于git pull中的合并步骤:
在这个例子中,Git将
远程追踪分支origin / master的内容合并到您的本地追踪
分支中,master strong>,使用一种称为
快速转发的特殊类型的合并。
但Git知道如何合并这些特定分支机构?答案
来自配置文件:
[branchmaster]
remote = origin
merge = refs / heads / master
解释一下,这给了Git两个关键信息:当master
是当前的已签出分支时,请使用origin作为默认远程
,在提取(或提取)期间从其中获取更新。
此外,在git pull的合并步骤中,使用来自远程的refs / heads / master
作为默认分支以合并到主
分支中。
-
一般而言,合并步骤是否将远程追踪分支合并到
master
或当前分支?我的猜测是当前分支,即由HEAD
指向的分支,它不一定是master
。
请注意,我的猜测来自 https:// git- scm.com/docs/git-pull
将来自远程存储库的更改合并到当前
更精确地说,git pull使用给定的参数运行git fetch,并且
分支。在其默认模式下,git pull是git fetch
后面跟着git merge FETCH_HEAD的缩写。
调用git merge来将检索到的分支头合并到当前
分支中。
-
git pull 远程跟踪分支总是合并到当前分支中吗? (我的猜测是肯定的)。
如果没有,是否有参数指向合并步骤中的目标分支git pull
>?
如果我是正确的,refspec
参数git pull
不会指定合并的目标分支为什么合并是快进合并?
关于git pull中的rebase步骤: b
命令git pull --rebase会在仅此拉取期间将Git重新绑定(而非
合并)本地追踪分支到远程追踪分支
。
- 是否正确:
git pull
rebase当前分支(即HEAD
指向的分支)到远程跟踪分支上?
如果是的话,那么为什么报价中会显示您的本地追踪分行而不是当前分行?
一般来说,合并步骤是否将远程追踪分支合并到主分支或当前分支?
这两个是相同的: master
是您当前的分支。远程跟踪分支是 origin / master
。
(其中 origin
)仅仅是用于远程的默认名称,而不是任何特殊的Git关键字 master
是默认分支,实际名称在实际场景中可能会有所不同。)
$ c> 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
下的两个本地提交会在UPSTREAM之上重写:
YOURS(master)
*< - 重写:SHA更改
\
YOURS的ghost *< - 重写:SHA更改
* ---- * \
\ * UPSTREAM(origin / master)
\ /
*
|
现在情况是,本地分支 master
超过 origin / master
2个提交。你准备好了(尝试) git push
。
原始的unrewritten提交依然存在(用ghost在ASCII图中)。它们在 git reflog
中被引用。当它们从那里过期或被手动清除时,它们会变成垃圾,最终会被垃圾收集。
使用 git merge
你做了其他的事情:你的改变被合并到 origin / master
中,并且创建了一个新的提交,它有两个父母:
* YOURS合并(主)
/ \
YOURS / \
* |
\ | UPSTREAM(origin / master)
* *
\ /
* < - git merge-base master origin / master
|
*
现在您的主人
在1次提交之前位于 origin / master
之前。如果您现在成功推送,则远程存储库的 master
也将采用上述形状,双亲提交一条路径上的更改,并沿着上一个上游提交另一条路。没有鬼的鬼魂:你的改变从未被重写过。
为什么合并是快进合并?
快速合并或重新绑定发生在两种情况下。一个是 origin / master
没有任何平行变化:
YOURS(master)
*
\
*
\
* UPSTREAM(origin / master)
|
*
在上面的例子中,没有什么可做的:一切都是最新的,日期,并且您在两次提交之前领先于 origin / master
。因此,这不是一个快进的东西;一个 git merge
或 git rebase
根本就不会做任何事情。如果您对这些提交感到满意,您可以尝试 git push
。
真正的快进场景发生在您没有任何本地变更:
* UPSTREAM(origin / master)
/
YOURS (主)*
|
*
在这种情况下,如果您执行 git rebase
或 git merge
,那么默认情况下,您的 master
HEAD
指针只是向前滑动指向与 origin / master
相同的提交,并且此幻灯片是快进:
YOURS(master)* UPSTREAM(origin / master)
/
*< - 主从这里向前滑动
|
*
快进术语可能指的是只有 HEAD
指针移动(以及重写本地文件系统树以匹配)。没有新的提交必须被写入或重写。
在分歧的情况下快速前进是不可能的(除非抛弃本地更改)。必须生成新的合并提交,或者必须重写某些更改。在这些操作之前,不存在 master
只能向前滑动的任何提交。
有些人使用Git以某种方式让他们的所有本地工作承诺合并。当没有新的工作上游合并时,可以强制Git使用 git merge --no-ff
(无快进)进行合并提交。从这开始:
YOURS(主)
*
\
*
\
* UPSTREAM(origin / master)
|
*
你得到这样的东西:
---- * YOURS-合并(主)
YOURS / |
* |
\ |
* |
\ |
* UPSTREAM(产地/主)
|
*
这个想法是在历史的主线路径中出现两个变化凝聚成一步。另一位家长可以通过多次提交来查看详细的血统。
为什么报价说你的本地 - 跟踪分支而不是当前分支?
这是一个错误。涉及的所有分支都是本地的(在您的存储库中)。有工作分支(如 master
)和它的远程跟踪分支(如 origin / master
)。两者都是本地的。
你工作的分支不叫做追踪分支;它不会跟踪任何内容。
有些本地分行不与远程追踪分行配对。所有没有远程仓库的分支(例如,由 git init
创建的)都是纯粹的本地仓库。任何本地创建的分支纯粹是本地的,除非推送到远程仓库。
远程追踪分支是一个类似分支的对象,它与本地分支配对。它会跟踪上游在做什么。每次执行 git fetch
时,它都可能被重写为指向一些不同的提交。本地分支不受影响。这两者可能会发生分歧,这可以通过重组或合并来解决。在执行 git push
时,本地分支会更新上游回购中的实际远程。当这个操作成功时(不被远端拒绝),那么本地跟踪分支也会更新指向同一个提交,所以它们保持同步。
在正常情况下,纯粹的本地操作不会改变 origin / master
:它跟踪远程回购中相应分支的状态。
From Version Control with Git by Loeliger 2ed, about the merge or rebase step in git pull:
In the second step of the pull operation, Git performs a merge (the default), or a rebase operation.
About the merge step in git pull:
In this example, Git merges the contents of the remote-tracking branch, origin/master, into your local-tracking branch, master, using a special type of merge called a fast-forward.
But how did Git know to merge those particular branches? The answer comes from the configuration file:
[branch "master"] remote = origin merge = refs/heads/master
Paraphrased, this gives Git two key pieces of information: When master is the current, checked out branch, use origin as the default remote from which to fetch updates during a fetch (or pull). Further, during the merge step of git pull, use refs/heads/master from the remote as the default branch to merge into this, the master branch.
Generally speaking, does the merge step merge the remote tracking branch into
master
or the current branch? My guess is the current branch, i.e. the branch pointed byHEAD
, and it is not necessarilymaster
.Note my guess is from https://git-scm.com/docs/git-pull
Incorporates changes from a remote repository into the current branch. In its default mode, git pull is shorthand for git fetch followed by git merge FETCH_HEAD.
More precisely, git pull runs git fetch with the given parameters and calls git merge to merge the retrieved branch heads into the current branch.
Does
git pull
merge the remote tracking branch always into the current branch? (My guess is yes). if not, is there an argument togit pull
that specifies the target branch in the merging step? If I am correct, therefspec
argument togit pull
doesn't specify the target branch for merging step.why is the merge a "fast-forward merge"?
About the rebase step in git pull:
The command git pull --rebase will cause Git to rebase (rather than merge) your local-tracking branch onto the remote-tracking branch during only this pull.
- Is it correct that the rebase step of
git pull
rebase the current branch (i.e. the branch pointed byHEAD
) onto the remote tracking branch? If yes, why does the quote says "your local-tracking branch" instead the current branch?
Generally speaking, does the merge step merge the remote tracking branch into master or the current branch?
Those two are the same: master
is your current branch. The remote tracking branch is origin/master
.
(Where origin
is just the default name used for a remote, not any special Git "keyword", and master
is the default branch. Actual names may differ in actual scenarios.)
The target of a rebase
or merge
operation (where the resulting changes will go) is the current branch.
Git will fight you if you try to do something silly like checkout origin/master
to try to make a tracking branch current.
So, the target of the merge is master
. The question is, what gets merged? If you pull some new upstream material, you may end up with (for example) this situation:
YOURS (master)
*
\ UPSTREAM (origin/master)
* *
\ /
* <--- "git merge-base master origin/master"
|
*
master
and origin/master
have diverged, and have 2 and 1 new commits, respectively.
With git rebase
, the two local commits under YOURS
get rewritten over top of UPSTREAM:
YOURS (master)
* <-- rewritten: SHA changes
\
ghost of YOURS * <-- rewritten: SHA changes
* ---- * \
\ * UPSTREAM (origin/master)
\ /
*
|
Now the situation is that "local branch master
is ahead of origin/master
by 2 commits". You are ready to (try to) git push
.
Your original unrewritten commits still exist (denoted by "ghost of YOURS" in the ASCII diagram). They are referenced in the git reflog
. When they expire from there or are manually cleared, they become garbage, which is eventually garbage-collected.
With git merge
you do something else: Your changes are merged against origin/master
and a new commit is created which has two parents:
* YOURS-merged (master)
/ \
YOURS / \
* |
\ | UPSTREAM (origin/master)
* *
\ /
* <--- "git merge-base master origin/master"
|
*
Now your master
is ahead of origin/master
by 1 commit. If you successfully push now, the remote repository's master
will take on the above shape also, with the two-parent commit with your changes along one path, and the previous upstream commit along the other path. There is no "ghost of YOURS": your changes were never rewritten.
why is the merge a "fast-forward merge"?
A fast-forward merge or rebase happens in two scenarios. One is that origin/master
doesn't have any parallel changes:
YOURS (master)
*
\
*
\
* UPSTREAM (origin/master)
|
*
In the above case there is nothing to do: everything is up-to-date and you are ahead of origin/master
by two commits. Thus, this is not a "fast forward anything"; a git merge
or git rebase
will simply do nothing at all. You can try to git push
if you are happy with those commits.
The true fast-forward scenario occurs when you don't have any local changes:
* UPSTREAM (origin/master)
/
YOURS (master) *
|
*
In this case if you do a git rebase
or git merge
, then by default, your master
HEAD
pointer just "slides ahead" to point to the same commit as origin/master
, and this slide is the "fast forward":
YOURS (master) * UPSTREAM (origin/master)
/
* <- master slid forward from here
|
*
The "fast forward" terminology probably refers to the idea that only the HEAD
pointer moves (along with a rewrite of your local filesystem tree to match). No new commits have to be written or rewritten.
A fast-forward is not possible in the diverging scenarios (unless you throw away your local changes). A new merge commit has to be produced, or a rebase has to rewrite some changes. Before these operations, there doesn't exist any commit to which master
can just slide forward.
Some people use Git in a certain way where they want all their commits of local work to be merges. When there is no new work upstream to merge against, you can force Git to make a merge commit anyway with git merge --no-ff
(no fast-forward). Starting with this:
YOURS (master)
*
\
*
\
* UPSTREAM (origin/master)
|
*
You get something like this:
----* YOURS-merge (master)
YOURS / |
* |
\ |
* |
\ |
* UPSTREAM (origin/master)
|
*
The idea is that in the mainline path of the history, the two changes appear condensed into one step. The other parent can be followed to see the detailed lineage with the multiple commits.
why does the quote says "your local-tracking branch" instead the current branch?
This is a mistake. All branches involved are local (in your repository). There is the working branch (like master
), and its remote-tracking branch (like origin/master
). Both are local.
The branch where you do work isn't called a tracking branch; it doesn't track anything.
Some local branches are not paired with remote-tracking branches. All branches in a repo which has no remote (for instance something newly created by git init
) are purely local. Any locally created branch is purely local unless pushed to a remote repo.
The remote tracking branch is a branch-like object which is paired with a local branch. It keeps track of what the upstream is doing. Every time you do a git fetch
, it is potentially rewritten to point to some different commit. The local branch is unaffected. The two may diverge, and that is resolved by rebase or merge. When you do a git push
, the local branch updates the actual remote one in the upstream repo. When this operation is successful (not rejected by the remote end), then the local tracking branch is also updated to point to that same commit, so they stay in sync.
Under normal circumstances, no purely local operation will change origin/master
: it tracks the state of the corresponding branch in the remote repo.
这篇关于关于git pull的merge / rebase步骤的困惑的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!