这确实不是一个很好的答案,因为它更多的是关于您使用的脚本 - 或者我应该说,您没有使用的脚本,因为您的评论说您使用了一个基于 您链接的脚本的脚本- 但是我将展示我在下面的一些原始存储库的假设脚本转换中得到的相当复杂的图表。请注意,此特定脚本将所有转换都保留为合并基础提交,本质上是 commit B
,并且 commitB
本身是empty。
你的问题说:
现在我想将 branch 合并source
到 branch target
,注意我确保两者在最终切换之前同步。
正如您将在下面看到的,所有新分支都以它们来自的项目命名 - 没有明确的方法来映射source
和target
到,例如,P 或 Q。但是如果您要运行:
git checkout P/master
git merge Q/master
在下面说明的过程之后,此的合并基础git merge
将为空B
提交,并且合并将顺利进行:Git 将查看我分别绘制为D
和的提交H
,跟踪它们的祖先,找到提交B
作为它们的合并基础,然后运行两个git diff
年代:
git diff <hash-of-B> <hash-of-D> # what we did on P/master
git diff <hash-of-B> <hash-of-H> # what they did on H/master
这些git diff
s 的输出会说每个文件都是从头开始创建的,并且它们的所有名称都不同:其中的所有内容都已P/master
命名,而其中的P/*
所有内容都已H/master
命名Q/*
。不会有名称冲突,合并将自行完成。
显然,那不是你正在做的事情。但是你在做什么,以及哪个提交是合并基础,仍然是神秘的。看起来您正在挑选两个提示提交,以便两个提示提交的合并基础是一个确实具有文件的提交,并且这些文件尚未从基础重命名为提示。
您链接的脚本的重点是进行设置,以便每个不相关项目的合并基础都是一个空提交。可能,在该脚本之后要做的事情 - 或者代替该脚本,真的 - 是对所有最终提交进行一次大规模的章鱼合并(注意:这是未经测试的,可能很明显):
git checkout P/master # just to be somewhere that's not master
git branch -d master # discard existing master branch name
git checkout --orphan master # arrange to create new master
git merge P/master Q/master R/master # make big octopus merge to marry all projects
此章鱼合并的合并基础将再次为 commit B
,结果将是一次合并,将所有项目都以新project/*
名称命名。原始存储库现在几乎都没有用了,但如果其中有新的提交,您可以从中获取,添加重命名提交,然后从重命名提交中合并(如果导入脚本没有删除添加的遥控器)。
对链接脚本工作的观察
我从未遇到过这个特殊问题,但脚本中的方法似乎是一个不合理的起点。我可能会做一些不同的事情,而不是为空的合并基础而烦恼,而是使用git read-tree
andgit commit-tree
来构建和创建最终章鱼合并。P/*
主要的关键是在下面的草图中的每个传入项目分支( 、Q/*
等)的末尾添加一个重命名提交。
该脚本似乎以这种方式工作。它具有项目 P、Q、R(其最后一个组件被视为项目名称的 URL)作为输入。
- 做空回购。
进行两次初始提交:
A--B <-- master
提交 A 有一个文件,提交 B 没有文件(为什么不将空树提交为 B?但没关系)。
循环,适用于所有三个项目。在这里,我扩展了循环以查看正在发生的事情。
(循环迭代 1)git remote add P <url>
和git fetch P
(使用--tags
!?)。我们在这里假设 P 有 master 和 dev。
A--B <-- master
P1-P2-...-Pm <-- origin/P/master
\
Pd <-- origin/P/dev
使用 git ls-remote --heads 在 P 中查找提交的名称,即与我们在refs/remotes/P/*
. (假设在 fetch 期间远程 hsa 没有改变——不明智但可能没问题。)
遍历这些名称。结果再次扩展以进行说明...
运行git checkout -b P/master master
。影响:
A--B <-- master, P/master
P1-P2-...-Pm <-- origin/P/master
\
Pd <-- origin/P/dev
git reset --hard
无明显原因运行:没有效果。也许这可能会对后面的某些步骤产生一些影响。
git clean -d --force
无明显原因运行:没有效果。
运行git merge --allow-unrelated-histories --no-commit remotes/P/master"
(does merge, but does not commit yet) and then run
git commit -m ...`。影响:
A--B <-- master
\
\-------C <-- P/master
/
P1-P2-...-Pm <-- origin/P/master
\
Pd <-- origin/P/dev
也许重命名文件,代码有点松散(第 160-180 行):如果项目 P 有一个名为 P 的顶级目录,则什么都不做,否则创建名为 P 的目录(不检查是否失败),然后生效:
git mv all-but-P P/
git commit -m "[Project] Move ${sub_project} files into sub directory"
给予:
A--B <-- master
\
\-------C--D <-- P/master
/
P1-P2-...-Pm <-- origin/P/master
\
Pd <-- origin/P/dev
请注意,git mv
如果其中一项操作失败-k
,它不会执行任何操作。git mv
但是,除了子目录 P 和.git
它本身之外,工作树顶层中的所有文件都应该在索引中并且git mv
应该成功,除非其中一个被命名P
(在这种情况下,哎呀!)。
我在这里假设我们做了 mv,否则提交D
不存在。
重复循环(参见步骤 5)dev
。运行git checkout -b P/dev master
:
A--B <-- master, P/dev
\
\-------C--D <-- P/master
/
P1-P2-...-Pm <-- origin/P/master
\
Pd <-- origin/P/dev
大概是无效的git reset
,并且git clean
在第 7 步和第 8 步中再次出现。(如果第 10 步真的很糟糕,这可能会有所作为git mv
?)像第 9 步那样做一个时髦的两步合并,给出:
A--B <-- master
|\
| \-------C--D <-- P/master
/
P1-P2-...-Pm <-- origin/P/master
\
\ Pd <-- origin/P/dev
\ \
\---E <-- P/dev
从 B 向下的线连接到从 E 向上的线。此时,图表已经变得相当失控。
重命名并按照步骤 10 提交。我在这里假设项目尚未在子目录中master
,如已经假设的那样,和dev
.
A--B <-- master
|\
| \-------C--D <-- P/master
/
P1-P2-...-Pm <-- origin/P/master
\
\ Pd <-- origin/P/dev
\ \
\---E--F <-- P/dev
在第 190-207 行重命名标签真的很丑陋。这应该在获取时使用聪明的 refspec 完成。写这篇文章的人可能不知道带注释的标签和轻量级标签。我不清楚这是否正常工作,我没有仔细看。让我们暂时假设没有标签。
删除远程 P。这origin/P/*
也会删除名称,但当然提交会保留,因为它们被新P/*
分支保留:
A--B <-- master
|\
| \-------C--D <-- P/master
/
P1-P2-...-Pm
\
\ Pd
\ \
\---E--F <-- P/dev
使用远程 Q 重复外部循环(步骤 3)。我们将添加 Q 并获取(再次使用--tags
,这不是第 14 步中提到的好计划,但我们假设没有标签)。origin/Q/*
所以现在我们得到另一个带有名称的不相交子图。为简单起见,我们只假设这次仅origin/Q/master
存在:
A--B <-- master
|\
| \-------C--D <-- P/master
/
P1-P2-...-Pm
\
\ Pd
\ \
\---E--F <-- P/dev
Q1-Q2-...-Qm <-- origin/Q/master
运行git checkout -b Q/master master
:
A--B <-- master, Q/master
|\
| \-------C--D <-- P/master
/
P1-P2-...-Pm
\
\ Pd
\ \
\---E--F <-- P/dev
Q1-Q2-...-Qm <-- origin/Q/master
运行(可能无效且仍然神秘)
git reset --hard
和git clean
步骤。
使用时髦的两步合并--allow-unrelated-histories
来创建新的提交G
,如下所示:
---------------G <-- Q/master
/ |
A--B <-- master | (down to Qm)
|\
| \-------C--D <-- P/master
/
P1-P2-...-Pm
\
\ Pd
\ \
\---E--F <-- P/dev
/ (up to G)
/
Q1-Q2-...-Qm <-- origin/Q/master
同样,可选:将 G 中的所有文件重命名为位于 Q/ 中并提交。再次假设这确实发生了:
---------------G--H <-- Q/master
/ |
A--B <-- master | (down to Qm)
|\
| \-------C--D <-- P/master
/
P1-P2-...-Pm
\
\ Pd
\ \
\---E--F <-- P/dev
/ (up to G)
/
Q1-Q2-...-Qm <-- origin/Q/master
丑陋的尝试重命名标签;我们将忽略这一点。
删除遥控器Q
和origin/Q/*
名称。(不需要画这个。)
对存储库 R 重复外部循环。假设它只有自己的master
,我们将得到一个像这样的纠结图:
--------------------I--J <-- R/master
/ | (down to Rm)
/
| ---------------G--H <-- Q/master
|/ |
A--B <-- master | (down to Qm)
|\
| \-------C--D <-- P/master
/
P1-P2-...-Pm
\
\ Pd
\ \
\---E--F <-- P/dev
/ (up to G)
/
Q1-Q2-...-Qm
/ (up to I)
/
R1-R2-...----Rm
(分析结束)