git@vger.kernel.org list mirror (unofficial, one of many)
 help / color / Atom feed
* "add worktree" fails with "fatal: Invalid path" error
@ 2019-05-12 10:12 Shaheed Haque
  2019-05-13  9:20 ` Duy Nguyen
  2019-05-13 10:49 ` [PATCH] worktree add: be tolerant of corrupt worktrees Nguyễn Thái Ngọc Duy
  0 siblings, 2 replies; 9+ messages in thread
From: Shaheed Haque @ 2019-05-12 10:12 UTC (permalink / raw)
  To: git

Hi,

I'm running git v.2.20.1 on Ubuntu from a program which follows the pattern:

============
1. create a temporary directory /tmp/tmpabc
2. in a loop:
    2a. create a second level of temporary directory /tmp/tmpabc/tmpworktree123
    2b. use "git worktree add" on the second level directory
    2c. do something
3. cleanup
    3b. "git branch -D" on each basename(second level directory)
    3a. "git worktree prune"
============

The loop size is of the order of 8-20. In step 2b, I often get errors
like this (from a Bash reproducer):

============
$ git worktree add /tmp/tmpgtxug4y9/git_worktree.gBGqnfnU
Preparing worktree (new branch 'git_worktree.gBGqnfnU')
fatal: Invalid path '/tmp/tmp1q9ysvyl': No such file or directory
============

I can see that the problematic path exists in the "gitdir" file of
what must be an earlier worktree from an older run (the branch is
gone, but the tree is still there). The path appear to relate to the
older run's first level directory:

============
$ grep -r /tmp/tmp1q9ysvyl ../.git/worktrees/
../.git/worktrees/git_worktree.frcwtjt_/gitdir:/tmp/tmp1q9ysvyl/git_worktree.frcwtjt_/.git
$ git worktree list
...
/tmp/tmp1q9ysvyl/git_worktree.frcwtjt_  edde3f25 (detached HEAD)
...
$ git branch | grep frcwtjt_
<no matches>
============

NOTE: I've not yet had to try deleting the worktree, since "add
worktree" does appear to work some of the time, so I am able to limp
along.

I have these questions:

1. There is no branch or first level directory, but "git prune" has
not deleted the worktree, is this expected?
2. Is there something wrong with the sequence of steps I am following?

Thanks, Shaheed

P.S. I have an strace of a failing worktree add if needed.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: "add worktree" fails with "fatal: Invalid path" error
  2019-05-12 10:12 "add worktree" fails with "fatal: Invalid path" error Shaheed Haque
