【问题标题】:How can I rewrite history so that all files, except the ones I already moved, are in a subdirectory?如何重写历史记录,以便除我已经移动的文件之外的所有文件都在子目录中?
【发布时间】:2011-05-01 20:46:09
【问题描述】:

我在git 下有一个项目。有一天,我将所有项目文件从当前目录移动到项目下的foo/bar/。我使用git mv 做到了。然后我添加了更多文件并对现有文件进行了一些更改。

因此,现在当我查看foo/bar/file.c 的历史记录时,我只能看到我在移动文件后所做的更改。

我尝试以各种方式解决此问题(filter-branch 使用子目录过滤器等),但没有任何帮助,所以我在这里很累。我会很感激你能给我的任何帮助。 谢谢!

【问题讨论】:

    标签: git history mv git-filter-branch


    【解决方案1】:

    用移动的文件重写历史记录:

    如果您希望项目的历史看起来好像所有文件一直都在目录foo/bar 中,那么您需要做一些小手术。使用带有“树过滤器”的git filter-branch 来重写提交,以便在任何不存在foo/bar 的地方创建它并将所有文件移动到它:

    git filter-branch --prune-empty --tree-filter '
    if [ ! -e foo/bar ]; then
        mkdir -p foo/bar
        git ls-tree --name-only $GIT_COMMIT | xargs -I files mv files foo/bar
    fi'
    

    现在将记录历史记录,就好像所有文件总是位于foo/bar

    要查看移动文件的历史记录:

    如果您只想查看过去某个时间点被移动或重命名的文件的历史记录,那么只需使用--follow 选项到git log

    git log --follow foo/bar/file.c
    

    【讨论】:

    • @Alexander:您可能想尝试使用 bash shebang 行将单行(单引号中的所有内容)放入实际脚本中。我认为filter-branch 可能试图在sh 中运行它,而不是bash
    • 我取得了一些进展。似乎 if 语句中的双括号导致了此错误。单括号效果更好,但它仍然不起作用。问题是,在我将所有内容移动到 foo/bar/ 之前,我有一个名为 foo 的目录,其中包含项目中的一些内容。所以现在它抱怨“无法移动foo' to a subdirectory of itself, foo/bar/foo'”。
    • @Alexander:您只需要相应地调整脚本。类似:if [[ ! -e foo/bar ]]; then mkdir -p foo/bar; git ls-tree --name-only $GIT_COMMIT | grep -v ^foo$ | xargs -I files mv files foo/bar; fi 使用 grep 从要移动的文件列表中过滤掉 foo。请注意,我还假设 bar 子目录不存在,直到您将所有内容移到它下面。如果不是这种情况,那么您还需要在脚本中考虑到这一点。
    • 使用[[给我带来了问题,因为没有这样的命令(它是一个shell bulitin),使用[]解决了这个问题。
    • @TTT 是的,它可以轻松撤消。 git filter-branch 将在 refs/original 下保留原始分支的副本。因此,在分支 foo 上,您可以执行 git reset --hard original/foo 之类的操作来恢复原状。
    【解决方案2】:

    在这里总结一下我所做的事情的简短摘要。对我有用的命令是:

    if [ ! -e foo/bar ]; then mkdir -p foo/bar; git ls-tree --name-only $GIT_COMMIT | grep -v ^foo$ | xargs -I files mv files foo/bar || echo ""; fi
    

    我最后添加的 echo 命令确保即使 mv 失败,整个命令也会继续运行。它没有移动 foo/bar/foo 的内容,但我可以忍受。

    非常感谢 Dan Moulding (!!!) 和 Jefromi 的帮助。

    【讨论】:

    • 使用|| true 代替|| echo "" 更快。
    【解决方案3】:

    安装 git-filter-repo:

    git clone https://github.com/newren/git-filter-repo/
    

    将 git-filter-repo 可执行文件添加到您的 $PATH(请参阅 INSTALL.MD 了解其他选项):

    # this is just an example, you probably want to edit bashrc,
    # or add a symlink to ~/bin or /usr/local/bin
    PATH=$PATH:${PWD}/git-filter-repo
    

    现在 cd 到您要修改的 git 存储库,然后运行:

    git filter-repo --to-subdirectory-filter foo/bar
    

    【讨论】:

      猜你喜欢
      • 2015-08-04
      • 2014-04-05
      • 1970-01-01
      • 2017-12-14
      • 2011-04-20
      • 1970-01-01
      • 2015-12-10
      • 1970-01-01
      相关资源
      最近更新 更多