两种git重定基址方法之间的差异

两种git重定基址方法之间的差异,git,git-rebase,Git,Git Rebase,我想执行从主机到我的本地分支的更新,该分支已在时间轴上从主机分支出来(从M2更改)。 Master用Mchanges表示,我的本地分支用Lchanges表示 新分支是从master的M2创建的: M1->M2-->M3->M4 \ L1->L2 我想我的结果应该是针对我的本地分支机构,如下所示: M1->M2->M3->M4->L1->L2 这意味着重新创建我的本地分支,使其首先具有所有主更改,然后才在其上具有

我想执行从主机到我的本地分支的更新,该分支已在时间轴上从主机分支出来(从M2更改)。 Master用
M
changes表示,我的本地分支用
L
changes表示

新分支是从master的
M2
创建的:

 M1->M2-->M3->M4
      \
       L1->L2
我想我的结果应该是针对我的本地分支机构,如下所示:

M1->M2->M3->M4->L1->L2
这意味着重新创建我的本地分支,使其首先具有所有主更改,然后才在其上具有我的本地分支更改,如:
(如果我错了,请纠正我)

我的问题是,以下方法之一是否没有创建上述所需的流,如果是,为什么

git checkout master
git pull --rebase 
git checkout branch_to_update
git rebase master` (method mentioned in attlasian tautorial)
VS

假设这两种情况具有相同的效果

在第一种情况下,您正在更新
主文件的本地副本,然后重新定基

在第二种情况下,您直接从远程存储库重定基址

当您可能不想费心更新要从中重定基址的分支的本地副本时,请使用第二个选项

例如,我们有一个main
develope
分支,我们将其作为主题分支,例如,
feature/0001
。工作时,我会不时检查
feature/0001
并简单地
git pull-r origin develope
。在这种情况下,拥有
develope
的本地最新副本是不相关的

合并我的功能分支后,我签出并拉取
development
,然后从更新的副本创建一个新的
feature/0002
分支


此外,请注意,它实际上会产生以下结果:

M1 -> M2 -> M3 -> M4 -> L1' -> L2'
我所说的
L1'
是什么意思?大致上,它将创建一个具有相同内容的新提交(具有新的SHA标识符)。因此,它本身并不相同

这是相同的结果,但方式不同
pull--rebase
参数简单地使用rebase

与其他两个答案一样,效果基本相同。但还有更多。为了了解原因和原因,我们应该将git-pull分解为它的组成部分

所有挑剔的细节(警告:长) 除了一些小的例外(例如在完全空的存储库中运行它),
git pull
意味着:

  • 使用各种选项和参数运行
    git fetch
    ;然后
  • 运行第二个Git命令,该命令在运行步骤1之前选择,并带有各种选项和参数
  • 第二个命令通常是
    gitmerge
    ,但是您可以告诉git使用
    gitrebase
    。传递给这两个命令的选项和参数取决于传递给
    git pull
    的选项和其他配置设置,以及步骤1中获取的一个或多个结果

    不过,作为一种一般规则,传递给
    git pull
    的参数被传递给
    git fetch
    ,因此这意味着传递
    origin master
    git pull
    的第二个命令序列也将
    origin master
    传递给
    git fetch
    。如果在没有这些参数的情况下运行
    git pull
    ,就像在第一个命令序列中一样,git会从您的配置中提取远程(通常是
    origin
    )和上游分支名称(通常与当前分支名称相同),特别是从这两个命令的结果中:1

    (其中,
    $branch
    是当前分支)。如果当前分支为
    master
    ,则将使用
    branch.master.remote
    作为远程分支。这就是我们假设只有一个遥控器的意思。
    merge
    名称可能是
    master
    ,但如果不是,那是我们必须做出的另一个假设,然后才能声称它们做同样的事情


    1如果您的Git足够大,
    Git pull
    是一个shell脚本,它可以运行各种其他Git命令。如果是较新的,
    git pull
    已转换为C语言程序,并直接内置这些程序


    重新设置副本的基础,然后切换到新副本 如果我们深入研究所有细节,
    git-rebase
    所做的事情会变得复杂,但在较高的层次上,它的工作是复制提交。要查看它将复制哪些提交,您应该绘制提交图,或者使用
    git log--graph
    让git为您绘制提交图。(有些GUI总是绘制它,有些web界面*cough*GitHub*cough*从不让您查看!)使用图形绘制,很容易,有时也很容易判断复制了哪些提交:

    ...--A--B--C--D   <-- master
             \
              E--F--G   <-- br
    
    现在我们可以看到,我们必须将
    br
    重新设置到
    origin/master
    上,以便副本在提交
    D
    之后进行。重新定位到
    master
    将把副本放在
    B
    之后,这就是原件所在的位置,因此根本不需要复制。(例如,重设基址是实际复制,还是仅仅重新使用原件,是一个很挑剔的细节:这取决于
    -f
    选项。)

    复制完成后,
    git-rebase
    只需将分支名称重新指向最终复制(或重复使用)的提交,我们可以在这里调用
    G'
    ,以注意它是
    G
    的副本。虽然HEAD和原始分支的reflog条目以及名称
    ORIG_HEAD
    临时保留它们,但原始提交实际上已被放弃:

                   E'-F'-G'  <-- br
                  /
              C--D   <-- origin/master
             /
    ...--A--B   <-- master
             \
              E--F--G   [abandoned, but see ORIG_HEAD and reflogs]
    
    这将把我们的
    连接到我们的
    主机
    ,检查提交
    B
    ;然后,假设上游是
    origin/master
    ,运行
    git fetch origin master
    更新我们的
    origin/master
    ,在这种情况下,
    origin/master
    指向
    D
    。如果我们没有运行
    git fetch
    ,这将获得提交
    C
    D
    ,并将我们的
    origin/master
    指向
    D

    最后,它将运行git-rebase
    。rebase操作使用哈希I
    git checkout branch_to_update
    git pull --rebase origin master
    
    git config --get branch.$branch.remote
    git config --get branch.$branch.merge
    
    ...--A--B--C--D   <-- master
             \
              E--F--G   <-- br
    
              C--D   <-- origin/master
             /
    ...--A--B   <-- master
             \
              E--F--G   <-- br
    
                   E'-F'-G'  <-- br
                  /
              C--D   <-- origin/master
             /
    ...--A--B   <-- master
             \
              E--F--G   [abandoned, but see ORIG_HEAD and reflogs]
    
    git checkout master
    git pull --rebase 
    
    git checkout br
    git rebase master
    
                    E'-F'-G'  <-- br (HEAD)
                   /
    ...--A--B--C--D   <-- master, origin/master
             \
              E--F--G   [abandoned]
    
    git checkout br
    git pull --rebase origin master
    
                   E'-F'-G'  <-- br
                  /
              C--D   <-- origin/master
             /
    ...--A--B   <-- master
             \
              E--F--G   [abandoned]
    
    git fetch origin master
    
    git checkout <whatever-name>
    git rebase origin/<whatever-other-name>