在 Git 中,如何获取与三向合并相关的三个提交 ID(例如在自定义合并驱动程序中)?



在下图中,时间从下到上流动:

| |
| |
3 | this is a commit on master, myfile.txt was modified by this commit
| |
| 2 this is a commit on branch mybranch, myfile.txt was modified by this commit
| |
|/
|
1   this is a commit on master, myfile.txt was modified by this commit

现在我需要将mybranch合并到master中,如果我正确理解 Git,myfile.txt现在需要一个文件级合并(见 https://git-scm.com/docs/gitattributes#_performing_a_three_way_merge(,因为合并中涉及的两个分支中都修改了myfile.txt

关于自定义合并驱动程序,帮助说:

merge.*.driver变量的值用于构造命令 运行以合并祖先的版本(%O(,当前版本(%A(和 其他分支的版本(%B(。这三个令牌被替换 带有保存这些内容的临时文件的名称 生成命令行时的版本。

我的理解是,%O将是提交时内容为myfile.txt的临时文件的名称1%A将是提交时内容为myfile.txt的临时文件的名称3%B将是临时文件的名称,内容为 在提交时myfile.txt2

临时文件的名称是否以某种方式嵌入了提交 ID(SHA-1(?

有没有办法获取123的提交 ID?

我的[理解]是%O将是提交时内容为myfile.txt的临时文件的名称1%A将是提交时内容为myfile.txt的临时文件的名称3%B将是临时文件的名称,内容在提交时为myfile.txt2

没错。

临时文件的名称是否以某种方式嵌入了提交 ID(SHA-1(?

不。

有没有办法获取123的提交 ID?

不可靠,不。 通常,您可以通过找到实际的git merge命令并解析其参数来查找为提交 3 提供的名称或哈希 ID,从而非常接近。 提交 2 通常是HEAD。 因此,提交 1 是git merge-base -all HEAD <3>的结果,只要它只是一个哈希 ID

当有多个合并基础时,这里的问题就出现了。 在这种情况下,所有三个提交的 ID 可能取决于这是否是递归合并。 如果合并是用git merge -s resolve运行的,则合并基是N个合并基之一,以(明显(随机选择。 如果使用git merge -s recursive(或默认值(运行合并,则合并将运行多次,一次针对每个合并基础,然后再次通过合并合并基础进行提交,可能是递归的。

你最好的选择是不需要这些信息,因为重建它是混乱和不可靠的。

有没有办法获取 1、2 和 3 的提交 ID?

是的,但不一定总是如此。

$ git init
$ touch .gitignore
$ git add .gitignore
$ git ci -m .gitignore
$ echo 1 > myfile.txt
$ git add myfile.txt
$ git ci -m 'this is a commit on master, myfile.txt was modified by this commit'
$ git co -b mybranch
$ echo 2 >> myfile.txt 
$ git ci -am "this is a commit on branch mybranch, myfile.txt was modified by this commit"
$ git co master 
$ echo 3 >> myfile.txt 
$ git ci -am "this is a commit on master, myfile.txt was modified by this commit"
$ git log --graph --all --oneline
* 2d0b94b (HEAD -> master) this is a commit on master, myfile.txt was modified by this commit
| * d223e74 (mybranch) this is a commit on branch mybranch, myfile.txt was modified by this commit
|/  
* 0bf67f0 this is a commit on master, myfile.txt was modified by this commit
* b6c7c02 .gitignore
$ git merge mybranch 
Auto-merging myfile.txt
CONFLICT (content): Merge conflict in myfile.txt
Automatic merge failed; fix conflicts and then commit the result.
$

此时,可以使用git ls-files -u轻松获取 1、2 和 3 的blob。从 blob 中,您可以找到相应的提交:

git ls-files -u
100644 d00491fd7e5bb6fa28c517a0bb32b8b506539d4d 1       myfile.txt
100644 2b2f2e1b9261c50c3816610eb3eb140fabf1745a 2       myfile.txt
100644 1191247b6d9a206f6ba3d8ac79e26d041dd86941 3       myfile.txt
$ ./what-commit-contains-file-blob.sh myfile.txt d00491fd7e5bb6fa28c517a0bb32b8b506539d4d
0bf67f0 this is a commit on master, myfile.txt was modified by this commit
$ ./what-commit-contains-file-blob.sh myfile.txt 2b2f2e1b9261c50c3816610eb3eb140fabf1745a
2d0b94b (HEAD -> master) this is a commit on master, myfile.txt was modified by this commit
$ ./what-commit-contains-file-blob.sh myfile.txt 1191247b6d9a206f6ba3d8ac79e26d041dd86941
d223e74 (mybranch) this is a commit on branch mybranch, myfile.txt was modified by this commit
$ cat what-commit-contains-file-blob.sh 
#!/bin/sh
# https://stackoverflow.com/questions/223678/which-commit-has-this-blob
# https://stackoverflow.com/a/32611564/23118
file=${1:?missing file name argument}
blob=${2:?missing blob argument}
git log --all --pretty=format:%H -- $file 
| xargs -n1 -I% sh -c "git ls-tree % -- $file | grep -q $blob && echo %" 
| xargs -n 1 git log -n 1 --oneline
$

因此,对于这个简单的示例存储库,该解决方案运行良好,但是一个 blob 可以是多个提交的一部分,所以我不确定这是否总是会给出唯一的结果。

最新更新