我可以将存储库的 .git 目录移动到其父目录吗?

39

我有两个子目录,每个目录下都有一个代码库,如下:

PPP/
 |--ABC/
 |   |--.git/
 |   |--AAA/
 |   |    BBB/
 |   |   CCC/
 |   
 |--DEF/
 |   |--.git/
 |   |--DDD/
 |   |--EEE/

我想把它们合并到一个仓库中,因此,我认为目录结构应该像这样:

PPP/
 |--.git/
 |--ABC/
 |   |--AAA/
 |   |--BBB/
 |   |--CCC/
 |   
 |--DEF/
 |   |--DDD/
 |   |--EEE/

这可行吗?

目前有几个人在他们的机器上拥有这些仓库。这会让生活变得更加复杂吗?

谢谢。


1
请参见合并多个git仓库 - Pat Notz
4个回答

47

您可以按照以下方式完成您所描述的操作:

  1. ABC 的内容移动到一个名为 ABC/ 的子目录中,并修复历史记录,使其看起来一直存在于该目录中:

    $ cd /path/to/ABC
    $ git filter-branch --index-filter \
        'git ls-files -s | sed "s-\t-&ABC/-" |
         GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
         git update-index --index-info &&
         mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE' HEAD
    

    现在你的目录结构为ABC/ABC/your_code

  2. DEF的内容也是一样的:

  3. $ cd /path/to/DEF
    $ git filter-branch --index-filter \
        'git ls-files -s | sed "s-\t-&DEF/-" |
         GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
         git update-index --index-info &&
         mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE' HEAD
    

    现在你的目录结构是DEF/DEF/your_code

  4. 最后,创建PPP仓库并将ABCDEF都拉到里面:

  5. $ mkdir /path/to/PPP
    $ cd /path/to/PPP
    $ git init
    $ git pull /path/to/ABC
    $ git pull /path/to/DEF
    

    现在你有 PPP/ABC/your_codePPP/DEF/your_code,以及所有的历史记录。

你应该让你的同事在他们的系统上运行之前的命令,以便每个人都同步。

注意:奇怪的 filter-branch 命令来自于 man 手册。 :-)


2
请注意,这将仅更新每个子项目中当前签出的分支,并仅将这些分支拉取到新存储库中。 - Lily Ballard
12
顺便说一下,将当前repo中的所有内容移入子目录的另一种修改方式是使用类似于 git filter-branch --tag-name-filter cat --index-filter 'SHA=$(git write-tree); rm $GIT_INDEX_FILE && git read-tree --prefix=ABC/ $SHA' -- --all 的命令。这将重写所有分支和标签,而不仅仅是HEAD。 - Lily Ballard
1
“Funky filter-branch” 命令来自于 Git 的 filter-branch 手册。你应该正确地进行归属。即使某个声誉很高的人在 StackOverflow 上发布了这样的命令,我也不会运行它。但如果知道它来自手册,我就会考虑。 - tymtam
3
嗨 Tymek。你说得完全正确,我刚刚添加了一条注释。我已经使用这个奇特的命令有一段时间了,而且我早就忘记了从哪里得到它(我甚至可能认为是我自己想出来的!)。毕加索曾经说过:"优秀的艺术家借鉴,伟大的艺术家窃取"(或者是我说的?)。 - MiniQuark
2
我刚遇到的一个与索引过滤器有关的问题:如果你的第一次提交没有对文件进行任何更改(例如从Subversion导入只创建了一个目录),那么index.new文件就不会被创建,mv命令就没有源并且失败。你可以重新基于分支并压缩前两个提交,或在mv命令之后添加||:,这总是会成功的,即使第一个mv失败。 - Wil Cooley

5
你是否真的需要将两个现有仓库合并为一个仓库,还是只想将它们分组?如果只想将它们分组,则git-submodule可以实现你想要的效果:最终你会得到三个仓库,其中顶层仓库链接到当前的两个仓库。以下是一些指导意见:
- 如果你要增加它们之间的耦合度,以至于使用repo A的一个版本与repo B的不同版本不再有意义,那么你应该将它们合并为单个仓库。 - 如果它们仍然相对独立(有时候单独处理一个仓库是有意义的),但你希望能够方便地同时处理它们(例如,同时下载两个仓库、在两个仓库之间进行已知状态的检查点等),那么你应该使用子模块。
使用子模块可以避免现有仓库副本的问题,因为历史记录不会改变。合并它们将创建一个新的历史记录,这将使从现有分支工作的人更难合并他们的更改。

1

(2022) 答案:考虑使用 git filter-repo 而不是 git filter-branch

filter-repo 更快,是这种情况下的推荐方法。

示例用例:

  1. 将 repoA/develop 合并到 repoB/develop 并放入文件夹 /android 中

示例命令(将基础目录中的所有提交重命名并移动到 /android/path/to/file)

filter-repo --path-rename :android/ --force

文档:https://github.com/newren/git-filter-repo


尝试使用git-filter-branch方法时,git建议使用这个第三方工具。我现在正在尝试使用这种方式。 - undefined

0

在我看來,按照你想要的方式進行似乎很困難,因為這兩個項目的歷史記錄不會合併。

我的最佳建議是創建一個新的存儲庫來包含ABC和DEF,保留這兩個舊存儲庫以備份歷史記錄,並使用這個新項目開始全新的歷史記錄。


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