Loop, for all three projects. Here I have expanded the loop to view
what's happening.
(loop iteration 1) git remote add P <url>
and git fetch P
(with --tags
!?). We're going to assume here that P has master and dev.
A
P1-P2-...-Pm <
\
Pd <
Use git ls-remote --heads to find names for commits in P, i.e.,
the same set of names we have in refs/remotes/P/*
. (Assumes the
remote hsa not changed during fetch -- unwise but probably OK.)
Loop over these names. Result again expanded in line for illustration...
Run git checkout -b P/master master
. Effect:
A
P1-P2-...-Pm <
\
Pd <
Run git reset --hard
for no apparent reason: no effect. Perhaps
this might have some effect on some later step.
Run git clean -d --force
for no apparent reason: no effect.
Run git merge --allow-unrelated-histories --no-commit remotes/P/master"
(does merge, but does not commit yet) and then run
git commit -m ...`.
Effect:
A
\
\
/
P1-P2-...-Pm <
\
Pd <
Maybe rename files, with somewhat squirrelly code (lines 160-180):
if project P has one top level directory named P, do nothing, otherwise
create directory named P (with no check to see if this fails) and
then in effect:
git mv all-but-P P/
git commit -m "[Project] Move ${sub_project} files into sub directory"
giving:
A
\
\
/
P1-P2-...-Pm <
\
Pd <
Note that the git mv
is given -k
so that it does nothing if
one of the git mv
operations would have failed. However, except
for subdirectory P and .git
itself, all files in the top level
of the work-tree should be in the index and the git mv
should
succeed unless one of them is named P
(in which case, yikes!).
I assume here that we did the mv, otherwise commit D
does not exist.
Repeat loop (see step 5) for dev
. Run git checkout -b P/dev master
:
A
\
\
/
P1-P2-...-Pm <
\
Pd <
Presumably-ineffectual git reset
and git clean
again
as in steps 7 and 8. (This might do something if the git mv
in step 10 went really badly?) Do a funky two step merge as in
step 9, giving:
A
|\
| \
/
P1-P2-...-Pm <
\
\ Pd <
\ \
\
where the line down from B connects to the one up from E. The
graph has gotten rather out of hand at this point.
Rename and commit as in step 10. I assume here that the
project isn't already in a subdirectory, in both master
, as
already assumed, and dev
.
A
|\
| \
/
P1-P2-...-Pm <
\
\ Pd <
\ \
\
Really ugly attempt to rename tags, at lines 190-207. This
should have been done at fetch time, using a clever refspec.
Whoever wrote this probably was not aware of annotated vs
lightweight tags. It is not clear to me whether this works
correctly and I did not look closely. Let's just assume no tags
for now.
Remove remote P. This removes the origin/P/*
names too,
but of course the commits stick around as they're retained by
the new P/*
branches:
A--B <-- master
|\
| \-------C--D <-- P/master
/
P1-P2-...-Pm
\
\ Pd
\ \
\---E--F <-- P/dev
Repeat outer loop (step 3) with remote Q. We'll add Q and
fetch (again with --tags
, not a good plan as noted in step
14, but let's just assume no tags). So now we get another
disjoint subgraph with origin/Q/*
names. For simplicity
let's just assume that only origin/Q/master
exists this time:
A--B <-- master
|\
| \-------C--D <-- P/master
/
P1-P2-...-Pm
\
\ Pd
\ \
\---E--F <-- P/dev
Q1-Q2-...-Qm <-- origin/Q/master
Run 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
Run the (probably ineffectual and still mysterious)
git reset --hard
and git clean
steps.
Use the funky two step merge with --allow-unrelated-histories
to create new commit G
like this:
---------------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
Again, optional: rename all files in G to live in Q/ and
commit. Again let's assume this does happen:
---------------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
Ugly attempt to rename tags; we'll ignore this.
Remove remote Q
and origin/Q/*
names. (No need to draw this.)
Repeat outer loop for repository R. Assuming it has only
its own master
, we'll get a tangled graph like this:
--------------------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
--no-commit
。如果你在第一个例子中也这样做了(git merge -s ours
),那么这就可以解释问题了。如果不是这样,提供更多关于你如何陷入这种情况的细节可能会有所帮助(你发布的第一个链接谈到了使用子树合并,因此更多细节可能很重要)。 - torekgit merge-base master target
指向超级合并之前还是之后的提交?第三个问题:source
和target
中的文件名是否相同,还是重命名前后的名称? - joanissource
和target
都已经创建了。是的,我们最终会放弃source
,但至少还需要几个月的时间。 - tanagergit merge -s ours
之后的所有合并都应该是针对发生在重新统一之后的提交,这意味着文件名不应更改。我故意选择了SHA(如上面的示例),以便git merge -s ours SHA
将包括作为重新统一一部分的所有活动。 - tanager