@ 2019-05-13  9:20 ` Duy Nguyen
  2019-05-13 12:55   ` Shaheed Haque
  2019-05-13 10:49 ` [PATCH] worktree add: be tolerant of corrupt worktrees Nguyễn Thái Ngọc Duy
  1 sibling, 1 reply; 9+ messages in thread
From: Duy Nguyen @ 2019-05-13  9:20 UTC (permalink / raw)
  To: Shaheed Haque; +Cc: Git Mailing List

On Sun, May 12, 2019 at 5:14 PM Shaheed Haque <shaheedhaque@gmail.com> wrote:
>
> Hi,
>
> I'm running git v.2.20.1 on Ubuntu from a program which follows the pattern:
>
> ============
> 1. create a temporary directory /tmp/tmpabc

When is this directory deleted? After step 3a?

> 2. in a loop:
>     2a. create a second level of temporary directory /tmp/tmpabc/tmpworktree123
>     2b. use "git worktree add" on the second level directory
>     2c. do something
> 3. cleanup
>     3b. "git branch -D" on each basename(second level directory)
>     3a. "git worktree prune"
> ============
>
> The loop size is of the order of 8-20. In step 2b, I often get errors
> like this (from a Bash reproducer):
>
> ============
> $ git worktree add /tmp/tmpgtxug4y9/git_worktree.gBGqnfnU
> Preparing worktree (new branch 'git_worktree.gBGqnfnU')
> fatal: Invalid path '/tmp/tmp1q9ysvyl': No such file or directory
> ============
>
> I can see that the problematic path exists in the "gitdir" file of
> what must be an earlier worktree from an older run (the branch is
> gone, but the tree is still there). The path appear to relate to the
> older run's first level directory:
>
> ============
> $ grep -r /tmp/tmp1q9ysvyl ../.git/worktrees/
> ../.git/worktrees/git_worktree.frcwtjt_/gitdir:/tmp/tmp1q9ysvyl/git_worktree.frcwtjt_/.git
> $ git worktree list
> ...
> /tmp/tmp1q9ysvyl/git_worktree.frcwtjt_  edde3f25 (detached HEAD)
> ...
> $ git branch | grep frcwtjt_
> <no matches>
> ============

Yeah I think I know where that "Invalid path" comes from and it should
not be there (at least it should not be a fatal error). I'll need to
reproduce this first. But I'm certain you've given me enough
information to do so.

> NOTE: I've not yet had to try deleting the worktree, since "add
> worktree" does appear to work some of the time, so I am able to limp
> along.

It's probably best to stay clean and delete things after you're done.
At least you should be able to avoid this problem this way until it's
fixed.

>
> I have these questions:
>
> 1. There is no branch or first level directory, but "git prune" has
> not deleted the worktree, is this expected?

I assume you meant "git worktree prune", not "git prune". See
gc.worktreePruneExpire. Dead worktree info stays for a while until
it's deleted, so that you can recover stuff if you need to.

> 2. Is there something wrong with the sequence of steps I am following?

Nope. I mean, you could try "git worktree remove" to be on the safe
side. But it should work even without that. To me this looks very much
like a bug.

> Thanks, Shaheed
>
> P.S. I have an strace of a failing worktree add if needed.
-- 
Duy

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH] worktree add: be tolerant of corrupt worktrees
  2019-05-12 10:12 "add worktree" fails with "fatal: Invalid path" error Shaheed Haque
  2019-05-13  9:20 ` Duy Nguyen
@ 2019-05-13 10:49 ` Nguyễn Thái Ngọc Duy
  2019-05-13 12:42   ` Shaheed Haque
  2019-05-17  7:46   ` Eric Sunshine
  1 sibling, 2 replies; 9+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2019-05-13 10:49 UTC (permalink / raw)
  To: shaheedhaque
  Cc: git, Junio C Hamano, Eric Sunshine,
	Nguyễn Thái Ngọc Duy

find_worktree() can die() unexpectedly because it uses real_path()
instead of the gentler version. When it's used in 'git worktree add' [1]
and there's a bad worktree, this die() could prevent people from adding
new worktrees.

The "bad" condition to trigger this is when a parent of the worktree's
location is deleted. Then real_path() will complain.

Use the other version so that bad worktrees won't affect 'worktree
add'. The bad ones will eventually be pruned, we just have to tolerate
them for a bit.

[1] added in cb56f55c16 (worktree: disallow adding same path multiple
    times, 2018-08-28), or since v2.20.0. Though the real bug in
    find_worktree() is much older.

Reported-by: Shaheed Haque <shaheedhaque@gmail.com>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 t/t2025-worktree-add.sh | 12 ++++++++++++
 worktree.c              |  7 +++++--
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
index 286bba35d8..d83a9f0fdc 100755
--- a/t/t2025-worktree-add.sh
+++ b/t/t2025-worktree-add.sh
@@ -570,4 +570,16 @@ test_expect_success '"add" an existing locked but missing worktree' '
 	git worktree add --force --force --detach gnoo
 '
 
+test_expect_success '"add" should not fail because of another bad worktree' '
+	git init add-fail &&
+	(
+		cd add-fail &&
+		test_commit first &&
+		mkdir sub &&
+		git worktree add sub/to-be-deleted &&
+		rm -rf sub &&
+		git worktree add second
+	)
+'
+
 test_done
diff --git a/worktree.c b/worktree.c
index d6a0ee7f73..c79b3e42bb 100644
--- a/worktree.c
+++ b/worktree.c
@@ -222,9 +222,12 @@ struct worktree *find_worktree(struct worktree **list,
 		free(to_free);
 		return NULL;
 	}
-	for (; *list; list++)
-		if (!fspathcmp(path, real_path((*list)->path)))
+	for (; *list; list++) {
+		const char *wt_path = real_path_if_valid((*list)->path);
+
+		if (wt_path && !fspathcmp(path, wt_path))
 			break;
+	}
 	free(path);
 	free(to_free);
 	return *list;
-- 
2.21.0.1141.gd54ac2cb17


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] worktree add: be tolerant of corrupt worktrees
  2019-05-13 10:49 ` [PATCH] worktree add: be tolerant of corrupt worktrees Nguyễn Thái Ngọc Duy
