git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2 v4] worktree: for_each_worktree and list
@ 2015-08-13 18:32 Michael Rappazzo
  2015-08-13 18:32 ` [PATCH 1/2 v4] worktree: add 'for_each_worktree' function Michael Rappazzo
  2015-08-13 18:32 ` [PATCH 2/2 v4] worktree: add 'list' command Michael Rappazzo
  0 siblings, 2 replies; 6+ messages in thread
From: Michael Rappazzo @ 2015-08-13 18:32 UTC (permalink / raw)
  To: gitster, sunshine; +Cc: git, Michael Rappazzo

This patch series adds a for_each_worktree function and then uses it to implement 
the `git worktree list` command.

Differences from [v3](http://www.mail-archive.com/git@vger.kernel.org/msg75599.html)
  - create the for_each_worktree function
  - uses the function in the list
  - a bare repo is NOT included in the iterated worktrees


Michael Rappazzo (2):
  worktree: add 'for_each_worktree' function
  worktree: add 'list' command

 Documentation/git-worktree.txt |  11 +++-
 builtin/worktree.c             | 139 +++++++++++++++++++++++++++++++++++++++++
 t/t2027-worktree-list.sh       |  51 +++++++++++++++
 3 files changed, 200 insertions(+), 1 deletion(-)
 create mode 100755 t/t2027-worktree-list.sh

-- 
2.5.0

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

* [PATCH 1/2 v4] worktree: add 'for_each_worktree' function
  2015-08-13 18:32 [PATCH 0/2 v4] worktree: for_each_worktree and list Michael Rappazzo
@ 2015-08-13 18:32 ` Michael Rappazzo
  2015-08-13 19:23   ` David Turner
  2015-08-13 18:32 ` [PATCH 2/2 v4] worktree: add 'list' command Michael Rappazzo
  1 sibling, 1 reply; 6+ messages in thread
From: Michael Rappazzo @ 2015-08-13 18:32 UTC (permalink / raw)
  To: gitster, sunshine; +Cc: git, Michael Rappazzo

for_each_worktree iterates through each worktree and invokes a callback
function.  The main worktree (if not bare) is always encountered first,
followed by worktrees created by `git worktree add`.

If the callback function returns a non-zero value, iteration stops, and
the callback's return value is returned from the for_each_worktree
function.

Signed-off-by: Michael Rappazzo <rappazzo@gmail.com>
---
 builtin/worktree.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 84 insertions(+)

diff --git a/builtin/worktree.c b/builtin/worktree.c
index 430b51e..a43e360 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -26,6 +26,14 @@ static int show_only;
 static int verbose;
 static unsigned long expire;
 
+/*
+ * The signature for the callback function for the for_each_worktree()
+ * function below.  The memory pointed to by the callback arguments
+ * is only guaranteed to be valid for the duration of a single
+ * callback invocation.
+ */
+typedef int each_worktree_fn(const char *path, const char *git_dir, void *cb_data);
+
 static int prune_worktree(const char *id, struct strbuf *reason)
 {
 	struct stat st;
@@ -358,6 +366,82 @@ static int add(int ac, const char **av, const char *prefix)
 
 	return add_worktree(path, branch, &opts);
 }
+/*
+ * Iterate through each worktree and invoke the callback function.  If
+ * the callback function returns non-zero, the iteration stops, and
+ * this function returns that return value
+ */
+static int for_each_worktree(each_worktree_fn fn, void *cb_data)
+{
+	struct strbuf main_path = STRBUF_INIT;
+	struct dirent *d;
+	struct stat st;
+	struct strbuf worktree_path = STRBUF_INIT;
+	struct strbuf worktree_git = STRBUF_INIT;
+	const char *common_dir;
+	DIR *dir;
+	int main_is_bare = 0;
+	int ret = 0;
+
+	common_dir = get_git_common_dir();
+	if (!strcmp(common_dir, get_git_dir())) {
+		/* simple case - this is the main repo */
+		main_is_bare = is_bare_repository();
+		if (!main_is_bare) {
+			strbuf_addstr(&main_path, get_git_work_tree());
+		} else {
+			strbuf_addstr(&main_path, common_dir);
+		}
+	} else {
+		strbuf_addstr(&main_path, common_dir);
+		strbuf_strip_suffix(&main_path, "/.git");
+		/* If the common_dir DOES NOT end with '/.git', then it is bare */
+		main_is_bare = !strcmp(common_dir, main_path.buf);
+	}
+
+	if (!main_is_bare) {
+		strbuf_addstr(&worktree_path, main_path.buf);
+
+		strbuf_addstr(&main_path, "/.git");
+		strbuf_addstr(&worktree_git, main_path.buf);
+
+		ret = fn(worktree_path.buf, worktree_git.buf, cb_data);
+		if (ret)
+			goto done;
+	}
+	strbuf_addstr(&main_path, "/worktrees");
+
+	if (is_directory(main_path.buf)) {
+		dir = opendir(main_path.buf);
+		if (dir) {
+			while ((d = readdir(dir)) != NULL) {
+				if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
+					continue;
+
+				strbuf_reset(&worktree_git);
+				strbuf_addf(&worktree_git, "%s/%s/gitdir", main_path.buf, d->d_name);
+
+				if (stat(worktree_git.buf, &st))
+					continue;
+
+				strbuf_reset(&worktree_path);
+				strbuf_read_file(&worktree_path, worktree_git.buf, st.st_size);
+				strbuf_strip_suffix(&worktree_path, "/.git\n");
+
+				strbuf_strip_suffix(&worktree_git, "/gitdir");
+				ret = fn(worktree_path.buf, worktree_git.buf, cb_data);
+				if (ret)
+					break;
+			}
+		}
+		closedir(dir);
+	}
+done:
+	strbuf_release(&worktree_git);
+	strbuf_release(&worktree_path);
+	strbuf_release(&main_path);
+	return ret;
+}
 
 int cmd_worktree(int ac, const char **av, const char *prefix)
 {
-- 
2.5.0

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

* [PATCH 2/2 v4] worktree: add 'list' command
  2015-08-13 18:32 [PATCH 0/2 v4] worktree: for_each_worktree and list Michael Rappazzo
  2015-08-13 18:32 ` [PATCH 1/2 v4] worktree: add 'for_each_worktree' function Michael Rappazzo
@ 2015-08-13 18:32 ` Michael Rappazzo
  2015-08-13 19:26   ` David Turner
  1 sibling, 1 reply; 6+ messages in thread
From: Michael Rappazzo @ 2015-08-13 18:32 UTC (permalink / raw)
  To: gitster, sunshine; +Cc: git, Michael Rappazzo

'git worktree list' uses the for_each_worktree function to iterate,
and outputs in the format: '<worktree>  (<short-ref>)'

Signed-off-by: Michael Rappazzo <rappazzo@gmail.com>
---
 Documentation/git-worktree.txt | 11 ++++++++-
 builtin/worktree.c             | 55 ++++++++++++++++++++++++++++++++++++++++++
 t/t2027-worktree-list.sh       | 51 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 116 insertions(+), 1 deletion(-)
 create mode 100755 t/t2027-worktree-list.sh

diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index fb68156..e953b4e 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -11,6 +11,7 @@ SYNOPSIS
 [verse]
 'git worktree add' [-f] [--detach] [-b <new-branch>] <path> [<branch>]
 'git worktree prune' [-n] [-v] [--expire <expire>]
+'git worktree list' [--path-only]
 
 DESCRIPTION
 -----------
@@ -59,6 +60,12 @@ prune::
 
 Prune working tree information in $GIT_DIR/worktrees.
 
+list::
+
+List the main worktree followed by all of the linked worktrees.  The default
+format of the list includes the full path to the worktree and the branch or
+revision that the head of that worktree is currently pointing to.
+
 OPTIONS
 -------
 
@@ -93,6 +100,9 @@ OPTIONS
 --expire <time>::
 	With `prune`, only expire unused working trees older than <time>.
 
+--path-only
+	With `list`, only show the worktree path
+
 DETAILS
 -------
 Each linked working tree has a private sub-directory in the repository's
@@ -167,7 +177,6 @@ performed manually, such as:
 - `remove` to remove a linked working tree and its administrative files (and
   warn if the working tree is dirty)
 - `mv` to move or rename a working tree and update its administrative files
-- `list` to list linked working trees
 - `lock` to prevent automatic pruning of administrative files (for instance,
   for a working tree on a portable device)
 
diff --git a/builtin/worktree.c b/builtin/worktree.c
index a43e360..b39ecbd 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -12,6 +12,7 @@
 static const char * const worktree_usage[] = {
 	N_("git worktree add [<options>] <path> <branch>"),
 	N_("git worktree prune [<options>]"),
+	N_("git worktree list [<options>]"),
 	NULL
 };
 
@@ -443,6 +444,58 @@ done:
 	return ret;
 }
 
