如何重写历史记录,以便除我已经移动的文件之外的所有文件都在子目录中?
Posted
技术标签:
【中文标题】如何重写历史记录,以便除我已经移动的文件之外的所有文件都在子目录中?【英文标题】: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
使用子目录过滤器等),但没有任何帮助,所以我在这里很累。我会很感激你能给我的任何帮助。
谢谢!
【问题讨论】:
【参考方案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
【讨论】:
以上是关于如何重写历史记录,以便除我已经移动的文件之外的所有文件都在子目录中?的主要内容,如果未能解决你的问题,请参考以下文章
JQuery 隐藏除我搜索的 div 之外的所有 div [关闭]
无法在除我之外的其他浏览器/机器上运行我的 chrome 扩展:未打包的发行版中有些不匹配?