11

我想要一个查找重复更改的方法。patch-id 可能相同,但提交属性可能不同。

这似乎是 patch-id 的预期用途:

git patch-id --help

IOW,您可以使用这个东西来寻找可能的重复提交。

我想将“git log”、“git patch-id”和 uniq 串在一起可能会做得很糟糕,但是如果有人有一个可以很好地完成工作的命令,我会很感激。

4

7 回答 7

12

因为重复的更改可能不在同一个分支上(除非它们之间有还原),您可以使用git cherry

git cherry [-v] [<upstream> [<head> [<limit>]]]

检查. upstream_head

于 2012-07-23T07:31:06.077 回答
11

要查找特定提交的重复项,这可能对您有用。

首先,确定目标提交的补丁 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 秒)

于 2013-11-03T21:08:50.897 回答
4

我有一个适用于玩具存储库的草稿,但是由于它将补丁->提交映射保留在内存中,因此在大型存储库中可能会出现问题:

# 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”更有用。

于 2012-07-25T04:30:30.447 回答
3

要搜索 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 showxargs -r -L1 git diff-tree -m -p. 这要慢得多,因为git diff-tree每次提交执行一次。

解释:

  • 第一行生成带有提交哈希的补丁 ID 映射(2 列数据,每列 40 个字符)。

  • 第二行仅保留与重复补丁 ID(第一列)相对应的提交哈希(第二列)。

  • 最后一行打印有关重复提交的自定义信息。

于 2017-08-30T01:49:31.050 回答
2

bsb建议的漂亮命令需要一些小的调整:

(1)命令应该使用而不是git show, which runsgit diff-tree --cc

    git diff-tree -p

否则会git patch-id生成虚假的空 SHA1 哈希。

(2) 使用管道时xargsxargs应有-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
于 2017-07-28T12:26:11.033 回答
0

对于任何想在 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 的调用!

于 2019-06-17T16:07:35.357 回答
0

确保使用最新版本的 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

于 2020-08-31T16:10:39.483 回答