我很难理解以下行为在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(+)
Run Code Online (Sandbox Code Playgroud)
请注意,在上面,a.txt在合并中更新,即使它未在branch2上触摸/修改.在上面的场景中,我希望git能够智能地识别出branch2上没有更改a.txt,因此在对branch1应用更新时,不要进行这些更改.
有什么我做错了吗?是的,我可以选择,这将是这个简单的例子,我知道我改变了什么,但在真正的情况下变化更大,你不知道可能会受到什么影响,这是不现实的.
要清楚,我不希望这种行为来自git.
'branch1' 和 'branch2' 只是提交指针。它们是提交历史记录在特定时刻的状态。因此,当将“branch2”合并到“branch1”时,git 所做的只不过是建立一个共同的祖先并尝试一起应用两棵树的更改。
举个简单的图:
branch1 E <- branch2
| /
v /
A - B - C - D <- master
Run Code Online (Sandbox Code Playgroud)
在上面的示例中,“branch1”指向 commit B,“branch2”指向 commit E。这或多或少描述了您在上面输入的操作顺序。如果您将“branch2”合并到“branch1”中,git 会找到一个共同的祖先,然后将和B之间存在的所有历史应用到“branch1”,特别是提交、和。BECDE
然而,你想要的只是E。正如您已经确定的那样,一种(糟糕的)解决方案是精挑细选。一个更好的解决方案是将“branch2”重新定位到“branch1”,从而重写“branch2”的历史记录以仅包含E过去“branch1”的提交:
git rebase --onto branch1 master branch2
Run Code Online (Sandbox Code Playgroud)
这正是您所寻求的结果,读作“将最初基于 master 的分支 2 重新设置到分支 1 上”。请注意,为了简单起见,我将“branch1”指针保留在该图中,因为它的提交哈希E发生E'了变化(这是这些图的常见约定):
E' <- branch2
/
/
A - B - C - D <- master
Run Code Online (Sandbox Code Playgroud)
您可以使用 获得类似的效果git checkout branch2 && git rebase -i B,然后从交互式变基会话中删除提交C和。D
在我的上一份工作中,我们经常遇到孤立的功能分支的问题。在不同的时间从同一个生产分支进行剪切,如果在没有变基的情况下合并,它们会带来不需要的更改。作为一名集成经理,我经常将他们的历史重写为过去的一个共同点(最后一个生产版本),从而允许自始至终进行干净的合并。这是许多可能的工作流程之一。最佳答案在很大程度上取决于您的团队如何移动代码。例如,在 CI 环境中,有时并不那么重要,C并且D会像您所描述的那样与合并一起被拉动。
最后,请注意,如果E依赖于C或中的任何代码,则在将“branch1”(现在包含更改集)合并回“master”D时,此解决方案将对您的历史记录造成严重破坏。E'如果您的工作流程是增量式的,并且“branch1”和“branch2”介入相似的函数和文件,那么合并冲突自然会出现。在这种情况下,可能有必要仔细查看团队的工作流程。