2014-03-31 264 views
1

我读这篇文章http://supercollider.github.io/development/git-cheat-sheet.html,其中提出以下工作流程:Git合并后git rebase?

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-commit-n-1)<--(master-commit-n)<--(chgs-commit-k-1)<--(chgs-commit-k) 
             \.(master-with-merged-chgs-commit-k)<--HEAD 

我不明白为什么顶叉是有用的。

回答

2

为了:

不第三行,git rebase master somechanges,把后终于从chgs承诺从master,但没有将它们合并犯...

是,假设somechangeschgs的错字(参考页面使用更多拼写)。

和叶HEAD指向最新从chgs

是承诺,但只是间接的:HEAD字面上包含ref: refs/heads/chgs,即,如果只剩下分支chgs签出。这是chgs本身,指向最新的提交。

这是否使我离开chgs签出?

是的。

具体来说,“当前分支”,在一个打印为on branch ...当您使用git status,只是无论refs/heads/branch是文件HEAD中,当HEAD包含refs: refs/heads/branch。首先运行git checkout branch确保可以更新工作树,然后通过重写HEAD来完成此操作并将其置于该分支上。

在内部,git rebase upstream branch调用git checkout branch,所以整个过程开始让你在分支上。

为什么我们需要将更改合并到主?这不是像[剪辑]一样的图表吗?

你需要的merge移动的标签。

我更喜欢用字母或有时候只是一点一点地绘制提交图表,用它们之间的单个破折号或短箭头表示父母关系。并且,从git log --graph --oneline --decorate中偷取(但修改)一片叶子,我用更长的箭头在右侧添加分支名称。如果HEAD命名分支,我在前面添加HEAD=

你有什么之后作为底垫由此可以得出:

... - E - F    <-- master 
      \ 
       G - H - I <-- HEAD=chgs 

这里提交标记F是分支master的顶端,所以masterF(和F点回E等上)。分支chgs的提示是提交I; I积分返回H; H积分返回G;并且G指向F。当然HEAD=chgs所以你在那个分支。

一旦你git checkout master,像往常一样更新你的工作树,并使HEAD指向master指向F。然后,如果你运行git merge chgs,Git会查找,看是否有可能做一个“快进”合并:

... - E - F    <-- HEAD=master 
      \ 
       G - H - I <-- chgs 

一个快进合并有可能在当前提交(F,在这种情况下)已经是一个祖先的目标提交(I)。如果是这样,分支标签揭下当前提交和简单粘贴到目标承诺:

... - E - F 
      \ 
       G - H - I <-- chgs, HEAD=master 

(现在,已经没有任何ASCII艺术-理由将扭结在绘图[从F下和但是我保持它的视觉对称。)

作为Cupcake noted in his faster answer,您可以强制与--no-ff真正合并。我会得出这样的:

... - E - F ------------- M <-- HEAD=master 
      \   /
       G - H - I  <-- chgs 

在这两种情况下(快进,或“真正合并”),一旦做到这一点,你可以安全地删除分支标签chgs,其所有提交的被发现可以从master开始并向后工作(如果是“真正的合并”,则沿着两个分支)。或者,如果您愿意,您可以保留它并添加更多提交。

这里一个有趣的注意的是,在这种特殊情况下与相关的产生工作树提交M是完全一样的一个提交I。关键的区别是,这会创建一个实际的合并提交(与多个父代一起提交)。第一个父节点是之前在分支上的任何提交 - 在这种情况下,提交F - 并且剩余的提交(这里是一个提交I)是要合并的分支。(你可以覆盖这个 - 工作树是相同的,我的意思是 - 有更多的合并标志,但在这种情况下,你不会想要这样的事情,重写工作树,主要是意味着“杀死”的一个分支,同时保留了历史:排序的“看,我们尝试这样做,也没有工作”的消息给某人明年看代码)


。或者不需要,如果你不想移动标签。但是,如果您打算将push工作返回给某人,或者让他们从您那里获得,他们会查看您的标签。如果你为他们安排好标签,这对他们很好。但这总是取决于你。

3

#1

没有第三行,git rebase master somechanges,把从chgs 提交后最后从master,但没有将它们合并提交,并留下HEAD 指向最新从chgs犯,像此:

(master-n-1) <- (master-n) <- (chgs-k-1) <- (chgs-k) <- HEAD 

衍合chgs到0123的作用相当于将master合并为chgs,因为上次提交时您的代码的状态将等于merge之后的状态。

#2

,这是否给我chgs签出?这就是为什么我需要再次检查 master

是的。

#3

,为什么我们需要合并变为主人?不使图形 这样的:

(master-n-1) <- (master-n) <- (chgs-k-1) <- (chgs-k) 
          \ 
          (master-with-merged-chgs-k) <- HEAD 

号因为你的master顶部重建基础chgs,git会认识到,最后一次提交的chgs有效地代表master“+” chgs状态,所以它只是“快进”的master分支的chgs尖端而不进行合并提交:

(n-1) <- (n) <- (k-1) <- (k) <- HEAD/master/chgs 

如果你想混帐做,而不是合并提交,你可以通过--no-ff标志merge

git merge --no-ff chgs 

# Results in this 

(n-1) <- (n) <- (k-1) <- (k) <- chgs 
      \    \ 
       --------------(merge) <- HEAD/master 

#4

我不明白为什么上叉是非常有用的。

这对更新功能分支的上游更改从master更新很有用,不会在功能分支中创建一堆冗余合并提交。最终的结果是,您的开发历史变得更简单,更容易处理,而不是包含一些您并不真正需要的额外合并提交,而这些合并提交只会使历史更加复杂且难以操作。

1

下面更详细地解释这些命令中的每一个在做什么。

GIT中结帐主

切换到master分支。

假设本地,我们有这个(其中*表示当前分支):

M1 -- M2 = master* 
     \__ C1 = chgs 

混帐拉--rebase

从远程分支更新本地master分支,重定义对master分支所做的任何本地更改,以便它们在远程更改之后发生。

假设这给了我们一个新的M3变化:

M1 -- M2 -- M3 = master* 
     \__ C1 = chgs 

git的重订主CHGS

底垫从本地chgs分支的变化,使他们从本地遵循master分支(但留在他们自己的分支)。也更改为chgs分支。

M1 -- M2 -- M3 = master 
      \__ C1' = chgs* 

GIT中结帐主

切换回所述master分支。

M1 -- M2 -- M3 = master* 
      \__ C1' = chgs 

混帐合并CHGS

梅杰斯chgsmaster

M1 -- M2 -- M3 ------- M4 = master* 
      \__ C1' __/ = chgs 

混帐推

推这些变化原点。