使用filter-branch
解释here,可以将某个子目录拆分为新的存储库。但是,建议的过滤器只会保留目录中文件与现在文件具有相同名称/路径的提交。
git filter-branch --prune-empty --subdirectory-filter FOLDER-NAME BRANCH-NAME
我需要一个过滤器,它会为每个文件保留与执行gitk --follow FILE-NAME
时相同的提交。
基本上我需要一个过滤器,它将为目录中的每个文件保留当前文件名/路径和旧文件名/路径的提交。
我试过了:
git filter-branch --index-filter 'git rm --cached -qr --ignore-unmatch -- . && git reset -q $GIT_COMMIT -- FOLDER-NAME' --prune-empty -- --all
但它与--subdirectory-filter
完全相同。
答案 0 :(得分:0)
你必须编写自己的,花哨的(也许是非常花哨的)过滤器。
据此,我并不是指修改git filter-branch
以添加新的--EJS-filter
。那个会成为一种方式,但需要你得到荒谬的幻想。 :-)相反,我的意思是:
在特定的提交范围中找到要保留的名称。
这可能相对容易:可能来自提交"之后" a123456
以后,您保留所有名为newdirname/*
的文件,并保留#34;之前的#34; a123456
,包括a123456
本身,您保留所有名为olddirname/*
的文件。
它甚至可能非常简单:也许在a123456
之后的提交中,没有名为olddirname/*
的文件,并且在提交到那时,没有文件名为newdirname/*
。在这种情况下,您的过滤器将转换为:保留所有名为olddirname/*
或newdirname/*
的文件;删除所有其他文件。
如果不那么容易,那就不那么容易了。
现在你已经确定要保留哪些文件,写一个--tree-filter
(慢,但很容易写)或--index-filter
(更快,但更难写)保留您想要的文件并删除您不想要的文件。
在这里,您可以(也许必须)使用git filter-branch
运作的方式。当你运行git filter-branch
时,Git所做的是:
根据您指定的任何gitrevisions样式条件,枚举您要过滤的分支可以访问的每个提交。最后只有--all
,枚举每个分支可以访问的每个提交。
将提交列表放入"反向拓扑顺序",即从 root 提交(有史以来第一次提交)开始,然后列出其立即孩子,然后他们的孩子,等等。因此对于一个看起来像这样的提交链:
G--H <-- branch1
/
...--E--F
\
I--J <-- branch2
该列表将以E F
结尾,后跟G H I J
或I J G H
。
对于列表中的每个提交,请执行以下步骤(或多或少):
$GIT_COMMIT
; --whatever-filter
; $GIT_COMMIT
成为刚制作的新哈希ID&#34;。
换句话说,git filter-branch
只需复制每次提交。使用--prune-empty
,它会跳过&#34;进行新的提交&#34;如果新提交与其父提交匹配,则执行步骤。
在任何情况下,新提交的父提交都是映射的 ID。也就是说,如果我们从原始提交A
开始,这是一个根提交而没有父提交,我们会进行新的提交A'
:
A--B--C--...
A' <-- (just made)
然后我们复制B
,因为那是A
的唯一孩子。当我们通过git filter-branch
- 进行新的提交B'
时,我们将B'
的父级设为A'
而不是A
:
A--B--C--...
A'-B' <-- (just made)
当我们从C'
提出C
时,我们将B'
作为其父级。或者,如果 - 由于--prune-empty
规则 - 我们实际上 make B'
,我们会设置C'
&# 39;父母A'
。
这意味着您可以根据需要使用$GIT_COMMIT
来决定您希望保留哪些文件名。您可以针对存储库中的所有现有提交对其进行测试,或者根据提交哈希或您喜欢的任何内容构建自己的名称映射。
请注意,一般情况下,由于您正在处理提交哈希的有向无环图(DAG),因此您通常要用来实现这些事情的测试是&#34;是祖先&#34;。如果提交 A 是提交 B 的祖先 - 更确切地说,如果A≼B,那么您允许 A = B - 然后你有&#34;之前&#34;情况。这就是我上面所描述的:提交&#34;之前和之后&#34; a123456
使用较旧的名称,而后续提交使用较新的名称。 git merge-base --is-ancestor A B
命令执行此A≼B测试,其结果作为shell命令退出状态传递:
if git-merge-base --is-ancestor $GIT_COMMIT a123456; then ...; else ...; fi
测试$GIT_COMMIT
≼a123456
。