@@ -683,6 +683,7 @@ void repair_worktree_at_path(const char *path,
683
683
struct strbuf gitdir = STRBUF_INIT ;
684
684
struct strbuf olddotgit = STRBUF_INIT ;
685
685
char * backlink = NULL ;
686
+ char * inferred_backlink = NULL ;
686
687
const char * repair = NULL ;
687
688
int err ;
688
689
@@ -698,12 +699,24 @@ void repair_worktree_at_path(const char *path,
698
699
goto done ;
699
700
}
700
701
702
+ inferred_backlink = infer_backlink (realdotgit .buf );
701
703
backlink = xstrdup_or_null (read_gitfile_gently (realdotgit .buf , & err ));
702
704
if (err == READ_GITFILE_ERR_NOT_A_FILE ) {
703
705
fn (1 , realdotgit .buf , _ ("unable to locate repository; .git is not a file" ), cb_data );
704
706
goto done ;
705
707
} else if (err == READ_GITFILE_ERR_NOT_A_REPO ) {
706
- if (!(backlink = infer_backlink (realdotgit .buf ))) {
708
+ if (inferred_backlink ) {
709
+ /*
710
+ * Worktree's .git file does not point at a repository
711
+ * but we found a .git/worktrees/<id> in this
712
+ * repository with the same <id> as recorded in the
713
+ * worktree's .git file so make the worktree point at
714
+ * the discovered .git/worktrees/<id>. (Note: backlink
715
+ * is already NULL, so no need to free it first.)
716
+ */
717
+ backlink = inferred_backlink ;
718
+ inferred_backlink = NULL ;
719
+ } else {
707
720
fn (1 , realdotgit .buf , _ ("unable to locate repository; .git file does not reference a repository" ), cb_data );
708
721
goto done ;
709
722
}
@@ -712,6 +725,30 @@ void repair_worktree_at_path(const char *path,
712
725
goto done ;
713
726
}
714
727
728
+ /*
729
+ * If we got this far, either the worktree's .git file pointed at a
730
+ * valid repository (i.e. read_gitfile_gently() returned success) or
731
+ * the .git file did not point at a repository but we were able to
732
+ * infer a suitable new value for the .git file by locating a
733
+ * .git/worktrees/<id> in *this* repository corresponding to the <id>
734
+ * recorded in the worktree's .git file.
735
+ *
736
+ * However, if, at this point, inferred_backlink is non-NULL (i.e. we
737
+ * found a suitable .git/worktrees/<id> in *this* repository) *and* the
738
+ * worktree's .git file points at a valid repository *and* those two
739
+ * paths differ, then that indicates that the user probably *copied*
740
+ * the main and linked worktrees to a new location as a unit rather
741
+ * than *moving* them. Thus, the copied worktree's .git file actually
742
+ * points at the .git/worktrees/<id> in the *original* repository, not
743
+ * in the "copy" repository. In this case, point the "copy" worktree's
744
+ * .git file at the "copy" repository.
745
+ */
746
+ if (inferred_backlink && fspathcmp (backlink , inferred_backlink )) {
747
+ free (backlink );
748
+ backlink = inferred_backlink ;
749
+ inferred_backlink = NULL ;
750
+ }
751
+
715
752
strbuf_addf (& gitdir , "%s/gitdir" , backlink );
716
753
if (strbuf_read_file (& olddotgit , gitdir .buf , 0 ) < 0 )
717
754
repair = _ ("gitdir unreadable" );
@@ -727,6 +764,7 @@ void repair_worktree_at_path(const char *path,
727
764
}
728
765
done :
729
766
free (backlink );
767
+ free (inferred_backlink );
730
768
strbuf_release (& olddotgit );
731
769
strbuf_release (& gitdir );
732
770
strbuf_release (& realdotgit );
0 commit comments