给出master -> A
,A->B1
和A->B2
。
如果将B2
合并为master,那么更新B1
的最佳方法是什么?
我正在尝试了解合并分支层次结构方面的最佳实践。
可接受和不可接受(即可能导致合并冲突或GitHub文件更改选项卡混乱)
什么时候应该按顺序合并回来,什么时候直接合并才有意义(无论是朝着master向后的特征分支还是朝着特征分支的master分支,还是朝着特征分支的分支之间?
答案 0 :(得分:2)
我不确定我是否理解正确,但是我认为您是在问这种情况:
B1 ,-o--o--o
/
A ,-o--o
/ \
B2 / '-o--o
/ \
master --o--o--o-----------o--
在A从master分支的情况下,B1和B2从A分支的情况。
对于这样用抽象术语描述的问题,我认为没有什么可以被描述为最佳实践,它很大程度上取决于所涉及的所有分支的目的。 / p>
如果分支A代表某个功能的工作,并打算进行其他提交并在某个时候合并回master,那么我会质疑为什么B2被合并到master中而不是重新合并到master中。
如果A不能代表某个特定功能,而B1和B2可以,那么我认为B1可以合并到master中。
如果B1从A分支出来的事实是一个问题,则有可能先将其重新建立到主服务器上。
最终,答案取决于开发过程的外观以及开发过程中分支的使用方式。
答案 1 :(得分:1)
(从逻辑上讲,这应该是注释,但是我需要对其进行格式化,而我不能在注释中进行格式化。当然,它太长了。:-))
在SpoonMeiser's answer中(正确和赞成),我们有这张图:
B1 ,-o--o--o
/
A ,-o--o
/ \
B2 / '-o--o
/ \
master --o--o--o-----------o--
我认为有必要指出,该图有点误导性:它使人们认为最下面一行的提交是从master
可以到达的提交,而下一行是可以从B2
到达的提交。 A
,第三行是从B1
可以到达的提交,而第一行是从C
可以到达的提交。
我使用了这个奇怪的短语“ 可从到达”,而不是更明显的单词“ on ”。为什么我们称提交为 reachable 而不是只说它们在哪个分支上?
答案是,提交通常同时在许多分支上。让我们为每个提交指定一个字母名称(从A
开始以避免B
和 ,-E--F--G <-- B1
/
,-D--H <-------- A
/ \
/ '-I--J <-- B2
/ \
...--C--K--L-----------M <-- master
),然后将分支名称移到我最喜欢的位置,在右边,就像这样:
master
Git处理这些提交的方式是从每个单独名称指向的提交开始:对于M
,这是提交H
,而对于分支A的是J
。从此结束提交(例如分支B2的J
)开始,Git 向后工作:I
导致回到H
,然后回到D
C
和master
,依此类推。因此,分支B2包含所有这些提交。同时,分支M
从J
开始,该分支同时返回到L
和master
。因此B2
包含L
当前包含的每个提交,以及提交K
和git merge
。
一个人应该为git checkout
使用的策略取决于一个人将来想要获得什么结果。也就是说,我们必须立即计划明天,下周或明年的工作。
git checkout
的作用是提取分支名称指向的提交。例如,如果我们G
分支B1,则得到提交G
。存储在M
中的快照进入我们的 index (到达该点时,我们将从该索引进行下一次提交)并进入我们的工作树 >(实际上我们可以在其中查看和处理文件)。如果我们进行新的提交,则将获得一个新的哈希ID-我们将在此处N
或 ,-E--F--G--N <-- B1 (HEAD)
/
,-D--H <-------- A
/ \
/ '-I--J <-- B2
/ \
...--C--K--L-----------M <-- master
之后使用下一个字母进行绘制:
git commit
请注意,git checkout
更新了当前分支(由于HEAD
将git checkout
附加在分支名称上,Git知道了这一点),因此它现在指向刚进行的新提交。新的提交指向我们git merge
编辑的提交,即当前为的提交,直到我们做出新的提交为止。
N
的作用是在当前提交(现为git merge A
)和我们命名的提交之间找到合并基础。如果我们说A
,则名称H
转换为提交H
,因此Git在图中找到提交N
,并在图中找到提交D
,然后在该图中向后进行搜索以找到最佳的 common 提交-最佳的提交同时在 分支上。最佳翻译为“最佳”,意思是“最靠近两端”,因此这里是提交N
。
merge动作(要进行合并的的动词部分)实际上是通过对两个H
提交D
和git diff
{1}}命令:
git diff --find-renames <hash-of-D> <hash-of-N> # what we changed
git diff --find-renames <hash-of-D> <hash-of-H> # what they changed
Git找出我们更改了哪些文件,以及我们对它们做了什么。然后,它找出它们更改了哪些文件以及它们做了什么。然后,它简单地(ha)组合这两组更改。这些合并的更改将应用于基础D
中的快照,以提供新的快照。
成功地组合了更改-至少在 Git 认为成功的情况下,Git会继续进行 merge commit ,例如{ {1}},有两个父母。第一个父级将是提交M
,第二个父级将是提交N
,我们选择合并。结果照常添加到H
分支中,因此我们得到:
HEAD
如果我们现在要让Git合并B1和B2,Git会走这张图以找到最佳的“共同起点”。在没有提交 ,-E--F--G--N--O <-- B1 (HEAD)
/ ,----------'
,-D--H <-------- A
/ \
/ '-I--J <-- B2
/ \
...--C--K--L-----------M <-- master
的情况下,该共同的起点是提交O
,但是在有了D
的情况下,该共同的起点是O
。
在所有情况下,这些“正常” Git命令只需添加到图。如果是常规提交,则每个新提交都有一个父提交;如果是合并提交,则每个新提交都有两个父提交。这些附加项重塑了图形,更改了合并,提交 future 合并将选择为其合并基础。因此,我们现在进行的合并是我们现在需要做的事情,但它们也是我们现在进行的使我们以后可能会更容易做的合并。
有些Git命令可以通过强制分支名称指向图中的另一个(旧)位置,而不是向图中添加新的提交,来删除提交。 H
命令在这方面特别擅长,但是git reset
也是这样做的:首先,它将一堆提交复制到“新的和改进的”提交中,然后将分支名称移动到最后一个刚刚制作的副本。通常,删除的提交实际上并不会立即消失:Git尝试给您一个月或更长时间来改变主意并将其重新带回。但是它们的确很难找到,因为Git通常查找提交的方式是从分支名称(或标签名称)开始,然后查看该名称找到的一个提交,然后使用该名称。致力于在图形中向后工作。