在另一个仓库中应用某个提交所引入的更改

159

我在本地机器上有一个名为repo1repo2的仓库。它们非常相似,但后者是另一种分支(repo1不再维护)。

/path/to/repo1 $ git log HEAD~5..HEAD~4
<some_sha> Add: Introduce feature X

如何将在 repo1 中进行的提交 <some_sha> 所做的更改应用到 repo2 中?

我需要准备一些补丁吗,还是可以在两个仓库之间使用cherry-pick来完成?

如果要对一系列提交进行相同的操作呢?


2
你不能直接从repo1拉取到repo2吗? - zwol
如果您正在寻找将更改应用于已移动到存储库之一中的文件或文件的略微更具体的情况,请查看此处:https://dev59.com/tXA75IYBdhLWcg3wFEoI - Braham Snyder
4个回答

251
你可以在你的第一个代码库中使用git format-patch,然后在你的第二个代码库中使用git am来应用该补丁:
/path/to/1 $ git format-patch sha1^..sha1
/path/to/1 $ cd /path/to/2
/path/to/2 $ git am -3 /path/to/1/0001-…-….patch

或者,用一句话来说:
/path/to/2 $ git --git-dir=/path/to/1/.git format-patch --stdout sha1^..sha1 | git am -3

10
这个解决方案比使用GIT_ALTERNATE_OBJECT_DIRECTORIES直接挑选提交记录的被接受答案更为简单和安全(后者会破坏我的代码库)。 - Chuim
3
当出现冲突时,由于无法找到另一个分支上的提交记录,因此操作会失败。 - Roger Far
2
git am 命令中添加 --ignore-whitespace 可能会解决任何冲突并避免执行三方合并。 - Hugheth
2
如果您只想获取最新的提交记录:git format-patch HEAD^1 - user3064538
请注意,此补丁将应用于/path/to/2中的当前分支,因此如果您想切换到在其他存储库上进行提交的分支,请在运行git am -3 ...之前执行该操作。 - BallpointBen

118

如果您将第二个存储库添加为第一个存储库的远程,然后进行fetch操作,就可以使用cherry-pick


12
那其实是正确的做法。 - Wilbert
5
我也觉得这是正确的方法。我刚刚尝试了一下,效果很好。 - Ricky Nelson
13
我会建议在第二个代码库中运行git fetch [remote-name],然后再运行git cherry-pick [sha1] - user113397
5
这种方法对我非常有效,谢谢。由于第二个代码库也是本地的,所以只需要在将其添加为远程代码库时使用文件URI即可。 - palimpsestor
3
就我个人而言,我有一个庞大的远程Git代码库的两个克隆版本(以允许并行工作),这意味着它的所有历史记录已经下载并存储在我的硬盘上两次。如果我还要将它们作为彼此的远程添加,那么就会创建出额外的两个相同历史记录的副本,并且可能需要在它们之间进行同步,然后才能进行“挑选”操作。 因此,尽管这可能感觉是“正确”的方法,但并不总是最实用的。 - Chuim
显示剩余5条评论

35
作为一种hack,您可以尝试修改GitTips页面上比较两个不同存储库中提交的配方,即:
GIT_ALTERNATE_OBJECT_DIRECTORIES=../repo/.git/objects \
git cherry-pick $(git --git-dir=../repo/.git rev-parse --verify <commit>)

../repo 是指另一个仓库的路径。

使用现代 Git,您可以使用多个修订版本和修订版本范围进行cherry-pick

$(git --git-dir=../repo/.git rev-parse --verify <commit>) 用于将<commit>(例如HEADv0.2master~2,这些是从第二个复制的存储库中的值)转换为提交的SHA-1标识符。如果您知道要选择的更改的SHA-1,则不需要此操作。

注意,Git 可能会跳过从源存储库复制对象,因为它不知道备用对象存储库仅用于一次操作。您可能需要使用以下命令从第二个存储库复制对象:

GIT_ALTERNATE_OBJECT_DIRECTORIES=../repo/.git/objects git repack -a -d -f

这将把从第二个仓库借来的对象放回原始仓库存储中

未经测试。


一个不那么hacky的解决方案是遵循knittl answer:

  • 进入你想要复制提交历史的第二个仓库,使用 git format-patch 生成想要的补丁
  • 可选地,将补丁(0001-*等)复制到你的仓库中
  • 使用 git am --3way 应用这些补丁

1
工作正常。如果您在提交方面遇到问题,则执行“git reset HEAD; git add。”。 - gumik
5
太棒了!你要怎么做一系列的提交?只需要用 sha1...sha2 就可以了吗? - hvgotcodes
我也遇到了“致命错误:无法读取树...”,但是在执行git reset HEAD^之后,一切都正常了。 - jmarceli
1
@Chuim:如果你想在其他仓库中使用基于引用的名称来引用提交,例如 masterHEAD^^ 或类似的名称,则需要使用 git rev-parse 命令;rev-parse 将其转换为通用的 SHA-1 标识符。 - Jakub Narębski
@Chuim:可能发生的一件事情(但不应该发生)是Git执行操作时假定临时备用对象始终可用。您可以尝试(在cherry-pick之后)GIT_ALTERNATE_OBJECT_DIRECTORIES=../repo/.git/objects git repack -a -d -f将这些对象放入原始存储库中,然后运行git gc。希望对您有所帮助。 - Jakub Narębski
显示剩余5条评论

6

如何获取diff输出并将其输入到您的脚本中? - Shiva

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