将多个git仓库合并为一个,保留分支历史记录

27

我有四个独立的项目,它们各自有自己的git存储库,并且所有项目都有相同名称的分支。

 /project/
 /project/projA/
 /project/projA/.git/
 /project/projB/
 /project/projB/.git/
 /project/projC/
 /project/projC/.git/
 /project/projD/
 /project/projD/.git/

所有的Git仓库分支都有相同的名称,当然也有自己的主分支。

问题

我想像这样将所有项目合并为一个:

  /Project/.git/
  /project/projA/
  /project/projB/
  /project/projC/
  /project/projD/

但是

我希望保留所有分支的历史记录。

附注-> 我在所有存储库中使用相同的分支名称。 例如:一个用于所有四个项目的分支名称:V6-004

细节

我尝试了子模块子树,但两者都没有解决这个问题。

我也尝试过这个。

  $ mkdir new_parent_project
  $ cd new_parent_project
  $ git init
  # Now we need to create the initial commit. This is essential.
  $ touch README.md
  $ git add README.md
  $ git commit -am "initial commit"

之后

  # merge project ProjA into subdirectory ProjA
  $ git remote add -f ProjA http://GitUrl
  $ git merge -s ours --no-commit ProjA/V6-006
  $ git read-tree --prefix=ProjA/ -u ProjA/V6-006
  $ git commit -m "merging ProjA into subdir: ProjA"

之后

  # merge project ProjB into subdirectory ProjB 
  $ git remote add -f ProjB http://GitUrl
  $ git merge -s ours --no-commit ProjB/V6-006
  $ git read-tree --prefix=ProjB/ -u ProjB/V6-006
  $ git commit -m "merging ProjB into subdir: ProjB"

但是

这些项目已经合并了,但我只拥有V6-006的历史记录,其他分支的历史记录我没有。


1
我尝试了子模块和子树,但两者都没有解决问题。太糟糕了:在这种情况下,子模块是一个简单的解决方案。 - VonC
1
是的,但是。当你想在项目中包含一个只需要偶尔更新的第三方库时,这个模型可以很好地工作。然而,如果你使用子模块来处理一个紧密耦合的库,而且你经常需要对其进行更改,你会发现子模块并不是最佳选择。 - Anas ZAHOURI
您的仓库中的子仓库只有一个分支(master)还是它们有自己的多个分支?(除了它们的 master 分支) - VonC
是的,这些子仓库有自己的多个分支。 - Anas ZAHOURI
你只是想要每个分支和子目录中的所有现有历史记录,然后在最后进行一个巨大的章鱼合并,将所有内容汇总在一起? - Andrew C
@AnasZAHOURI 你好,我也遇到了类似的问题。你有找到合理的解决方法吗? - Tomas Votruba
1个回答

14

这个解决方案与你尝试的方法并没有太大不同。 只有当你的不同项目没有共同的文件时才有效(否则解决冲突可能会很困难)。

# create a new repo:
git init all_projects
cd all_project
# to make it more easy to understand, let's create a new branch
git checkout -b main

# import 1st project
git remote add projectA http://projectA
git fetch --all --tags
git checkout masterA projectA/master
git rebase masterA main
# move the main branch to the current state
git branch main -f
# Now your branch main is at the same state as your A project

# import 2st project
git remote add projectB http://projectB
git fetch --all --tags
git checkout masterB projectB/master
git rebase masterB main
# move the main branch to the current state
git branch main -f
# Now your branch main contains all commits from projectA and projectB

# etc..

结果将是一个仓库,其中先包含项目A的所有提交,然后包含项目B的所有提交,即使项目B有一些提交日期早于项目A的最后一次提交,但这不应该是一个问题(并且历史记录树将更容易阅读)。

编辑:很抱歉我刚刚注意到这不能解决您获取所有远程分支的问题。也许您可以根据那个问题找到一个解决方案,使用类似以下内容的东西:

for i in $(git branch -r |grep projectA|awk -F'/' '{print $2}'); do
  git checkout $i projectA/$i
  git rebase $i main
done

但这会使您的树更加复杂,因为所有分支都将从main提交开始...


3
我无法让它工作,执行步骤git checkout masterA projectA/master时出现错误,显示error: pathspec "masterA" did not match any files known to git。在"masterA"中应该放什么? - ESala
如果git将masterA视为文件,则可能意味着本地(我想远程也是如此)不存在该分支。或者可能缺少git fetch命令。 - Asenar
@Asenar,你有没有想法针对两个共享公共文件的存储库,其中一个是另一个的分支而没有历史记录?我正在这里尝试解决这个问题 - NobleUplift
当没有远程HTTP仓库,只有本地文件时,这个会起作用吗? - przemo_li
2
@przemo_li 远程仓库的 URL 可以以 httpuser@server/path/to/loca/dir 开头,所以我不明白为什么这样不起作用。但你可以查看 git help clone 来了解一些有趣的选项(例如 --no-hardlinks, --shared, …)。 - Asenar
1
我认为这不起作用,因为需要将masterA放在子目录中;现在合并和变基只会将文件添加到主目录中。 - axd

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接