@ 2019-05-13 12:42   ` Shaheed Haque
  2019-05-17  7:46   ` Eric Sunshine
  1 sibling, 0 replies; 9+ messages in thread
From: Shaheed Haque @ 2019-05-13 12:42 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: git, Junio C Hamano, Eric Sunshine

Hi Nguyễn,

Thanks for the quick response. While I leave the code to the experts,
I can confirm that restoring the missing directory (but no content in
it) does allow "worktree add" to function again.

One point may be worth clarifying...

On Mon, 13 May 2019 at 11:50, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:
>
> find_worktree() can die() unexpectedly because it uses real_path()
> instead of the gentler version. When it's used in 'git worktree add' [1]
> and there's a bad worktree, this die() could prevent people from adding
> new worktrees.
>
> The "bad" condition to trigger this is when a parent of the worktree's
> location is deleted. Then real_path() will complain.
>
> Use the other version so that bad worktrees won't affect 'worktree
> add'. The bad ones will eventually be pruned, we just have to tolerate
> them for a bit.

...as I mentioned, from my experiments, trying a "worktree prune" did
NOT resolve the issue for me. But since I don't know the logic that
prune uses, there may have been some other reason for this.

Thanks again, Shaheed

> [1] added in cb56f55c16 (worktree: disallow adding same path multiple
>     times, 2018-08-28), or since v2.20.0. Though the real bug in
>     find_worktree() is much older.
>
> Reported-by: Shaheed Haque <shaheedhaque@gmail.com>
> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
> ---
>  t/t2025-worktree-add.sh | 12 ++++++++++++
>  worktree.c              |  7 +++++--
>  2 files changed, 17 insertions(+), 2 deletions(-)
>
> diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
> index 286bba35d8..d83a9f0fdc 100755
> --- a/t/t2025-worktree-add.sh
> +++ b/t/t2025-worktree-add.sh
> @@ -570,4 +570,16 @@ test_expect_success '"add" an existing locked but missing worktree' '
>         git worktree add --force --force --detach gnoo
>  '
>
> +test_expect_success '"add" should not fail because of another bad worktree' '
> +       git init add-fail &&
> +       (
> +               cd add-fail &&
> +               test_commit first &&
> +               mkdir sub &&
> +               git worktree add sub/to-be-deleted &&
> +               rm -rf sub &&
> +               git worktree add second
> +       )
> +'
> +
>  test_done
> diff --git a/worktree.c b/worktree.c
> index d6a0ee7f73..c79b3e42bb 100644
> --- a/worktree.c
> +++ b/worktree.c
> @@ -222,9 +222,12 @@ struct worktree *find_worktree(struct worktree **list,
>                 free(to_free);
>                 return NULL;
>         }
> -       for (; *list; list++)
> -               if (!fspathcmp(path, real_path((*list)->path)))
> +       for (; *list; list++) {
> +               const char *wt_path = real_path_if_valid((*list)->path);
> +
> +               if (wt_path && !fspathcmp(path, wt_path))
>                         break;
> +       }
>         free(path);
>         free(to_free);
>         return *list;
> --
> 2.21.0.1141.gd54ac2cb17
>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: "add worktree" fails with "fatal: Invalid path" error
  2019-05-13  9:20 ` Duy Nguyen
@ 2019-05-13 12:55   ` Shaheed Haque
  2019-05-14 12:33     ` Duy Nguyen
  0 siblings, 1 reply; 9+ messages in thread
From: Shaheed Haque @ 2019-05-13 12:55 UTC (permalink / raw)
  To: Duy Nguyen; +Cc: Git Mailing List

Hi Duy,

On Mon, 13 May 2019 at 10:21, Duy Nguyen <pclouds@gmail.com> wrote:
>
> On Sun, May 12, 2019 at 5:14 PM Shaheed Haque <shaheedhaque@gmail.com> wrote:
> >
> > Hi,
> >
> > I'm running git v.2.20.1 on Ubuntu from a program which follows the pattern:
> >
> > ============
> > 1. create a temporary directory /tmp/tmpabc
>
> When is this directory deleted? After step 3a?

Yes. I note that I screwed up the numbering in my note - the order is
["git branch -D", "git worktree prune", delete directory].

> > 2. in a loop:
> >     2a. create a second level of temporary directory /tmp/tmpabc/tmpworktree123
> >     2b. use "git worktree add" on the second level directory
> >     2c. do something
> > 3. cleanup
> >     3b. "git branch -D" on each basename(second level directory)
> >     3a. "git worktree prune"
> > ============
> >
> > The loop size is of the order of 8-20. In step 2b, I often get errors
> > like this (from a Bash reproducer):
> >
> > ============
> > $ git worktree add /tmp/tmpgtxug4y9/git_worktree.gBGqnfnU
> > Preparing worktree (new branch 'git_worktree.gBGqnfnU')
> > fatal: Invalid path '/tmp/tmp1q9ysvyl': No such file or directory
> > ============
> >
> > I can see that the problematic path exists in the "gitdir" file of
> > what must be an earlier worktree from an older run (the branch is
> > gone, but the tree is still there). The path appear to relate to the
> > older run's first level directory:
> >
> > ============
> > $ grep -r /tmp/tmp1q9ysvyl ../.git/worktrees/
> > ../.git/worktrees/git_worktree.frcwtjt_/gitdir:/tmp/tmp1q9ysvyl/git_worktree.frcwtjt_/.git
> > $ git worktree list
> > ...
> > /tmp/tmp1q9ysvyl/git_worktree.frcwtjt_  edde3f25 (detached HEAD)
> > ...
> > $ git branch | grep frcwtjt_
> > <no matches>
> > ============
>
> Yeah I think I know where that "Invalid path" comes from and it should
> not be there (at least it should not be a fatal error). I'll need to
> reproduce this first. But I'm certain you've given me enough
> information to do so.
>
> > NOTE: I've not yet had to try deleting the worktree, since "add
> > worktree" does appear to work some of the time, so I am able to limp
> > along.
>
> It's probably best to stay clean and delete things after you're done.
> At least you should be able to avoid this problem this way until it's
> fixed.

Ack.

> > I have these questions:
> >
> > 1. There is no branch or first level directory, but "git prune" has
> > not deleted the worktree, is this expected?
>
> I assume you meant "git worktree prune", not "git prune". See
> gc.worktreePruneExpire. Dead worktree info stays for a while until
> it's deleted, so that you can recover stuff if you need to.

Yes, sorry for typo.

> > 2. Is there something wrong with the sequence of steps I am following?
>
> Nope. I mean, you could try "git worktree remove" to be on the safe
> side. But it should work even without that. To me this looks very much
> like a bug.

The original code used the more obvious "git worktree remove" rather
than "git worktree prune" but I switched partly because remove seemed
slow (I cannot now quantify what caused me to think that), and partly
because I was having other issues which, I now realise, you probably
addressed in your recent "stat versus mkdir race" change.

BTW: I *love* worktrees. I have used/wrapped/developed multiple source
control systems over the years, and IMHO, this is one of the killer
features of git.

Thanks, Shaheed

> > Thanks, Shaheed
> >
> > P.S. I have an strace of a failing worktree add if needed.
> --
> Duy

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: "add worktree" fails with "fatal: Invalid path" error
  2019-05-13 12:55   ` Shaheed Haque
