关于git pull的merge / rebase步骤的困惑 [英] Confusions about the merge/rebase step of git pull

查看:302
本文介绍了关于git pull的merge / rebase步骤的困惑的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述


在第二步中的第二步中, 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 merge FETCH_HEAD的缩写。

    更精确地说,git pull使用给定的参数运行git fetch,并且
    调用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 by HEAD, and it is not necessarily master.

    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 to git pull that specifies the target branch in the merging step? If I am correct, the refspec argument to git 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 by HEAD) 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