filter-branch,包含重命名文件的所有提交

时间:2018-01-08 09:17:57

标签: git

使用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完全相同。

1 个答案:

答案 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所做的是:

  1. 根据您指定的任何gitrevisions样式条件,枚举您要过滤的分支可以访问的每个提交。最后只有--all,枚举每个分支可以访问的每个提交。

  2. 将提交列表放入"反向拓扑顺序",即从 root 提交(有史以来第一次提交)开始,然后列出其立即孩子,然后他们的孩子,等等。因此对于一个看起来像这样的提交链:

              G--H   <-- branch1
             /
    ...--E--F
             \
              I--J   <-- branch2
    

    该列表将以E F结尾,后跟G H I JI J G H

  3. 对于列表中的每个提交,请执行以下步骤(或多或少):

    • 通过哈希ID检查提交,暂时保存在变量$GIT_COMMIT;
    • 运行每个--whatever-filter;
    • 从左边的任何地方做新的提交;
    • 更新地图:&#34;旧$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'

  4. 这意味着您可以根据需要使用$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_COMMITa123456

相关问题