将一个仓库中最近的更改合并到另一个无关快照(而非克隆)的仓库中,使用git。

3

我有两个Git仓库:内部和外部。内部仓库包含了我们的全部历史记录。外部仓库只有一个快照,它是三周前内部仓库的一个提交版本。从图形上看,它类似于这样:

A01
 |
A02
 |
A03
 |
A04  --> snapshot to B01
 |
A05
 |
A06 - A07
 |     |
A08    |
 |    /
A09  /
 |  /
 | /
 +
 |
A10
 |
A11
 |
A12

我的问题是如何将提交 A05 到 A12 最好地合并到本地副本仓库 B 中?(我会在推送到我们公开的仓库之前将它们压缩)
A 和 B 是完全不相关的仓库(B 不是作为 A 的克隆创建的;我们将仓库 A 从提交 A04 处检出副本,并将其检入新仓库 B)。
这其中的复杂之处在于我有文件重命名。仓库 A 包含了重构提交,其中文件被重命名和移动了。如果我只是拍摄 A12 的快照并提交到 B01,那么我必须告诉 Git 如何关联移动前后的文件(就像 Mercurial 中的 hg rename -A 一样)。这些信息已经在仓库 A 的历史记录中了,我不想重新创建它。

A07与A09-A10之间有什么关系? - Rémi Becheras
如果我从头开始重新做,我应该这样做:将A(包括A01-A04)克隆到私有仓库,压缩所有提交,然后再克隆到公共仓库B。 - Jason S
A07是一个分支,A10将其合并回主分支。 - Jason S
B01之后的新提交是否已经转发到仓库B? - Rémi Becheras
"forwarded"?哦,你是指我对B做了其他的修改吗?没有。 - Jason S
对不起,是的,那就是我的意思。好的。所以我认为@thirtythreeforty的答案是最佳选择。我也会这样做。 - Rémi Becheras
3个回答

2

有些人建议手动将已检出的版本复制到仓库B中。你真正想做的是将提交A01、A02和A03“压缩”到B01上。这样可以确保在提交到B仓库时不会犯粗心的错误。

如果A和B在同一个仓库中,那么这将很简单,但它们并不在同一个仓库中。幸运的是,你可以通过在A的副本中添加B作为远程仓库来实现类似的效果:

~/A $ git remote add external ssh://path/to/B
~/A $ git fetch external

B已经设置为远程外部。它具有完全独立的DAG,但它们在同一个存储库中,因此现在可以压缩提交记录。不幸的是,我认为你必须知道你从哪个提交记录创建了B01。可能有一些晦涩的Git命令可以告诉你,但自己找出来也很容易。对于这个示例,提交记录是A04。(显然在实际操作中会是一个短哈希值。)现在进行压缩:

~/A $ git rebase --interactive A04 --onto external/master

这里的 external/master 指的是你DAG中的 B01
当你运行上述命令时,会出现一个编辑器,在除第一次提交以外的每个提交上修改操作为 squash。(在Vim中,使用块模式很容易实现。)它应该像这样:
pick A03
squash A02
squash A01

退出编辑器并允许 Git 应用更改。现在您可以将更改推送到远程仓库中的 external


1
一旦您通过创建快照以进行检查(例如仅用于发布或其他原因)启动了单独的存储库,您应该计划在每次想要更新该单独存储库时执行此过程,以正确跟踪文件删除/重命名等情况:
  1. 在真实的存储库中创建一个快照(git archive 很好用)
  2. 在“发布”存储库中,从工作副本中删除所有内容(只留下 .git/ 和可能的 .gitignore.gitattributes等),但请注意,不要立即提交这些更改
$ git clean -fdx
$ git rm -r *
  1. 解压您的快照
  2. 提交新版本

(注意:此处保留了HTML标签,仅进行了翻译)
$ git add -A .
$ git commit
我有许多软件包需要执行这项任务(例如gcc),以保留发布历史记录 - 生成的代码库比保留所有发行版档案要小得多。

或者,您可能可以通过使用git bundlegit mergegit cherry-pickgit rebase和一些git format-patch/git am/git apply的技巧来找到某种复杂的方法以实现类似的功能,但是其中许多技巧都依赖于两个代码库之间具有某种公共历史的近似值,而这在您的情况下并不存在。这种过程的复杂性可能会超过您能够想象到的任何潜在好处。


我不同意;使“快照”方法变得困难的是文件重命名。然而,如果你告诉我仓库没有关联,那么我想我也可以用克隆的方法重新开始。 - Jason S
@JasonS,请查看上面编辑过的程序,它将解决有关文件重命名等问题的顾虑。 - twalberg

0

假设您在拍摄快照后没有对B进行任何更改,那么您真正想要做的是使B看起来像A的镜像副本。由于您提到它们是“完全不相关的存储库”,我假设您在本地机器上有两个目录(每个存储库一个)。由于您计划将这些更改压缩为一个提交,建议您只需将指向A的本地目录的内容(去除.git目录)复制到指向B的目录中。执行 git add --all .,提交然后推送即可。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接