我知道我可以使用如下命令为git
中的指定分支提取给定文件夹的历史记录:
git filter-branch --subdirectory-filter "a sub directory" -- myBranch
不幸的是,子目录在历史记录的某个时刻从a subdirectory
重命名为aSubdirectory
。不幸的是,filter-branch
在重命名时停止。
有没有办法实现这个目标?
答案 0 :(得分:2)
git filter-branch --prune-empty --index-filter '
git ls-files -z |
egrep --invert-match --null-data "^(a subdirectory|aSubdirectory)/" |
xargs -0 --no-run-if-empty git rm --cached -q
git ls-files -s | sed -re "s-\t(a subdirectory|aSubdirectory)/-\t-" |
git update-index --index-info
git ls-files -z |
egrep --null-data "^(a subdirectory|aSubdirectory)/" |
xargs -0 git rm --cached -q
' -- myBranch
重命名文件是一个高级操作(哈!),因此我们将其分解为删除并添加组件。
脚本中的第一个命令会删除a subdirectory
或aSubdirectory
之外的所有内容。第二个将这些目录中的所有内容添加到存储库根目录中最后,第三个通过删除这些目录中的任何文件来完成移动。
例如,从
的历史开始$ git lol --name-status * 27c7275 (HEAD, myBranch) file2 | A aSubdirectory/file2 * 39d7e75 mv | D a subdirectory/file1 | A aSubdirectory/file1 * c710654 file1 A a subdirectory/file1
运行上面的git filter-branch
命令会产生
$ git lola --name-status * da6c7ae (HEAD, myBranch) file2 | A file2 * d94110a file1 A file1 * 27c7275 (refs/original/refs/heads/myBranch) file2 | A aSubdirectory/file2 * 39d7e75 mv | D a subdirectory/file1 | A aSubdirectory/file1 * c710654 file1 A a subdirectory/file1
refs/original/refs/heads/myBranch
是一个备份,在验证结果后,您可以使用
git update-ref -d refs/original/refs/heads/myBranch
离开
$ git lola * da6c7ae (HEAD, myBranch) file2 * d94110a file1
备注:强>
--prune-empty
。git lol
和git lola
是非标准的highly useful aliases 答案 1 :(得分:0)
我发现这很有用,但是我在OSX上并且在@Greg Bacon的解决方案上遇到了一些麻烦,因为xargs和egrep缺乏一些功能。 我最终编写了一个perl脚本,我确信它是在$ PATH
上git filter-branch --prune-empty --tag-name-filter cat --index-filter 'git_prune_non_proxy_dirs.pl' -- --all
perl脚本看起来像这样(我想你可以修改它来执行所有这三个步骤"第一部分"确保在这种情况下使用系统而不是exec来调用git)
#!/usr/bin/perl
open(LS,"git ls-files|") || die "Failed to git ls-files: $!\n";
my %to_remove=();
while ( <LS> ) {
chomp;
if( $_ =~ m#(^adserver-proxy(|-api)/)#) {
}else{
my @components = split('/',$_, 2);
my $path_to_delete = $components[0];
$to_remove{$path_to_delete}=1;
}
}
if (%to_remove) {
my @cmd=(
"git","rm","-rfq","--cached","--", keys %to_remove);
exec(@cmd) || die "Failed to invoke git rm"
}