我们分支master(我们不使用dev分支,不要问为什么)然后当QA为分支发出合并请求时,我们将它合并到qc分支,然后当它们完成测试时,我们将它合并到主分支。我们永远不会将qc合并为master或rebase从master到rebc的分支,尽管我们可以将分支快进到master(通过git merge --ff-only master或git rebase -i),尽管通常只需合并就可以了。 / p>
但是,分支(基于经理确定的任务)可以在不同的基础上启动,以不同的顺序合并到qc中,并以不同的顺序合并回主服务器。
问题是因为我们经常不得不为不同的功能更改相同的代码行(由于代码最初的结构方式和请求的更改,我们无法完全避免这种情况)所以我们几乎得到了合并冲突每周,当事情以不同的顺序合并到不同的分支时,我们最终可能不得不一遍又一遍地修复相同的冲突,或者将不同的更改合并到同一行(或者必须在不同的分支中分散新行)到不同的路线)。呼
为了消除相同的合并冲突修复,我们尝试将合并的分支重新绑定到QC(可能基于主提交回去),但是它以某种方式复制了qc和master上的提交;我们很好地将提交重新应用于掌握并丢失qc上的提交,因为我们可以将它合并回qc(我们会在更新时将master合并到qc中)。
我们如何避免这些重复的提交和冲突,有没有更好的方法来管理它?
有人提出了一件事:git rebase --onto master qc branch
这对于那些需要从qc主控以防止多余冲突修复的分支是否可行?
答案 0 :(得分:0)
重新提供重复提交,因为 是什么?:它是git cherry-pick
操作的自动化系列,而git cherry-pick
是提交复印机。
每个对象的标识都是其哈希值:例如251654c5f6f256fe6e23c2c85f1a70594aae00d4
。哈希值是被哈希对象内容的校验和。对于提交对象,内容为:
通常情况下,你选择提交的原因是稍微修改一下版本 - 事实上,如果你做了一点一点的完全相同的副本你就得到了原始提交的ID返回,因为同一组输入位的散列是相同的值。但是,通过一个樱桃挑选的提交,您通常会有一个稍微不同的源树,并且几乎总是有不同的父ID。
考虑这一点(经过如此轻微的修改,以打败垃圾邮件 - 电子邮件扫描程序)示例提交:
tree 3b2ac3530e713fc93aa93525bed9623679f99173
parent d2628061aa3b38b9f5dbdcd9136711a5a4ac3a1a
author Chris Torek <chris.torek@somewhere.com> 1459821791 -0700
committer Chris Torek <chris.torek@somewhere.com> 1459821791 -0700
distributed: clarify GUID uniqueness
Add the phrase {Doppelg\"anger commit} in a side-note.
Git and Mercurial allow them as long as they never meet.
我可以通过首先针对其父提交执行git diff
来复制此提交(以显示我更改的内容):
diff --git a/distributed.tex b/distributed.tex
index 40fb7fd..6d8854b 100644
--- a/distributed.tex
+++ b/distributed.tex
@@ -41,8 +41,18 @@ to discover and exchange commits
whenever you direct the system to synchronize your clone
with a peer.
In order to make this work correctly,
-these GUIDs really must be globally unique
-(across all repositories).
+these GUIDs really must be globally unique.\sidenote
+{More specifically, they must be unique
+among all clones of a given repository,
+\emph{including forks that may rejoin in the future}.
+This is a somewhat weaker requirement than true global uniqueness.
+For instance, if Alice makes a commit,
+but then destroys it without ever sharing it with anyone else,
+the destroyed commit is allowed to have the same GUID
+as some future commit,
+or a commit in an unrelated repository.
+You can think of this as allowing Doppelg\"anger commits:
+they may share a GUID only as long as they never meet.}
It would not do
for Bob to create a \emph{different} commit (in \git)
or changeset (in \mercurial)
现在我有了diff,我可以检查一些其他提交,将diff作为补丁应用,并从结果中重新提交,重新使用日志消息。我将获得一个新的提交,具有相同的日志消息和对文件distributed.tex
的相同效果,但(可能)不同的tree
和(肯定)不同的parent
,以及新的提交时间邮票,因此是一个不同的哈希。
这是一个挑选:将提交与其父级进行比较(将其转换为变更集),将该更改应用于其他位置,并从结果中进行新的提交。假设我们为提交的链 重复此操作:
... <- B3 <- B4 <- B5 <-- branch-X
\
F6 <- F7 <- F8 <-- feature-Y
我们假设我们将F6
复制到F8
。请拨打F6
,F6'
的副本,将其与原始版本区分开来。将F6'
的父级设为B5
,将F7'
的父级设为F6'
,将F8'
的父级设为F7'
,以便我们得到:
F6' <- F7' <- F8'
/
... <- B3 <- B4 <- B5 <-- branch-X
\
F6 <- F7 <- F8 <-- feature-Y
现在让我们做最后一件事。让我们删除当前卡在提交feature-Y
上的标签F8
,然后将其粘贴到F8'
上:
F6' <- F7' <- F8' <-- feature-Y
/
... <- B3 <- B4 <- B5 <-- branch-X
\
F6 <- F7 <- F8 [abandoned]
呃瞧,我们刚刚重新安排了 - 即。复制了 - feature-Y
上的一些提交。新副本现在位于分支feature-Y
上(在复制过程中,它们位于 no 分支上,或者更确切地说,在您处于&#34;分离的HEAD&时的特殊匿名分支上#34;模式)原始副本......好吧,还在那里。
我在这里标记了[弃],但是如果有其他分支或标记标签可以让您找到提交F8
,您仍然可以看到所有原始提交。 git rebase
命令移动feature-Y
标签,但不会查看是否有其他标签使提交保持可见。
编辑:如果通过合并提交可以看到某些复制并随后放弃的提交,则情况也是如此,例如:
F6' <- F7' <- F8' <-- feature-Y
/
.... <- B3 <- B4 <- B5 <-- branch-X
\ \
\ F6 <- F7 <- F8 [abandoned]
\ \
C2 <--- C3 <-- C4 <-- branch-C
此处branch-C
使提交C2
到C4
可见,但C4
是合并提交,使F8
可见。现在,当您浏览存储库时,F8
(来自C4
的{{1}})和branch-C
(来自F8'
)都会显示。
这种事情控制着你应该或不应该变革的时间和原因。由于rebase 副本提交,你需要确定以下两件事之一:原件真的会被遗弃,或者原件保存是可以的别处。 [结束编辑。]
feature-Y
为您自动化的另一件事是选择提交复制。为什么我们决定通过git rebase
来复制F6
?为什么要包括这三个并排除所有其他?这就是F8
的论据进入的地方。让我们回到这个建议:
git rebase
这是git rebase --onto master qc branch
的完全指定形式。在这种情况下,最后一个参数git rebase
会使branch
从git rebase
开始。也就是说,额外的参数只是传递给git checkout branch
。在那之后,额外的参数不再使用,所以我们可以这样做:
git checkout
代替。
命令的git checkout branch && git rebase --onto master gc
部分指定副本的位置。更具体地说,我们将--onto commit
复制到F6
,其新父级为F6'
。如果使用B5
,则指定此目标提交。 (在这种情况下使用分支名称--onto
,只意味着在该分支上使用提示提交。)
在我们的案例中,剩余的一个论点master
是gc
调用git rebase
的内容。
如果我们不指定<upstream>
,--onto
参数将有两个角色:它会命名目标提交,和它会提供<upstream>
提交的标识,它应该专门不复制(然后不复制更多提交,基于该ID)。但是,当我们使用git rebase
时,我们已经指定了目标提交,因此剩下的参数只剩下一个角色:指定提交以避免复制。
这个&#34;承诺避免复制&#34;事情的作用可能有点棘手,包裹你的头。我们指定了一个特定的提交,但是rebase使用git本身一直使用的技巧。当我们将git指向某个提交时,我们可以要求它查看提交的 :
--onto
或者我们可以要求它查看提交及其所有父提交(又名 ancestry ):
$ git rev-parse c96a
c96af44caf036cf9f04d77c6146086a4ee422ceb
($ git rev-list c96a
c96af44caf036cf9f04d77c6146086a4ee422ceb
bca8213e6fda6fdf92b3a5fbc4ee59f755e04a9c
86ac01b3e1d771033e93af93366ace1b586d7c74
bc3fa7a3571231e334f6f06e5610e04227ef1f0b
执行一次提交操作,而rev-parse
默认执行祖先变种,尽管rev-list
非常灵活,位于心脏或至少肝脏或脾脏 - 许多git命令)。
Git&#39; rev-list
选择带有祖先的rebase
参数来提交排除,同时选择当前分支(如果你给它,请在检查之后)一个额外的参数)与祖先提交包括。无论剩下什么,在排除排除集后,都是要复制的提交。
使用<upstream>
表单从其双重职责中释放--onto
,以便在选择哪些提交以避免复制时更具选择性。但是,你仍然会复制提交,而这一切都需要。特别是,如果您使用rebase来复制(然后忘记其他人正在使用的提交的原件),他们还必须根据原件重新定义他们所做的任何工作。