git将多个提交合并为孤立分支中的一个,每个提交在前缀子目录中

git将多个提交合并为孤立分支中的一个,每个提交在前缀子目录中,git,git-merge,git-commit,git-merge-conflict,git-plumbing,Git,Git Merge,Git Commit,Git Merge Conflict,Git Plumbing,我需要将一个分支或远程repo中的多个提交合并到另一个分支中的单个提交中 input branch#1: o--o- - -o (C1) \ input branch#2: o--o- - -o | (C2) : \| input branch#N: o--o- - -o | (Cn) \| output branch: o--o- -

我需要将一个分支或远程repo中的多个提交合并到另一个分支中的单个提交中

input branch#1: o--o- - -o   (C1)
                          \
input branch#2: o--o- - -o | (C2)
    :                     \|
input branch#N: o--o- - -o | (Cn)
                          \|
 output branch:   o--o- - -o (Cm)
我需要以一种特殊的方式进行操作,其中每个输入分支合并提交的源树是输出分支合并提交的源树中的前缀或子目录:

<C1>       <C2>       ...  <Cn>
 |          |               |
 +- c1.txt  +- c2.txt       +- cn.txt

<Cm>
 |
 +- C1/c1.txt
 |
 +- C2/c2.txt
 |
 :     :
 |
 +- Cn/cn.txt
但当输出分支是孤立分支时,它的工作方式确实不同。在这种情况下,输入分支的内容会另外合并到输出分支提交的源树的根中:

<Cm>
 |
 +- C1/c1.txt
 |
 +- c1.txt

|
+-C1/C1.txt
|
+-c1.txt
基本上,当输入分支是唯一的输入分支时,就会发生这种情况(当输出分支是孤立分支时,我没有测试多个输入分支的情况,因为我还没有这种情况,但我不排除这种情况)

我已经找到了发生这种情况的原因。因为head还不存在,也不可能存在,包括输出分支,所以merge命令会在调用时创建它,同时让merge不完整,因为输出分支指向一个输入分支,这实际上使输出分支成为其自身的父分支。这会将输入分支的源树的内容放入输出分支提交的源树的根中,而无需用户通知

我知道至少有一种方法可以避免这种行为,例如,在合并之前在输出分支中创建一个空提交,这使得孤立分支不是孤立的,并将头部与对输出分支的引用一起初始化

但我不希望这样做,因为我必须在以后以某种方式删除提交,这实际上是git的变通代码


是否存在一种众所周知的处理git guts的方法,使所有事情都能正常工作并按预期合并在一起?

如果要使用git read tree来填充正在构建的提交的索引,是的,这是为每个提交添加前缀的简单方法,正如您正在做的那样,您已经深入到Git的内部,因此您最好使用
Git提交树
来构建提交对象

换句话说,根本不要从git merge开始。只需使用git read tree--empty清空索引即可。然后读取每个提交Ci,1≤ 我≤ N您的索引现在包含要放入此合并提交Cm的文件

然后,不要使用
git commit
,而是使用
git write tree
将索引转换为树对象,然后使用
git commit tree
将树对象嵌入到新的提交中。由于
git commit tree
允许您指定每个父项,因此您可以直接将您的N路八达通合并:

git read-tree --empty
git read-tree --prefix prefix1 C1
git read-tree --prefix prefix2 C2
...
git read-tree --prefix prefixn Cn

tree=$(git write-tree) || die ...
commit=$(cat ... | git commit-tree -p C1 -p C2 -p C3 ... -p Cn) || die ...
最后,将新的分支名称附加到结果提交:

git branch the-final-result $commit
您在这个新分支上有您的提交Cm

Edit:显然我有点误读了这个问题,而且您已经有了一个现有的分支名称B,其tip commit当前是commit CB。如果要保留其文件,您应该首先读取此树,而不是使用
git read tree--empty
,然后在最后的
git commit tree
中将该提交用作父级之一,并将该新提交快速转发到现有的分支名称B。因此:


根据实际需要的结果进行调整。

此方法至少有一个问题,
提交树
应包含
-p Cm-1
提交哈希,否则与
Cm
分支没有任何关系,推送将被拒绝。这意味着如果
Cm
分支除了合并的提交之外还有其他提交,则必须应用
读取树Cm-1
。啊:我让你的问题标题覆盖你的问题正文。您要求结果是一个孤立分支,我从中得到的唯一合理的含义是,新提交由一个新的分支名称指向,而与任何输入提交分支名称无关。但您实际想要的是新提交成为一个分支的新提示,该分支是C-sub-i的分支之一。(1)我想要一个
C1..Cn
的合并,这在孤立分支的情况下不起预期的作用,但这并不意味着
Cm
分支在任何合并点都是孤立的。(2)
Cm
分支没有从
C1..Cn
完全合并,它仍然可以包含非来自
C1..Cn
的提交,我只是没有提到这一点,因为我使用了
merge
命令,该命令确实考虑到了这一点。更重要的一点是
git read tree
不能将两个或多个源代码树合并到单个目录或子目录中,因此
C1..Cn
Cm
之间不应该通过源代码树,否则只应用最后一个
git读取树
。@Andry:对,这就是为什么这里需要独立的
--前缀=
设置。您可以合并重叠的树,但在这种情况下需要使用不同的
读取树
参数,并且不能使用
--前缀
git branch the-final-result $commit
git read-tree Cm
git read-tree --prefix prefix1 C1
  .
  .
  .
git read-tree --prefix prefixn Cn

tree=$(git write-tree) || die ...
commit=$(cat ... | git commit-tree -p Cm -p C1 -p C2 ... -p Cn) || die ...
git push . $commit:refs/heads/B  # or git branch -f B $commit