git:如何更改所有分支中的repo中的文件路径,完全重写其历史记录?

时间:2013-02-14 13:00:37

标签: git

之前我曾问过类似的问题,但在对此事进行了相当彻底的分析后得出的结论是git filter-branch是我正在寻找的主力。在.git本身中执行脏工作的那个或shell脚本(因为git无论如何都将其内容暴露为其接口的一部分)。

我有一个项目目录,其中包含构建脚本和构建配置定义。更重要的是,它包含src文件夹,其中包含项目的各种源代码,是一个git存储库。

我现在意识到整个项目文件夹应该是一个git存储库,而不仅仅是包含的源代码文件夹,但我希望保留源代码开发的历史记录。实际上,我希望历史记录完全重写,以便跟踪名为main.c的文件中的更改,而不是跟踪文件src/main.c中的相同内容更改。然后我可以简单地从父文件夹(构建脚本所在的位置)移动文件,并在repo中检查它们。

我不想打扰子树合并或git子模块,或者在更改存储库后必须合并或重置任何内容。我现在对gits内部有一些相当好的了解 - 提交引用了引用与文件名配对的blob的树。

有了这些知识,我认为应该可以重写我的历史记录,为所有路径添加前缀src/

我只是不想做额外的工作,似乎filter-branch是要走的路,但是在使用它之后我会混淆示例和必要的内务管理。 “原始参考”?另一个问题是我完全没有“裸”回购,我不需要任何工作树,我也不确定为什么我需要索引。

1 个答案:

答案 0 :(得分:3)

这并不像你想象的那么简单。您目前有两个存储库,每个存储库都有自己的历史记录 每个提交都有一个明确定义的父级。

要获得单个,按时间顺序排列的正确历史记录,您必须更改许多提交的父级。

一个简短的例子说明了这一点:

存储库“配置”:

A <- C <- E

存储库“src”

B <- D <- F

让我们假设提交B发生在B等之后的A和C之后,所以你想得到这个结果:

A <- B' <- C' <- D' <- E' <- F'

要实现此目的,您必须将B'的父级更改为AC'的父级必须从A更改为B'等。

这不是微不足道的。但可能。

假设配置存储库位于“/ usr / git / config”,src存储库位于“/ usr / git / config / src”。

首先,我们必须准备“src”存储库以包含“src”子文件夹中的所有文件:

  1. CD to“/ usr / git / config / src”
  2. 执行这个怪物:

    git filter-branch --index-filter 'git ls-files -s | sed "s-\t\"*-&src/-" | GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info && mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"' HEAD
    
  3. 其余的将在“config”存储库中发生,因此CD为“/ usr / git / config”。

    1. 将“src”存储库添加为远程:git remote add src /usr/git/config/src
    2. 获取“src”存储库的提交:git fetch src
    3. 将“src / master”中的提交与本地“master”合并:git merge src/master master
    4. 找出两个存储库的初始提交:git rev-list --max-parents=0 --pretty HEAD
    5. 请注意两个旧版本
    6. 的提交哈希值
    7. 执行完整存储库的rebase以摆脱合并:git rebase -f <hash from step 5>
    8. 删除遥控器:git remote remove src
    9. 删除文件夹“/ usr / git / config / src / src”和“/usr/git/config/src/.git”
    10. 更新.gitignore不再忽略“src”文件夹。
    11. 请注意:
      这假设您在两个存储库中只有一个主分支。

      哦,并且在执行此操作之前进行备份。我只在一个小型测试存储库上测试了它,每个提交两次...


      如果你在src子文件夹中只有一个存储库,那就更简单了,只需执行以下命令:

      1. CD to“/ usr / git / config / src”
      2. 执行上面的怪物
      3. 将“/ usr / git / config / src”重命名为“/ usr / git / config / src_tmp”
      4. 将“/ usr / git / config / src_tmp”的完整内容移至“/ usr / git / config”,包括“.git”存储库
      5. 删除现在为空的“/ usr / git / config / src_tmp”