我想从master到我的本地分支执行更新,该分支在时间轴上从早期分支出来(从M2更改)。
Master用M
更改表示,我的本地分支L
更改
新分支是从主人的M2
:
M1->M2-->M3->M4
\
L1->L2
我想我的结果应该是我当地的分支机构如下:
M1->M2->M3->M4->L1->L2
这意味着重新创建我的本地分支以首先进行所有主更改,然后我的本地分支在其上更改,如下所述:
https://www.atlassian.com/git/tutorials/merging-vs-rebasing
(如果我错了,请纠正我)
我的问题是,下列方法之一是否未创建上述所需流程,如果是,为什么?
git checkout master
git pull --rebase
git checkout branch_to_update
git rebase master` (method mentioned in attlasian tautorial)
VS
git checkout branch_to_update
git pull --rebase origin master
答案 0 :(得分:3)
假设there is only one remote repository,这两者将具有相同的效果。
在第一种情况下,您要更新master
的本地副本,然后重新定位。
在第二种情况下,您直接从远程存储库重新定位。
当您可能不想更新您正在变基的分支的本地副本时,请使用第二个选项。
例如,我们有一个主develop
分支,我们可以在其中创建主题分支,例如feature/0001
。在工作期间,我会不时地feature/0001
签出git pull -r origin develop
。develop
。在这种情况下,拥有develop
的本地最新副本是无关紧要的。
在合并我的功能分支后,我结帐并拉出feature/0002
,然后从该更新的副本中创建一个新的M1 -> M2 -> M3 -> M4 -> L1' -> L2'
分支。
此外,请注意,它实际上会创建 this :
L1'
for (int i = 0; i < 12; i++) {
cout << "Month number " << i + 1 << endl;
array[i] = i+1;
}
我的意思是什么?粗略地说,它将使用相同的内容创建一个新的提交 - 使用新的SHA标识符。所以它本身不是提交 。
答案 1 :(得分:2)
与其他两个答案一样,效果通常几乎相同。 msanford has pointed out one definite and one potential difference但还有更多。为了了解什么和为什么,我们应该将git pull
反汇编成其成分。
除了一些小的例外(例如在完全空的存储库中运行它),git pull
表示:
git fetch
;然后第二个命令通常是git merge
,但您可以告诉Git使用git rebase
。传递给这两个命令的选项和参数取决于传递给git pull
的选项和其他配置设置,以及步骤1中获取的结果或结果。
但是,作为一种一般规则,传递给git pull
的参数将传递给git fetch
,这意味着您的第二个命令序列 - 将origin master
传递给git pull
} - 也将origin master
传递给git fetch
。如果您在没有这些参数的情况下运行git pull
,就像在第一个命令序列中一样,Git会提取远程(通常是origin
)和您的配置中的上游分支名称(通常与当前分支名称相同),特别是来自这两个命令的结果: 1
git config --get branch.$branch.remote
git config --get branch.$branch.merge
(其中$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
会复制三次提交,此处为E
到G
,在提交D
后放置副本。这与你画的类似。
假设我们添加origin/
远程跟踪名称,并显示您自己的master
当前指向提交B
,而origin/master
当前指向提交{{1}像这样:
D
现在我们可以看到,我们必须将 C--D <-- origin/master
/
...--A--B <-- master
\
E--F--G <-- br
重新定位到br
,以便在提交origin/master
之后复制副本。重新定位到D
会将副本放在master
之后,这是原件所在的位置,因此根本不需要复制。 (无论rebase实际上是复制还是只是重新使用原件,都是一个挑剔的细节:例如,它取决于B
选项。)
复制完成后,-f
只需将分支名称重新指向最终复制(或重复使用)的提交,我们可以在此处调用git rebase
来注意它&# 39; G'
的副本。虽然HEAD和原始分支的reflog条目以及名称G
暂时保留了原始提交,但原始提交已被有效放弃:
ORIG_HEAD
默认情况下,reflog条目使原件至少可以保留30天。最终 E'-F'-G' <-- br
/
C--D <-- origin/master
/
...--A--B <-- master
\
E--F--G [abandoned, but see ORIG_HEAD and reflogs]
由于其他操作而转移到其他地方,并且reflog条目到期,原始提交被垃圾收集。
为了论证,我们假设我们有上面的图表(就像你的一样,但在分支ORIG_HEAD
上还有一个提交,我们已经运行br
来获取{{1 }} 更新)。然后Atlassian命令序列以这两个命令开始:
git fetch
这会将我们的origin/master
附加到我们的git checkout master
git pull --rebase
,并检查提交HEAD
;然后,假设上游为master
,请运行B
更新我们的origin/master
,在这种情况下,git fetch origin master
指向origin/master
。如果我们尚未运行origin/master
,那么获取提交D
和git fetch
并将C
指向D
。
最后,这将运行origin/master
。 rebase操作使用哈希ID,因为它使用D
在git rebase <hash-of-commit-D>
中留下的跟踪,并且根据确切的Git版本以及我们在这里忽略的更多详细信息,还使用git fetch
找到提交哈希以便从上游rebase恢复。 (这个过程有时会出错,取决于你自己的工作流程,我不确定我是否喜欢默认行为。)
完成所有操作后,我们将完成最后两个命令:
.git/FETCH_HEAD
第一个将git merge-base --fork-point
附加到名称git checkout br
git rebase master
,检出提交HEAD
。然后,rebase将br
提交序列复制到G
现在指向的提交之后。因此,忽略所有reflog条目,我们得到图表:
E-F-G
将此与较短的命令序列进行比较:
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
。 HEAD
运行br
,确保我们提交pull
(如果我们尚未提取)并更新git fetch origin master
(如果我们的Git至少为1.8.4) ),然后运行复制C-D
链的origin/master
,给出:
git rebase <hash-of-D>
因此,关键区别在于您自己的名称E-F-G
永远不会更新为指向提交 E'-F'-G' <-- br
/
C--D <-- origin/master
/
...--A--B <-- master
\
E--F--G [abandoned]
。
重要的是要注意(并且知道)如果你自己运行master
- 这是我首选的方法 - 这将告诉你的Git调用另一个Git在远程的URL上,并为你的Git提供了另一个Git列表,所有(我们假设的原点)分支。然后,您的Git将获取所有他们所拥有的提交,并将它们放入您的Git存储库中,并更新您所有的遥控器 - 跟踪D
和git fetch
之类的名称,等等。
换句话说,您的远程跟踪名称(即Git记住 分支的方式)将所有更新。这通常是件好事。如果他们有很多分支机构和大量提交并且你的网络连接很慢,那就很糟糕;在这种情况下,您可能需要等待很长时间才能下载所有内容。
当origin/master
运行origin/develop
时,它会使用限制选项运行它。例如,如果您的git pull
运行:
git fetch
告诉您的Git在git pull
的网址上调用Git,并要求他们仅将 > 提交给他们的git fetch origin master
。如果他们对origin
以及master
和develop
等进行了更新,那么您将无法获得其中的任何内容 - 您只会获得{{1}上的新提交}}。您的Git会更新您的production
以记住新提交, 2 ,但不会更改其余的远程跟踪名称。
在第二个命令序列中,您运行一个明确的feature/tall
(同时也带有master
),这会限制您的Git更新origin/master
。在第一个命令序列中,您运行git pull origin master
但没有参数 - 但--rebase
插入origin/master
和git pull
,假设这些是已配置的设置您的git pull
分支,因此这也限制了您的Git只更新了您的origin
。
我提到这一切是因为我建议不要使用master
。自己运行master
- 您可以让它默认从origin/master
获取所有内容 - 然后运行您想要的任何git pull
命令!在git fetch
之后,您拥有所有提交和所有相应的origin
名称;然后你可以运行:
git rebase
复制任何提交和/或调整您想要更新的自己的分支名称。一次提取允许您执行任意数量的合并,重置,快进伪合并或rebase操作。在决定运行其他Git命令之前,您还可以查看获取的内容!
2 这假设你的Git至少是版本1.8.4。如果没有,这种fetch
甚至无法更新origin/*
。您必须运行git checkout <whatever-name>
git rebase origin/<whatever-other-name>
或git fetch
才能更新远程跟踪名称!
答案 2 :(得分:0)
git checkout branch_to_update git rebase master
或
git checkout branch_to_update git pull --rebase origin master
这些结果相同但方式不同
pull --rebase
参数简要使用rebase