我很难理解以下行为在git中是一件好事。请参阅下面的示例,我将它放在一起以帮助说明我的问题。很多时候,我的团队和我自己正在进行更改/提交进入我们不想去的分支机构。
> git init sandbox && cd sandbox
> echo "data a" > a.txt && echo "data b" > b.txt
> git add -A && git commit -a -m "initial population"
[master (root-commit) d7eb6af] initial population
2 files changed, 2 insertions(+)
create mode 100644 a.txt
create mode 100644 b.txt
> git branch branch1
> echo "more data a" >> a.txt && git commit -a -m "changed a.txt on master"
[master 11eb82a] changed a.txt on master
1 file changed, 1 insertion(+)
> git branch branch2 && git checkout branch2
Switched to branch 'branch2'
> echo "more data b" >> b.txt && git commit -a -m "changed b.txt on branch2"
[branch2 25b38db] changed b.txt on branch2
1 file changed, 1 insertion(+)
> git checkout branch1
Switched to branch 'branch1'
> git merge branch2
Updating d7eb6af..25b38db
Fast-forward
a.txt | 1 +
b.txt | 1 +
2 files changed, 2 insertions(+)
请注意,在上面,a.txt在合并中更新,即使它未在branch2上被触摸/修改。在上面的场景中,我希望git能够智能地识别出branch2上没有更改a.txt,因此在对branch1应用更新时,不要进行更改。
我有什么问题吗?是的,我可以选择,这可以用于这个简单的例子,我知道我改变了什么,但在实际情况下变化更大并且你不知道可能会受到什么影响的情况下是不现实的。
要清楚,我不希望git出现这种行为。
答案 0 :(得分:3)
如果完全正确地输入上面的命令,那么git是正确的。这就是你做的:
这正是您描述的内容以及应该发生的内容。你可能出错的地方认为你在“master1”上更改了a.txt 在你创建“branch2”之前真正改变了它“”从而给出了错觉当与“branch2”合并时,变化神奇地出现在“master1”的“branch1”上,但实际上变化来自“branch2”。
如果您重复测试,但在第3步切换到“branch1”(git checkout -b branch1
)而不是将更改提交到a.txt为“master”我认为你会得到合并你期待。
答案 1 :(得分:3)
'branch1'和'branch2'只是提交指针。它们是某些时刻的提交历史状态。因此,当将'branch2'合并到'branch1'时,git只会建立一个共同的祖先并尝试同时应用来自两个树的更改。
采用简单的图表:
branch1 E <- branch2
| /
v /
A - B - C - D <- master
在上面的示例中,'branch1'指向提交B
,'branch2'指向提交E
。这或多或少地描述了您在上面输入的操作顺序。如果你将'branch2'合并到'branch1',git会在B
中找到一个共同的祖先,然后将B
和E
之间存在的所有历史记录应用于'branch1',特别是提交C
,D
和E
。
然而,你想要的只是E
。正如您已经确定的那样,一个(坏的)解决方案就是采摘樱桃。一个更好的解决方案是将'branch2'重新设置为'branch1',从而重写'branch2的历史记录,只包括提交E
过去'branch1':
git rebase --onto branch1 master branch2
这正是你所寻求的,并且读作'rebase branch2,它最初是基于master,到branch1'。注意,为了简单起见,我将'branch1'指针从这个图中删除了,E
变成了E'
,因为它的提交哈希发生了变化(这是这些图的常见约定):
E' <- branch2
/
/
A - B - C - D <- master
您可以使用git checkout branch2 && git rebase -i B
获得类似的效果,然后从交互式rebase会话中删除提交C
和D
。
在我上一份工作中,我们经常使用隔离的功能分支来解决这个问题。在同一生产分支的不同时刻切割,如果合并而没有变基,他们会进行不必要的更改。作为一名集成经理,我经常将他们的历史重写为过去的共同点(上一个生产版本),从而允许整个过程中的清晰合并。这是许多可能的工作流程之一。最佳答案在很大程度上取决于您的团队如何移动代码。例如,在CI环境中,C
和D
与您所描述的合并一样,有时不那么重要。
最后请注意,如果E
取决于C
或D
中的任何代码,此解决方案会在合并'branch1'(现在包含{{1}时对您的历史造成严重破坏}更改设置)回到'主'。如果您的工作流是增量的,并且'branch1'和'branch2'插入类似的函数和文件,那么合并冲突将成为理所当然。在这种情况下,可能需要仔细查看您团队的工作流程。
答案 2 :(得分:2)
a.txt在合并中更新,即使它未被触摸/修改 BRANCH2
但是先生,是的。运行所有命令,但git merge branch2
,然后
$ cat a.txt
data a
$ git checkout branch2
Switched to branch 'branch2'
$ cat a.txt
data a
more data a
我知道它在branch2中就是这样,但是我没有修改/触摸它 在我分支后。
您已将more data a
提交给master
。然后,您从branch2
创建了master
。因此,branch2
也会包含more data a
。