你想要的是可能的,但是两个repos的同步需要一些工作。
任何涉及git-filter-branch 的策略都不适用于此处,因为您会通过重写分叉的历史失去两个存储库之间的连接。
为了说明这样做的基本原理,让我们创建一个测试存储库
> git init merge-move-test && cd merge-move-test/
@master> echo "foo" > foo
@master> git add .
@master> git commit -m "Initial commit"
接下来我们创建用于移动物体的分叉
@master> git checkout -b fork
@fork> git mv foo bar
@fork> git commit -m "Rename foo to bar"
@fork> git tag rename-commit
在你的分叉之后不久,上游进行了修改
@master> echo "Upstream update" > foo
@master> git commit -am "Upstream update of foo"
此时,您可以很容易地让您的 fork 与 master 保持同步
@fork> git merge --no-edit master
就是这样。看一下diff,你会发现效果完全符合预期
@fork> git diff HEAD^ HEAD
diff --git a/bar b/bar
index 257cc56..f7f3304 100644
--- a/bar
+++ b/bar
@@ -1 +1 @@
-foo
+Upstream update
此时进行本地开发和合并上游更改不需要特殊步骤。
当您想将更改合并回上游时,它会变得很有趣。因此,假设您在master
中介绍了一些
必须 的
惊人 更改
@fork> echo "Improvement from fork" > bar
@fork> git commit -am "Improve bar in fork"
如果您现在只是将fork 合并到master,您不仅会将内容更改应用到foo,而且还将foo 重命名为bar。这是有道理的,因为这正是主人尚未看到的fork 的一组变化。
所以我们需要做的是告诉master我们不想要那块改变。一种方法是合并所有内容,然后恢复不需要的更改。如果您想在一次提交中包含所有内容,这就是这样做的方法
@master> git merge --no-commit --no-ff fork
@master> git revert --no-commit rename-commit
@master> git commit -m "Merge improvement from fork"
另一种方法是首先使用策略ours 合并不需要的更改,然后再进行实际合并。
@master> git merge --no-edit -s ours rename-commit
@master> git merge --no-edit fork
More information on excluding changes from a merge.
在你这样做之后,情况有点逆转。您现在可以将任意数量的更改从 fork 合并到 master,但是尝试执行相反的操作将撤消您在 fork 中的初始重命名,因为这是 master 中合并提交的一部分。
因此,每次您想要合并从 A 到 B 的更改时,都必须确保这些不包括从 B 到 A 的更改的反转。如果有任何此类更改,请使用上述方法之一将其还原。
如果你想玩测试 repo,here's a shell script that runs the above commands。