* [PATCH] merge-ort: fix a crash in process_renames @ 2024-09-21 2:45 dgoncharov 2024-09-21 2:45 ` dgoncharov 0 siblings, 1 reply; 5+ messages in thread From: dgoncharov @ 2024-09-21 2:45 UTC (permalink / raw) To: git; +Cc: newren Good morning. Resending https://lore.kernel.org/git/20240706211407.512652-1-dgoncharov@users.sf.net/. ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH] merge-ort: fix a crash in process_renames 2024-09-21 2:45 [PATCH] merge-ort: fix a crash in process_renames dgoncharov @ 2024-09-21 2:45 ` dgoncharov 2025-03-06 15:27 ` Elijah Newren 0 siblings, 1 reply; 5+ messages in thread From: dgoncharov @ 2024-09-21 2:45 UTC (permalink / raw) To: git; +Cc: newren, Dmitry Goncharov From: Dmitry Goncharov <dgoncharov@users.sf.net> cherry-pick --strategy=ort (the default at the moment) crashes in the following scenario $ ls -a . .. $ mkdir tools $ git init -q -b side2 $ echo hello>tools/hello $ git add tools/hello $ git commit -q tools/hello -m'Add tools/hello.' $ git branch side1 $ echo world>world $ git add world $ git commit -q world -m'Add world.' $ git mv world tools/world $ git commit -q -m'mv world tools/world.' $ git checkout -q side1 $ git mv tools/hello hello $ git commit -q -m'mv tools/hello hello.' $ git cherry-pick --strategy=ort side2 git: merge-ort.c:3006: process_renames: Assertion `source_deleted || oldinfo->filemask & old_sidemask' failed. Aborted (core dumped) While cherry picking the top commit from side2 to side1 collect_renames is confused by the preceding move from "tools/hello" to "hello" that took place on side1. This move from "tools/hello" to "hello" causes the logic in check_for_directory_rename to incorrectly conclude that "tools/world" should be renamed to "world". detect_and_process_renames proceeds with "world" instead of "tools/world" and ends up tripping on an assertion in process_renames. In the same scenario cherry-pick --strategy=recursive detects a merge conflict. $ rm .git/index.lock $ git reset -q --hard $ git cherry-pick --strategy=recursive side2 CONFLICT (file location): world renamed to tools/world in fead592 (mv world tools/world.), inside a directory that was renamed in HEAD, suggesting it should perhaps be moved to world. CONFLICT (content): Merge conflict in world error: cache entry has null sha1: world error: cherry-pick: Unable to write new index file fatal: cherry-pick failed There really is a merge conflict and the goal of this commit is to have cherry-pick --strategy=ort detect the conflict. This commit modifies collect_renames to ignore an implicit directory rename that suggests moving a file to itself. Also, see test t3515-cherry-pick-move.sh. Signed-off-by: Dmitry Goncharov <dgoncharov@users.sf.net> --- merge-ort.c | 9 +++++++ t/t3515-cherry-pick-move.sh | 48 +++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100755 t/t3515-cherry-pick-move.sh diff --git a/merge-ort.c b/merge-ort.c index 691db9050e..e58fb7a7fa 100644 --- a/merge-ort.c +++ b/merge-ort.c @@ -3369,6 +3369,15 @@ static int collect_renames(struct merge_options *opt, collisions, &clean); + if (new_path && !strcmp(new_path, p->one->path)) { + /* Ignore an implicit directory rename that suggests replacing a move + * from one->path to two->path with a move + * from one->path to one->path. + */ + free(new_path); + new_path = NULL; + } + possibly_cache_new_pair(renames, p, side_index, new_path); if (p->status != 'R' && !new_path) { pool_diff_free_filepair(&opt->priv->pool, p); diff --git a/t/t3515-cherry-pick-move.sh b/t/t3515-cherry-pick-move.sh new file mode 100755 index 0000000000..20af478d4e --- /dev/null +++ b/t/t3515-cherry-pick-move.sh @@ -0,0 +1,48 @@ +#!/bin/sh + +test_description='Test cherry-picking a move commit.' + + +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=side2 +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME + +TEST_PASSES_SANITIZE_LEAK=true +. ./test-lib.sh + +test_expect_success setup ' + mkdir tools && + + echo hello >tools/hello && + + git add tools/hello && + git commit -m"Add tools/hello." tools/hello && + + git branch side1 && + + # This commit is the base of the fatal cherry-pick merge. + echo world >world && + git add world && + git commit -m"Add world." && + + # Cherry picking this commit crashes git. + # This commit is side 2 of the fatal cherry-pick merge. + git mv -v world tools/world && + git commit -m"mv world tools/world." && + + git checkout side1 && + # This commit is side 1 of the fatal cherry-pick merge. + git mv -v tools/hello hello && + git commit -m"mv tools/hello hello" +' + +test_expect_success 'recursive cherry-pick of a move commit' ' + test_must_fail git cherry-pick --strategy=recursive side2 +' + +test_expect_success 'ort cherry-pick of a move commit' ' + rm -f world && + git reset --hard && + test_must_fail git cherry-pick --strategy=ort side2 +' + +test_done -- 2.34.1 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH] merge-ort: fix a crash in process_renames 2024-09-21 2:45 ` dgoncharov @ 2025-03-06 15:27 ` Elijah Newren 2025-03-06 17:19 ` Elijah Newren 0 siblings, 1 reply; 5+ messages in thread From: Elijah Newren @ 2025-03-06 15:27 UTC (permalink / raw) To: dgoncharov; +Cc: git I apologize for the very delayed response... On Fri, Sep 20, 2024 at 7:46 PM <dgoncharov@users.sf.net> wrote: > > From: Dmitry Goncharov <dgoncharov@users.sf.net> > > cherry-pick --strategy=ort (the default at the moment) crashes in the following > scenario Good job, you found a testcase that caused both `ort` and `recursive` to fail. :-) For other readers, I'll note that this isn't special to cherry-pick; I can also reproduce using merge for example. > $ ls -a > . .. > $ mkdir tools > $ git init -q -b side2 > $ echo hello>tools/hello > $ git add tools/hello > $ git commit -q tools/hello -m'Add tools/hello.' > $ git branch side1 > $ echo world>world > $ git add world > $ git commit -q world -m'Add world.' > $ git mv world tools/world > $ git commit -q -m'mv world tools/world.' > $ git checkout -q side1 > $ git mv tools/hello hello > $ git commit -q -m'mv tools/hello hello.' > $ git cherry-pick --strategy=ort side2 > git: merge-ort.c:3006: process_renames: Assertion `source_deleted || oldinfo->filemask & old_sidemask' failed. > Aborted (core dumped) Thanks for putting together a testcase; very helpful. And you even provided it in the form of a patch, and provided an attempted fix; very nice! > While cherry picking the top commit from side2 to side1 collect_renames is > confused by the preceding move from "tools/hello" to "hello" that took place on > side1. This move from "tools/hello" to "hello" causes the logic in > check_for_directory_rename to incorrectly conclude that "tools/world" should be > renamed to "world". detect_and_process_renames proceeds with "world" instead > of "tools/world" and ends up tripping on an assertion in process_renames. > > In the same scenario cherry-pick --strategy=recursive detects a merge conflict. > > $ rm .git/index.lock > $ git reset -q --hard > $ git cherry-pick --strategy=recursive side2 > CONFLICT (file location): world renamed to tools/world in fead592 (mv world tools/world.), inside a directory that was renamed in HEAD, suggesting it should perhaps be moved to world. > CONFLICT (content): Merge conflict in world Yes, this is the correct resolution... > error: cache entry has null sha1: world > error: cherry-pick: Unable to write new index file > fatal: cherry-pick failed ...but it looks like the recursive backend still trips up on it, just not until after it prints the conflict message. It shouldn't fail to write out a new index file; while it got further than ort, that's still pretty bad. > There really is a merge conflict and the goal of this commit is to have > cherry-pick --strategy=ort detect the conflict. This commit modifies > collect_renames to ignore an implicit directory rename that suggests moving a > file to itself. > > Also, see test t3515-cherry-pick-move.sh. > > Signed-off-by: Dmitry Goncharov <dgoncharov@users.sf.net> > --- > merge-ort.c | 9 +++++++ > t/t3515-cherry-pick-move.sh | 48 +++++++++++++++++++++++++++++++++++++ > 2 files changed, 57 insertions(+) > create mode 100755 t/t3515-cherry-pick-move.sh > > diff --git a/merge-ort.c b/merge-ort.c > index 691db9050e..e58fb7a7fa 100644 > --- a/merge-ort.c > +++ b/merge-ort.c > @@ -3369,6 +3369,15 @@ static int collect_renames(struct merge_options *opt, > collisions, > &clean); > > + if (new_path && !strcmp(new_path, p->one->path)) { > + /* Ignore an implicit directory rename that suggests replacing a move > + * from one->path to two->path with a move > + * from one->path to one->path. > + */ > + free(new_path); > + new_path = NULL; > + } Unfortunately, this solution makes it display the wrong conflict message, which I think could be quite confusing for the user: CONFLICT (rename/delete): world renamed to tools/world in dac8a10 (Move world into tools/), but deleted in HEAD. The file was not deleted in HEAD. HEAD moved `tools/hello` to `hello`, so the only thing it could have been said to delete was `tools/hello`, not `world`. So I appreciate the attempt to fix, but I don't think this solution is quite right. > + > possibly_cache_new_pair(renames, p, side_index, new_path); > if (p->status != 'R' && !new_path) { > pool_diff_free_filepair(&opt->priv->pool, p); > diff --git a/t/t3515-cherry-pick-move.sh b/t/t3515-cherry-pick-move.sh > new file mode 100755 > index 0000000000..20af478d4e > --- /dev/null > +++ b/t/t3515-cherry-pick-move.sh > @@ -0,0 +1,48 @@ > +#!/bin/sh > + > +test_description='Test cherry-picking a move commit.' > + > + > +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=side2 > +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME > + > +TEST_PASSES_SANITIZE_LEAK=true > +. ./test-lib.sh > + > +test_expect_success setup ' > + mkdir tools && > + > + echo hello >tools/hello && > + > + git add tools/hello && > + git commit -m"Add tools/hello." tools/hello && > + > + git branch side1 && > + > + # This commit is the base of the fatal cherry-pick merge. > + echo world >world && > + git add world && > + git commit -m"Add world." && > + > + # Cherry picking this commit crashes git. > + # This commit is side 2 of the fatal cherry-pick merge. > + git mv -v world tools/world && > + git commit -m"mv world tools/world." && > + > + git checkout side1 && > + # This commit is side 1 of the fatal cherry-pick merge. > + git mv -v tools/hello hello && > + git commit -m"mv tools/hello hello" > +' Thanks for including this. I have a slight preference to include this in a related testsuite rather than introducing a new testsuite file just for it. > + > +test_expect_success 'recursive cherry-pick of a move commit' ' > + test_must_fail git cherry-pick --strategy=recursive side2 > +' Yes, but this doesn't really test that the `recursive` strategy fails appropriately. In particular, the error messages you showed above pointed out that the recursive backend failed to write a new index file, leaving the working tree and index out of sync. However, since I have some patches to delete the recursive backend (and remap it to ort), I think it makes sense to just drop this and not worry about recursive. > + > +test_expect_success 'ort cherry-pick of a move commit' ' > + rm -f world && > + git reset --hard && > + test_must_fail git cherry-pick --strategy=ort side2 > +' Thanks for sending this in and even for pinging on it. I kept it in my notes, even though I didn't have time back then to respond. I did forget about it for a while, but came back after re-checking my notes. Anyway, I've got a couple patches, the first with your testcase moved and adjusted slightly to fit into the existing t6423 with you as the author, and a second patch with an alternate fix. I'll submit them shortly. ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] merge-ort: fix a crash in process_renames 2025-03-06 15:27 ` Elijah Newren @ 2025-03-06 17:19 ` Elijah Newren 0 siblings, 0 replies; 5+ messages in thread From: Elijah Newren @ 2025-03-06 17:19 UTC (permalink / raw) To: dgoncharov; +Cc: git On Thu, Mar 6, 2025 at 7:27 AM Elijah Newren <newren@gmail.com> wrote: [...] > Anyway, I've got a couple patches, the first with your testcase moved > and adjusted slightly to fit into the existing t6423 with you as the > author, and a second patch with an alternate fix. I'll submit them > shortly. For those scrolling the archives later, the fixes are at: https://lore.kernel.org/git/pull.1873.git.1741275027.gitgitgadget@gmail.com/T/#t ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH] merge-ort: fix a crash in process_renames @ 2024-07-06 21:14 dgoncharov 0 siblings, 0 replies; 5+ messages in thread From: dgoncharov @ 2024-07-06 21:14 UTC (permalink / raw) To: git; +Cc: newren, Dmitry Goncharov From: Dmitry Goncharov <dgoncharov@users.sf.net> cherry-pick --strategy=ort (the default at the moment) crashes in the following scenario $ ls -a . .. $ mkdir tools $ git init -q -b side2 $ echo hello>tools/hello $ git add tools/hello $ git commit -q tools/hello -m'Add tools/hello.' $ git branch side1 $ echo world>world $ git add world $ git commit -q world -m'Add world.' $ git mv world tools/world $ git commit -q -m'mv world tools/world.' $ git checkout -q side1 $ git mv tools/hello hello $ git commit -q -m'mv tools/hello hello.' $ git cherry-pick --strategy=ort side2 git: merge-ort.c:3006: process_renames: Assertion `source_deleted || oldinfo->filemask & old_sidemask' failed. Aborted (core dumped) While cherry picking the top commit from side2 to side1 collect_renames is confused by the preceding move from "tools/hello" to "hello" that took place on side1. This move from "tools/hello" to "hello" causes the logic in check_for_directory_rename to incorrectly conclude that "tools/world" should be renamed to "world". detect_and_process_renames proceeds with "world" instead of "tools/world" and ends up tripping on an assertion in process_renames. In the same scenario cherry-pick --strategy=recursive detects a merge conflict. $ rm .git/index.lock $ git reset -q --hard $ git cherry-pick --strategy=recursive side2 CONFLICT (file location): world renamed to tools/world in fead592 (mv world tools/world.), inside a directory that was renamed in HEAD, suggesting it should perhaps be moved to world. CONFLICT (content): Merge conflict in world error: cache entry has null sha1: world error: cherry-pick: Unable to write new index file fatal: cherry-pick failed There really is a merge conflict and the goal of this commit is to have cherry-pick --strategy=ort detect the conflict. This commit modifies collect_renames to ignore an implicit directory rename that suggests moving a file to itself. Also, see test t3515-cherry-pick-move.sh. Signed-off-by: Dmitry Goncharov <dgoncharov@users.sf.net> --- merge-ort.c | 9 +++++++ t/t3515-cherry-pick-move.sh | 48 +++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100755 t/t3515-cherry-pick-move.sh diff --git a/merge-ort.c b/merge-ort.c index 691db9050e..e58fb7a7fa 100644 --- a/merge-ort.c +++ b/merge-ort.c @@ -3369,6 +3369,15 @@ static int collect_renames(struct merge_options *opt, collisions, &clean); + if (new_path && !strcmp(new_path, p->one->path)) { + /* Ignore an implicit directory rename that suggests replacing a move + * from one->path to two->path with a move + * from one->path to one->path. + */ + free(new_path); + new_path = NULL; + } + possibly_cache_new_pair(renames, p, side_index, new_path); if (p->status != 'R' && !new_path) { pool_diff_free_filepair(&opt->priv->pool, p); diff --git a/t/t3515-cherry-pick-move.sh b/t/t3515-cherry-pick-move.sh new file mode 100755 index 0000000000..20af478d4e --- /dev/null +++ b/t/t3515-cherry-pick-move.sh @@ -0,0 +1,48 @@ +#!/bin/sh + +test_description='Test cherry-picking a move commit.' + + +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=side2 +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME + +TEST_PASSES_SANITIZE_LEAK=true +. ./test-lib.sh + +test_expect_success setup ' + mkdir tools && + + echo hello >tools/hello && + + git add tools/hello && + git commit -m"Add tools/hello." tools/hello && + + git branch side1 && + + # This commit is the base of the fatal cherry-pick merge. + echo world >world && + git add world && + git commit -m"Add world." && + + # Cherry picking this commit crashes git. + # This commit is side 2 of the fatal cherry-pick merge. + git mv -v world tools/world && + git commit -m"mv world tools/world." && + + git checkout side1 && + # This commit is side 1 of the fatal cherry-pick merge. + git mv -v tools/hello hello && + git commit -m"mv tools/hello hello" +' + +test_expect_success 'recursive cherry-pick of a move commit' ' + test_must_fail git cherry-pick --strategy=recursive side2 +' + +test_expect_success 'ort cherry-pick of a move commit' ' + rm -f world && + git reset --hard && + test_must_fail git cherry-pick --strategy=ort side2 +' + +test_done -- 2.34.1 ^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2025-03-06 17:20 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2024-09-21 2:45 [PATCH] merge-ort: fix a crash in process_renames dgoncharov 2024-09-21 2:45 ` dgoncharov 2025-03-06 15:27 ` Elijah Newren 2025-03-06 17:19 ` Elijah Newren -- strict thread matches above, loose matches on Subject: below -- 2024-07-06 21:14 dgoncharov
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).