2025-03-16 09:00:01

组合多个git存储库

假设我有一个这样的设置

phd/code/
phd/figures/
phd/thesis/

由于历史原因,这些都有自己的git存储库。但是我想把它们合并成一个,这样可以简化一些。例如,现在我可能要做两组更改,并且必须做一些类似的事情

cd phd/code
git commit 
cd ../figures
git commit

(现在)只要能表演就好了

cd phd
git commit

似乎有几种方法可以使用子模块或从我的子存储库中提取,但这比我想要的要复杂一些。至少让我满意的

cd phd
git init
git add [[everything that's already in my other repositories]]

但这似乎不是一句俏皮话。git中有什么可以帮助我的吗?


当前回答

亚里士多德Pagaltzis回答的git-stitch-repo只适用于具有简单线性历史的存储库。

MiniQuark的答案适用于所有存储库,但它不处理标记和分支。

我创建了一个与MiniQuark描述的工作方式相同的程序,但是它使用一个合并提交(有N个父级),并且还重新创建了指向这些合并提交的所有标记和分支。

有关如何使用它的示例,请参阅git-merge-repos存储库。

其他回答

你可以尝试子树合并策略。它可以让你将回购B合并到回购A。相对于git-filter-branch的优点是它不需要你重写回购A的历史记录(破坏SHA1和)。

@MiniQuark解决方案帮助了我很多,但不幸的是,它没有考虑到源存储库中的标记(至少在我的情况下)。以下是我对@ mini夸克答案的改进。

First create directory which will contain composed repo and merged repos, create directory for each merged one. $ mkdir new_phd $ mkdir new_phd/code $ mkdir new_phd/figures $ mkdir new_phd/thesis Do a pull of each repository and fetch all tags. (Presenting instructions only for code sub-directory) $ cd new_phd/code $ git init $ git pull ../../original_phd/code master $ git fetch ../../original_phd/code refs/tags/*:refs/tags/* (This is improvement to point 2 in MiniQuark answer) Move the content of new_phd/code to new_phd/code/code and add code_ prefeix before each tag $ git filter-branch --index-filter 'git ls-files -s | sed "s-\t\"*-&code/-" | GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info && mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE' --tag-name-filter 'sed "s-.*-code_&-"' HEAD After doing so there will be twice as many tags as it was before doing filter-branch. Old tags remain in repo and new tags with code_ prefix are added. $ git tag mytag1 code_mytag1 Remove old tags manually: $ ls .git/refs/tags/* | grep -v "/code_" | xargs rm Repeat point 2,3,4 for other subdirectories Now we have structure of directories as in @MiniQuark anwser point 3. Do as in point 4 of MiniQuark anwser, but after doing a pull and before removing .git dir, fetch tags: $ git fetch catalog refs/tags/*:refs/tags/* Continue..

这是另一个解。希望它能帮助别人,它帮助了我:)

这个bash脚本可以解决sed制表符问题(例如在MacOS上)和丢失文件的问题。

export SUBREPO="subrepo"; # <= your subrepository name here
export TABULATOR=`printf '\t'`;
FILTER='git ls-files -s | sed "s#${TABULATOR}#&${SUBREPO}/#" |
  GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
  git update-index --index-info &&
  if [ -f "$GIT_INDEX_FILE.new" ]; then mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE; else echo "git filter skipped missing file: $GIT_INXEX_FILE.new"; fi'

git filter-branch --index-filter "$FILTER" HEAD

这是迷你夸克,马里乌斯-布图克和瑞恩的哨子的组合。为他们干杯!

你建议的顺序

git init
git add *
git commit -a -m "import everything"

将工作,但您将丢失提交历史。

git-stitch-repo将在命令行中给出的git存储库上处理git-fast-export——all——date-order的输出,并创建一个适合于git-fast-import的流,该流将创建一个新的存储库,其中包含一个新的提交树中的所有提交,该提交树尊重所有源存储库的历史。