如何使用 git 合并两个非 git 项目
How to use git to merge two non-git projects
我有两个项目最初来自一个我不再拥有的共同祖先。他们每个人都在很长一段时间内朝着自己的方向发展。现在,我想做一个合并,我想使用 git 来做到这一点。
我创建了这个存储库:
* Project A [BranchA]
| * Project B [BranchB]
|/
* Initial init (Project A)
首先我想找出不同的文件:
git checkout BranchA
git diff --stat BranchB
我可以通过
轻松地执行从 BranchB 到 BranchA 的手动合并
git difftool BranchA
并将修改保存到正确的文件中。但是我有时想修改 BranchA 和 BranchB 的两个文件。例如,如果我注意到 BranchA 上的变量名更改,我可以停止合并,替换 BranchB 中的变量名,提交 BranchB 上的更改并继续手动合并。
此时我会迷路,因为我中断了合并并且没有保留我正在处理哪个文件的任何痕迹。 git diff --stat BranchB
对我没有帮助,因为即使我成功地将更改从 BranchB 导入到 BranchA,它仍然会存在一些差异。
值得一提的是,我无法使用 git merge
,因为 git 上没有可用的共同祖先,因为我在一个空的 git 存储库中导入了两个截然不同的项目。在这种情况下 git merge
会做得很糟糕。所以我正在寻找更好的解决方案,以便:
- 使用 difftool 浏览两个分支中的每个文件,推送并获取差异,直到两个文件完全相同。
- 使用 git 跟踪我的更改,并在需要时帮助我回滚到以前的版本。
- 使用git跟踪与
git diff --stat
的合并过程。
我找到的唯一解决方案是初始化一个包含 BranchA 和 BranchB 的裸存储库。然后我将它克隆到两个本地目录中。他们每个人都指向不同的分支。
+-->[ ]<--+ Bare repository
| |
Branch A [ ] [ ] Branch B
| |
+->diff<--+
由此我可以使用我最喜欢的 merge/diff 工具在两个分支上手动修改我的文件。我可以随时 commit
、push
、pull
我的工作。
不过我确信有更好的方法。
听起来您对存储库的初始提交是项目 A 的副本,然后您从该项目分支并在分支上替换为 B。您是否尝试过让父提交只是一个空提交?我认为这会给 git 一个更好的正确合并的机会,因为它不是假设项目 B 中的所有更改都是对项目 A 的编辑的结果。所以你的 git 树看起来像这个:
* A
| * B
|/
* Initial Commit (empty)
借助变基的魔力,您甚至可以开始将一些真正通用的代码放入父级中,这也可能有所帮助。
您是否需要尽可能多地保留项目 A 和 B 的历史记录?
如果没有,我建议采用以下方法:
创建一个 repo 和一个初始的空提交。
除了 master,在初始提交后创建两个分支:A 和 B
将项目 A 和 B 的快照放入各自的分支。
此时,使用您知道如何使用的现有工具来找到两个分支的相同部分,并将相同部分提交给 master。然后,您应该能够将分支 A 和 B 变基到 master 上的新提交上。
起泡、漂洗、重复,并继续从 A 和 B 中获取大块相同的代码,将它们放入 master 中,并基于它们进行变基。您可以逐步执行此操作。
在这个过程中的每一步,您都应该在 A 和 B 分支上进行一次提交,这是从 master 分支上分叉出来的。
在某些时候,您将到达需要查看差异的步骤。让我们以分支A和B上相同变量的不同名称的假设情况为例
好吧,将一个分支上的变量重命名为另一个分支的名称,然后对其进行 rebase-squash,这样您仍然可以在 A 和 B 分支上进行一次提交。这应该最终导致两个分支上的更多代码变得相同,您可以将其拉出,提交到 master 上,然后在其上重新设置 A 和 B 分支的基线。
当你达到 A 和 B 之间没有任何共同点的地步时,它们都与 master 相差一个提交,并且 none 它们改变了重叠的部分,那么你应该能够将一个分支合并到另一个分支;可能会解决一些小的冲突。
在此过程的每一步,您的更改都应该相当小,您不需要使用复杂的差异或合并工具来完成它。
我还建议,在您将您认为是公共代码块提交给 master 并尝试在 master 的新提交之上对 A 和 B 进行变基后,标记分支 A 和 B,如果其中一个失败了,你可以将另一个分支的提示恢复到之前的标签,去掉master上的新提交,然后再试一次。
这个过程的另一个改进是,在创建初始 repo 之后,而不是使用两个分支 + master,克隆 repo 目录两次,然后使用两个新的 repos,本质上是分支:隔离相同的代码后,提交该块到父回购,重新拉动子回购中的父回购,并尝试重新设置子回购中的分支。
我肯定会建议一些接近 的东西来重建历史,更清楚地显示 A 和 B 的共同点。
然而,"pausing a manual merge, applying a patch to B, and resume the manual merge" 的唯一目的是,git stash 看起来像您需要的工具:
- 开始使用你提到的
git difftool
当点击一些您想同时应用于 A 和 B 的内容时,将您当前的更改保存在存储中:
git stash
转到 BranchB
,应用您的更改:
git checkout BranchB
# do whatever you want
git add / git commit
return 到 BranchA
git checkout BranchA
从存储中检索您的更改
git stash pop
git difftool BranchB
...
我有两个项目最初来自一个我不再拥有的共同祖先。他们每个人都在很长一段时间内朝着自己的方向发展。现在,我想做一个合并,我想使用 git 来做到这一点。
我创建了这个存储库:
* Project A [BranchA]
| * Project B [BranchB]
|/
* Initial init (Project A)
首先我想找出不同的文件:
git checkout BranchA
git diff --stat BranchB
我可以通过
轻松地执行从 BranchB 到 BranchA 的手动合并 git difftool BranchA
并将修改保存到正确的文件中。但是我有时想修改 BranchA 和 BranchB 的两个文件。例如,如果我注意到 BranchA 上的变量名更改,我可以停止合并,替换 BranchB 中的变量名,提交 BranchB 上的更改并继续手动合并。
此时我会迷路,因为我中断了合并并且没有保留我正在处理哪个文件的任何痕迹。 git diff --stat BranchB
对我没有帮助,因为即使我成功地将更改从 BranchB 导入到 BranchA,它仍然会存在一些差异。
值得一提的是,我无法使用 git merge
,因为 git 上没有可用的共同祖先,因为我在一个空的 git 存储库中导入了两个截然不同的项目。在这种情况下 git merge
会做得很糟糕。所以我正在寻找更好的解决方案,以便:
- 使用 difftool 浏览两个分支中的每个文件,推送并获取差异,直到两个文件完全相同。
- 使用 git 跟踪我的更改,并在需要时帮助我回滚到以前的版本。
- 使用git跟踪与
git diff --stat
的合并过程。
我找到的唯一解决方案是初始化一个包含 BranchA 和 BranchB 的裸存储库。然后我将它克隆到两个本地目录中。他们每个人都指向不同的分支。
+-->[ ]<--+ Bare repository
| |
Branch A [ ] [ ] Branch B
| |
+->diff<--+
由此我可以使用我最喜欢的 merge/diff 工具在两个分支上手动修改我的文件。我可以随时 commit
、push
、pull
我的工作。
不过我确信有更好的方法。
听起来您对存储库的初始提交是项目 A 的副本,然后您从该项目分支并在分支上替换为 B。您是否尝试过让父提交只是一个空提交?我认为这会给 git 一个更好的正确合并的机会,因为它不是假设项目 B 中的所有更改都是对项目 A 的编辑的结果。所以你的 git 树看起来像这个:
* A
| * B
|/
* Initial Commit (empty)
借助变基的魔力,您甚至可以开始将一些真正通用的代码放入父级中,这也可能有所帮助。
您是否需要尽可能多地保留项目 A 和 B 的历史记录?
如果没有,我建议采用以下方法:
创建一个 repo 和一个初始的空提交。
除了 master,在初始提交后创建两个分支:A 和 B
将项目 A 和 B 的快照放入各自的分支。
此时,使用您知道如何使用的现有工具来找到两个分支的相同部分,并将相同部分提交给 master。然后,您应该能够将分支 A 和 B 变基到 master 上的新提交上。
起泡、漂洗、重复,并继续从 A 和 B 中获取大块相同的代码,将它们放入 master 中,并基于它们进行变基。您可以逐步执行此操作。
在这个过程中的每一步,您都应该在 A 和 B 分支上进行一次提交,这是从 master 分支上分叉出来的。
在某些时候,您将到达需要查看差异的步骤。让我们以分支A和B上相同变量的不同名称的假设情况为例
好吧,将一个分支上的变量重命名为另一个分支的名称,然后对其进行 rebase-squash,这样您仍然可以在 A 和 B 分支上进行一次提交。这应该最终导致两个分支上的更多代码变得相同,您可以将其拉出,提交到 master 上,然后在其上重新设置 A 和 B 分支的基线。
当你达到 A 和 B 之间没有任何共同点的地步时,它们都与 master 相差一个提交,并且 none 它们改变了重叠的部分,那么你应该能够将一个分支合并到另一个分支;可能会解决一些小的冲突。
在此过程的每一步,您的更改都应该相当小,您不需要使用复杂的差异或合并工具来完成它。
我还建议,在您将您认为是公共代码块提交给 master 并尝试在 master 的新提交之上对 A 和 B 进行变基后,标记分支 A 和 B,如果其中一个失败了,你可以将另一个分支的提示恢复到之前的标签,去掉master上的新提交,然后再试一次。
这个过程的另一个改进是,在创建初始 repo 之后,而不是使用两个分支 + master,克隆 repo 目录两次,然后使用两个新的 repos,本质上是分支:隔离相同的代码后,提交该块到父回购,重新拉动子回购中的父回购,并尝试重新设置子回购中的分支。
我肯定会建议一些接近
然而,"pausing a manual merge, applying a patch to B, and resume the manual merge" 的唯一目的是,git stash 看起来像您需要的工具:
- 开始使用你提到的
git difftool
当点击一些您想同时应用于 A 和 B 的内容时,将您当前的更改保存在存储中:
git stash
转到
BranchB
,应用您的更改:git checkout BranchB # do whatever you want git add / git commit
return 到
BranchA
git checkout BranchA
从存储中检索您的更改
git stash pop
git difftool BranchB
...