В Git, как получить три идентификатора фиксации, относящиеся к трехстороннему слиянию (например, в пользовательском драйвере слияния)? - PullRequest
1 голос
/ 18 октября 2019

На следующем графике время течет снизу вверх:

| |
| |
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 будет именем временного файла с контентомиз at myfile.txt at commit 2.

Встраивает ли имя временных файлов каким-либо образом идентификатор фиксации (SHA-1)?

Есть ли способ получитьидентификатор фиксации 1, 2 и 3?

Ответы [ 2 ]

1 голос
/ 20 октября 2019

Есть ли способ получить идентификатор фиксации 1, 2 и 3?

Да, но не обязательно всегда.

$ 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, чтобы легко получить BLOB-объекты для 1, 2 и 3. И от 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

# /179224/kakoi-kommit-imeet-etot-blob-obekt
# 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-объект может быть частью нескольких коммитов, поэтому я не уверен, что это всегда даст уникальный результат.

1 голос
/ 18 октября 2019

Мое [понимание] заключается в том, что %O будет именем временного файла с содержимым myfile.txt при фиксации 1, %A будет именем временного файла с содержимымmyfile.txt при коммите 3 и %B будет именем временного файла с содержанием в myfile.txt при коммите 2.

Это верно.

Встраивает ли имя временных файлов каким-либо образом идентификатор фиксации (SHA-1)?

Нет.

Есть ли какие-либоспособ получить идентификатор коммита 1, 2 и 3?

Не достоверно, нет. Обычно вы можете довольно близко подобраться, найдя фактическую команду git merge и проанализировав ее аргументы, чтобы найти имя или хэш-идентификатор, предоставленные для фиксации 3. Коммит 2 обычно равен HEAD. Коммит 1, таким образом, является результатом git merge-base -all HEAD <3>, , если это всего лишь один хэш-идентификатор .

Проблема здесь возникает, когда существует более одной базы слияния. В этом случае идентификатор всех трех коммитов может зависеть от того, является ли это рекурсивным слиянием. Если слияние было выполнено с git merge -s resolve, база слияния является одной из N баз слияния, выбранных с (кажущейся) случайностью. Если слияние было выполнено с git merge -s recursive (или по умолчанию), слияние будет выполняться несколько раз, один раз для каждой базы слияния, затем снова с фиксацией, сделанной слиянием баз слияния, возможно, рекурсивно.

ВашЛучше всего, чтобы эта информация не требовалась, поскольку ее восстановление является грязным и ненадежным.

...