2020-08-27 08:21:25 +00:00
|
|
|
#!/bin/sh
|
|
|
|
|
|
|
|
test_description='test git worktree repair'
|
|
|
|
|
2023-02-06 23:07:43 +00:00
|
|
|
TEST_PASSES_SANITIZE_LEAK=true
|
2020-08-27 08:21:25 +00:00
|
|
|
. ./test-lib.sh
|
|
|
|
|
|
|
|
test_expect_success setup '
|
|
|
|
test_commit init
|
|
|
|
'
|
|
|
|
|
2020-08-31 06:57:57 +00:00
|
|
|
test_expect_success 'skip missing worktree' '
|
|
|
|
test_when_finished "git worktree prune" &&
|
|
|
|
git worktree add --detach missing &&
|
|
|
|
rm -rf missing &&
|
|
|
|
git worktree repair >out 2>err &&
|
|
|
|
test_must_be_empty out &&
|
|
|
|
test_must_be_empty err
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'worktree path not directory' '
|
|
|
|
test_when_finished "git worktree prune" &&
|
|
|
|
git worktree add --detach notdir &&
|
|
|
|
rm -rf notdir &&
|
|
|
|
>notdir &&
|
|
|
|
test_must_fail git worktree repair >out 2>err &&
|
|
|
|
test_must_be_empty out &&
|
2023-10-31 05:23:30 +00:00
|
|
|
test_grep "not a directory" err
|
2020-08-31 06:57:57 +00:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success "don't clobber .git repo" '
|
|
|
|
test_when_finished "rm -rf repo && git worktree prune" &&
|
|
|
|
git worktree add --detach repo &&
|
|
|
|
rm -rf repo &&
|
|
|
|
test_create_repo repo &&
|
|
|
|
test_must_fail git worktree repair >out 2>err &&
|
|
|
|
test_must_be_empty out &&
|
2023-10-31 05:23:30 +00:00
|
|
|
test_grep ".git is not a file" err
|
2020-08-31 06:57:57 +00:00
|
|
|
'
|
|
|
|
|
|
|
|
test_corrupt_gitfile () {
|
|
|
|
butcher=$1 &&
|
|
|
|
problem=$2 &&
|
|
|
|
repairdir=${3:-.} &&
|
|
|
|
test_when_finished 'rm -rf corrupt && git worktree prune' &&
|
|
|
|
git worktree add --detach corrupt &&
|
|
|
|
git -C corrupt rev-parse --absolute-git-dir >expect &&
|
|
|
|
eval "$butcher" &&
|
worktree: send "chatty" messages to stderr
The order in which the stdout and stderr streams are flushed is not
guaranteed to be the same across platforms or `libc` implementations.
This lack of determinism can lead to anomalous and potentially confusing
output if normal (stdout) output is flushed after error (stderr) output.
For instance, the following output which clearly indicates a failure due
to a fatal error:
% git worktree add ../foo bar
Preparing worktree (checking out 'bar')
fatal: 'bar' is already checked out at '.../wherever'
has been reported[1] on Microsoft Windows to appear as:
% git worktree add ../foo bar
fatal: 'bar' is already checked out at '.../wherever'
Preparing worktree (checking out 'bar')
which may confuse the reader into thinking that the command somehow
recovered and ran to completion despite the error.
This problem crops up because the "chatty" status message "Preparing
worktree" is sent to stdout, whereas the "fatal" error message is sent
to stderr. One way to fix this would be to flush stdout manually before
git-worktree reports any errors to stderr.
However, common practice in Git is for "chatty" messages to be sent to
stderr. Therefore, a more appropriate fix is to adjust git-worktree to
conform to that practice by sending its "chatty" messages to stderr
rather than stdout as is currently the case.
There may be concern that relocating messages from stdout to stderr
could break existing tooling, however, these messages are already
internationalized, thus are unstable. And, indeed, the "Preparing
worktree" message has already been the subject of somewhat significant
changes in 2c27002a0a (worktree: improve message when creating a new
worktree, 2018-04-24). Moreover, there is existing precedent, such as
68b939b2f0 (clone: send diagnostic messages to stderr, 2013-09-18) which
likewise relocated "chatty" messages from stdout to stderr for
git-clone.
[1]: https://lore.kernel.org/git/CA+34VNLj6VB1kCkA=MfM7TZR+6HgqNi5-UaziAoCXacSVkch4A@mail.gmail.com/T/
Reported-by: Baruch Burstein <bmburstein@gmail.com>
Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-12-03 03:44:19 +00:00
|
|
|
git -C "$repairdir" worktree repair 2>err &&
|
2023-10-31 05:23:30 +00:00
|
|
|
test_grep "$problem" err &&
|
2020-08-31 06:57:57 +00:00
|
|
|
git -C corrupt rev-parse --absolute-git-dir >actual &&
|
|
|
|
test_cmp expect actual
|
|
|
|
}
|
|
|
|
|
|
|
|
test_expect_success 'repair missing .git file' '
|
|
|
|
test_corrupt_gitfile "rm -f corrupt/.git" ".git file broken"
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'repair bogus .git file' '
|
|
|
|
test_corrupt_gitfile "echo \"gitdir: /nowhere\" >corrupt/.git" \
|
|
|
|
".git file broken"
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'repair incorrect .git file' '
|
|
|
|
test_when_finished "rm -rf other && git worktree prune" &&
|
|
|
|
test_create_repo other &&
|
|
|
|
other=$(git -C other rev-parse --absolute-git-dir) &&
|
|
|
|
test_corrupt_gitfile "echo \"gitdir: $other\" >corrupt/.git" \
|
|
|
|
".git file incorrect"
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'repair .git file from main/.git' '
|
|
|
|
test_corrupt_gitfile "rm -f corrupt/.git" ".git file broken" .git
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'repair .git file from linked worktree' '
|
|
|
|
test_when_finished "rm -rf other && git worktree prune" &&
|
|
|
|
git worktree add --detach other &&
|
|
|
|
test_corrupt_gitfile "rm -f corrupt/.git" ".git file broken" other
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'repair .git file from bare.git' '
|
|
|
|
test_when_finished "rm -rf bare.git corrupt && git worktree prune" &&
|
|
|
|
git clone --bare . bare.git &&
|
|
|
|
git -C bare.git worktree add --detach ../corrupt &&
|
|
|
|
git -C corrupt rev-parse --absolute-git-dir >expect &&
|
|
|
|
rm -f corrupt/.git &&
|
|
|
|
git -C bare.git worktree repair &&
|
|
|
|
git -C corrupt rev-parse --absolute-git-dir >actual &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
2020-08-31 06:57:58 +00:00
|
|
|
test_expect_success 'invalid worktree path' '
|
|
|
|
test_must_fail git worktree repair /notvalid >out 2>err &&
|
|
|
|
test_must_be_empty out &&
|
2023-10-31 05:23:30 +00:00
|
|
|
test_grep "not a valid path" err
|
2020-08-31 06:57:58 +00:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'repo not found; .git not file' '
|
|
|
|
test_when_finished "rm -rf not-a-worktree" &&
|
|
|
|
test_create_repo not-a-worktree &&
|
|
|
|
test_must_fail git worktree repair not-a-worktree >out 2>err &&
|
|
|
|
test_must_be_empty out &&
|
2023-10-31 05:23:30 +00:00
|
|
|
test_grep ".git is not a file" err
|
2020-08-31 06:57:58 +00:00
|
|
|
'
|
|
|
|
|
worktree: teach `repair` to fix multi-directional breakage
`git worktree repair` knows how to repair the two-way links between the
repository and a worktree as long as a link in one or the other
direction is sound. For instance, if a linked worktree is moved (without
using `git worktree move`), repair is possible because the worktree
still knows the location of the repository even though the repository no
longer knows where the worktree is. Similarly, if the repository is
moved, repair is possible since the repository still knows the locations
of the worktrees even though the worktrees no longer know where the
repository is.
However, if both the repository and the worktrees are moved, then links
are severed in both directions, and no repair is possible. This is the
case even when the new worktree locations are specified as arguments to
`git worktree repair`. The reason for this limitation is twofold. First,
when `repair` consults the worktree's gitfile (/path/to/worktree/.git)
to determine the corresponding <repo>/worktrees/<id>/gitdir file to fix,
<repo> is the old path to the repository, thus it is unable to fix the
`gitdir` file at its new location since it doesn't know where it is.
Second, when `repair` consults <repo>/worktrees/<id>/gitdir to find the
location of the worktree's gitfile (/path/to/worktree/.git), the path
recorded in `gitdir` is the old location of the worktree's gitfile, thus
it is unable to repair the gitfile since it doesn't know where it is.
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. 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>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-12-21 08:16:01 +00:00
|
|
|
test_expect_success 'repo not found; .git not referencing repo' '
|
|
|
|
test_when_finished "rm -rf side not-a-repo && git worktree prune" &&
|
|
|
|
git worktree add --detach side &&
|
|
|
|
sed s,\.git/worktrees/side$,not-a-repo, side/.git >side/.newgit &&
|
|
|
|
mv side/.newgit side/.git &&
|
|
|
|
mkdir not-a-repo &&
|
|
|
|
test_must_fail git worktree repair side 2>err &&
|
2023-10-31 05:23:30 +00:00
|
|
|
test_grep ".git file does not reference a repository" err
|
worktree: teach `repair` to fix multi-directional breakage
`git worktree repair` knows how to repair the two-way links between the
repository and a worktree as long as a link in one or the other
direction is sound. For instance, if a linked worktree is moved (without
using `git worktree move`), repair is possible because the worktree
still knows the location of the repository even though the repository no
longer knows where the worktree is. Similarly, if the repository is
moved, repair is possible since the repository still knows the locations
of the worktrees even though the worktrees no longer know where the
repository is.
However, if both the repository and the worktrees are moved, then links
are severed in both directions, and no repair is possible. This is the
case even when the new worktree locations are specified as arguments to
`git worktree repair`. The reason for this limitation is twofold. First,
when `repair` consults the worktree's gitfile (/path/to/worktree/.git)
to determine the corresponding <repo>/worktrees/<id>/gitdir file to fix,
<repo> is the old path to the repository, thus it is unable to fix the
`gitdir` file at its new location since it doesn't know where it is.
Second, when `repair` consults <repo>/worktrees/<id>/gitdir to find the
location of the worktree's gitfile (/path/to/worktree/.git), the path
recorded in `gitdir` is the old location of the worktree's gitfile, thus
it is unable to repair the gitfile since it doesn't know where it is.
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. 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>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-12-21 08:16:01 +00:00
|
|
|
'
|
|
|
|
|
2020-08-31 06:57:58 +00:00
|
|
|
test_expect_success 'repo not found; .git file broken' '
|
|
|
|
test_when_finished "rm -rf orig moved && git worktree prune" &&
|
|
|
|
git worktree add --detach orig &&
|
|
|
|
echo /invalid >orig/.git &&
|
|
|
|
mv orig moved &&
|
|
|
|
test_must_fail git worktree repair moved >out 2>err &&
|
|
|
|
test_must_be_empty out &&
|
2023-10-31 05:23:30 +00:00
|
|
|
test_grep ".git file broken" err
|
2020-08-31 06:57:58 +00:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'repair broken gitdir' '
|
|
|
|
test_when_finished "rm -rf orig moved && git worktree prune" &&
|
|
|
|
git worktree add --detach orig &&
|
|
|
|
sed s,orig/\.git$,moved/.git, .git/worktrees/orig/gitdir >expect &&
|
|
|
|
rm .git/worktrees/orig/gitdir &&
|
|
|
|
mv orig moved &&
|
worktree: send "chatty" messages to stderr
The order in which the stdout and stderr streams are flushed is not
guaranteed to be the same across platforms or `libc` implementations.
This lack of determinism can lead to anomalous and potentially confusing
output if normal (stdout) output is flushed after error (stderr) output.
For instance, the following output which clearly indicates a failure due
to a fatal error:
% git worktree add ../foo bar
Preparing worktree (checking out 'bar')
fatal: 'bar' is already checked out at '.../wherever'
has been reported[1] on Microsoft Windows to appear as:
% git worktree add ../foo bar
fatal: 'bar' is already checked out at '.../wherever'
Preparing worktree (checking out 'bar')
which may confuse the reader into thinking that the command somehow
recovered and ran to completion despite the error.
This problem crops up because the "chatty" status message "Preparing
worktree" is sent to stdout, whereas the "fatal" error message is sent
to stderr. One way to fix this would be to flush stdout manually before
git-worktree reports any errors to stderr.
However, common practice in Git is for "chatty" messages to be sent to
stderr. Therefore, a more appropriate fix is to adjust git-worktree to
conform to that practice by sending its "chatty" messages to stderr
rather than stdout as is currently the case.
There may be concern that relocating messages from stdout to stderr
could break existing tooling, however, these messages are already
internationalized, thus are unstable. And, indeed, the "Preparing
worktree" message has already been the subject of somewhat significant
changes in 2c27002a0a (worktree: improve message when creating a new
worktree, 2018-04-24). Moreover, there is existing precedent, such as
68b939b2f0 (clone: send diagnostic messages to stderr, 2013-09-18) which
likewise relocated "chatty" messages from stdout to stderr for
git-clone.
[1]: https://lore.kernel.org/git/CA+34VNLj6VB1kCkA=MfM7TZR+6HgqNi5-UaziAoCXacSVkch4A@mail.gmail.com/T/
Reported-by: Baruch Burstein <bmburstein@gmail.com>
Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-12-03 03:44:19 +00:00
|
|
|
git worktree repair moved 2>err &&
|
2020-08-31 06:57:58 +00:00
|
|
|
test_cmp expect .git/worktrees/orig/gitdir &&
|
2023-10-31 05:23:30 +00:00
|
|
|
test_grep "gitdir unreadable" err
|
2020-08-31 06:57:58 +00:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'repair incorrect gitdir' '
|
|
|
|
test_when_finished "rm -rf orig moved && git worktree prune" &&
|
|
|
|
git worktree add --detach orig &&
|
|
|
|
sed s,orig/\.git$,moved/.git, .git/worktrees/orig/gitdir >expect &&
|
|
|
|
mv orig moved &&
|
worktree: send "chatty" messages to stderr
The order in which the stdout and stderr streams are flushed is not
guaranteed to be the same across platforms or `libc` implementations.
This lack of determinism can lead to anomalous and potentially confusing
output if normal (stdout) output is flushed after error (stderr) output.
For instance, the following output which clearly indicates a failure due
to a fatal error:
% git worktree add ../foo bar
Preparing worktree (checking out 'bar')
fatal: 'bar' is already checked out at '.../wherever'
has been reported[1] on Microsoft Windows to appear as:
% git worktree add ../foo bar
fatal: 'bar' is already checked out at '.../wherever'
Preparing worktree (checking out 'bar')
which may confuse the reader into thinking that the command somehow
recovered and ran to completion despite the error.
This problem crops up because the "chatty" status message "Preparing
worktree" is sent to stdout, whereas the "fatal" error message is sent
to stderr. One way to fix this would be to flush stdout manually before
git-worktree reports any errors to stderr.
However, common practice in Git is for "chatty" messages to be sent to
stderr. Therefore, a more appropriate fix is to adjust git-worktree to
conform to that practice by sending its "chatty" messages to stderr
rather than stdout as is currently the case.
There may be concern that relocating messages from stdout to stderr
could break existing tooling, however, these messages are already
internationalized, thus are unstable. And, indeed, the "Preparing
worktree" message has already been the subject of somewhat significant
changes in 2c27002a0a (worktree: improve message when creating a new
worktree, 2018-04-24). Moreover, there is existing precedent, such as
68b939b2f0 (clone: send diagnostic messages to stderr, 2013-09-18) which
likewise relocated "chatty" messages from stdout to stderr for
git-clone.
[1]: https://lore.kernel.org/git/CA+34VNLj6VB1kCkA=MfM7TZR+6HgqNi5-UaziAoCXacSVkch4A@mail.gmail.com/T/
Reported-by: Baruch Burstein <bmburstein@gmail.com>
Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-12-03 03:44:19 +00:00
|
|
|
git worktree repair moved 2>err &&
|
2020-08-31 06:57:58 +00:00
|
|
|
test_cmp expect .git/worktrees/orig/gitdir &&
|
2023-10-31 05:23:30 +00:00
|
|
|
test_grep "gitdir incorrect" err
|
2020-08-31 06:57:58 +00:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'repair gitdir (implicit) from linked worktree' '
|
|
|
|
test_when_finished "rm -rf orig moved && git worktree prune" &&
|
|
|
|
git worktree add --detach orig &&
|
|
|
|
sed s,orig/\.git$,moved/.git, .git/worktrees/orig/gitdir >expect &&
|
|
|
|
mv orig moved &&
|
worktree: send "chatty" messages to stderr
The order in which the stdout and stderr streams are flushed is not
guaranteed to be the same across platforms or `libc` implementations.
This lack of determinism can lead to anomalous and potentially confusing
output if normal (stdout) output is flushed after error (stderr) output.
For instance, the following output which clearly indicates a failure due
to a fatal error:
% git worktree add ../foo bar
Preparing worktree (checking out 'bar')
fatal: 'bar' is already checked out at '.../wherever'
has been reported[1] on Microsoft Windows to appear as:
% git worktree add ../foo bar
fatal: 'bar' is already checked out at '.../wherever'
Preparing worktree (checking out 'bar')
which may confuse the reader into thinking that the command somehow
recovered and ran to completion despite the error.
This problem crops up because the "chatty" status message "Preparing
worktree" is sent to stdout, whereas the "fatal" error message is sent
to stderr. One way to fix this would be to flush stdout manually before
git-worktree reports any errors to stderr.
However, common practice in Git is for "chatty" messages to be sent to
stderr. Therefore, a more appropriate fix is to adjust git-worktree to
conform to that practice by sending its "chatty" messages to stderr
rather than stdout as is currently the case.
There may be concern that relocating messages from stdout to stderr
could break existing tooling, however, these messages are already
internationalized, thus are unstable. And, indeed, the "Preparing
worktree" message has already been the subject of somewhat significant
changes in 2c27002a0a (worktree: improve message when creating a new
worktree, 2018-04-24). Moreover, there is existing precedent, such as
68b939b2f0 (clone: send diagnostic messages to stderr, 2013-09-18) which
likewise relocated "chatty" messages from stdout to stderr for
git-clone.
[1]: https://lore.kernel.org/git/CA+34VNLj6VB1kCkA=MfM7TZR+6HgqNi5-UaziAoCXacSVkch4A@mail.gmail.com/T/
Reported-by: Baruch Burstein <bmburstein@gmail.com>
Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-12-03 03:44:19 +00:00
|
|
|
git -C moved worktree repair 2>err &&
|
2020-08-31 06:57:58 +00:00
|
|
|
test_cmp expect .git/worktrees/orig/gitdir &&
|
2023-10-31 05:23:30 +00:00
|
|
|
test_grep "gitdir incorrect" err
|
2020-08-31 06:57:58 +00:00
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'unable to repair gitdir (implicit) from main worktree' '
|
|
|
|
test_when_finished "rm -rf orig moved && git worktree prune" &&
|
|
|
|
git worktree add --detach orig &&
|
|
|
|
cat .git/worktrees/orig/gitdir >expect &&
|
|
|
|
mv orig moved &&
|
worktree: send "chatty" messages to stderr
The order in which the stdout and stderr streams are flushed is not
guaranteed to be the same across platforms or `libc` implementations.
This lack of determinism can lead to anomalous and potentially confusing
output if normal (stdout) output is flushed after error (stderr) output.
For instance, the following output which clearly indicates a failure due
to a fatal error:
% git worktree add ../foo bar
Preparing worktree (checking out 'bar')
fatal: 'bar' is already checked out at '.../wherever'
has been reported[1] on Microsoft Windows to appear as:
% git worktree add ../foo bar
fatal: 'bar' is already checked out at '.../wherever'
Preparing worktree (checking out 'bar')
which may confuse the reader into thinking that the command somehow
recovered and ran to completion despite the error.
This problem crops up because the "chatty" status message "Preparing
worktree" is sent to stdout, whereas the "fatal" error message is sent
to stderr. One way to fix this would be to flush stdout manually before
git-worktree reports any errors to stderr.
However, common practice in Git is for "chatty" messages to be sent to
stderr. Therefore, a more appropriate fix is to adjust git-worktree to
conform to that practice by sending its "chatty" messages to stderr
rather than stdout as is currently the case.
There may be concern that relocating messages from stdout to stderr
could break existing tooling, however, these messages are already
internationalized, thus are unstable. And, indeed, the "Preparing
worktree" message has already been the subject of somewhat significant
changes in 2c27002a0a (worktree: improve message when creating a new
worktree, 2018-04-24). Moreover, there is existing precedent, such as
68b939b2f0 (clone: send diagnostic messages to stderr, 2013-09-18) which
likewise relocated "chatty" messages from stdout to stderr for
git-clone.
[1]: https://lore.kernel.org/git/CA+34VNLj6VB1kCkA=MfM7TZR+6HgqNi5-UaziAoCXacSVkch4A@mail.gmail.com/T/
Reported-by: Baruch Burstein <bmburstein@gmail.com>
Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-12-03 03:44:19 +00:00
|
|
|
git worktree repair 2>err &&
|
2020-08-31 06:57:58 +00:00
|
|
|
test_cmp expect .git/worktrees/orig/gitdir &&
|
|
|
|
test_must_be_empty err
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'repair multiple gitdir files' '
|
|
|
|
test_when_finished "rm -rf orig1 orig2 moved1 moved2 &&
|
|
|
|
git worktree prune" &&
|
|
|
|
git worktree add --detach orig1 &&
|
|
|
|
git worktree add --detach orig2 &&
|
|
|
|
sed s,orig1/\.git$,moved1/.git, .git/worktrees/orig1/gitdir >expect1 &&
|
|
|
|
sed s,orig2/\.git$,moved2/.git, .git/worktrees/orig2/gitdir >expect2 &&
|
|
|
|
mv orig1 moved1 &&
|
|
|
|
mv orig2 moved2 &&
|
worktree: send "chatty" messages to stderr
The order in which the stdout and stderr streams are flushed is not
guaranteed to be the same across platforms or `libc` implementations.
This lack of determinism can lead to anomalous and potentially confusing
output if normal (stdout) output is flushed after error (stderr) output.
For instance, the following output which clearly indicates a failure due
to a fatal error:
% git worktree add ../foo bar
Preparing worktree (checking out 'bar')
fatal: 'bar' is already checked out at '.../wherever'
has been reported[1] on Microsoft Windows to appear as:
% git worktree add ../foo bar
fatal: 'bar' is already checked out at '.../wherever'
Preparing worktree (checking out 'bar')
which may confuse the reader into thinking that the command somehow
recovered and ran to completion despite the error.
This problem crops up because the "chatty" status message "Preparing
worktree" is sent to stdout, whereas the "fatal" error message is sent
to stderr. One way to fix this would be to flush stdout manually before
git-worktree reports any errors to stderr.
However, common practice in Git is for "chatty" messages to be sent to
stderr. Therefore, a more appropriate fix is to adjust git-worktree to
conform to that practice by sending its "chatty" messages to stderr
rather than stdout as is currently the case.
There may be concern that relocating messages from stdout to stderr
could break existing tooling, however, these messages are already
internationalized, thus are unstable. And, indeed, the "Preparing
worktree" message has already been the subject of somewhat significant
changes in 2c27002a0a (worktree: improve message when creating a new
worktree, 2018-04-24). Moreover, there is existing precedent, such as
68b939b2f0 (clone: send diagnostic messages to stderr, 2013-09-18) which
likewise relocated "chatty" messages from stdout to stderr for
git-clone.
[1]: https://lore.kernel.org/git/CA+34VNLj6VB1kCkA=MfM7TZR+6HgqNi5-UaziAoCXacSVkch4A@mail.gmail.com/T/
Reported-by: Baruch Burstein <bmburstein@gmail.com>
Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-12-03 03:44:19 +00:00
|
|
|
git worktree repair moved1 moved2 2>err &&
|
2020-08-31 06:57:58 +00:00
|
|
|
test_cmp expect1 .git/worktrees/orig1/gitdir &&
|
|
|
|
test_cmp expect2 .git/worktrees/orig2/gitdir &&
|
2023-10-31 05:23:30 +00:00
|
|
|
test_grep "gitdir incorrect:.*orig1/gitdir$" err &&
|
|
|
|
test_grep "gitdir incorrect:.*orig2/gitdir$" err
|
2020-08-31 06:57:58 +00:00
|
|
|
'
|
|
|
|
|
worktree: teach `repair` to fix multi-directional breakage
`git worktree repair` knows how to repair the two-way links between the
repository and a worktree as long as a link in one or the other
direction is sound. For instance, if a linked worktree is moved (without
using `git worktree move`), repair is possible because the worktree
still knows the location of the repository even though the repository no
longer knows where the worktree is. Similarly, if the repository is
moved, repair is possible since the repository still knows the locations
of the worktrees even though the worktrees no longer know where the
repository is.
However, if both the repository and the worktrees are moved, then links
are severed in both directions, and no repair is possible. This is the
case even when the new worktree locations are specified as arguments to
`git worktree repair`. The reason for this limitation is twofold. First,
when `repair` consults the worktree's gitfile (/path/to/worktree/.git)
to determine the corresponding <repo>/worktrees/<id>/gitdir file to fix,
<repo> is the old path to the repository, thus it is unable to fix the
`gitdir` file at its new location since it doesn't know where it is.
Second, when `repair` consults <repo>/worktrees/<id>/gitdir to find the
location of the worktree's gitfile (/path/to/worktree/.git), the path
recorded in `gitdir` is the old location of the worktree's gitfile, thus
it is unable to repair the gitfile since it doesn't know where it is.
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. 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>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-12-21 08:16:01 +00:00
|
|
|
test_expect_success 'repair moved main and linked worktrees' '
|
|
|
|
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
|
|
|
|
'
|
|
|
|
|
2020-08-27 08:21:25 +00:00
|
|
|
test_done
|