5

我有一个包含这段历史的存储库:

A---B---C---D

然后,这个存储库被“拆分”(基本上,使用 git-subtrees 创建了另一个存储库,它的历史从“D”开始)。

现在,我有这个历史的另一个回购:

# The same D as the other
D---E---F---G

如何将同一项目故事情节的这两个“部分”合并到一个存储库中?
最终结果必须是:

A---B---C---D---E---F---G

我已经尝试了很多东西,但所有这些都包括合并,这不是我想要的,因为合并不会保留一些更改,例如已删除的文件。
此外,我尝试为存储库的最后一个版本的所有更改生成补丁并将它们应用到旧版本中,但出现了很多error: <file> already exists in index错误。

更新

我发现了另一个关于重新提交提交的问题,这正是解决我的问题的方法,结合了git replace --graftgit filter-branch.

更新 2

现在我的任务已经完成,我发布了对以下问题的完整、正确的答案。

4

2 回答 2

2

更新 - 实际完美的方法:

准备

# Inside the older repo
$ cd old_repo

# Add the remote to newer repo with updated content
$ git remote add <remote name> <new_repo>

# Fetch the remote
$ git fetch <remote name>

# Track all branches of the remote so you have all of it's history in your older git (be aware of the remote's name in the command)
$ for b in `git branch -r | grep -v -- '->'`; do git branch --track ${b##<remote name>/} $b; done

# Delete the remote so you avoid messing up with the newer repo
$ git remote remove <remote name>

现在,我强烈建议你在这个 repo 中使用可视化工具(比如 Gitkraken),因为现在那里有点乱。您将有两个相互独立的历史记录,可能有很多重复的提交。

现在,选择将被操纵的提交。让我们用散列来调用A旧历史中的提交,它现在将成为B最新历史提交的父级。现在,您可以使用下面的脚本(或手动运行命令)来加入树并清理留下的混乱(在提交时修剪较新的历史记录B,丢弃所有父级,因为现在它有一个新的父级)。
(您必须安装 git-replace 和git-filter-repo

#!/bin/sh

# Argument "$1" is commit A, and argument "$2" is commit B of the explanation above

if [ -z "$1" ] || [ -z "$2" ]
then
        echo "You must provide two commit hashes for this script";
        exit 1;
fi

git replace --graft $1 $2
result="$?"

[ "$result" = "0" ] && git filter-repo --force

年龄较大,不重要(仅用于学习不做什么),请在下面回答。

首先,我尝试了使用 的方法git-rebase,但由于多种原因没有成功,最大的一个原因是它有点矫枉过正,例如将提交的父级更改为另一个提交,即使它与历史无关.
然后我尝试git cherry-pick将所有历史从点重新应用E..G到旧存储库,由于多种原因也没有工作,但主要原因是它没有递归复制其他分支。

尝试过的方法

$ git replace --graft <commit> <new parent to this commit>
现在,将 放在HEAD新历史记录的顶端(您要保留的主行中的最新提交),然后:
$ git filter-branch <new parent to this commit>..HEAD

您可能会松散尚未合并到 HEAD 所在分支的分支,我目前找不到解决方法。

于 2020-06-19T17:12:08.097 回答
1

您可以创建一个新的存储库,将两个存储库都添加为远程存储库,并将第二个存储库重新定位到第一个存储库:

这是回购1:

repo1[master]/$ git log --oneline
b3ae047 D
5c68b5e C
4a0bfe9 B
0d88f30 A
repo1[master]/$ git grep -e .
a:a
b:b
c:c
d:d

这是回购 2:

$ cd ../repo2/
repo2[master]/ $ git log --oneline
7b05da3 G
3a72ace F
acd2388 E
5bfa6b3 D
repo2[master]/$ git grep -e .
a:a
b:b
c:c
d:d
e:e
f:f
g:g

从提交 D 开始,与 repo 1 相同:

repo2[master]/$ git log --oneline HEAD~3
5bfa6b3 D
repo2[master]/$ git grep -e . HEAD~3
HEAD~3:a:a
HEAD~3:b:b
HEAD~3:c:c
HEAD~3:d:d

现在让我们创建一个连接它们的存储库:

repo2[master]/$ mkdir ../repo3
repo2[master]/$ cd ../repo3
repo3$ git init
repo3[master]/$ git remote add r1 ../repo1
repo3[master]/$ git remote add r2 ../repo2
repo3[master]/$ git fetch r1 && git fetch r2
...boring output omitted...

现在我们要从 repo 2 的提示重新设置基准:

fat:repo3[master]/$ git reset --hard r2/master
HEAD is now at 7b05da3 G

您需要执行git rebase -i r1/master并删除第一个提交 D,因为它重复了r1/master. 如果您使用完整的命令行(并且没有在 gitconfig 中配置编辑器):

repo3[master]/$ export EDITOR='sed -ibak 1d'
repo3[master]/$ git rebase -i r1/master
Successfully rebased and updated refs/heads/master.
repo3[master]/$ git log --oneline
fc2eb8e G
de5161b F
e85ce17 E
b3ae047 D
5c68b5e C
4a0bfe9 B
0d88f30 A
repo3[master]/ (INT)$ git grep -e .
a:a
b:b
c:c
d:d
e:e
f:f
g:g
于 2020-06-19T05:59:13.817 回答