【问题标题】:Detect a commit diff/patch/hunk in another branch similar to the way cherry-pick does在另一个分支中检测提交差异/补丁/大块,类似于cherry-pick的方式
【发布时间】:2019-12-18 21:38:30
【问题描述】:

使用git,我想检查来自特定提交的哪些差异(如果有)已应用于(以及在何处)特定分支。

cherry-pick 在您选择提交时执行此操作(“where”部分除外)并且仅应用尚未应用于该分支的差异。例如,如果我将两个文件更改提交到一个主题分支,我手动将其中一个相同的文件更改应用到 master,当我挑选具有从主题到 master 的两个文件差异的提交时,它只应用未应用的差异。为了证明这一点,从一个空文件夹运行以下命令并查看最终的差异输出:

git init
echo file 1 > file1.txt
git add .
git commit -m "Initial commit"
git branch topic
echo file 1.1 > file1.txt
git add .
git commit -m "Change file1.txt on master"
git checkout topic
echo file 1.1 > file1.txt
echo file 2 > file2.txt
git add .
git commit -m "Change file1.txt and add file2.txt on topic"
git tag to-cherrypick
git checkout master
git cherry-pick --no-commit to-cherrypick
git diff --cached

差异输出是:

diff --git a/file2.txt b/file2.txt
new file mode 100644
index 0000000..6bb4b1d
--- /dev/null
+++ b/file2.txt
@@ -0,0 +1 @@
+file 2

表明即使精心挑选的提交有两个文件更改,它检测到第一个已被应用。

所以我的问题是:git 是否有一个暴露的管道(或介于管道和瓷器之间的某个位置)命令,它将查看提交中的大块并检查另一个分支中的每个大块,显示应用每个大块的提交?

如果该命令不存在,有哪些途径可以找到它?我已经在考虑编写一个脚本/程序来将提交分解成它的块,在每个上运行 patch-id 或类似的东西,然后从共同祖先开始循环遍历另一个分支并对每个提交执行相同的操作,并且比较帅哥。如果它已经暴露,我想避免写它——我知道它存在,因为cherry-pick会这样做(除了显示“位置”)。

更新:git cherry 会做一些我正在寻找的东西。它会告诉我一个分支中的哪些提交具有一个或多个尚未应用于另一个分支的差异块。它不会告诉您应用了这些差异数据块的位置,或者提交是否包含应用了的数据块和其他未应用的数据块。

【问题讨论】:

  • 首先,旁注:git cherry-pick 在这里没有做任何特别的事情;是 git rebase 使用 git cherry / git rev-list --right-only --cherry-pick 做特别的事情。第二:计算“相同性”的命令是git patch-id。这会读取标准输入并打印哈希。如果你拿一个 diff hunk 并通过git patch-id 运行它,你会得到一个哈希,你可以与任何其他 diff hunk 的哈希进行比较,看看这些 diff hunk 是否“相同”。见the git patch-id documentation
  • (当您使用git cherry-pick 应用已应用的提交时,在大多数情况下,您最终会得到一种美化的无操作,但这会使 rebase 有点混淆,这就是为什么rebase 只是在前面跳过它们。)
  • @torek 我以cherry-pick 为例,但我很欣赏有关cherry-pick 和rebase 如何工作的信息。这让我有更多的研究。关于您的第二条评论,我的示例表明,cherry-pick 足够聪明,可以比仅仅提交更深入,并查看单个帅哥并忽略已经应用的帅哥,同时仍然应用那些尚未应用的帅哥。
  • 右:cherry-pick 使用了合并 machinery,只是方式有点奇怪。它将合并基础提交设置为所选择提交的父级。 --ours 提交(索引槽 2)像往常一样是 HEAD--theirs 提交(索引槽 3)是精心挑选的提交,索引槽 1(合并基)是(单个)父(因此-m 是必要的,如果樱桃挑选的提交有 2 个或更多的父母)。最终的 commit 不是 merge commit,但该操作使用了合并 code
  • 没有。使用相对简单的脚本编写的最佳方法是分离出每个差异块(实现 add -preset -p 的 perl 代码执行此操作),通过 git patch-id 运行它(Git 中的多个内部位置执行此操作,包括 @ 987654342@),并将补丁 ID 保存在某处,以便您可以比较它们。

标签: git git-plumbing


【解决方案1】:

如评论:

使用相对简单的脚本可以得到最好的结果是分离出每个差异块(实现 add -preset -p 的 perl 代码执行此操作),通过 git patch-id 运行它(Git 中的多个内部位置执行此操作,包括git rerere),并将补丁 ID 保存在某处,以便您进行比较。

首先:不再有任何 Git 命令的“perl”版本。
一切都用 C 重写了。

例如 git add -p 被 inc C 重写为 part of Git 2.25 (Q4 2019) (commit f6aa7ec)

其次,如果您使用的是git patch-id,请确保使用 Git 2.36(2022 年第二季度)。

与 "git apply"(man) 不同,"git patch-id"(man) 不处理只有 1 行的块的补丁在原像或后像中,已使用 Git 2.36(2022 年第二季度)进行了更正。

参见Jerry Zhang (jerry-skydio)commit 757e75ccommit 56fa5ac(2022 年 2 月 1 日)。
(由 Junio C Hamano -- gitster -- 合并到 commit d077db1,2022 年 2 月 17 日)

patch-id: 修复 scan_hunk_header 的差异与 1 行之前/之后

签字人:Jerry Zhang

通常,差异将包含格式为“@@ -2,2 +2,15 @@ code”的大块标头。
但是,当只有 1 行更改时,统一 diff 格式允许在行数之前或之后省略第二个逗号分隔值。

这可以生成类似于“@@ -2 +2,18 @@ code”或“@@ -2,2 +2 @@ code”的大块标头。
结果,scan_hunk_header 错误地将行号返回为行 count,这会导致补丁的其余部分出现不可预知的解析错误,包括为单个提交提供多行输出。 p>

通过在没有逗号时将行数显式设置为 1 来修复,并添加测试。

apply.c 包含相同的逻辑,但它是正确的。
一个有价值的未来项目可能是统一这两个差异解析器,以便它们都从修复中受益。

【讨论】:

    猜你喜欢
    • 2012-12-02
    • 1970-01-01
    • 2017-07-23
    • 2020-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多