@ 2019-05-14 12:33     ` Duy Nguyen
  2019-05-14 14:48       ` Shaheed Haque
  0 siblings, 1 reply; 9+ messages in thread
From: Duy Nguyen @ 2019-05-14 12:33 UTC (permalink / raw)
  To: Shaheed Haque; +Cc: Git Mailing List

On Mon, May 13, 2019 at 7:55 PM Shaheed Haque <shaheedhaque@gmail.com> wrote:
> The original code used the more obvious "git worktree remove" rather
> than "git worktree prune" but I switched partly because remove seemed
> slow (I cannot now quantify what caused me to think that), and partly
> because I was having other issues which, I now realise, you probably
> addressed in your recent "stat versus mkdir race" change.

It should be as slow as "git status; rm -r". The first command _could_
be slow. But if you find it significantly slower than that, I will be
glad to receive another bug report.
-- 
Duy

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: "add worktree" fails with "fatal: Invalid path" error
  2019-05-14 12:33     ` Duy Nguyen
@ 2019-05-14 14:48       ` Shaheed Haque
  0 siblings, 0 replies; 9+ messages in thread
From: Shaheed Haque @ 2019-05-14 14:48 UTC (permalink / raw)
  To: Duy Nguyen; +Cc: Git Mailing List

On Tue, 14 May 2019 at 13:34, Duy Nguyen <pclouds@gmail.com> wrote:
>
> On Mon, May 13, 2019 at 7:55 PM Shaheed Haque <shaheedhaque@gmail.com> wrote:
> > The original code used the more obvious "git worktree remove" rather
> > than "git worktree prune" but I switched partly because remove seemed
> > slow (I cannot now quantify what caused me to think that), and partly
> > because I was having other issues which, I now realise, you probably
> > addressed in your recent "stat versus mkdir race" change.
>
> It should be as slow as "git status; rm -r". The first command _could_
> be slow. But if you find it significantly slower than that, I will be
> glad to receive another bug report.

