diff options
author | Junio C Hamano <gitster@pobox.com> | 2023-06-30 02:43:21 +0300 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2023-06-30 02:43:21 +0300 |
commit | 3ea43bbe17b9f0d8ffcad17ce602d36ea0668ab8 (patch) | |
tree | 256f0aebc98100cdf485b1c38b3dd2c74e7b8f90 | |
parent | a1264a08a1a6e0cd7e510c899cd0ba42dcf1045d (diff) | |
parent | 34d765e736e015f5c4790db2c0a1d3ddbd4bd3e9 (diff) |
Merge branch 'jc/abort-ll-merge-with-a-signal'
When the external merge driver is killed by a signal, its output
should not be trusted as a resolution with conflicts that is
proposed by the driver, but the code did.
* jc/abort-ll-merge-with-a-signal:
t6406: skip "external merge driver getting killed by a signal" test on Windows
ll-merge: killing the external merge driver aborts the merge
-rw-r--r-- | Documentation/gitattributes.txt | 5 | ||||
-rw-r--r-- | merge-ll.c | 9 | ||||
-rwxr-xr-x | t/t6406-merge-attr.sh | 23 |
3 files changed, 35 insertions, 2 deletions
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt index 02a3ec83e4..6deb89a296 100644 --- a/Documentation/gitattributes.txt +++ b/Documentation/gitattributes.txt @@ -1132,7 +1132,10 @@ size (see below). The merge driver is expected to leave the result of the merge in the file named with `%A` by overwriting it, and exit with zero status if it managed to merge them cleanly, or non-zero if there -were conflicts. +were conflicts. When the driver crashes (e.g. killed by SEGV), +it is expected to exit with non-zero status that are higher than +128, and in such a case, the merge results in a failure (which is +different from producing a conflict). The `merge.*.recursive` variable specifies what other merge driver to use when the merge driver is called for an internal diff --git a/merge-ll.c b/merge-ll.c index 740b8c6bfd..478983309d 100644 --- a/merge-ll.c +++ b/merge-ll.c @@ -243,7 +243,14 @@ static enum ll_merge_result ll_ext_merge(const struct ll_merge_driver *fn, unlink_or_warn(temp[i]); strbuf_release(&cmd); strbuf_release(&path_sq); - ret = (status > 0) ? LL_MERGE_CONFLICT : status; + + if (!status) + ret = LL_MERGE_OK; + else if (status <= 128) + ret = LL_MERGE_CONFLICT; + else + /* died due to a signal: WTERMSIG(status) + 128 */ + ret = LL_MERGE_ERROR; return ret; } diff --git a/t/t6406-merge-attr.sh b/t/t6406-merge-attr.sh index 5e4e4dd6d9..9677180a5b 100755 --- a/t/t6406-merge-attr.sh +++ b/t/t6406-merge-attr.sh @@ -56,6 +56,12 @@ test_expect_success setup ' ) >"$ours+" cat "$ours+" >"$ours" rm -f "$ours+" + + if test -f ./please-abort + then + echo >>./please-abort killing myself + kill -9 $$ + fi exit "$exit" EOF chmod +x ./custom-merge @@ -162,6 +168,23 @@ test_expect_success 'custom merge backend' ' rm -f $o $a $b ' +test_expect_success !WINDOWS 'custom merge driver that is killed with a signal' ' + test_when_finished "rm -f output please-abort" && + + git reset --hard anchor && + git config --replace-all \ + merge.custom.driver "./custom-merge %O %A %B 0 %P" && + git config --replace-all \ + merge.custom.name "custom merge driver for testing" && + + >./please-abort && + echo "* merge=custom" >.gitattributes && + test_must_fail git merge main && + git ls-files -u >output && + git diff --name-only HEAD >>output && + test_must_be_empty output +' + test_expect_success 'up-to-date merge without common ancestor' ' git init repo1 && git init repo2 && |