我需要从一个存储库 (
repo-a
) 创建补丁并将它们合并到另一个存储库 (repo-b
)。这些补丁需要包含提交本身,所以我发现 git format-patch
和 git am
是完美的选择。
我们在
repo-a
中使用多个分支,有时,文件会 added
来自两个不同的分支并合并到 main
。
git am
不喜欢这样..这是问题的完整示例;
mkdir repo-a; cd repo-a
git init
touch randomfile
git add randomfile
git commit -m "Adding an initial file"
git checkout -b anotherbranch
touch a-file
git add a-file
git commit -m "Adding a-file from anotherbranch"
git checkout main
touch a-file
git add a-file
git commit -m "Adding a-file from main"
git merge anotherbranch
git format-patch -o patches HEAD~2
# patches/0001-Adding-a-file-from-anotherbranch.patch
# patches/0002-Adding-a-file-from-main.patch
cd ..
mkdir repo-b; cd repo-b
git init
cp -r ../repo-a/patches ./
git am patches/*
# Applying: Adding a-file from anotherbranch
# applying to an empty history
# Applying: Adding a-file from main
# error: a-file: already exists in index
# Patch failed at 0002 Adding a-file from main
# hint: Use 'git am --show-current-patch=diff' to see the failed patch
# When you have resolved this problem, run "git am --continue".
# If you prefer to skip this patch, run "git am --skip" instead.
# To restore the original branch and stop patching, run "git am --abort".
以上失败,因为
git
已经拥有该文件。通常情况下,git 会很高兴并按其应有的方式添加补丁..
有没有办法做到这一点,并保留 git 提交?我不想创建一个大补丁,我也想要提交。
我已阅读https://git-scm.com/docs/git-format-patch并在此处输入链接描述。我也尝试过一些随机选项(如
--find-copies-harder
),但没有任何运气。
一些附加信息:
cp -r
、rm -rf .git and-some-other-files
和新的 git init
制成的。
git format-patch
非常适合提取提交的线性历史记录,但不适用于合并:
git help format-patch
,重点是我的):描述
准备每个非合并提交及其“补丁”...[...]
注意事项
请注意,格式补丁将从输出中省略合并提交,即使它们是请求范围的一部分。
为
anotherbranch
和 main
上的每个提交创建一个补丁,但没有为合并提交创建补丁,并且如果您检查这些 pacthe,它们不包含表明它们具有相同父级的信息。
这些信息不足以通过合并自动重建历史记录。
可能有多种策略可以将提交从
repo-a
移植到 repo-b
,同时保留分支和合并,但我们需要更多的上下文来为您提供更准确的答案。
例如:一种方法可能是将
repo-a
添加为 repo-b
中的遥控器,并使用 git rebase -r
(-r
是 --rebase-merges
的缩写)或 git filter-repo
的某些子命令来移植完整的历史记录块.
如果您想从 repo-a 中删除文件,但可以显示剩余文件的历史记录,则可以使用
git filter-repo
将 repo-a
转换为精简版本。好处是该命令以可重复的方式创建提交,因此新提交的历史记录将与之前的提取相匹配。
我找到了一种按照我想要的方式做到这一点的方法。
git remote add otherrepo ../otherrepo
git fetch otherrepo
# If you want to fetch lfs objects as well
git lfs fetch --all otherrepo
# -X subtree: Or you will get a lot of merge-conflicts, some of them with empty lines.
# --signoff: To add signoff on the merge-commit (not the merged commits)
# --allow-unrelated-histories: This is the main trick!
git merge -X subtree --signoff --allow-unrelated-histories otherrepo/main
整个历史和一切都按其应有的方式进行。合并提交包含合并的内容,历史记录、图表、作者和一切看起来都不错。
git merge anotherbranch
我宁愿rebase目标分支顶部的分支(在主分支之上),然后在新分支HEAD和主分支之间打补丁(而不是
HEAD~2
)
git switch anotherbranch
git rebase main
git format-patch -o patches main