@@ -721,6 +721,110 @@ static int handle_content_merge(struct merge_options *opt,
721
721
722
722
/*** Function Grouping: functions related to directory rename detection ***/
723
723
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
+
724
828
static void compute_rename_counts (struct diff_queue_struct * pairs ,
725
829
struct strmap * dir_rename_count ,
726
830
struct strset * dirs_removed )
0 commit comments