我已经执行了git filter-branch --index-filter 'git rm --cached --ignore-unmatched badfiles/ badfiles2/' --prune-empty
(每个here)以删除一堆文件,以准备将其余文件移动到另一个存储库。 --prune-empty
消除了所有空提交,但对合并无效,这很有意义。
现在,此特定回购的历史记录看起来非常丑陋,其中包含一堆实际上未添加任何内容的合并,而某些合并只是实际上未添加任何更改的其他合并的合并(在重写的历史记录中;可能在过滤器分支之前是“有用的”。
考虑以下带注释的代码段(由git log --graph --oneline --shortstat
生成):
* 575e3b5 Merge pull request #68 from chris/feature # KEEP THIS MERGE!
|\
| * 5dbc3f1 Actual feature changes
| | 2 files changed, 2 insertions(+), 2 deletions(-)
| * 35abc98 Cleanup/prep
|/
| 2 files changed, 22 insertions(+), 16 deletions(-)
* c3b3d86 Merge pull request #46 from org/topic_branch-mods # USELESS-C
|\
* \ 892de05 Merge pull request #47 from org/topic_branch # USELESS-B
|\ \
| |/
|/|
| * e738d4b Merge branch 'master' into topic_branch # USELESS-A
| |\
| |/
|/|
* | 4182dac CommitMsg #40 #SQUASHED-PR
| | 2 files changed, 15 insertions(+), 6 deletions(-)
* | 3b42762 CommitMsg
|/
| 2 files changed, 29 insertions(+), 14 deletions(-)
* c4e62ba CommitMsg
| 2 files changed, 39 insertions(+), 16 deletions(-)
* c2bb13f CommitMsg
4 files changed, 241 insertions(+)
我想将其缩短为(显然,适当地使用不同的ID):
* 575e3b5 Merge pull request #68 from chris/feature # KEEP THIS MERGE!
|\
| * 5dbc3f1 Actual feature changes
| | 2 files changed, 2 insertions(+), 2 deletions(-)
| * 35abc98 Cleanup/prep
|/
| 2 files changed, 22 insertions(+), 16 deletions(-)
* 4182dac CommitMsg #40 #SQUASHED-PR
| 2 files changed, 15 insertions(+), 6 deletions(-)
* 3b42762 CommitMsg
| 2 files changed, 29 insertions(+), 14 deletions(-)
* c4e62ba CommitMsg
| 2 files changed, 39 insertions(+), 16 deletions(-)
* c2bb13f CommitMsg
4 files changed, 241 insertions(+)
因此,我想摆脱所有“ 空”合并(无合并更改)的“ USELESS”合并,但我想保留相关的历史记录/分组KEEP合并在顶部,并且 also-'empty'将这些提交组合到一个'changeset'中。
或者看看传统的简化侧面历史中的另一个例子:
A -- B -- C -- D ==> A -- B --- D'
\----\--/ / \-E-/
\----E
我已经尝试了删除“空”合并的解决方案(例如this),但是那些删除了“ 所有”空合并,并且我想保留“有用”的空合并,如下所示例子...
据我所知,“无用”的空合并不包含历史上并非一直到左/上的所有提交。有办法干净地过滤掉那些东西吗?我想我什至不知道如何描述/定义那些东西...
请注意,给定的示例是故意简单的。对于它的价值,在历史的后面,此仓库看起来像这样,我想对它们进行修剪:
* 3d37e42 Merge pull request #239 from jim/topic-dev
|\
| * 05eaf9e Merge pull request #7 from org/master
| |\
| |/
|/|
* | 1576482 Merge pull request #193 from john/master
|\ \
| * \ 187100e Merge branch 'master' of github.com:org/repo into master
| |\ \
| * \ \ 067cc55 Merge branch 'master' of github.com:org/repo into master
| |\ \ \
| * \ \ \ a69e3d2 Merge branch 'master' of github.com:org/repo into master
| |\ \ \ \
| | |/ / /
* | | | | 0ce6813 Merge pull request #212 from jim/feature
|\ \ \ \ \
| | |_|_|/
| |/| | |
| * | | | 0f5352e Merge pull request #5 from org/master
| |\ \ \ \
| |/ / / /
答案 0 :(得分:1)
这是问题的核心:
我想我什至不知道该如何形容/定义那些...
Git本质上是一个图形操作程序,旨在构建DAG(有向无环图),其中图形中的每个节点都是提交。每个提交都将源快照作为一种数据有效负载的事实与该过程无关。 (当然,这与Git最终成为有用密切相关。)
您要采用现有的(后过滤)DAG并构建其他DAG。您需要定义一种算法,用于将不需要的DAG转换为需要的DAG。您不一定必须使用git filter-branch
来完成转换,但是如果您打算这样做,则必须进一步将此转换精炼为可以使用“到目前为止”知识的算法:查看filter-branch建议复制的提交的当前提交哈希ID。在$GIT_COMMIT
中。它可以读取该提交(使用Git管道命令),并且可以使用the git filter-branch
documentation中所述的shell函数map
从其他已复制的提交中查找映射。
我也不太了解如何定义“有用的合并”。不过,我认为最明显的算法不(至少直接适用于)过滤分支:这是一种迭代松弛算法,其中您从完整图开始,反复拔出合并节点,将其父节点连接到它们子节点,只要这些节点没有用处。 (定义无用仍由您决定。)最后,您有一个要保留的节点列表和要删除的节点。 该列表对于您为过滤器分支编写的过滤器很有用:您现在可以使用git filter-branch
运行--commit-filter
,该git commit-tree
可以照常运行skip_commit
,或者提供了uint16_t I106_CALL_DECL uCalcHeaderChecksum(SuI106Ch10Header * psuHeader)
{
int iHdrIdx;
uint16_t uHdrSum;
uint16_t * aHdr = (uint16_t *)psuHeader;
uHdrSum = 0;
for (iHdrIdx=0; iHdrIdx<(HEADER_SIZE-2)/2; iHdrIdx++)
uHdrSum += aHdr[iHdrIdx];
return uHdrSum;
}
功能,如文档中所述。决定“保留”还是“跳过”取决于您使用松弛算法生成的列表。
答案 1 :(得分:0)
好的,我认为这并不完美,但是在这种情况下确实可以解决问题。在某些情况下,它可能不会尽最大可能地进行清理,但是如果有人感兴趣,这是一个步骤:
git filter-branch --commit-filter '
if ! git rev-parse --verify "$GIT_COMMIT^2" 1>/dev/null 2>&1 ||
[ "$(git log --no-merges "$GIT_COMMIT^2" "^$GIT_COMMIT^1" --oneline | wc -l)" -gt 0 ];
then
#echo take $GIT_COMMIT >&2
# Pick one:
git_commit_non_empty_tree "$@" # Drop empty commits
#git commit-tree "$@" # Keep empty commits
else
#echo "breakup $GIT_COMMIT ($*)" >&2
skip_commit "$1" "$2" "$3" # (quietly) only keep the first parent
fi' -f HEAD
如果1)提交没有第二个父级(git rev-parse
返回错误,如果引用的提交($GIT_COMMIT^2
)不存在)或2)第二个父级({{1 }})包含第一个父项($GIT_COMMIT^2
)不提交的提交(请参阅here),该提交被保留(如果不是空的;如果要保留,请使用$GIT_COMMIT^1
空); 如果第二个父级存在并且不添加任何有用的信息,我们将跳过提交,并且有意地仅通过第一个父级-我不确定这是否是“合法” ,但它从历史记录中删除了第二个父级,并且在我的情况下有效...(请参见下面的注意事项)
从下至上:
git commit-tree
它通过* 575e3b5 Merge pull request #68 from chris/feature # KEEP THIS MERGE!
|\
| * 5dbc3f1 Actual feature changes
| | 2 files changed, 2 insertions(+), 2 deletions(-)
| * 35abc98 Cleanup/prep
|/
| 2 files changed, 22 insertions(+), 16 deletions(-)
* c3b3d86 Merge pull request #46 from org/topic_branch-mods # USELESS-C
|\
* \ 892de05 Merge pull request #47 from org/topic_branch # USELESS-B
|\ \
| |/
|/|
| * e738d4b Merge branch 'master' into topic_branch # USELESS-A
| |\
| |/
|/|
* | 4182dac CommitMsg #40 #SQUASHED-PR
| | 2 files changed, 15 insertions(+), 6 deletions(-)
* | 3b42762 CommitMsg
|/
| 2 files changed, 29 insertions(+), 14 deletions(-)
* c4e62ba CommitMsg
| 2 files changed, 39 insertions(+), 16 deletions(-)
* c2bb13f CommitMsg
4 files changed, 241 insertions(+)
保留了所有内容(请注意,提交ID为SQUASHED-PR
,并且保留了父母的身份,因为他们的历史没有改变)。决定4182dac
应该坚持在其第二个父级(USELESS-A
)包含提交其第一个父级(4182dac
)的情况下,不包含,但是,然后查看了c4e62ba
,它的第二个父级(包括 USELESS-B
)没有添加任何有用的内容,因此将其删除(再次包括USELESS-A
)。然后USELESS-A
就没用了,因此被丢弃了,USELESS-C
在第二个父对象中有“有用的东西”,因此被保留了。因此,您结束了:
KEEP
* 63b4d39 Merge pull request #68 from chris/feature # KEEP THIS MERGE!
|\
| * 9a5570d Actual feature changes
| | 2 files changed, 2 insertions(+), 2 deletions(-)
| * a251317 Cleanup/prep
|/
| 2 files changed, 22 insertions(+), 16 deletions(-)
* 4182dac CommitMsg #40 #SQUASHED-PR
| 2 files changed, 15 insertions(+), 6 deletions(-)
* 3b42762 CommitMsg
| 2 files changed, 29 insertions(+), 14 deletions(-)
* c4e62ba CommitMsg
| 2 files changed, 39 insertions(+), 16 deletions(-)
* c2bb13f CommitMsg
4 files changed, 241 insertions(+)
,在这种情况下忽略了"$1" "$2" "$3"
,否则将包括在内在"$4" "$5"
中。如果您有多个父母(或者您的 commit 有多个父母),则必须对此进行调整以解决此问题;不应该太难,但是我现在不假想解决它-您可能要选择特定的父母,idk。"$@"
之后有一个“有用的”提交,然后才被合并到USELESS-A
(这可能毫无用处),USELESS-B
将不是被修剪/删除,因此您可能还会感到有些丑陋。