git merge更新源分支上未更改的文件

时间:2013-01-22 02:57:46

标签: git git-merge

我很难理解以下行为在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出现这种行为。

3 个答案:

答案 0 :(得分:3)

如果完全正确地输入上面的命令,那么git是正确的。这就是你做的:

  1. 创建了一个repo(默认为分支“master”)
  2. 将一个变更集(2个新文件)添加到“master”
  3. 创建了一个分支(“branch1”),但没有改变它
  4. 在“master”
  5. 上添加了一个变更集(已更改a.txt)
  6. 创建了一个分支(“branch2”)并更改为它(此分支包含a.txt已修改)
  7. 在“branch2”
  8. 上添加了一个chageset(更改了b.txt)
  9. 切换到“branch1”(包含两个原始的,未更改的文件)
  10. 与“branch2”合并(快进)(同时应用两项更改:a.txt和b.txt)
  11. 这正是您描述的内容以及应该发生的内容。你可能出错的地方认为你在“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中找到一个共同的祖先,然后将BE之间存在的所有历史记录应用于'branch1',特别是提交CDE

然而,你想要的只是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会话中删除提交CD

在我上一份工作中,我们经常使用隔离的功能分支来解决这个问题。在同一生产分支的不同时刻切割,如果合并而没有变基,他们会进行不必要的更改。作为一名集成经理,我经常将他们的历史重写为过去的共同点(上一个生产版本),从而允许整个过程中的清晰合并。这是许多可能的工作流程之一。最佳答案在很大程度上取决于您的团队如何移动代码。例如,在CI环境中,CD与您所描述的合并一样,有时不那么重要。

最后请注意,如果E取决于CD中的任何代码,此解决方案会在合并'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