我正在阅读这篇文章http://supercollider.github.io/development/git-cheat-sheet.html,其中提出了以下工作流程:
git checkout master
git pull --rebase # update local from remote
git rebase master chgs
git checkout master
git merge chgs
git push
我确定我不明白这是如何运作的以及为什么它有用。
第三行git rebase master somechanges
是否在chgs
的最后一次提交后从master
提交了提交但未合并它们,并留下HEAD
指向来自chgs
的最新提交,如下所示:
(master-commit-n-1)<--(master-commit-n)<--(chgs-commit-k-1)<--(chgs-commit-k)<--HEAD
这会让我chgs
签出吗?这就是为什么我需要再次查看master
的原因?
为什么我们需要将更改合并到master中?不能制作这样的图表:
(master-commit-n-1)<--(master-commit-n)<--(chgs-commit-k-1)<--(chgs-commit-k)
\.(master-with-merged-chgs-commit-k)<--HEAD
我不明白为什么顶叉很有用。
答案 0 :(得分:3)
不是第三行
git rebase master somechanges
来自chgs
的提交 在master
的最后一次提交之后但没有合并它们,并离开HEAD
指向chgs
的最新提交,如下所示:(master-n-1) <- (master-n) <- (chgs-k-1) <- (chgs-k) <- HEAD
将chgs
重新定位到master
的效果相当于将master
合并到chgs
,因为上次提交时代码的状态将等同于州在merge
之后。
这会让我
chgs
签出吗?这就是我需要退房的原因 再次master
?
是
为什么我们需要将更改合并到master中?这不是图表 像这样:
(master-n-1) <- (master-n) <- (chgs-k-1) <- (chgs-k) \ (master-with-merged-chgs-k) <- HEAD
没有。由于您在chgs
之上重新定位master
,因此git会认识到chgs
上的最后一次提交实际上代表了master
“+”chgs
的状态,因此它只是将master
分支“快速转发”到chgs
的提示而不进行合并提交:
(n-1) <- (n) <- (k-1) <- (k) <- HEAD/master/chgs
如果您希望 强制 git执行合并提交,您可以将--no-ff
标记传递给merge
:
git merge --no-ff chgs
# Results in this
(n-1) <- (n) <- (k-1) <- (k) <- chgs
\ \
--------------(merge) <- HEAD/master
我不明白为什么上叉很有用。
更新来自master
的上游更改的功能分支非常有用,而无需在功能分支中创建一堆冗余的合并提交。最终结果是您的开发历史变得更简单,更容易使用,而不是包含一些您并不真正需要的额外合并提交,这只会使历史更复杂,更难以操作。
答案 1 :(得分:2)
按顺序:
第三行
git rebase master somechanges
是否在chgs
的最后一次提交后从master
提交了提交但没有合并它们......
是的,假设somechanges
是chgs
的拼写错误(引用的页面使用了更多的拼写)。
并将
的最新提交HEAD
指向chgs
是,但只是间接地:HEAD
字面上包含ref: refs/heads/chgs
,即您选择了分支chgs
。它的chgs
本身指向最新的提交。
这会让我
chgs
签出吗?
是
具体来说,使用on branch ...
时打印为git status
的&#34;当前分支&#34;就是refs/heads/branch
文件HEAD
中的任何内容},HEAD
包含refs: refs/heads/branch
时。首先运行git checkout branch
可确保更新工作树,然后执行此操作并通过重写HEAD
将您置于该分支上。
在内部,git rebase upstream branch
调用git checkout branch
,所以整个过程从让你进入分支开始。
为什么我们需要将更改合并到master中?是不是像[剪掉]那样制作图表?
您需要 1 merge
来移动标签。
我更喜欢使用字母或有时只是小o
个节点绘制提交图,其中单个破折号或短箭头表示父母关系。并且,从git log --graph --oneline --decorate
窃取(但修改)一个叶子,我在右边添加一个带有更长箭头的分支名称。如果HEAD
为分支命名,我会在前面添加HEAD=
。
因此,在变基之后你所拥有的就是:
... - E - F <-- master
\
G - H - I <-- HEAD=chgs
此处标记为F
的提交是分支master
的提示,因此master
指向F
(并且F
指向E
} 等等)。分支chgs
的提示是提交I
; I
指回H
; H
指回G
;并G
指向F
。当然HEAD=chgs
所以你就在那个分支上。
一旦git checkout master
,就像往常一样更新工作树,并使HEAD
指向master
,指向F
。然后,如果您运行git merge chgs
,git会查看是否可以快速前进&#34;合并:
... - E - F <-- HEAD=master
\
G - H - I <-- chgs
当前提交(在这种情况下为F
)已经是目标提交(I
)的祖先时,可以进行快进合并。如果是这样,分支标签将从当前提交中剥离并简单地粘贴到目标提交:
... - E - F
\
G - H - I <-- chgs, HEAD=master
(已经不再有任何ASCII艺术理由在图纸中保持扭结[从F
向右 - 向右到G
],但我保留了视觉效果对称性。)
作为Cupcake noted in his faster answer,您可以强制与--no-ff
进行真正的合并。我会把它画成:
... - E - F ------------- M <-- HEAD=master
\ /
G - H - I <-- chgs
在任何一种情况下(快进,或&#34;真正的合并&#34;),一旦完成,您可以安全地删除分支标签 chgs
,因为所有它的提交是可以找到的,从master
开始并向后工作(如果&#34;真正的合并&#34;则沿着两个分支)。或者,如果您愿意,可以保留它并添加更多提交。
这里有一个有趣的注意事项是,在这种特殊情况下,与提交M
相关联的结果工作树与提交I
的结果完全相同。关键的区别在于,这会创建一个实际的合并提交(具有多个父项的提交)。第一个父是之前在分支上的任何提交 - 在这种情况下,提交F
- 剩余的提交(这里只是一个提交I
)是合并的分支。
(你可以覆盖这个 - 工作树是相同的,我的意思是 - 有更多的合并标志,但在这种情况下你不会想要。那种事情,覆盖工作树,主要是指为了&#34;在保留历史的同时杀死了一个分支:看起来像是一个&#34;看起来,我们尝试了这个并且它没有工作,并且明年有人在看代码。 )
1 或者如果您不想移动标签,则不需要。但是,如果您打算将push
您的作品发回给某人,或让他们pull
给您,他们会查看您的标签。如果你很好地为他们安排标签,那对他们来说真好。但它始终取决于你。
答案 2 :(得分:1)
以下更详细地解释了每个命令正在做什么。
git checkout master
切换到master
分支。
假设我们在本地有这个(其中*
表示当前分支):
M1 -- M2 = master*
\__ C1 = chgs
git pull --rebase
从远程分支更新本地master
分支,重新定义对master
分支所做的任何本地更改,以便它们在远程更改后进行。
假设这给我们一个新的M3改变:
M1 -- M2 -- M3 = master*
\__ C1 = chgs
git rebase master chgs
重新定义来自本地chgs
分支的更改,以便它们从本地master
分支继续(但保留在它们自己的分支中)。也改为chgs
分支。
M1 -- M2 -- M3 = master
\__ C1' = chgs*
git checkout master
切换回master
分支。
M1 -- M2 -- M3 = master*
\__ C1' = chgs
git merge chgs
将chgs
合并到master
。
M1 -- M2 -- M3 ------- M4 = master*
\__ C1' __/ = chgs
git push
将这些更改推送到原点。