After I wrote, I went back and checked, and I have no idea why I
thought it slow. It seems just fine (by the time I have spawned out of
Python and all), and so I have switched the code back to
(synchronous/predictable) "git worktree remove".

Thanks, Shaheed

> --
> Duy

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] worktree add: be tolerant of corrupt worktrees
  2019-05-13 10:49 ` [PATCH] worktree add: be tolerant of corrupt worktrees Nguyễn Thái Ngọc Duy
  2019-05-13 12:42   ` Shaheed Haque
@ 2019-05-17  7:46   ` Eric Sunshine
  2019-05-18 11:49     ` Duy Nguyen
  1 sibling, 1 reply; 9+ messages in thread
From: Eric Sunshine @ 2019-05-17  7:46 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy
  Cc: shaheedhaque, Git List, Junio C Hamano

On Mon, May 13, 2019 at 6:50 AM Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:
> find_worktree() can die() unexpectedly because it uses real_path()
> instead of the gentler version. When it's used in 'git worktree add' [1]
> and there's a bad worktree, this die() could prevent people from adding
> new worktrees.

This is good to know because, to fix [1], I think we'll want to add a
new function[2] akin to find_worktree(), but without magic suffix
matching (that is, just literal absolute path comparison).

[1]: https://public-inbox.org/git/0308570E-AAA3-43B8-A592-F4DA9760DBED@synopsys.com/
[2]: https://public-inbox.org/git/CAPig+cQh8hxeoVjLHDKhAcZVQPpPT5v0AUY8gsL9=qfJ7z-L2A@mail.gmail.com/

> The "bad" condition to trigger this is when a parent of the worktree's
> location is deleted. Then real_path() will complain.
>
> Use the other version so that bad worktrees won't affect 'worktree
> add'. The bad ones will eventually be pruned, we just have to tolerate
> them for a bit.

