将 git 存储库向上移动一个层次结构级别

Posted

技术标签:

【中文标题】将 git 存储库向上移动一个层次结构级别【英文标题】:Moving a git repository up one hierarchy level 【发布时间】:2011-07-21 11:27:10 【问题描述】:

Git 初学者问题:

我有一个使用 msysgit 在本地进行版本控制的小型私人 web 项目。没有外部存储库,因为它只适合我,所以我可以做任何我想做的事情。

我已经在项目目录中设置了这个,即在“webroot”中。

现在必须创建第二个目录,与 webroot 平行放置。我们称之为资产。

所以现在的结构如下:

\ project directory
----\webroot
----\assets

我很想将这个新目录包含在 git 存储库中,这样我还可以对存储在那里的文件进行版本更改,但我当然不能使用“git add ../assets”。我也不倾向于在 project_directory 中创建一个新的 git 项目,因为这会丢失我之前的所有提交。

那么我该如何将存储库从“webroot”移到“project_directory”,同时保留我的提交,然后能够包含“assets”?

【问题讨论】:

不完全符合您的要求,但您可以创建一个分支并将资产添加到其中。 【参考方案1】:

所以,你希望你的 git repo 看起来像这样:

<projectdir>
    /.git
    /webroot
    /assets

为此,您必须将现有文件在您的存储库中移动到新的webroot 子目录中。

cd <git repo root>
mkdir webroot
git mv <all your files> webroot
git commit --all -m "moved all existing files to new 'webroot' directory"

然后,在您的本地文件系统上,您希望将您的克隆重新定位到它现在所在位置之上的一个目录:

cd <projectdir>
mv webroot/* .
rmdir webroot

然后你想将assets 目录(和文件)添加到git repo:

git add assets
git commit -m "added assets to the repo"

【讨论】:

好吧,显然我没有提供足够的信息。存储库已经在 /projectdir/webroot/ 中,因为这是它最初创建的位置。由于资产目录通过了,如果存储库的行为就像它是在 /projectdir/ 中创建的一样,我更喜欢它,可惜它不是。 git mv 不允许我将文件移出存储库。 @Sorcy:我相信我明白你想做什么。我更新了我的答案以澄清它。 谢谢,这正是我正在寻找的解决方案。 :) 我发现这个解决方案也需要mv webroot/.* .,以便移动 repo 和 .gitignore 文件。 git mv * webroot 不起作用,因为 bash 通配符 * 也将被替换为 webroot,从而使命令为 git mv webroot webroot。 Git 会失败的。另一个有问题的文件夹是 .git。所以我不得不使用特殊的 bash 环境变量 GLOBIGNORE=webroot:.git 以便 * 不会被这两个目录替换。多亏了这一点,我不必手动制作几十个 git mv - 我的目录有很多文件夹和文件。我只需要手动移动 .git 文件夹。【参考方案2】:

您也可以将您的 .git 目录上移一级并更新您的工作树。

cd projectdir
mv ./webroot/.git ./.git
git config core.worktree /absolute-path-to-project-dir
git add assets
git commit -m 'adding assets folder'

不是肯定的,但我很确定 core.worktree 的路径必须是绝对的。

【讨论】:

这是对我有用的顺序。当我在要移动 .git 文件的文件夹中时:mv .git / ../ 我在类似的情况下这样做了,我不得不将文件重新添加到之前位置时已经添加的 repo。所以本质上,我认为我丢失了这些文件的 git 历史记录。【参考方案3】:

我假设您打算重写历史记录以包含所有修订版中的所有文件就好像它们一直位于子目录 webroot/ 而不是根目录中一样

git filter-branch 手册页有答案,这里是一个改进版本,它重写了所有现有的 refs(分支)和标签:

time git filter-branch --index-filter 'git ls-files -s |
         sed "s-\t\"*-&webroot/-" |
         GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info && 
     mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE' --tag-name-filter cat -- --all

已注意将此操作设为仅索引操作,以便该过程即使对于大型存储库也能快速运行。请记住(在满意时)摆脱原始 refs (.git/refs/original/*) 并重新打包 repo 以释放过时的树对象。

【讨论】:

你能解释一下如何摆脱原来的 refs 并重新打包 repo 吗?是 GC 还是别的什么? 这正是我想要的。谢谢!迷茫的人,这个操作应该在what Tim Henigan suggested完成后进行。【参考方案4】:

您的提交并未本地绑定到它们存储在 git 存储库中的“webroot”文件夹。

您可以简单地删除 webroot 目录,在新位置“/project 目录”中重新签出存储库,添加资产目录并提交。

rm -Rf webroot
git clone path-to-repo
git add assets 
git commit -m "Added assets directory"
git push

【讨论】:

【参考方案5】:

以下命令将重写您的 Git 历史记录。看起来好像内容一直在webroot 中。如果多个人在处理一个 repo,通常重写历史是很麻烦的。既然你一个人在做,应该没问题。

git filter-branch --index-filter '
    git read-tree --prefix="webroot/" $GIT_COMMIT && \
    git ls-files \
      | sed "s/\/.*//" \
      | sort \
      | uniq \
      | grep -v "^webroot" \
      | xargs -L1 git rm -r --cached > /dev/null'

【讨论】:

以上是关于将 git 存储库向上移动一个层次结构级别的主要内容,如果未能解决你的问题,请参考以下文章

自底向上递归求和(最低级别只有值)

从文件恢复文件系统层次结构

如何将移动的 git 存储库与其在 Egit 中的原始项目重新连接?

如何将文件从一个文件夹移动到同一git存储库中的另一个文件夹保留历史记录[重复]

这种分层类结构的合适设计模式是啥?

单独的 git 存储库中的服务结构项目