Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/git/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Git 如何重写历史记录,使所有文件(已移动的文件除外)都位于子目录中?_Git_History_Mv_Git Filter Branch - Fatal编程技术网

Git 如何重写历史记录,使所有文件(已移动的文件除外)都位于子目录中?

Git 如何重写历史记录,使所有文件(已移动的文件除外)都位于子目录中?,git,history,mv,git-filter-branch,Git,History,Mv,Git Filter Branch,我在git下有一个项目。有一天,我将所有项目文件从当前目录移动到项目下的foo/bar/。我是用git mv做的。然后我又添加了一些文件,并对已经存在的文件做了一些更改 因此,现在当我查看foo/bar/file.c的历史记录时,我只能看到移动文件后所做的更改 我试着用各种方法来解决这个问题(filter branchwith subdirectory filter,等等),但没有任何帮助,所以我在这里很忙。如果你能给我任何帮助,我将不胜感激。 谢谢 要使用移动的文件重写历史记录: 如果您希望项

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

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

我试着用各种方法来解决这个问题(
filter branch
with subdirectory filter,等等),但没有任何帮助,所以我在这里很忙。如果你能给我任何帮助,我将不胜感激。
谢谢

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

如果您希望项目的历史记录看起来好像所有文件都一直在目录
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

总结一下,这是我所做的一个简短的总结。对我有效的命令是:

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的内容,但我可以接受


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

安装git filter repo:

git clone https://github.com/newren/git-filter-repo/
将git filter repo可执行文件添加到$PATH(有关其他选项,请参阅):

现在
cd
转到要修改的git回购,然后运行:

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

@Alexander:您可能想尝试将一行(单引号中的所有内容)放入实际脚本中,并使用bash-shebang行。我想,
filter branch
可能正试图在
sh
中运行它,而不是
bash
。我取得了一些进展。if语句中的双括号似乎是导致此错误的原因。单括号效果更好,但仍然不起作用。问题是,在我将所有内容移动到foo/bar/I之前,我在项目中有一个名为foo的目录,其中包含一些内容。所以现在它抱怨“无法将
foo'移动到自己的子目录,
foo/bar/foo'”。@Alexander:您只需要相应地调整脚本。类似于:
if[!-e-foo/bar];然后mkdir-p foo/bar;git ls tree——仅命名$git|u COMMIT | grep-v^foo$| xargs-I files mv files foo/bar;fi
使用grep从要移动的文件列表中筛选出
foo
。请注意,我还假设
bar
子目录在您移动其下的所有内容之前从未存在过。如果不是这样,那么您也需要在脚本中说明这一点。使用
[
会给我带来问题,因为没有这样的命令(它是一个shell bulitin),使用
[
]
解决了这个问题。@TTT是的,它可以很容易地撤消。
git filter branch
将原始分支的副本保存在refs/original下。因此,在branch foo上,您可以执行类似于
git reset--hard original/foo
的操作,将事情恢复原状。使用
|true
而不是
|echo“”
速度更快。
git filter-repo --to-subdirectory-filter foo/bar