非线性历史情境
如果您的历史记录不是线性的,并且让它们变成线性的不是一个选项(您不想这样做或者这会导致许多冲突,这些冲突可能会因错误而解决),您也可以尝试通过手动编辑交互式变基序列来融合存储库。
假设您的存储库Y(主机)具有以下主分支图:
touch Cx && git add Cx && git commit -m Cx Cx
git branch -m y/master
git checkout -b y/master-Cy && touch Cy && git add Cy && git commit -m Cy \
&& git checkout - && git merge --no-edit --no-ff y/master-Cy && git branch -d y/master-Cy
git checkout -b y/master-Cz && touch Cz && git add Cz && git commit -m Cz \
&& git checkout - && git merge --no-edit --no-ff y/master-Cz && git branch -d y/master-Cz
* 478d271 (HEAD -> y/master) - Merge branch 'y/master-Cz' into y/master 3 seconds ago
|\
| * 93fbaf8 - Cz 3 seconds ago
|/
* e80b2ea - Merge branch 'y/master-Cy' into y/master 6 seconds ago
|\
| * a1842d1 - Cy 6 seconds ago
|/
* 9467260 - Cx 31 seconds ago
为了简洁起见并省略了仓库X的源获取阶段,假设我们可以将其直接构建在同一仓库中。
git checkout --orphan x/master
git reset --hard
touch Ca && git add Ca && git commit -m Ca Ca
git checkout -b x/master-Cb && touch Cb && git add Cb && git commit -m Cb \
&& git checkout - && git merge --no-edit --no-ff x/master-Cb && git branch -d x/master-Cb
git checkout -b x/master-Cc && touch Cc && git add Cc && git commit -m Cc \
&& git checkout - && git merge --no-edit --no-ff x/master-Cc && git branch -d x/master-Cc
* e271022 (HEAD -> x/master) - Merge branch 'x/master-Cc' into x/master 1 second ago
|\
| * a403baf - Cc 1 second ago
|/
* c34f424 - Merge branch 'x/master-Cb' into x/master 4 seconds ago
|\
| * 6107552 - Cb 4 seconds ago
|/
* 70d7b2d - Ca 7 seconds ago
那时有两个分支:
y/master
代表您的主机存储库主分支,
x/master
代表您的外部存储库主分支。现在,让我们为两个主分支准备交互式变基TODO序列:
git checkout y/master
git rebase -i --rebase-merges --root
l onto
t [new root]
p 9467260 Cx
l branch-point
p a1842d1 Cy
l y-master-Cy
t branch-point
m -C e80b2ea y-master-Cy
l branch-point-2
p 93fbaf8 Cz
l y-master-Cz
t branch-point-2
m -C 478d271 y-master-Cz
请将其保存为文本文件,命名为y-master.txt
,并放在某个地方。
git checkout x/master # or git checkout to the foreign repository remote ref (that leads to a detached HEAD but it's definitely not an issue)
git rebase -i --rebase-merges --root
git checkout y/master
l onto
t [new root]
p 70d7b2d Ca
l branch-point
p 6107552 Cb
l x-master-Cb
t branch-point
m -C c34f424 x-master-Cb
l branch-point-2
p a403baf Cc
l x-master-Cc
t branch-point-2
m -C e271022 x-master-Cc
请保存这个文件,
x-master.txt
。
现在,假设您已经为y/master创建了一个快照标签(以避免崩溃原始分支),"唯一"的事情现在就是"
编程"融合库序列。
git rebase -i --rebase-merges --root
(选项卡命令表示X存储库命令。FOREIGN-前缀是手动插入的。)
l onto
t [new root]
p 9467260 Cx
p 70d7b2d Ca
l branch-point
p a1842d1 Cy
l y-master-Cy
t branch-point
m -C e80b2ea y-master-Cy
l FOREIGN-branch-point
p 6107552 Cb
l FOREIGN-x-master-Cb
t FOREIGN-branch-point
m -C c34f424 FOREIGN-x-master-Cb
l branch-point-2
p 93fbaf8 Cz
l y-master-Cz
t branch-point-2
m -C 478d271 y-master-Cz
l FOREIGN-branch-point-2
p a403baf Cc
l FOREIGN-x-master-Cc
t FOREIGN-branch-point-2
m -C e271022 FOREIGN-x-master-Cc
这将会导致类似以下的结果:
* cbbf73b (HEAD -> y/master) - Merge branch 'x/master-Cc' into x/master 10 minutes ago
|\
| * b143f45 - Cc 10 minutes ago
|/
* bd0c586 - Merge branch 'y/master-Cz' into y/master 3 hours ago
|\
| * dfb5e4e - Cz 3 hours ago
|/
* 01f078d - Merge branch 'x/master-Cb' into x/master 10 minutes ago
|\
| * 26b2f61 - Cb 10 minutes ago
|/
* f1105a4 - Merge branch 'y/master-Cy' into y/master 3 hours ago
|\
| * aa67233 - Cy 3 hours ago
|/
* 7a23a6e - Ca 10 minutes ago
* 9467260 - Cx 3 hours ago
这看起来很像你在问题描述中所描述的提交顺序,并包括测试合并。它可能可以以某种方式脚本化,但是这种方法的脚本编写肯定超出了我的能力范围。
上述方法没有经过充分测试,可能包含错误或其他使得你的合并历史出错的问题。
即使存在文本冲突(这可以更轻松地解决),线性化两个历史记录并将它们合并在一起要容易得多。分歧的提交需要你介入到变基序列中。
这里还有一个 gawk
脚本,可以帮助您为生成的变基序列中出现的每个提交构建时间轴时间戳作为注释:
#!/usr/bin/awk
function print_with_extra(orig_line, object) {
cmd = "git rev-list -1 --format='%ai%n%ci' " object
author_date = ""
committer_date = ""
i = 0
while ( (cmd | getline line) > 0 ) {
switch ( ++i ) {
case 2: author_date = line; break
case 3: committer_date = line; break
}
}
close(cmd)
print orig_line " # (" author_date ") (" committer_date ")"
}
{
switch ( $0 ) {
case /^p [0-9a-f]+/: print_with_extra($0, $2); break
case /^m -C [0-9a-f]+/: print_with_extra($0, $3); break
default: print; break
}
}
使用示例:gawk -f timestamps.awk y-master.txt
或 gawk f- timestamps.awk x-master.txt
。以下是示例输出:
l onto
t [new root]
p 9979de5 Ca
l branch-point
p 4dcff42 Cb
l x-master-Cb
t branch-point
m -C 4de8360 x-master-Cb
l branch-point-2
p 206f5a8 Cc
l x-master-Cc
t branch-point-2
m -C c3ac7e5 x-master-Cc
Y
的历史记录完全是线性的吗?还是有多个分叉和合并点(例如:您是否使用合并请求来推进主分支)?b. 您只需要重写一个单独的分支(即master
分支)吗?还是您还有从它派生的其他分支? - LeGECgit rebase
默认情况下不会保留合并提交。从两个仓库的根提交开始,将存储库历史记录完全线性化是否可行? - terrorrussia-keeps-killinggit rebase --rebase-merges
输出编写脚本(生成的待办事项序列似乎可以使用诸如awk
之类的工具进行解析,而像sort
这样的工具则会失败),但我不确定这样的脚本有多复杂。 - terrorrussia-keeps-killinggit rebase
完成而需要额外的工作,正如您在问题中提到的)。我将尝试使用非线性存储库场景更新答案,但正如我上面提到的,我不知道如何编写脚本,因此最终可能需要进行极其繁琐的手动工作来编辑rebase TODO序列。 - terrorrussia-keeps-killing