我想要一个查找重复更改的方法。patch-id 可能相同,但提交属性可能不同。
这似乎是 patch-id 的预期用途:
git patch-id --help
IOW,您可以使用这个东西来寻找可能的重复提交。
我想将“git log”、“git patch-id”和 uniq 串在一起可能会做得很糟糕,但是如果有人有一个可以很好地完成工作的命令,我会很感激。
我想要一个查找重复更改的方法。patch-id 可能相同,但提交属性可能不同。
这似乎是 patch-id 的预期用途:
git patch-id --help
IOW,您可以使用这个东西来寻找可能的重复提交。
我想将“git log”、“git patch-id”和 uniq 串在一起可能会做得很糟糕,但是如果有人有一个可以很好地完成工作的命令,我会很感激。
因为重复的更改可能不在同一个分支上(除非它们之间有还原),您可以使用git cherry:
git cherry [-v] [<upstream> [<head> [<limit>]]]
检查. upstream
_head
要查找特定提交的重复项,这可能对您有用。
首先,确定目标提交的补丁 id:
$ THE_COMMIT_REF_OR_SHA_YOURE_SEEKING_DUPES_OF='7a3e67c'
$ git show $THE_COMMIT_REF_OR_SHA_YOURE_SEEKING_DUPES_OF | git patch-id
f6ea51cd6acd30cd627ce1a56e2733c1777d5b52 7a3e67ce38dbef471889d9f706b9161da7dc5cf3
第一个 SHA 是补丁 ID。接下来,列出每个提交的补丁 ID 并过滤掉任何匹配的内容:
$ for c in $(git rev-list --all); do git show $c | git patch-id; done | grep 'f6ea51cd6acd30cd627ce1a56e2733c1777d5b52'
f6ea51cd6acd30cd627ce1a56e2733c1777d5b52 5028e2b5500bd5f4637531e337e17b73f5d0c0b1
f6ea51cd6acd30cd627ce1a56e2733c1777d5b52 7a3e67ce38dbef471889d9f706b9161da7dc5cf3
f6ea51cd6acd30cd627ce1a56e2733c1777d5b52 929c66b5783a0127a7689020d70d398f095b9e00
总之,带有一些额外的标志,并以实用程序脚本的形式:
test ! -z "$1" && TARGET_COMMIT_SHA="$1" || TARGET_COMMIT_SHA="HEAD"
TARGET_COMMIT_PATCHID=$(
git show --patch-with-raw "$TARGET_COMMIT_SHA" |
git patch-id |
cut -d' ' -f1
)
MATCHING_COMMIT_SHAS=$(
for c in $(git rev-list --all); do
git show --patch-with-raw "$c" |
git patch-id
done |
fgrep "$TARGET_COMMIT_PATCHID" |
cut -d' ' -f2
)
echo "$MATCHING_COMMIT_SHAS"
用法:
$ git list-dupe-commits 7a3e67c
5028e2b5500bd5f4637531e337e17b73f5d0c0b1
7a3e67ce38dbef471889d9f706b9161da7dc5cf3
929c66b5783a0127a7689020d70d398f095b9e00
它的速度不是特别快,但对于大多数 repos 来说应该可以完成工作(对于 2.4GHz Core 2 Duo 上具有 826 次提交和 158MB .git 目录的 repo 只测量了 36 秒)。
我有一个适用于玩具存储库的草稿,但是由于它将补丁->提交映射保留在内存中,因此在大型存储库中可能会出现问题:
# print commit pairs with the same patch-id
for c in $(git rev-list HEAD); do \
git show $c | git patch-id; done \
| perl -anle '($p,$c)=@F;print "$c $s{$p}" if $s{$p};$s{$p}=$c'
输出应该是具有相同补丁 ID 的提交对(3 个重复的 ABC 出现为“A B”然后是“B C”)。
更改 git rev-list 命令以限制检查的提交:
git log --format=%H HEAD somefile
附加“| xargs git show”以查看提交的详细信息,或附加“| xargs git show -s --oneline”以获取摘要:
0569473 add 6-8
5e56314 add 6-8 again
bece3c3 comment
e037ed6 add comment again
事实证明,patch-id 在我原来的情况下不起作用,因为后来的提交中有额外的变化。“git log -S”更有用。
要搜索 commit 的重复提交$hash
,不包括合并提交:
git rev-list --no-merges --all | xargs -r git show | git patch-id \
| grep ^$(git show $hash|git patch-id|cut -c1-40) | cut -c42-80 \
| xargs -r git show -s --oneline
要搜索合并提交的副本$mergehash
,请将$(git show $hash|git patch-id|cut -c1-40)
上面替换为由 给出的两个补丁 ID(第一列)之一git diff-tree -m -p $mergehash | git patch-id
。它们对应于合并提交与其两个父级中的每一个的差异。
要查找所有提交的重复项,不包括合并提交:
git rev-list --no-merges --all | xargs -r git show | git patch-id \
| sort | uniq -w40 -D | cut -c42-80 \
| xargs -r git log --no-walk --pretty=format:"%h %ad %an (%cn) %s" --date-order --date=iso
可以通过将参数更改为 来扩展或限制重复提交的搜索,该参数git rev-list
接受许多选项。例如,要将搜索限制为特定分支,请指定其名称而不是选项--all
;或在最后 100 次提交中搜索传递参数HEAD ^HEAD~100
。
请注意,这些命令速度很快,因为它们不使用 shell 循环和批处理提交。
要包括合并提交,请删除选项--no-merges
,并替换xargs -r git show
为xargs -r -L1 git diff-tree -m -p
. 这要慢得多,因为git diff-tree
每次提交执行一次。
解释:
第一行生成带有提交哈希的补丁 ID 映射(2 列数据,每列 40 个字符)。
第二行仅保留与重复补丁 ID(第一列)相对应的提交哈希(第二列)。
最后一行打印有关重复提交的自定义信息。
bsb建议的漂亮命令需要一些小的调整:
(1)命令应该使用而不是git show
, which runsgit diff-tree --cc
git diff-tree -p
否则会git patch-id
生成虚假的空 SHA1 哈希。
(2) 使用管道时xargs
,xargs
应有-L 1
参数。否则,三重提交将不会与等效提交配对。
这是一个别名~/.gitconfig
:
dup = "!f() { for c in $(git rev-list HEAD); do git diff-tree -p $c | git patch-id; done | perl -anle '($p,$c)=@F;print \"$c $s{$p}\" if $s{$p};$s{$p}=$c' | xargs -L 1 git show -s --oneline; }; f" # "git dup" lists duplicate commits
对于任何想在 windows powershell 上执行此操作的人,unagi 答案的等效命令是:
git rev-list --no-merges --all | %{&git.exe show $_} |
git patch-id | ConvertFrom-String -PropertyNames PatchId, Commit |
Group-Object PatchId | Where-Object count -gt 1 |
%{$_.group.Commit + " "}
给出如下输出:
1605e0e1e13d7b3f456c20432d8edec664ca7117
1e8efa8f2f01962a2c08fd25caf687d330383428
b45b6db084b27ae420ac8e9cf6511110ebb46513
4a2e1e3ba5a9a1d5db1d00343813e1404f6124e2
将重复的提交哈希分组在一起。
注意:在我的 repo 中,这是一个缓慢的命令,因此请务必适当过滤对 rev-list 的调用!
确保使用最新版本的 Git
OP bsb的答案git log --format=%H
提到的并不总是唯一的。
这是因为,在 Git 2.29(2020 年第四季度)之前,patch-id 计算并没有忽略空格等“不完整的最后一行”标记。
请参阅René Scharfe ( ) 的提交 82a6201(2020 年 8 月 19 日)。(由Junio C Hamano 合并 -- --在提交 5122614中,2020 年 8 月 24 日)rscharfe
gitster
patch-id
: 忽略文件末尾的换行符diff_flush_patch_id()
报告人:Tilman Vogel
初始测试人:Tilman Vogel
签字人:René Scharfe
计算补丁 ID 时忽略空格。
这是通过在散列它们之前从差异行中删除所有空格来完成的,包括文件末尾的换行符。
但是,如果缺少该换行符,则 diff 在包含“\文件末尾没有换行符\n”的单独行中报告该事实,并且该标记像上下文行一样被散列。这违背了我们使补丁 ID 独立于空格的目标。
使用与添加到( man )的2485eab55cc (git-patch-id: 不要跳过“无换行符”标记,2011-02-17)相同的启发式方法,并跳过以反斜杠和空格开头且更长的差异行超过十二个字符。
git patch-id