繁体   English   中英

包含所有重命名文件提交的筛选器分支

[英]filter-branch that includes all commits of renamed files

使用此处说明的filter-branch ,可以将某些子目录拆分到新的存储库中。 但是,建议的过滤器将仅保留目录中文件具有与现在相同名称/路径的提交。

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

您将必须编写自己的,花哨的(也许非常花哨的)过滤器。

我的意思不是修改git filter-branch来添加一个新的--EJS-filter 是做到这一点的一种方式,但会要求你可笑幻想。 :-)相反,我的意思是:

  • 找到您要保留的特定提交范围内的名称。

    这可能相对容易:从a123456之后的“提交”开始,保留所有名为newdirname/*文件,从a123456 “ before” a123456 (包括a123456本身),则保留所有名为olddirname/*文件。

    这甚至可能非常容易:也许在a123456之后的a123456没有名为olddirname/*文件 ,并且在此之前的提交中,没有名为newdirname/*文件。 在这种情况下,您的过滤器olddirname/*为: 保留所有名为olddirname/*newdirname/* 删除所有其他文件。

    如果不是那么容易,那么那就不是那么容易。

  • 现在,您已经确定了要保留的文件,编写一个--tree-filter (很慢,但是很容易编写)或--index-filter (要快得多,但是很难编写),以保留您想要的文件并删除不需要的文件。

在这里,您可以(也许必须)利用git filter-branch操作方式。 当您运行git filter-branch ,Git的作用是:

  1. 根据您指定的任何gitrevisions样式标准,枚举您要过滤的分支中可到达的每个提交。 最后,仅--all枚举每个分支可到达的每个提交。

  2. 将提交列表放入“反向拓扑顺序”,即从提交(有史以来的第一个提交)开始,然后列出其直接子代,然后是其子代,依此类推。 因此,对于部分看起来像这样的提交链:

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

    该列表将以EF结尾,然后是GHIJIJGH

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

    • 通过其哈希ID来检查提交,该哈希ID临时保存在变量$GIT_COMMIT
    • 每次运行-- whatever -filter ;
    • 从剩下的任何东西重新提交;
    • 更新地图:“旧的$GIT_COMMIT变成刚创建的新哈希ID”。

    换句话说, git filter-branch复制每个提交。 如果新提交与它的父提交匹配,则使用--prune-empty可以跳过“提交新提交”步骤。

    在任何情况下,新提交的父提交都是映射的 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规则,我们实际上并不 B'毕竟,我们将设置C'的家长A'

这意味着您可以使用$GIT_COMMIT来确定要保留的文件名。 您可以针对存储库中所有现有的提交对其进行测试,也可以构建自己的名称映射以基于提交哈希或任何您喜欢的名称进行保留。

请注意,通常,由于您要处理提交哈希的有向无环图(DAG),因此通常要用于实现这些目的的测试是“祖先”。 如果提交A是提交B的祖先(更确切地说,如果A≼B ,那么您允许A = B) ,那么您将处于“之前”的情况。 这就是我在上面描述的内容:“在a123456之前和包含”的a123456使用较旧的名称,而后续的提交使用较新的名称。 git merge-base --is-ancestor AB命令执行此A≼B测试,其结果作为shell命令退出状态传递:

if git-merge-base --is-ancestor $GIT_COMMIT a123456; then ...; else ...; fi

测试是否$GIT_COMMITa123456

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM