From: "Elijah Newren via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: Johannes Schindelin Johannes.Schindelin@gmx.de,
Junio C Hamano <gitster@pobox.com>,
Elijah Newren <newren@gmail.com>
Subject: [PATCH 2/2] merge-recursive: fix merging a subdirectory into the root directory
Date: Fri, 11 Oct 2019 13:42:25 -0700 (PDT) [thread overview]
Message-ID: <37aee862e14b1352eb08485f15ea06bab33679df.1570826543.git.gitgitgadget@gmail.com> (raw)
In-Reply-To: <pull.390.git.gitgitgadget@gmail.com>
From: Elijah Newren <newren@gmail.com>
We allow renaming all entries in e.g. a directory named z/ into a
directory named y/ to be detected as a z/ -> y/ rename, so that if the
other side of history adds any files to the directory z/ in the mean
time, we can provide the hint that they should be moved to y/.
There is no reason to not allow 'y/' to be the root directory, but the
code did not handle that case correctly. Add a testcase and the
necessary special checks to support this case.
Signed-off-by: Elijah Newren <newren@gmail.com>
---
merge-recursive.c | 29 +++++++++++++++
t/t6043-merge-rename-directories.sh | 56 +++++++++++++++++++++++++++++
2 files changed, 85 insertions(+)
diff --git a/merge-recursive.c b/merge-recursive.c
index f80e48f623..7bd4a7cf10 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -1931,6 +1931,16 @@ static char *apply_dir_rename(struct dir_rename_entry *entry,
return NULL;
oldlen = strlen(entry->dir);
+ if (entry->new_dir.len == 0)
+ /*
+ * If someone renamed/merged a subdirectory into the root
+ * directory (e.g. 'some/subdir' -> ''), then we want to
+ * avoid returning
+ * '' + '/filename'
+ * as the rename; we need to make old_path + oldlen advance
+ * past the '/' character.
+ */
+ oldlen++;
newlen = entry->new_dir.len + (strlen(old_path) - oldlen) + 1;
strbuf_grow(&new_path, newlen);
strbuf_addbuf(&new_path, &entry->new_dir);
@@ -1980,6 +1990,25 @@ static void get_renamed_dir_portion(const char *old_path, const char *new_path,
*end_of_old == *end_of_new)
return; /* We haven't modified *old_dir or *new_dir yet. */
+ /*
+ * If end_of_new got back to the beginning of its string, and
+ * end_of_old got back to the beginning of some subdirectory, then
+ * we have a rename/merge of a subdirectory into the root, which
+ * needs slightly special handling.
+ *
+ * Note: There is no need to consider the opposite case, with a
+ * rename/merge of the root directory into some subdirectory.
+ * Our rule elsewhere that a directory which still exists is not
+ * considered to have been renamed means the root directory can
+ * never be renamed (because the root directory always exists).
+ */
+ if (end_of_new == new_path &&
+ end_of_old != old_path && end_of_old[-1] == '/') {
+ *old_dir = xstrndup(old_path, end_of_old-1 - old_path);
+ *new_dir = xstrndup(new_path, end_of_new - new_path);
+ return;
+ }
+
/*
* We've found the first non-matching character in the directory
* paths. That means the current characters we were looking at
diff --git a/t/t6043-merge-rename-directories.sh b/t/t6043-merge-rename-directories.sh
index c966147d5d..b920bb0850 100755
--- a/t/t6043-merge-rename-directories.sh
+++ b/t/t6043-merge-rename-directories.sh
@@ -4051,6 +4051,62 @@ test_expect_success '12c-check: Moving one directory hierarchy into another w/ c
)
'
+# Testcase 12d, Rename/merge of subdirectory into the root
+# Commit O: a/b/{foo.c}
+# Commit A: foo.c
+# Commit B: a/b/{foo.c,bar.c}
+# Expected: a/b/{foo.c,bar.c}
+
+test_expect_success '12d-setup: Rename (merge) of subdirectory into the root' '
+ test_create_repo 12d &&
+ (
+ cd 12d &&
+
+ mkdir -p a/b/subdir &&
+ test_commit a/b/subdir/foo.c &&
+
+ git branch O &&
+ git branch A &&
+ git branch B &&
+
+ git checkout A &&
+ mkdir subdir &&
+ git mv a/b/subdir/foo.c.t subdir/foo.c.t &&
+ test_tick &&
+ git commit -m "A" &&
+
+ git checkout B &&
+ test_commit a/b/bar.c
+ )
+'
+
+test_expect_success '12d-check: Rename (merge) of subdirectory into the root' '
+ (
+ cd 12d &&
+
+ git checkout A^0 &&
+
+ git -c merge.directoryRenames=true merge -s recursive B^0 &&
+
+ git ls-files -s >out &&
+ test_line_count = 2 out &&
+
+ git rev-parse >actual \
+ HEAD:subdir/foo.c.t HEAD:bar.c.t &&
+ git rev-parse >expect \
+ O:a/b/subdir/foo.c.t B:a/b/bar.c.t &&
+ test_cmp expect actual &&
+
+ git hash-object bar.c.t >actual &&
+ git rev-parse B:a/b/bar.c.t >expect &&
+ test_cmp expect actual &&
+
+ test_must_fail git rev-parse HEAD:a/b/subdir/foo.c.t &&
+ test_must_fail git rev-parse HEAD:a/b/bar.c.t &&
+ test_path_is_missing a/
+ )
+'
+
###########################################################################
# SECTION 13: Checking informational and conflict messages
#
--
gitgitgadget
next prev parent reply other threads:[~2019-10-11 20:42 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-10-11 20:42 [PATCH 0/2] Dir rename fixes Elijah Newren via GitGitGadget
2019-10-11 20:42 ` [PATCH 1/2] merge-recursive: clean up get_renamed_dir_portion() Elijah Newren via GitGitGadget
2019-10-12 19:47 ` Johannes Schindelin
2019-10-11 20:42 ` Elijah Newren via GitGitGadget [this message]
2019-10-12 20:37 ` [PATCH 2/2] merge-recursive: fix merging a subdirectory into the root directory Johannes Schindelin
2019-10-13 0:40 ` Elijah Newren
2019-10-14 10:41 ` Johannes Schindelin
2019-10-22 19:15 ` Elijah Newren
2019-10-24 22:22 ` Johannes Schindelin
2019-10-25 0:12 ` Elijah Newren
2019-10-25 13:30 ` Johannes Schindelin
2019-10-29 1:20 ` Junio C Hamano
2019-10-30 7:01 ` Elijah Newren
2019-10-30 22:16 ` Johannes Schindelin
2019-10-30 22:31 ` Elijah Newren
2019-10-31 8:28 ` Johannes Schindelin
2019-10-12 18:41 ` [PATCH 0/2] Dir rename fixes Johannes Schindelin
2019-10-22 21:22 ` [PATCH v2 0/3] " Elijah Newren via GitGitGadget
2019-10-22 21:22 ` [PATCH v2 1/3] merge-recursive: clean up get_renamed_dir_portion() Elijah Newren via GitGitGadget
2019-10-22 21:22 ` [PATCH v2 2/3] merge-recursive: fix merging a subdirectory into the root directory Elijah Newren via GitGitGadget
2019-10-22 21:22 ` [PATCH v2 3/3] t604[236]: do not run setup in separate tests Elijah Newren via GitGitGadget
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=37aee862e14b1352eb08485f15ea06bab33679df.1570826543.git.gitgitgadget@gmail.com \
--to=gitgitgadget@gmail.com \
--cc=git@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.