+/* list callback data */
+struct list_opts {
+	int path_only;
+};
+
+static int print_worktree_details(const char *path, const char *git_dir, void *cb_data)
+{
+	struct strbuf head_file = STRBUF_INIT;
+	struct strbuf head_ref = STRBUF_INIT;
+	struct stat st;
+	struct list_opts *opts = cb_data;
+	const char *ref_prefix = "ref: refs/heads/";
+
+	strbuf_addf(&head_file, "%s/HEAD", git_dir);
+	if (!opts->path_only && !stat(head_file.buf, &st)) {
+		strbuf_read_file(&head_ref, head_file.buf, st.st_size);
+		strbuf_strip_suffix(&head_ref, "\n");
+
+		if (starts_with(head_ref.buf, ref_prefix)) {
+			/* branch checked out */
+			strbuf_remove(&head_ref, 0, strlen(ref_prefix));
+		/* } else {
+		 *  headless -- no-op
+		 */
+		}
+		printf("%s  (%s)\n", path, head_ref.buf);
+	} else {
+		printf("%s\n", path);
+	}
+
+	strbuf_release(&head_ref);
+	strbuf_release(&head_file);
+	return 0;
+}
+
+static int list(int ac, const char **av, const char *prefix)
+{
+	struct list_opts opts;
+	struct option options[] = {
+		OPT_BOOL(0, "path-only", &opts.path_only, N_("only show the path of the worktree")),
+		OPT_END()
+	};
+
+	opts.path_only = 0;
+
+	ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
+	if (ac)
+		usage_with_options(worktree_usage, options);
+
+	return for_each_worktree(&print_worktree_details, &opts);
+}
+
 int cmd_worktree(int ac, const char **av, const char *prefix)
 {
 	struct option options[] = {
@@ -455,5 +508,7 @@ int cmd_worktree(int ac, const char **av, const char *prefix)
 		return add(ac - 1, av + 1, prefix);
 	if (!strcmp(av[1], "prune"))
 		return prune(ac - 1, av + 1, prefix);
+	if (!strcmp(av[1], "list"))
+		return list(ac - 1, av + 1, prefix);
 	usage_with_options(worktree_usage, options);
 }
diff --git a/t/t2027-worktree-list.sh b/t/t2027-worktree-list.sh
new file mode 100755
index 0000000..220f98e
--- /dev/null
+++ b/t/t2027-worktree-list.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+
+test_description='test git worktree list'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+	test_commit init
+'
+
+test_expect_success '"list" all worktrees from main' '
+	echo "$(git rev-parse --show-toplevel)  ($(git symbolic-ref --short HEAD))" >expect &&
+	git worktree add --detach here master &&
+	echo "$(git -C here rev-parse --show-toplevel)  ($(git -C here rev-parse HEAD))" >>expect &&
+	git worktree list >actual &&
+	test_cmp expect actual &&
+	rm -rf here &&
+	git worktree prune
+'
+
+test_expect_success '"list" all worktrees from linked' '
+	echo "$(git rev-parse --show-toplevel)  ($(git symbolic-ref --short HEAD))" >expect &&
+	git worktree add --detach here master &&
+	echo "$(git -C here rev-parse --show-toplevel)  ($(git -C here rev-parse HEAD))" >>expect &&
+	git -C here worktree list >actual &&
+	test_cmp expect actual &&
+	rm -rf here &&
+	git worktree prune
+'
+
+test_expect_success '"list" all worktrees from main --path-only' '
+	git rev-parse --show-toplevel >expect &&
+	git worktree add --detach here master &&
+	git -C here rev-parse --show-toplevel >>expect &&
+	git worktree list --path-only >actual &&
+	test_cmp expect actual &&
+	rm -rf here &&
+	git worktree prune
+'
+
+test_expect_success '"list" all worktrees from linked --path-only' '
+	git rev-parse --show-toplevel >expect &&
+	git worktree add --detach here master &&
+	git -C here rev-parse --show-toplevel >>expect &&
+	git -C here worktree list --path-only >actual &&
+	test_cmp expect actual &&
+	rm -rf here &&
+	git worktree prune
+'
+
+test_done
-- 
2.5.0

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

* Re: [PATCH 1/2 v4] worktree: add 'for_each_worktree' function
  2015-08-13 18:32 ` [PATCH 1/2 v4] worktree: add 'for_each_worktree' function Michael Rappazzo
@ 2015-08-13 19:23   ` David Turner
  2015-08-13 23:32     ` Mike Rappazzo
  0 siblings, 1 reply; 6+ messages in thread
From: David Turner @ 2015-08-13 19:23 UTC (permalink / raw)
  To: Michael Rappazzo; +Cc: gitster, sunshine, git

On Thu, 2015-08-13 at 14:32 -0400, Michael Rappazzo wrote:
> for_each_worktree iterates through each worktree and invokes a callback
> function.  The main worktree (if not bare) is always encountered first,
> followed by worktrees created by `git worktree add`.

Thanks!  This will be super-useful!  I particularly appreciate the
detailed function documentation.

More comments below.

> If the callback function returns a non-zero value, iteration stops, and
> the callback's return value is returned from the for_each_worktree
> function.
> 
> Signed-off-by: Michael Rappazzo <rappazzo@gmail.com>
> ---
>  builtin/worktree.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 84 insertions(+)
> 
> diff --git a/builtin/worktree.c b/builtin/worktree.c
> index 430b51e..a43e360 100644
> --- a/builtin/worktree.c
> +++ b/builtin/worktree.c
> @@ -26,6 +26,14 @@ static int show_only;
>  static int verbose;
>  static unsigned long expire;
>  
> +/*
> + * The signature for the callback function for the for_each_worktree()
> + * function below.  The memory pointed to by the callback arguments
> + * is only guaranteed to be valid for the duration of a single
> + * callback invocation.
> + */
> +typedef int each_worktree_fn(const char *path, const char *git_dir, void *cb_data);
> +
>  static int prune_worktree(const char *id, struct strbuf *reason)
>  {
>  	struct stat st;
> @@ -358,6 +366,82 @@ static int add(int ac, const char **av, const char *prefix)
>  
>  	return add_worktree(path, branch, &opts);
>  }
> +/*

nit: newline above this line

> + * Iterate through each worktree and invoke the callback function.  If
> + * the callback function returns non-zero, the iteration stops, and
> + * this function returns that return value
> + */
> +static int for_each_worktree(each_worktree_fn fn, void *cb_data)
> +{
> +	struct strbuf main_path = STRBUF_INIT;
> +	struct dirent *d;


The scope of d can be smaller; move it down to the place I've marked
below

> +	struct stat st;
> +	struct strbuf worktree_path = STRBUF_INIT;
> +	struct strbuf worktree_git = STRBUF_INIT;
> +	const char *common_dir;
> +	DIR *dir;

ditto

> +	int main_is_bare = 0;
> +	int ret = 0;
> +
> +	common_dir = get_git_common_dir();
> +	if (!strcmp(common_dir, get_git_dir())) {
> +		/* simple case - this is the main repo */
> +		main_is_bare = is_bare_repository();
> +		if (!main_is_bare) {
> +			strbuf_addstr(&main_path, get_git_work_tree());
> +		} else {
> +			strbuf_addstr(&main_path, common_dir);
> +		}
> +	} else {
> +		strbuf_addstr(&main_path, common_dir);
> +		strbuf_strip_suffix(&main_path, "/.git");
> +		/* If the common_dir DOES NOT end with '/.git', then it is bare */
> +		main_is_bare = !strcmp(common_dir, main_path.buf);

strbuf_strip_suffix returns 1 if the suffix was stripped and 0
otherwise, so there is no need for this strcmp.

I'm a little worried about this path manipulation; it looks like the
config setting core.bare is the actual thing to check?  (Along with
maybe the GIT_WORK_TREE environment var; not sure how that interacts
with worktrees).

> +	}
> +
> +	if (!main_is_bare) {
> +		strbuf_addstr(&worktree_path, main_path.buf);
> +
> +		strbuf_addstr(&main_path, "/.git");
> +		strbuf_addstr(&worktree_git, main_path.buf);
> +
> +		ret = fn(worktree_path.buf, worktree_git.buf, cb_data);
> +		if (ret)
> +			goto done;
> +	}
> +	strbuf_addstr(&main_path, "/worktrees");

Earlier, you said:
		strbuf_addstr(&main_path, common_dir);
		strbuf_strip_suffix(&main_path, "/.git");

Now you are adding /worktrees.  Doesn't this mean, in the non-bare case,
that you'll be looking in $common_dir/worktrees instead of
$common_dir/.git/worktrees ?

> +	if (is_directory(main_path.buf)) {

declare dir here...

> +		dir = opendir(main_path.buf);
> +		if (dir) {

... and d here.

> +			while ((d = readdir(dir)) != NULL) {
> +				if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
> +					continue;
> +
> +				strbuf_reset(&worktree_git);
> +				strbuf_addf(&worktree_git, "%s/%s/gitdir", main_path.buf, d->d_name);

tioli: main_path never changes, so no need to keep chopping it off and
adding it back on; just truncate worktree_git to main_path.len + 1 here
and then add d->name.

> +				if (stat(worktree_git.buf, &st))
> +					continue;

Do we want to report errors other than ENOENT? (genuine question)

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

* Re: [PATCH 2/2 v4] worktree: add 'list' command
  2015-08-13 18:32 ` [PATCH 2/2 v4] worktree: add 'list' command Michael Rappazzo
@ 2015-08-13 19:26   ` David Turner
  0 siblings, 0 replies; 6+ messages in thread
From: David Turner @ 2015-08-13 19:26 UTC (permalink / raw)
  To: Michael Rappazzo; +Cc: gitster, sunshine, git

On Thu, 2015-08-13 at 14:32 -0400, Michael Rappazzo wrote:
> 'git worktree list' uses the for_each_worktree function to iterate,
> and outputs in the format: '<worktree>  (<short-ref>)'

I'm not sure I'm going to have time to review the whole thing, but I
think we ought to have tests with both bare and non-bare main repos.

> Signed-off-by: Michael Rappazzo <rappazzo@gmail.com>
> ---
>  Documentation/git-worktree.txt | 11 ++++++++-
>  builtin/worktree.c             | 55 ++++++++++++++++++++++++++++++++++++++++++
>  t/t2027-worktree-list.sh       | 51 +++++++++++++++++++++++++++++++++++++++
>  3 files changed, 116 insertions(+), 1 deletion(-)
>  create mode 100755 t/t2027-worktree-list.sh
> 
> diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
> index fb68156..e953b4e 100644
> --- a/Documentation/git-worktree.txt
> +++ b/Documentation/git-worktree.txt
> @@ -11,6 +11,7 @@ SYNOPSIS
>  [verse]
>  'git worktree add' [-f] [--detach] [-b <new-branch>] <path> [<branch>]
>  'git worktree prune' [-n] [-v] [--expire <expire>]
> +'git worktree list' [--path-only]
>  
>  DESCRIPTION
>  -----------
> @@ -59,6 +60,12 @@ prune::
>  
>  Prune working tree information in $GIT_DIR/worktrees.
>  
> +list::
> +
> +List the main worktree followed by all of the linked worktrees.  The default
> +format of the list includes the full path to the worktree and the branch or
> +revision that the head of that worktree is currently pointing to.
> +
>  OPTIONS
>  -------
>  
> @@ -93,6 +100,9 @@ OPTIONS
>  --expire <time>::
>  	With `prune`, only expire unused working trees older than <time>.
>  
> +--path-only
> +	With `list`, only show the worktree path
> +
>  DETAILS
>  -------
>  Each linked working tree has a private sub-directory in the repository's
> @@ -167,7 +177,6 @@ performed manually, such as:
>  - `remove` to remove a linked working tree and its administrative files (and
>    warn if the working tree is dirty)
>  - `mv` to move or rename a working tree and update its administrative files
> -- `list` to list linked working trees
>  - `lock` to prevent automatic pruning of administrative files (for instance,
>    for a working tree on a portable device)
>  
> diff --git a/builtin/worktree.c b/builtin/worktree.c
> index a43e360..b39ecbd 100644
> --- a/builtin/worktree.c
> +++ b/builtin/worktree.c
> @@ -12,6 +12,7 @@
>  static const char * const worktree_usage[] = {
>  	N_("git worktree add [<options>] <path> <branch>"),
>  	N_("git worktree prune [<options>]"),
> +	N_("git worktree list [<options>]"),
>  	NULL
>  };
>  
> @@ -443,6 +444,58 @@ done:
>  	return ret;
>  }
>  
> +/* list callback data */
> +struct list_opts {
> +	int path_only;
> +};
> +
> +static int print_worktree_details(const char *path, const char *git_dir, void *cb_data)
> +{
> +	struct strbuf head_file = STRBUF_INIT;
> +	struct strbuf head_ref = STRBUF_INIT;
> +	struct stat st;
> +	struct list_opts *opts = cb_data;
> +	const char *ref_prefix = "ref: refs/heads/";
> +
> +	strbuf_addf(&head_file, "%s/HEAD", git_dir);
> +	if (!opts->path_only && !stat(head_file.buf, &st)) {
> +		strbuf_read_file(&head_ref, head_file.buf, st.st_size);
> +		strbuf_strip_suffix(&head_ref, "\n");
> +
> +		if (starts_with(head_ref.buf, ref_prefix)) {
> +			/* branch checked out */
> +			strbuf_remove(&head_ref, 0, strlen(ref_prefix));
> +		/* } else {
> +		 *  headless -- no-op
> +		 */
> +		}
> +		printf("%s  (%s)\n", path, head_ref.buf);
> +	} else {
> +		printf("%s\n", path);
> +	}
> +
> +	strbuf_release(&head_ref);
> +	strbuf_release(&head_file);
> +	return 0;
> +}
> +
> +static int list(int ac, const char **av, const char *prefix)
> +{
> +	struct list_opts opts;
> +	struct option options[] = {
> +		OPT_BOOL(0, "path-only", &opts.path_only, N_("only show the path of the worktree")),
> +		OPT_END()
> +	};
> +
> +	opts.path_only = 0;
> +
> +	ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
> +	if (ac)
> +		usage_with_options(worktree_usage, options);
> +
> +	return for_each_worktree(&print_worktree_details, &opts);
> +}
> +
>  int cmd_worktree(int ac, const char **av, const char *prefix)
>  {
>  	struct option options[] = {
> @@ -455,5 +508,7 @@ int cmd_worktree(int ac, const char **av, const char *prefix)
>  		return add(ac - 1, av + 1, prefix);
>  	if (!strcmp(av[1], "prune"))
>  		return prune(ac - 1, av + 1, prefix);
> +	if (!strcmp(av[1], "list"))
> +		return list(ac - 1, av + 1, prefix);
>  	usage_with_options(worktree_usage, options);
>  }
> diff --git a/t/t2027-worktree-list.sh b/t/t2027-worktree-list.sh
> new file mode 100755
> index 0000000..220f98e
> --- /dev/null
> +++ b/t/t2027-worktree-list.sh
> @@ -0,0 +1,51 @@
> +#!/bin/sh
> +
> +test_description='test git worktree list'
> +
> +. ./test-lib.sh
> +
> +test_expect_success 'setup' '
> +	test_commit init
> +'
> +
> +test_expect_success '"list" all worktrees from main' '
> +	echo "$(git rev-parse --show-toplevel)  ($(git symbolic-ref --short HEAD))" >expect &&
> +	git worktree add --detach here master &&
> +	echo "$(git -C here rev-parse --show-toplevel)  ($(git -C here rev-parse HEAD))" >>expect &&
> +	git worktree list >actual &&
> +	test_cmp expect actual &&
> +	rm -rf here &&
> +	git worktree prune
> +'
> +
> +test_expect_success '"list" all worktrees from linked' '
> +	echo "$(git rev-parse --show-toplevel)  ($(git symbolic-ref --short HEAD))" >expect &&
> +	git worktree add --detach here master &&
> +	echo "$(git -C here rev-parse --show-toplevel)  ($(git -C here rev-parse HEAD))" >>expect &&
> +	git -C here worktree list >actual &&
> +	test_cmp expect actual &&
> +	rm -rf here &&
> +	git worktree prune
> +'
> +
> +test_expect_success '"list" all worktrees from main --path-only' '
> +	git rev-parse --show-toplevel >expect &&
> +	git worktree add --detach here master &&
> +	git -C here rev-parse --show-toplevel >>expect &&
> +	git worktree list --path-only >actual &&
> +	test_cmp expect actual &&
> +	rm -rf here &&
> +	git worktree prune
> +'
> +
> +test_expect_success '"list" all worktrees from linked --path-only' '
> +	git rev-parse --show-toplevel >expect &&
> +	git worktree add --detach here master &&
> +	git -C here rev-parse --show-toplevel >>expect &&
> +	git -C here worktree list --path-only >actual &&
> +	test_cmp expect actual &&
> +	rm -rf here &&
> +	git worktree prune
> +'
> +
> +test_done

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

* Re: [PATCH 1/2 v4] worktree: add 'for_each_worktree' function
  2015-08-13 19:23   ` David Turner
@ 2015-08-13 23:32     ` Mike Rappazzo
  0 siblings, 0 replies; 6+ messages in thread
From: Mike Rappazzo @ 2015-08-13 23:32 UTC (permalink / raw)
  To: David Turner; +Cc: Junio C Hamano, Eric Sunshine, Git List

I will reroll this series with adjustments as you suggested, and I
will add the extra tests for bare repos.

On Thu, Aug 13, 2015 at 3:23 PM, David Turner <dturner@twopensource.com> wrote:
> The scope of d can be smaller; move it down to the place I've marked
> below

I have adjusted the scoping.  I misunderstood the meaning of some
comments from the v3 patch, but your statements have helped me
understand.


>
> strbuf_strip_suffix returns 1 if the suffix was stripped and 0
> otherwise, so there is no need for this strcmp.

Done.

>
> I'm a little worried about this path manipulation; it looks like the
> config setting core.bare is the actual thing to check?  (Along with
> maybe the GIT_WORK_TREE environment var; not sure how that interacts
> with worktrees).

As Junio pointed out in a previous version of this patch, the
core.bare will always be 'true' since they share the config.  He also
suggested that this could be the cause for concern.  Therefore, I can
use core.bare to check if the main is a bare repo.  I guess that with
the inclusion of tests using a bare repo, that will catch it if things
change in the future.

>
>> +     }
>> +
>> +     if (!main_is_bare) {
>> +             strbuf_addstr(&worktree_path, main_path.buf);
>> +
>> +             strbuf_addstr(&main_path, "/.git");
>> +             strbuf_addstr(&worktree_git, main_path.buf);
>> +
>> +             ret = fn(worktree_path.buf, worktree_git.buf, cb_data);
>> +             if (ret)
>> +                     goto done;
>> +     }
>> +     strbuf_addstr(&main_path, "/worktrees");
>
> Earlier, you said:
>                 strbuf_addstr(&main_path, common_dir);
>                 strbuf_strip_suffix(&main_path, "/.git");
>
> Now you are adding /worktrees.  Doesn't this mean, in the non-bare case,
> that you'll be looking in $common_dir/worktrees instead of
> $common_dir/.git/worktrees ?

I read the gitdir file from the common dir.

>> +                     while ((d = readdir(dir)) != NULL) {
>> +                             if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
>> +                                     continue;
>> +
>> +                             strbuf_reset(&worktree_git);
>> +                             strbuf_addf(&worktree_git, "%s/%s/gitdir", main_path.buf, d->d_name);
>
> tioli: main_path never changes, so no need to keep chopping it off and
> adding it back on; just truncate worktree_git to main_path.len + 1 here
> and then add d->name.

I will try to clean it up a bit.  I am not very experienced with C,
but I will do my best.

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

end of thread, other threads:[~2015-08-13 23:32 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-08-13 18:32 [PATCH 0/2 v4] worktree: for_each_worktree and list Michael Rappazzo
2015-08-13 18:32 ` [PATCH 1/2 v4] worktree: add 'for_each_worktree' function Michael Rappazzo
2015-08-13 19:23   ` David Turner
2015-08-13 23:32     ` Mike Rappazzo
2015-08-13 18:32 ` [PATCH 2/2 v4] worktree: add 'list' command Michael Rappazzo
2015-08-13 19:26   ` David Turner

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).