@@ -683,6 +683,7 @@ void repair_worktree_at_path(const char *path,
683683 struct strbuf gitdir = STRBUF_INIT ;
684684 struct strbuf olddotgit = STRBUF_INIT ;
685685 char * backlink = NULL ;
686+ char * inferred_backlink = NULL ;
686687 const char * repair = NULL ;
687688 int err ;
688689
@@ -698,12 +699,24 @@ void repair_worktree_at_path(const char *path,
698699 goto done ;
699700 }
700701
702+ inferred_backlink = infer_backlink (realdotgit .buf );
701703 backlink = xstrdup_or_null (read_gitfile_gently (realdotgit .buf , & err ));
702704 if (err == READ_GITFILE_ERR_NOT_A_FILE ) {
703705 fn (1 , realdotgit .buf , _ ("unable to locate repository; .git is not a file" ), cb_data );
704706 goto done ;
705707 } 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 {
707720 fn (1 , realdotgit .buf , _ ("unable to locate repository; .git file does not reference a repository" ), cb_data );
708721 goto done ;
709722 }
@@ -712,6 +725,30 @@ void repair_worktree_at_path(const char *path,
712725 goto done ;
713726 }
714727
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+
715752 strbuf_addf (& gitdir , "%s/gitdir" , backlink );
716753 if (strbuf_read_file (& olddotgit , gitdir .buf , 0 ) < 0 )
717754 repair = _ ("gitdir unreadable" );
@@ -727,6 +764,7 @@ void repair_worktree_at_path(const char *path,
727764 }
728765done :
729766 free (backlink );
767+ free (inferred_backlink );
730768 strbuf_release (& olddotgit );
731769 strbuf_release (& gitdir );
732770 strbuf_release (& realdotgit );
0 commit comments