The patch itself makes sense, though, as Shaheed noted in his
response, pruning seems to get short-circuited somehow under this
situation; perhaps that needs its own fix, but certainly shouldn't
hold up this fix.

> Reported-by: Shaheed Haque <shaheedhaque@gmail.com>
> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] worktree add: be tolerant of corrupt worktrees
  2019-05-17  7:46   ` Eric Sunshine
@ 2019-05-18 11:49     ` Duy Nguyen
  0 siblings, 0 replies; 9+ messages in thread
From: Duy Nguyen @ 2019-05-18 11:49 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: Shaheed Haque, Git List, Junio C Hamano

On Fri, May 17, 2019 at 2:46 PM Eric Sunshine <sunshine@sunshineco.com> wrote:
>
> On Mon, May 13, 2019 at 6:50 AM Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:
> > find_worktree() can die() unexpectedly because it uses real_path()
> > instead of the gentler version. When it's used in 'git worktree add' [1]
> > and there's a bad worktree, this die() could prevent people from adding
> > new worktrees.
>
> This is good to know because, to fix [1], I think we'll want to add a
> new function[2] akin to find_worktree(), but without magic suffix
> matching (that is, just literal absolute path comparison).

Yeah. find_worktree() was made to handle command line options from
worktree's move/remove, it's probably a bit too magical for this case.

I still want to store relative path in "gitdir" files at some point,
which would complicate the last "absolute path comparison" part a bit.
But it should be manageable.

> [1]: https://public-inbox.org/git/0308570E-AAA3-43B8-A592-F4DA9760DBED@synopsys.com/
> [2]: https://public-inbox.org/git/CAPig+cQh8hxeoVjLHDKhAcZVQPpPT5v0AUY8gsL9=qfJ7z-L2A@mail.gmail.com/
>
> > The "bad" condition to trigger this is when a parent of the worktree's
> > location is deleted. Then real_path() will complain.
> >
> > Use the other version so that bad worktrees won't affect 'worktree
> > add'. The bad ones will eventually be pruned, we just have to tolerate
> > them for a bit.
>
> The patch itself makes sense, though, as Shaheed noted in his
> response, pruning seems to get short-circuited somehow under this
> situation; perhaps that needs its own fix, but certainly shouldn't
> hold up this fix.

I might have missed that detail. Thanks for pointing out. Will get another look.
-- 
Duy

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, back to index

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-05-12 10:12 "add worktree" fails with "fatal: Invalid path" error Shaheed Haque
2019-05-13  9:20 ` Duy Nguyen
2019-05-13 12:55   ` Shaheed Haque
2019-05-14 12:33     ` Duy Nguyen
2019-05-14 14:48       ` Shaheed Haque
2019-05-13 10:49 ` [PATCH] worktree add: be tolerant of corrupt worktrees Nguyễn Thái Ngọc Duy
2019-05-13 12:42   ` Shaheed Haque
2019-05-17  7:46   ` Eric Sunshine
2019-05-18 11:49     ` Duy Nguyen

git@vger.kernel.org list mirror (unofficial, one of many)

Archives are clonable:
	git clone --mirror https://public-inbox.org/git
	git clone --mirror http://ou63pmih66umazou.onion/git
	git clone --mirror http://czquwvybam4bgbro.onion/git
	git clone --mirror http://hjrcffqmbrq6wope.onion/git

Newsgroups are available over NNTP:
	nntp://news.public-inbox.org/inbox.comp.version-control.git
	nntp://ou63pmih66umazou.onion/inbox.comp.version-control.git
	nntp://czquwvybam4bgbro.onion/inbox.comp.version-control.git
	nntp://hjrcffqmbrq6wope.onion/inbox.comp.version-control.git
	nntp://news.gmane.org/gmane.comp.version-control.git

 note: .onion URLs require Tor: https://www.torproject.org/

AGPL code for this site: git clone https://public-inbox.org/ public-inbox