mbox series

[v2,0/1] teach `worktree repair` to fix two-way linkage

Message ID 20201221081601.55546-1-sunshine@sunshineco.com (mailing list archive)
Headers show
Series teach `worktree repair` to fix two-way linkage | expand

Message

Eric Sunshine Dec. 21, 2020, 8:16 a.m. UTC
This is a re-roll of [1] which addresses a limitation of `git worktree
repair` in which it is unable to repair the two-way links between the
repository and its secondary worktrees if both the repository and the
worktrees have been moved manually.

The primary change in v2 is that the commit message has been expanded
quite a bit to explain how the new repair mechanism works, rather than
expecting the reader to glean the necessary information from the patch
itself, as well as to express the reasoning behind a couple changes
which might not be obvious at first glance.

The patch itself is unchanged with the exception of two minor
alterations to one of the two added tests. First, anchoring has been
added to a couple `sed` expressions. Second, the rename of the main and
secondary worktrees is now done with two distinct `mv` commands rather
than a single "clever" `mv` so as to avoid giving the reader the false
impression that the cleverness implies something about how the repair
mechanism works (it doesn't imply anything, it was just done as a
convenience in v1).

[1]: https://lore.kernel.org/git/20201208173705.5770-1-sunshine@sunshineco.com/

Eric Sunshine (1):
  worktree: teach `repair` to fix multi-directional breakage

 Documentation/git-worktree.txt |  5 +++++
 builtin/worktree.c             |  2 +-
 t/t2406-worktree-repair.sh     | 26 +++++++++++++++++++++
 worktree.c                     | 41 ++++++++++++++++++++++++++++++++++
 4 files changed, 73 insertions(+), 1 deletion(-)

Range-diff against v1:
1:  956e61bbc8 ! 1:  cd38528672 worktree: teach `repair` to fix multi-directional breakage
    @@ Commit message
         Fix these shortcomings by teaching `repair` to attempt to infer the new
         location of the <repo>/worktrees/<id>/gitdir file when the location
         recorded in the worktree's gitfile has become stale but the file is
    -    otherwise well-formed.
    +    otherwise well-formed. The inference is intentionally simple-minded.
    +    For each worktree path specified as an argument, `git worktree repair`
    +    manually reads the ".git" gitfile at that location and, if it is
    +    well-formed, extracts the <id>. It then searches for a corresponding
    +    <id> in <repo>/worktrees/ and, if found, concludes that there is a
    +    reasonable match and updates <repo>/worktrees/<id>/gitdir to point at
    +    the specified worktree path. In order for <repo> to be known, `git
    +    worktree repair` must be run in the main worktree or bare repository.
    +
    +    `git worktree repair` first attempts to repair each incoming
    +    /path/to/worktree/.git gitfile to point at the repository, and then
    +    attempts to repair outgoing <repo>/worktrees/<id>/gitdir files to point
    +    at the worktrees. This sequence was chosen arbitrarily when originally
    +    implemented since the order of fixes is immaterial as long as one side
    +    of the two-way link between the repository and a worktree is sound.
    +    However, for this new repair technique to work, the order must be
    +    reversed. This is because the new inference mechanism, when it is
    +    successful, allows the outgoing <repo>/worktrees/<id>/gitdir file to be
    +    repaired, thus fixing one side of the two-way link. Once that side is
    +    fixed, the other side can be fixed by the existing repair mechanism,
    +    hence the order of repairs is now significant.
    +
    +    Two safeguards are employed to avoid hijacking a worktree from a
    +    different repository if the user accidentally specifies a foreign
    +    worktree as an argument. The first, as described above, is that it
    +    requires an <id> match between the repository and the worktree. That
    +    itself is not foolproof for preventing hijack, so the second safeguard
    +    is that the inference will only kick in if the worktree's
    +    /path/to/worktree/.git gitfile does not point at a repository.
     
         Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
     
    @@ t/t2406-worktree-repair.sh: test_expect_success 'repair multiple gitdir files' '
      '
      
     +test_expect_success 'repair moved main and linked worktrees' '
    -+	test_when_finished "rm -rf orig moved" &&
    -+	test_create_repo orig/main &&
    -+	test_commit -C orig/main init &&
    -+	git -C orig/main worktree add --detach ../side &&
    -+	sed s,orig/side/\.git,moved/side/.git, \
    -+		orig/main/.git/worktrees/side/gitdir >expect-gitdir &&
    -+	sed s,orig/main/.git/worktrees/side,moved/main/.git/worktrees/side, \
    -+		orig/side/.git >expect-gitfile &&
    -+	mv orig moved &&
    -+	git -C moved/main worktree repair ../side &&
    -+	test_cmp expect-gitdir moved/main/.git/worktrees/side/gitdir &&
    -+	test_cmp expect-gitfile moved/side/.git
    ++	test_when_finished "rm -rf main side mainmoved sidemoved" &&
    ++	test_create_repo main &&
    ++	test_commit -C main init &&
    ++	git -C main worktree add --detach ../side &&
    ++	sed "s,side/\.git$,sidemoved/.git," \
    ++		main/.git/worktrees/side/gitdir >expect-gitdir &&
    ++	sed "s,main/.git/worktrees/side$,mainmoved/.git/worktrees/side," \
    ++		side/.git >expect-gitfile &&
    ++	mv main mainmoved &&
    ++	mv side sidemoved &&
    ++	git -C mainmoved worktree repair ../sidemoved &&
    ++	test_cmp expect-gitdir mainmoved/.git/worktrees/side/gitdir &&
    ++	test_cmp expect-gitfile sidemoved/.git
     +'
     +
      test_done