“Frankensteining”来自git存储库的fork - 允许对移动文件进行合并

时间:2015-08-01 03:23:33

标签: git version-control

我想从Arduino repository创建一个fork,以便创建AVR核心和库的独立版本,但我想:

  1. 隔离其中的一部分,只有libraries/hardware/arduino/avr/cores/arduino/(移至core/)从原始存储库分叉,

  2. 允许合并回原始存储库以及从原始存储库进行更新。

  3. readread以及read,但它们似乎都不符合第二项要求。

    我也有兴趣了解其他工具如何处理这个问题,但看看源存储库是git的方式,这将是我的首选工具。

1 个答案:

答案 0 :(得分:1)

你想要什么是可能的但两个回购的同步需要一些工作。

任何涉及git-filter-branch的策略都不适用于此,因为您通过重写fork的历史记录而失去了两个回购之间的联系。

为了说明这样做的基本原则,让我们创建一个测试库

> git init merge-move-test && cd merge-move-test/
@master> echo "foo" > foo
@master> git add .
@master> git commit -m "Initial commit"

接下来我们创建一个可以移动东西的fork

@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> git merge --no-edit master

那就是它。看看差异,你会看到效果完全符合预期

@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中合并提交的一部分。 1}}。

因此,每次您要将A的更改合并到B时,必须确保这些更改不包括BA的更改撤消。如果有任何此类更改,请使用上述方法之一将其还原。

如果您想使用测试仓库,here's a shell script that runs the above commands