在下图中,时间从下到上流动:
| |
| |
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.txt
2
。
临时文件的名称是否以某种方式嵌入了提交 ID(SHA-1(?
有没有办法获取1
、2
和3
的提交 ID?
我的[理解]是
%O
将是提交时内容为myfile.txt
的临时文件的名称1
,%A
将是提交时内容为myfile.txt
的临时文件的名称3
%B
将是临时文件的名称,内容在提交时为myfile.txt
2
。
没错。
临时文件的名称是否以某种方式嵌入了提交 ID(SHA-1(?
不。
有没有办法获取
1
、2
和3
的提交 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 可以是多个提交的一部分,所以我不确定这是否总是会给出唯一的结果。