Re: [PATCH 5/9] worktree: disallow adding same path multiple times

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Aug 28, 2018 at 05:20:22PM -0400, Eric Sunshine wrote:

> A given path should only ever be associated with a single registered
> worktree. This invariant is enforced by refusing to create a new
> worktree at a given path if that path already exists. For example:
> 
>     $ git worktree add -q --detach foo
>     $ git worktree add -q --detach foo
>     fatal: 'foo' already exists
> 
> However, the check can be fooled, and the invariant broken, if the
> path is missing. Continuing the example:
> [...]

Nicely explained.

> diff --git a/builtin/worktree.c b/builtin/worktree.c
> index 46c93771e8..1122f27b5f 100644
> --- a/builtin/worktree.c
> +++ b/builtin/worktree.c
> @@ -221,8 +221,33 @@ static const char *worktree_basename(const char *path, int *olen)
>  
>  static void validate_worktree_add(const char *path, const struct add_opts *opts)
>  {
> +	struct worktree **worktrees;
> +	struct worktree *wt;
> +	int locked;
> +
>  	if (file_exists(path) && !is_empty_dir(path))
>  		die(_("'%s' already exists"), path);
> +
> +	worktrees = get_worktrees(0);
> +	/*
> +	 * find_worktree()'s suffix matching may undesirably find the main
> +	 * rather than a linked worktree (for instance, when the basenames
> +	 * of the main worktree and the one being created are the same).
> +	 * We're only interested in linked worktrees, so skip the main
> +	 * worktree with +1.
> +	 */
> +	wt = find_worktree(worktrees + 1, NULL, path);

Very appropriate use of a comment. :)

I wondered whether find_worktree() would discover a collision like this:

  git worktree add --detach foo
  rm -rf foo
  git worktree add --detach bar/foo

but it is smart enough to actually compare the gitdirs and so we
(correctly) create "foo" and "foo1" in $GIT_DIR/worktrees.

> +	if (!wt)
> +		goto done;
> +
> +	locked = !!is_worktree_locked(wt);
> +	if (locked)
> +		die(_("'%s' is a missing but locked worktree;\nuse 'unlock' and 'prune' or 'remove' to clear"), path);
> +	else
> +		die(_("'%s' is a missing but already registered worktree;\nuse 'prune' or 'remove' to clear"), path);

Nice, I like giving separate messages for the locked and unlocked cases
(which I imagine will become even more obvious as you add --force
support).

The formatting of the message itself is a little funny:

  $ git worktree add --detach foo
  fatal: 'foo' is a missing but already registered worktree;
  use 'prune' or 'remove' to clear

I'd say that the second line would ideally be advise(), since we're
dying. You could do:

  error(%s is missing...)
  advise(use prune...)
  exit(128);

but that loses the "fatal" in the first message. I wonder if just
manually writing "hint:" would be so bad.

> +done:
> +	free_worktrees(worktrees);

You could easily avoid this goto with:

  if (wt) {
     /* check wt or die */
  }

  free_worktrees(worktrees);

but it may not be worth it if the logic gets more complicated in future
patches.

-Peff



[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux