Skip to content

Commit 9fe37e7

Browse files
newrengitster
authored andcommitted
merge-ort: copy get_renamed_dir_portion() from merge-recursive.c
Signed-off-by: Elijah Newren <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 04264d4 commit 9fe37e7

File tree

1 file changed

+104
-0
lines changed

1 file changed

+104
-0
lines changed

merge-ort.c

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,110 @@ static int handle_content_merge(struct merge_options *opt,
721721

722722
/*** Function Grouping: functions related to directory rename detection ***/
723723

724+
MAYBE_UNUSED
725+
static void get_renamed_dir_portion(const char *old_path, const char *new_path,
726+
char **old_dir, char **new_dir)
727+
{
728+
char *end_of_old, *end_of_new;
729+
730+
/* Default return values: NULL, meaning no rename */
731+
*old_dir = NULL;
732+
*new_dir = NULL;
733+
734+
/*
735+
* For
736+
* "a/b/c/d/e/foo.c" -> "a/b/some/thing/else/e/foo.c"
737+
* the "e/foo.c" part is the same, we just want to know that
738+
* "a/b/c/d" was renamed to "a/b/some/thing/else"
739+
* so, for this example, this function returns "a/b/c/d" in
740+
* *old_dir and "a/b/some/thing/else" in *new_dir.
741+
*/
742+
743+
/*
744+
* If the basename of the file changed, we don't care. We want
745+
* to know which portion of the directory, if any, changed.
746+
*/
747+
end_of_old = strrchr(old_path, '/');
748+
end_of_new = strrchr(new_path, '/');
749+
750+
/*
751+
* If end_of_old is NULL, old_path wasn't in a directory, so there
752+
* could not be a directory rename (our rule elsewhere that a
753+
* directory which still exists is not considered to have been
754+
* renamed means the root directory can never be renamed -- because
755+
* the root directory always exists).
756+
*/
757+
if (end_of_old == NULL)
758+
return; /* Note: *old_dir and *new_dir are still NULL */
759+
760+
/*
761+
* If new_path contains no directory (end_of_new is NULL), then we
762+
* have a rename of old_path's directory to the root directory.
763+
*/
764+
if (end_of_new == NULL) {
765+
*old_dir = xstrndup(old_path, end_of_old - old_path);
766+
*new_dir = xstrdup("");
767+
return;
768+
}
769+
770+
/* Find the first non-matching character traversing backwards */
771+
while (*--end_of_new == *--end_of_old &&
772+
end_of_old != old_path &&
773+
end_of_new != new_path)
774+
; /* Do nothing; all in the while loop */
775+
776+
/*
777+
* If both got back to the beginning of their strings, then the
778+
* directory didn't change at all, only the basename did.
779+
*/
780+
if (end_of_old == old_path && end_of_new == new_path &&
781+
*end_of_old == *end_of_new)
782+
return; /* Note: *old_dir and *new_dir are still NULL */
783+
784+
/*
785+
* If end_of_new got back to the beginning of its string, and
786+
* end_of_old got back to the beginning of some subdirectory, then
787+
* we have a rename/merge of a subdirectory into the root, which
788+
* needs slightly special handling.
789+
*
790+
* Note: There is no need to consider the opposite case, with a
791+
* rename/merge of the root directory into some subdirectory
792+
* because as noted above the root directory always exists so it
793+
* cannot be considered to be renamed.
794+
*/
795+
if (end_of_new == new_path &&
796+
end_of_old != old_path && end_of_old[-1] == '/') {
797+
*old_dir = xstrndup(old_path, --end_of_old - old_path);
798+
*new_dir = xstrdup("");
799+
return;
800+
}
801+
802+
/*
803+
* We've found the first non-matching character in the directory
804+
* paths. That means the current characters we were looking at
805+
* were part of the first non-matching subdir name going back from
806+
* the end of the strings. Get the whole name by advancing both
807+
* end_of_old and end_of_new to the NEXT '/' character. That will
808+
* represent the entire directory rename.
809+
*
810+
* The reason for the increment is cases like
811+
* a/b/star/foo/whatever.c -> a/b/tar/foo/random.c
812+
* After dropping the basename and going back to the first
813+
* non-matching character, we're now comparing:
814+
* a/b/s and a/b/
815+
* and we want to be comparing:
816+
* a/b/star/ and a/b/tar/
817+
* but without the pre-increment, the one on the right would stay
818+
* a/b/.
819+
*/
820+
end_of_old = strchr(++end_of_old, '/');
821+
end_of_new = strchr(++end_of_new, '/');
822+
823+
/* Copy the old and new directories into *old_dir and *new_dir. */
824+
*old_dir = xstrndup(old_path, end_of_old - old_path);
825+
*new_dir = xstrndup(new_path, end_of_new - new_path);
826+
}
827+
724828
static void compute_rename_counts(struct diff_queue_struct *pairs,
725829
struct strmap *dir_rename_count,
726830
struct strset *dirs_removed)

0 commit comments

Comments
 (0)