[英]filter-branch that includes all commits of renamed files
Using filter-branch
like explained here it's possible to split out some subdirectory to a new repository. 使用此处说明的
filter-branch
,可以将某些子目录拆分到新的存储库中。 However the suggested filter will only keep commits where the files in the directory had the same name/path as they do now. 但是,建议的过滤器将仅保留目录中文件具有与现在相同名称/路径的提交。
git filter-branch --prune-empty --subdirectory-filter FOLDER-NAME BRANCH-NAME
I need a filter that will keep the same commits for each file as when doing gitk --follow FILE-NAME
. 我需要一个过滤器,该过滤器将使每个文件的提交与执行
gitk --follow FILE-NAME
时的提交相同。
Essentially I need a filter that will keep commits for both the current filename/path and older filenames/paths for each file in the directory. 本质上,我需要一个过滤器,该过滤器将保留目录中每个文件的当前文件名/路径和旧文件名/路径的提交。
I tried: 我试过了:
git filter-branch --index-filter 'git rm --cached -qr --ignore-unmatch -- . && git reset -q $GIT_COMMIT -- FOLDER-NAME' --prune-empty -- --all
but it did the same as --subdirectory-filter
. 但是它和
--subdirectory-filter
。
You will have to write your own, fancy (perhaps very fancy), filter. 您将必须编写自己的,花哨的(也许非常花哨的)过滤器。
By this I don't mean modify git filter-branch
to add a new --EJS-filter
. 我的意思不是修改
git filter-branch
来添加一个新的--EJS-filter
。 That would be one way to do it, but would require that you get ridiculously fancy. 这将是做到这一点的一种方式,但会要求你可笑幻想。 :-) Instead, what I mean is this:
:-)相反,我的意思是:
Find the name(s) you want to preserve in particular commit range(s). 找到您要保留的特定提交范围内的名称。
This might be relatively easy: perhaps from commits "after" a123456
onward, you keep all files named newdirname/*
, and from commits "before" a123456
, including a123456
itself, you keep all files named olddirname/*
. 这可能相对容易:从
a123456
之后的“提交”开始,保留所有名为newdirname/*
文件,从a123456
“ before” a123456
(包括a123456
本身),则保留所有名为olddirname/*
文件。
It might even be extremely easy: perhaps in commits after a123456
, there are no files named olddirname/*
, and in commits up to that point, there are no files named newdirname/*
. 这甚至可能非常容易:也许在
a123456
之后的a123456
, 没有名为olddirname/*
文件 ,并且在此之前的提交中,没有名为newdirname/*
文件。 In this case, your filter devolves to: Retain all files named olddirname/*
or newdirname/*
; 在这种情况下,您的过滤器将
olddirname/*
为: 保留所有名为olddirname/*
或newdirname/*
; remove all other files. 删除所有其他文件。
If it's not that easy, well, then it's not that easy. 如果不是那么容易,那么那就不是那么容易。
Now that you have identified which files to keep, write a --tree-filter
(slow, but very easy to write) or --index-filter
(much faster, but harder to write) that retains the files you want and deletes the files you don't want. 现在,您已经确定了要保留的文件,编写一个
--tree-filter
(很慢,但是很容易编写)或--index-filter
(要快得多,但是很难编写),以保留您想要的文件并删除不需要的文件。
Here, you can (and maybe must) make use of the way that git filter-branch
operates. 在这里,您可以(也许必须)利用
git filter-branch
操作方式。 When you run git filter-branch
, what Git does is: 当您运行
git filter-branch
,Git的作用是:
Enumerate every commit reachable from the branch(es) you're filtering, according to whatever gitrevisions style criteria you specify. 根据您指定的任何gitrevisions样式标准,枚举您要过滤的分支中可到达的每个提交。 With just
--all
at the end, enumerate every commit reachable from every branch. 最后,仅
--all
枚举每个分支可到达的每个提交。
Put that list of commits into "reverse topological order", ie, start with the root commit (the very first commit ever made) and then list its immediate children, then their children, and so on. 将提交列表放入“反向拓扑顺序”,即从根提交(有史以来的第一个提交)开始,然后列出其直接子代,然后是其子代,依此类推。 Hence for a commit chain that looks in part like this:
因此,对于部分看起来像这样的提交链:
G--H <-- branch1 / ...--E--F \\ I--J <-- branch2
the list would end with EF
followed by either GHIJ
or IJGH
. 该列表将以
EF
结尾,然后是GHIJ
或IJGH
。
For every commit in the list, do these steps (more or less): 对于列表中的每个提交,执行以下步骤(或多或少):
$GIT_COMMIT
; $GIT_COMMIT
; -- whatever -filter
; -- whatever -filter
; $GIT_COMMIT
becomes new hash ID just made". $GIT_COMMIT
变成刚创建的新哈希ID”。 In other words, git filter-branch
simply copies every commit. 换句话说,
git filter-branch
只复制每个提交。 With --prune-empty
it skips the "make a new commit" step if the new commit would match its parent commit. 如果新提交与它的父提交匹配,则使用
--prune-empty
可以跳过“提交新提交”步骤。
In any case, the new commit's parent commit(s) is/are the mapped IDs. 在任何情况下,新提交的父提交都是映射的 ID。 That is, if we start from original commit
A
, which is a root commit and has no parents, we make a new commit A'
: 也就是说,如果我们从原始提交
A
开始,它是一个根提交并且没有父母,我们将创建一个新的提交A'
:
A--B--C--... A' <-- (just made)
Then we copy B
, since that's the only child of A
. 然后我们复制
B
,因为那是A
的唯一孩子。 When we—through git filter-branch
—make the new commit B'
we make B'
's parent be A'
rather than A
: 当我们通过
git filter-branch
进行新的提交B'
我们使B'
的父对象为A'
而不是A
:
A--B--C--... A'-B' <-- (just made)
When we make C'
from C
, we'll have B'
as its parent. 当我们从
C
制作C'
时,我们将B'
作为其父代。 Or, if—due to the --prune-empty
rule—we don't actually make B'
after all, we'll set C'
's parent to A'
. 或者,如果-由于
--prune-empty
规则,我们实际上并不做 B'
毕竟,我们将设置C'
的家长A'
What this means is that you can use $GIT_COMMIT
, if necessary, to decide which file name(s) you wish to keep. 这意味着您可以使用
$GIT_COMMIT
来确定要保留的文件名。 You can test it against all the existing commits in the repository, or build your own map of names to keep based on commit hashes, or whatever you like. 您可以针对存储库中所有现有的提交对其进行测试,也可以构建自己的名称映射以基于提交哈希或任何您喜欢的名称进行保留。
Note that in general, since you are dealing with a directed acyclic graph (DAG) of commit hashes, the test you usually want to use to implement these things is "is ancestor". 请注意,通常,由于您要处理提交哈希的有向无环图(DAG),因此通常要用于实现这些目的的测试是“祖先”。 If commit A is an ancestor of commit B —more precisely, if A ≼ B , so that you allow for A = B —then you have a "before" situation.
如果提交A是提交B的祖先(更确切地说,如果A≼B ,那么您允许A = B) ,那么您将处于“之前”的情况。 This is what I described above: commits "before and including"
a123456
use an older name, while subsequent commits use a newer one. 这就是我在上面描述的内容:“在
a123456
之前和包含”的a123456
使用较旧的名称,而后续的提交使用较新的名称。 The git merge-base --is-ancestor AB
command performs this A ≼ B test, with its result delivered as a shell command exit status: git merge-base --is-ancestor AB
命令执行此A≼B测试,其结果作为shell命令退出状态传递:
if git-merge-base --is-ancestor $GIT_COMMIT a123456; then ...; else ...; fi
tests whether $GIT_COMMIT
≼ a123456
. 测试是否
$GIT_COMMIT
≼ a123456
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.