git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v9 0/5] worktree: list functions and command
@ 2015-10-02 11:55 Michael Rappazzo
  2015-10-02 11:55 ` [PATCH v9 1/5] worktree: add top-level worktree.c Michael Rappazzo
                   ` (4 more replies)
  0 siblings, 5 replies; 8+ messages in thread
From: Michael Rappazzo @ 2015-10-02 11:55 UTC (permalink / raw)
  To: gitster, sunshine, dturner; +Cc: git, Michael Rappazzo

Notable changes since v8[1]:
 - Rework the commit history to try to better maintain blame
 - Use ALLOC_GROW instead of pre-allocating when building the worktree array
 - Refine the `--porcelain` format and describe it in the documentation
 - Remove whitespace from expected and actual test output

[1]: http://thread.gmane.org/gmane.comp.version-control.git/278190

Michael Rappazzo (5):
  worktree: add top-level worktree.c
  worktree: refactor find_linked_symref function
  worktree: add a function to get worktree details
  worktree: add details to the worktree struct
  worktree: add 'list' command

 Documentation/git-worktree.txt |  49 +++++++++-
 Makefile                       |   1 +
 branch.c                       |  79 +--------------
 branch.h                       |   8 --
 builtin/notes.c                |   2 +-
 builtin/worktree.c             |  82 ++++++++++++++++
 t/t2027-worktree-list.sh       |  89 +++++++++++++++++
 worktree.c                     | 216 +++++++++++++++++++++++++++++++++++++++++
 worktree.h                     |  38 ++++++++
 9 files changed, 476 insertions(+), 88 deletions(-)
 create mode 100755 t/t2027-worktree-list.sh
 create mode 100644 worktree.c
 create mode 100644 worktree.h

-- 
2.6.0

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

* [PATCH v9 1/5] worktree: add top-level worktree.c
  2015-10-02 11:55 [PATCH v9 0/5] worktree: list functions and command Michael Rappazzo
@ 2015-10-02 11:55 ` Michael Rappazzo
  2015-10-02 11:55 ` [PATCH v9 2/5] worktree: refactor find_linked_symref function Michael Rappazzo
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Michael Rappazzo @ 2015-10-02 11:55 UTC (permalink / raw)
  To: gitster, sunshine, dturner; +Cc: git, Michael Rappazzo

worktree.c contains functions to work with and get information from
worktrees.  This introduction moves functions related to worktrees
from branch.c into worktree.c

Signed-off-by: Michael Rappazzo <rappazzo@gmail.com>
---
 Makefile        |  1 +
 branch.c        | 79 +-----------------------------------------------------
 branch.h        |  8 ------
 builtin/notes.c |  2 +-
 worktree.c      | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 worktree.h      | 12 +++++++++
 6 files changed, 97 insertions(+), 87 deletions(-)
 create mode 100644 worktree.c
 create mode 100644 worktree.h

diff --git a/Makefile b/Makefile
index 8d5df7e..f4ee2d2 100644
--- a/Makefile
+++ b/Makefile
@@ -807,6 +807,7 @@ LIB_OBJS += version.o
 LIB_OBJS += versioncmp.o
 LIB_OBJS += walker.o
 LIB_OBJS += wildmatch.o
+LIB_OBJS += worktree.o
 LIB_OBJS += wrapper.o
 LIB_OBJS += write_or_die.o
 LIB_OBJS += ws.o
diff --git a/branch.c b/branch.c
index d013374..77d7f2a 100644
--- a/branch.c
+++ b/branch.c
@@ -4,6 +4,7 @@
 #include "refs.h"
 #include "remote.h"
 #include "commit.h"
+#include "worktree.h"
 
 struct tracking {
 	struct refspec spec;
@@ -311,84 +312,6 @@ void remove_branch_state(void)
 	unlink(git_path_squash_msg());
 }
 
-static char *find_linked_symref(const char *symref, const char *branch,
-				const char *id)
-{
-	struct strbuf sb = STRBUF_INIT;
-	struct strbuf path = STRBUF_INIT;
-	struct strbuf gitdir = STRBUF_INIT;
-	char *existing = NULL;
-
-	/*
-	 * $GIT_COMMON_DIR/$symref (e.g. HEAD) is practically outside
-	 * $GIT_DIR so resolve_ref_unsafe() won't work (it uses
-	 * git_path). Parse the ref ourselves.
-	 */
-	if (id)
-		strbuf_addf(&path, "%s/worktrees/%s/%s", get_git_common_dir(), id, symref);
-	else
-		strbuf_addf(&path, "%s/%s", get_git_common_dir(), symref);
-
-	if (!strbuf_readlink(&sb, path.buf, 0)) {
-		if (!starts_with(sb.buf, "refs/") ||
-		    check_refname_format(sb.buf, 0))
-			goto done;
-	} else if (strbuf_read_file(&sb, path.buf, 0) >= 0 &&
-	    starts_with(sb.buf, "ref:")) {
-		strbuf_remove(&sb, 0, strlen("ref:"));
-		strbuf_trim(&sb);
-	} else
-		goto done;
-	if (strcmp(sb.buf, branch))
-		goto done;
-	if (id) {
-		strbuf_reset(&path);
-		strbuf_addf(&path, "%s/worktrees/%s/gitdir", get_git_common_dir(), id);
-		if (strbuf_read_file(&gitdir, path.buf, 0) <= 0)
-			goto done;
-		strbuf_rtrim(&gitdir);
-	} else
-		strbuf_addstr(&gitdir, get_git_common_dir());
-	strbuf_strip_suffix(&gitdir, ".git");
-
-	existing = strbuf_detach(&gitdir, NULL);
-done:
-	strbuf_release(&path);
-	strbuf_release(&sb);
-	strbuf_release(&gitdir);
-
-	return existing;
-}
-
-char *find_shared_symref(const char *symref, const char *target)
-{
-	struct strbuf path = STRBUF_INIT;
-	DIR *dir;
-	struct dirent *d;
-	char *existing;
-
-	if ((existing = find_linked_symref(symref, target, NULL)))
-		return existing;
-
-	strbuf_addf(&path, "%s/worktrees", get_git_common_dir());
-	dir = opendir(path.buf);
-	strbuf_release(&path);
-	if (!dir)
-		return NULL;
-
-	while ((d = readdir(dir)) != NULL) {
-		if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
-			continue;
-		existing = find_linked_symref(symref, target, d->d_name);
-		if (existing)
-			goto done;
-	}
-done:
-	closedir(dir);
-
-	return existing;
-}
-
 void die_if_checked_out(const char *branch)
 {
 	char *existing;
diff --git a/branch.h b/branch.h
index d3446ed..58aa45f 100644
--- a/branch.h
+++ b/branch.h
@@ -59,12 +59,4 @@ extern int read_branch_desc(struct strbuf *, const char *branch_name);
  */
 extern void die_if_checked_out(const char *branch);
 
-/*
- * Check if a per-worktree symref points to a ref in the main worktree
- * or any linked worktree, and return the path to the exising worktree
- * if it is.  Returns NULL if there is no existing ref.  The caller is
- * responsible for freeing the returned path.
- */
-extern char *find_shared_symref(const char *symref, const char *target);
-
 #endif
diff --git a/builtin/notes.c b/builtin/notes.c
index 3608c64..13c0af9 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -19,7 +19,7 @@
 #include "string-list.h"
 #include "notes-merge.h"
 #include "notes-utils.h"
-#include "branch.h"
+#include "worktree.h"
 
 static const char * const git_notes_usage[] = {
 	N_("git notes [--ref <notes-ref>] [list [<object>]]"),
diff --git a/worktree.c b/worktree.c
new file mode 100644
index 0000000..10e1496
--- /dev/null
+++ b/worktree.c
@@ -0,0 +1,82 @@
+#include "cache.h"
+#include "refs.h"
+#include "strbuf.h"
+#include "worktree.h"
+
+static char *find_linked_symref(const char *symref, const char *branch,
+				const char *id)
+{
+	struct strbuf sb = STRBUF_INIT;
+	struct strbuf path = STRBUF_INIT;
+	struct strbuf gitdir = STRBUF_INIT;
+	char *existing = NULL;
+
+	/*
+	 * $GIT_COMMON_DIR/$symref (e.g. HEAD) is practically outside
+	 * $GIT_DIR so resolve_ref_unsafe() won't work (it uses
+	 * git_path). Parse the ref ourselves.
+	 */
+	if (id)
+		strbuf_addf(&path, "%s/worktrees/%s/%s", get_git_common_dir(), id, symref);
+	else
+		strbuf_addf(&path, "%s/%s", get_git_common_dir(), symref);
+
+	if (!strbuf_readlink(&sb, path.buf, 0)) {
+		if (!starts_with(sb.buf, "refs/") ||
+		    check_refname_format(sb.buf, 0))
+			goto done;
+	} else if (strbuf_read_file(&sb, path.buf, 0) >= 0 &&
+	    starts_with(sb.buf, "ref:")) {
+		strbuf_remove(&sb, 0, strlen("ref:"));
+		strbuf_trim(&sb);
+	} else
+		goto done;
+	if (strcmp(sb.buf, branch))
+		goto done;
+	if (id) {
+		strbuf_reset(&path);
+		strbuf_addf(&path, "%s/worktrees/%s/gitdir", get_git_common_dir(), id);
+		if (strbuf_read_file(&gitdir, path.buf, 0) <= 0)
+			goto done;
+		strbuf_rtrim(&gitdir);
+	} else
+		strbuf_addstr(&gitdir, get_git_common_dir());
+	strbuf_strip_suffix(&gitdir, ".git");
+
+	existing = strbuf_detach(&gitdir, NULL);
+done:
+	strbuf_release(&path);
+	strbuf_release(&sb);
+	strbuf_release(&gitdir);
+
+	return existing;
+}
+
+char *find_shared_symref(const char *symref, const char *target)
+{
+	struct strbuf path = STRBUF_INIT;
+	DIR *dir;
+	struct dirent *d;
+	char *existing;
+
+	if ((existing = find_linked_symref(symref, target, NULL)))
+		return existing;
+
+	strbuf_addf(&path, "%s/worktrees", get_git_common_dir());
+	dir = opendir(path.buf);
+	strbuf_release(&path);
+	if (!dir)
+		return NULL;
+
+	while ((d = readdir(dir)) != NULL) {
+		if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
+			continue;
+		existing = find_linked_symref(symref, target, d->d_name);
+		if (existing)
+			goto done;
+	}
+done:
+	closedir(dir);
+
+	return existing;
+}
diff --git a/worktree.h b/worktree.h
new file mode 100644
index 0000000..71b1409
--- /dev/null
+++ b/worktree.h
@@ -0,0 +1,12 @@
+#ifndef WORKTREE_H
+#define WORKTREE_H
+
+/*
+ * Check if a per-worktree symref points to a ref in the main worktree
+ * or any linked worktree, and return the path to the exising worktree
+ * if it is.  Returns NULL if there is no existing ref.  The caller is
+ * responsible for freeing the returned path.
+ */
+extern char *find_shared_symref(const char *symref, const char *target);
+
+#endif
-- 
2.6.0

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

* [PATCH v9 2/5] worktree: refactor find_linked_symref function
  2015-10-02 11:55 [PATCH v9 0/5] worktree: list functions and command Michael Rappazzo
  2015-10-02 11:55 ` [PATCH v9 1/5] worktree: add top-level worktree.c Michael Rappazzo
@ 2015-10-02 11:55 ` Michael Rappazzo
  2015-10-02 21:16   ` Junio C Hamano
  2015-10-02 11:55 ` [PATCH v9 3/5] worktree: add a function to get worktree details Michael Rappazzo
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 8+ messages in thread
From: Michael Rappazzo @ 2015-10-02 11:55 UTC (permalink / raw)
  To: gitster, sunshine, dturner; +Cc: git, Michael Rappazzo

Refactoring will help transition this code to provide additional useful
worktree functions.

Signed-off-by: Michael Rappazzo <rappazzo@gmail.com>
---
 worktree.c | 94 ++++++++++++++++++++++++++++++++++++++++++++------------------
 1 file changed, 67 insertions(+), 27 deletions(-)

diff --git a/worktree.c b/worktree.c
index 10e1496..c049947 100644
--- a/worktree.c
+++ b/worktree.c
@@ -3,6 +3,62 @@
 #include "strbuf.h"
 #include "worktree.h"
 
+/*
+ * read 'path_to_ref' into 'ref'.  Also if is_detached is not NULL,
+ * set is_detached to 1 (0) if the ref is detatched (is not detached).
+ *
+ * $GIT_COMMON_DIR/$symref (e.g. HEAD) is practically outside $GIT_DIR so
+ * for linked worktrees, `resolve_ref_unsafe()` won't work (it uses
+ * git_path). Parse the ref ourselves.
+ *
+ * return -1 if the ref is not a proper ref, 0 otherwise (success)
+ */
+static int parse_ref(char *path_to_ref, struct strbuf *ref, int *is_detached)
+{
+	if (is_detached)
+		*is_detached = 0;
+	if (!strbuf_readlink(ref, path_to_ref, 0))
+		if (!starts_with(ref->buf, "refs/") ||
+				check_refname_format(ref->buf, 0))
+			return -1;
+	else if (strbuf_read_file(ref, path_to_ref, 0) >= 0) {
+		if (!starts_with(ref->buf, "ref:"))
+			if (is_detached)
+				*is_detached = 1;
+		else {
+			strbuf_remove(ref, 0, strlen("ref:"));
+			strbuf_trim(ref);
+			if (check_refname_format(ref->buf, 0))
+				return -1;
+		}
+	} else
+		return -1;
+	return 0;
+}
+
+static char *find_main_symref(const char *symref, const char *branch)
+{
+	struct strbuf sb = STRBUF_INIT;
+	struct strbuf path = STRBUF_INIT;
+	struct strbuf gitdir = STRBUF_INIT;
+	char *existing = NULL;
+
+	strbuf_addf(&path, "%s/%s", get_git_common_dir(), symref);
+	if (parse_ref(path.buf, &sb, NULL) < 0)
+		goto done;
+	if (strcmp(sb.buf, branch))
+		goto done;
+	strbuf_addstr(&gitdir, get_git_common_dir());
+	strbuf_strip_suffix(&gitdir, ".git");
+	existing = strbuf_detach(&gitdir, NULL);
+done:
+	strbuf_release(&path);
+	strbuf_release(&sb);
+	strbuf_release(&gitdir);
+
+	return existing;
+}
+
 static char *find_linked_symref(const char *symref, const char *branch,
 				const char *id)
 {
@@ -11,36 +67,20 @@ static char *find_linked_symref(const char *symref, const char *branch,
 	struct strbuf gitdir = STRBUF_INIT;
 	char *existing = NULL;
 
-	/*
-	 * $GIT_COMMON_DIR/$symref (e.g. HEAD) is practically outside
-	 * $GIT_DIR so resolve_ref_unsafe() won't work (it uses
-	 * git_path). Parse the ref ourselves.
-	 */
-	if (id)
-		strbuf_addf(&path, "%s/worktrees/%s/%s", get_git_common_dir(), id, symref);
-	else
-		strbuf_addf(&path, "%s/%s", get_git_common_dir(), symref);
+	if (!id)
+		die("Missing linked worktree name");
 
-	if (!strbuf_readlink(&sb, path.buf, 0)) {
-		if (!starts_with(sb.buf, "refs/") ||
-		    check_refname_format(sb.buf, 0))
-			goto done;
-	} else if (strbuf_read_file(&sb, path.buf, 0) >= 0 &&
-	    starts_with(sb.buf, "ref:")) {
-		strbuf_remove(&sb, 0, strlen("ref:"));
-		strbuf_trim(&sb);
-	} else
+	strbuf_addf(&path, "%s/worktrees/%s/%s", get_git_common_dir(), id, symref);
+
+	if (parse_ref(path.buf, &sb, NULL) < 0)
 		goto done;
 	if (strcmp(sb.buf, branch))
 		goto done;
-	if (id) {
-		strbuf_reset(&path);
-		strbuf_addf(&path, "%s/worktrees/%s/gitdir", get_git_common_dir(), id);
-		if (strbuf_read_file(&gitdir, path.buf, 0) <= 0)
-			goto done;
-		strbuf_rtrim(&gitdir);
-	} else
-		strbuf_addstr(&gitdir, get_git_common_dir());
+	strbuf_reset(&path);
+	strbuf_addf(&path, "%s/worktrees/%s/gitdir", get_git_common_dir(), id);
+	if (strbuf_read_file(&gitdir, path.buf, 0) <= 0)
+		goto done;
+	strbuf_rtrim(&gitdir);
 	strbuf_strip_suffix(&gitdir, ".git");
 
 	existing = strbuf_detach(&gitdir, NULL);
@@ -59,7 +99,7 @@ char *find_shared_symref(const char *symref, const char *target)
 	struct dirent *d;
 	char *existing;
 
-	if ((existing = find_linked_symref(symref, target, NULL)))
+	if ((existing = find_main_symref(symref, target)))
 		return existing;
 
 	strbuf_addf(&path, "%s/worktrees", get_git_common_dir());
-- 
2.6.0

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

* [PATCH v9 3/5] worktree: add a function to get worktree details
  2015-10-02 11:55 [PATCH v9 0/5] worktree: list functions and command Michael Rappazzo
  2015-10-02 11:55 ` [PATCH v9 1/5] worktree: add top-level worktree.c Michael Rappazzo
  2015-10-02 11:55 ` [PATCH v9 2/5] worktree: refactor find_linked_symref function Michael Rappazzo
@ 2015-10-02 11:55 ` Michael Rappazzo
  2015-10-02 11:55 ` [PATCH v9 4/5] worktree: add details to the worktree struct Michael Rappazzo
  2015-10-02 11:55 ` [PATCH v9 5/5] worktree: add 'list' command Michael Rappazzo
  4 siblings, 0 replies; 8+ messages in thread
From: Michael Rappazzo @ 2015-10-02 11:55 UTC (permalink / raw)
  To: gitster, sunshine, dturner; +Cc: git, Michael Rappazzo

The worktree structure provided for an individual worktree includes the
absolute path of the worktree.  The fuction to get the worktree details
is a refactor of the find main/linked symref functions.

Signed-off-by: Michael Rappazzo <rappazzo@gmail.com>
---
 worktree.c | 161 ++++++++++++++++++++++++++++++++++++++++++-------------------
 worktree.h |  22 +++++++++
 2 files changed, 133 insertions(+), 50 deletions(-)

diff --git a/worktree.c b/worktree.c
index c049947..11a3364 100644
--- a/worktree.c
+++ b/worktree.c
@@ -3,6 +3,17 @@
 #include "strbuf.h"
 #include "worktree.h"
 
+void free_worktrees(struct worktree **worktrees)
+{
+	int i = 0;
+
+	for (i = 0; worktrees[i]; i++) {
+		free(worktrees[i]->path);
+		free(worktrees[i]);
+	}
+	free (worktrees);
+}
+
 /*
  * read 'path_to_ref' into 'ref'.  Also if is_detached is not NULL,
  * set is_detached to 1 (0) if the ref is detatched (is not detached).
@@ -17,15 +28,15 @@ static int parse_ref(char *path_to_ref, struct strbuf *ref, int *is_detached)
 {
 	if (is_detached)
 		*is_detached = 0;
-	if (!strbuf_readlink(ref, path_to_ref, 0))
+	if (!strbuf_readlink(ref, path_to_ref, 0)) {
 		if (!starts_with(ref->buf, "refs/") ||
 				check_refname_format(ref->buf, 0))
 			return -1;
-	else if (strbuf_read_file(ref, path_to_ref, 0) >= 0) {
-		if (!starts_with(ref->buf, "ref:"))
+	} else if (strbuf_read_file(ref, path_to_ref, 0) >= 0) {
+		if (!starts_with(ref->buf, "ref:")) {
 			if (is_detached)
 				*is_detached = 1;
-		else {
+		} else {
 			strbuf_remove(ref, 0, strlen("ref:"));
 			strbuf_trim(ref);
 			if (check_refname_format(ref->buf, 0))
@@ -36,87 +47,137 @@ static int parse_ref(char *path_to_ref, struct strbuf *ref, int *is_detached)
 	return 0;
 }
 
-static char *find_main_symref(const char *symref, const char *branch)
+/**
+ * get the main worktree
+ */
+static struct worktree *get_main_worktree(void)
 {
-	struct strbuf sb = STRBUF_INIT;
+	struct worktree *worktree = NULL;
 	struct strbuf path = STRBUF_INIT;
+	struct strbuf worktree_path = STRBUF_INIT;
 	struct strbuf gitdir = STRBUF_INIT;
-	char *existing = NULL;
+	struct strbuf head_ref = STRBUF_INIT;
 
-	strbuf_addf(&path, "%s/%s", get_git_common_dir(), symref);
-	if (parse_ref(path.buf, &sb, NULL) < 0)
-		goto done;
-	if (strcmp(sb.buf, branch))
-		goto done;
-	strbuf_addstr(&gitdir, get_git_common_dir());
-	strbuf_strip_suffix(&gitdir, ".git");
-	existing = strbuf_detach(&gitdir, NULL);
-done:
+	strbuf_addf(&gitdir, "%s", absolute_path(get_git_common_dir()));
+	strbuf_addbuf(&worktree_path, &gitdir);
+	if (!strbuf_strip_suffix(&worktree_path, "/.git"))
+		strbuf_strip_suffix(&worktree_path, "/.");
+
+	strbuf_addf(&path, "%s/HEAD", get_git_common_dir());
+
+	if (parse_ref(path.buf, &head_ref, NULL) >= 0) {
+		worktree = xmalloc(sizeof(struct worktree));
+		worktree->path = strbuf_detach(&worktree_path, NULL);
+		worktree->git_dir = strbuf_detach(&gitdir, NULL);
+	}
 	strbuf_release(&path);
-	strbuf_release(&sb);
 	strbuf_release(&gitdir);
-
-	return existing;
+	strbuf_release(&worktree_path);
+	strbuf_release(&head_ref);
+	return worktree;
 }
 
-static char *find_linked_symref(const char *symref, const char *branch,
-				const char *id)
+static struct worktree *get_linked_worktree(const char *id)
 {
-	struct strbuf sb = STRBUF_INIT;
+	struct worktree *worktree = NULL;
 	struct strbuf path = STRBUF_INIT;
+	struct strbuf worktree_path = STRBUF_INIT;
 	struct strbuf gitdir = STRBUF_INIT;
-	char *existing = NULL;
+	struct strbuf head_ref = STRBUF_INIT;
 
 	if (!id)
 		die("Missing linked worktree name");
 
-	strbuf_addf(&path, "%s/worktrees/%s/%s", get_git_common_dir(), id, symref);
-
-	if (parse_ref(path.buf, &sb, NULL) < 0)
-		goto done;
-	if (strcmp(sb.buf, branch))
+	strbuf_addf(&gitdir, "%s/worktrees/%s",
+			absolute_path(get_git_common_dir()), id);
+	strbuf_addf(&path, "%s/gitdir", gitdir.buf);
+	if (strbuf_read_file(&worktree_path, path.buf, 0) <= 0)
+		/* invalid gitdir file */
 		goto done;
+
+	strbuf_rtrim(&worktree_path);
+	if (!strbuf_strip_suffix(&worktree_path, "/.git")) {
+		strbuf_reset(&worktree_path);
+		strbuf_addstr(&worktree_path, absolute_path("."));
+		strbuf_strip_suffix(&worktree_path, "/.");
+	}
+
 	strbuf_reset(&path);
-	strbuf_addf(&path, "%s/worktrees/%s/gitdir", get_git_common_dir(), id);
-	if (strbuf_read_file(&gitdir, path.buf, 0) <= 0)
-		goto done;
-	strbuf_rtrim(&gitdir);
-	strbuf_strip_suffix(&gitdir, ".git");
+	strbuf_addf(&path, "%s/worktrees/%s/HEAD", get_git_common_dir(), id);
+
+	if (parse_ref(path.buf, &head_ref, NULL) >= 0) {
+		worktree = xmalloc(sizeof(struct worktree));
+		worktree->path = strbuf_detach(&worktree_path, NULL);
+		worktree->git_dir = strbuf_detach(&gitdir, NULL);
+	}
 
-	existing = strbuf_detach(&gitdir, NULL);
 done:
 	strbuf_release(&path);
-	strbuf_release(&sb);
 	strbuf_release(&gitdir);
-
-	return existing;
+	strbuf_release(&worktree_path);
+	strbuf_release(&head_ref);
+	return worktree;
 }
 
-char *find_shared_symref(const char *symref, const char *target)
+struct worktree **get_worktrees(void)
 {
+	struct worktree **list = NULL;
 	struct strbuf path = STRBUF_INIT;
 	DIR *dir;
 	struct dirent *d;
-	char *existing;
+	int counter = 0, alloc = 2;
+
+	list = xmalloc(alloc * sizeof(struct worktree *));
 
-	if ((existing = find_main_symref(symref, target)))
-		return existing;
+	if ((list[counter] = get_main_worktree()))
+		counter++;
 
 	strbuf_addf(&path, "%s/worktrees", get_git_common_dir());
 	dir = opendir(path.buf);
 	strbuf_release(&path);
-	if (!dir)
-		return NULL;
+	if (dir) {
+		while ((d = readdir(dir)) != NULL) {
+			struct worktree *linked = NULL;
+			if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
+				continue;
 
-	while ((d = readdir(dir)) != NULL) {
-		if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
+				if ((linked = get_linked_worktree(d->d_name))) {
+					ALLOC_GROW(list, alloc + 1, alloc);
+					list[counter++] = linked;
+				}
+		}
+		closedir(dir);
+	}
+	list[counter] = NULL;
+	return list;
+}
+
+char *find_shared_symref(const char *symref, const char *target)
+{
+	char *existing = NULL;
+	struct strbuf path = STRBUF_INIT;
+	struct strbuf sb = STRBUF_INIT;
+	struct worktree **worktrees = get_worktrees();
+	int i = 0;
+
+	for (i = 0; worktrees[i]; i++) {
+		strbuf_reset(&path);
+		strbuf_reset(&sb);
+		strbuf_addf(&path, "%s/%s", worktrees[i]->git_dir, symref);
+
+		if (parse_ref(path.buf, &sb, NULL)) {
 			continue;
-		existing = find_linked_symref(symref, target, d->d_name);
-		if (existing)
-			goto done;
+		}
+
+		if (!strcmp(sb.buf, target)) {
+			existing = xstrdup(worktrees[i]->path);
+			break;
+		}
 	}
-done:
-	closedir(dir);
+
+	strbuf_release(&path);
+	strbuf_release(&sb);
+	free_worktrees(worktrees);
 
 	return existing;
 }
diff --git a/worktree.h b/worktree.h
index 71b1409..7022029 100644
--- a/worktree.h
+++ b/worktree.h
@@ -1,6 +1,28 @@
 #ifndef WORKTREE_H
 #define WORKTREE_H
 
+struct worktree {
+	char *path;
+	char *git_dir;
+};
+
+/* Functions for acting on the information about worktrees. */
+
+/*
+ * Get the worktrees.  The primary worktree will always be the first returned,
+ * and linked worktrees will be pointed to by 'next' in each subsequent
+ * worktree.  No specific ordering is done on the linked worktrees.
+ *
+ * The caller is responsible for freeing the memory from the returned
+ * worktree(s).
+ */
+extern struct worktree **get_worktrees(void);
+
+/*
+ * Free up the memory for worktree(s)
+ */
+extern void free_worktrees(struct worktree **);
+
 /*
  * Check if a per-worktree symref points to a ref in the main worktree
  * or any linked worktree, and return the path to the exising worktree
-- 
2.6.0

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

* [PATCH v9 4/5] worktree: add details to the worktree struct
  2015-10-02 11:55 [PATCH v9 0/5] worktree: list functions and command Michael Rappazzo
                   ` (2 preceding siblings ...)
  2015-10-02 11:55 ` [PATCH v9 3/5] worktree: add a function to get worktree details Michael Rappazzo
@ 2015-10-02 11:55 ` Michael Rappazzo
  2015-10-02 11:55 ` [PATCH v9 5/5] worktree: add 'list' command Michael Rappazzo
  4 siblings, 0 replies; 8+ messages in thread
From: Michael Rappazzo @ 2015-10-02 11:55 UTC (permalink / raw)
  To: gitster, sunshine, dturner; +Cc: git, Michael Rappazzo

In addition to the absolute path in the worktree struct, add the location
of the git dir, the head ref (if not detached), the head revision sha1,
whether or not head is detached, and whether or not the worktree is a
bare repo.

Signed-off-by: Michael Rappazzo <rappazzo@gmail.com>
---
 worktree.c | 55 ++++++++++++++++++++++++++++++++++++++++++++-----------
 worktree.h |  4 ++++
 2 files changed, 48 insertions(+), 11 deletions(-)

diff --git a/worktree.c b/worktree.c
index 11a3364..27af98a 100644
--- a/worktree.c
+++ b/worktree.c
@@ -9,6 +9,8 @@ void free_worktrees(struct worktree **worktrees)
 
 	for (i = 0; worktrees[i]; i++) {
 		free(worktrees[i]->path);
+		free(worktrees[i]->git_dir);
+		free(worktrees[i]->head_ref);
 		free(worktrees[i]);
 	}
 	free (worktrees);
@@ -48,6 +50,21 @@ static int parse_ref(char *path_to_ref, struct strbuf *ref, int *is_detached)
 }
 
 /**
+ * Add the head_sha1 and head_ref (if not detached) to the given worktree
+ */
+static void add_head_info(struct strbuf *head_ref, struct worktree *worktree)
+{
+	if (head_ref->len) {
+		if (worktree->is_detached) {
+			get_sha1_hex(head_ref->buf, worktree->head_sha1);
+		} else {
+			resolve_ref_unsafe(head_ref->buf, 0, worktree->head_sha1, NULL);
+			worktree->head_ref = strbuf_detach(head_ref, NULL);
+		}
+	}
+}
+
+/**
  * get the main worktree
  */
 static struct worktree *get_main_worktree(void)
@@ -57,19 +74,29 @@ static struct worktree *get_main_worktree(void)
 	struct strbuf worktree_path = STRBUF_INIT;
 	struct strbuf gitdir = STRBUF_INIT;
 	struct strbuf head_ref = STRBUF_INIT;
+	int is_bare = 0;
+	int is_detached = 0;
 
 	strbuf_addf(&gitdir, "%s", absolute_path(get_git_common_dir()));
 	strbuf_addbuf(&worktree_path, &gitdir);
-	if (!strbuf_strip_suffix(&worktree_path, "/.git"))
+	is_bare = !strbuf_strip_suffix(&worktree_path, "/.git");
+	if (is_bare)
 		strbuf_strip_suffix(&worktree_path, "/.");
 
 	strbuf_addf(&path, "%s/HEAD", get_git_common_dir());
 
-	if (parse_ref(path.buf, &head_ref, NULL) >= 0) {
-		worktree = xmalloc(sizeof(struct worktree));
-		worktree->path = strbuf_detach(&worktree_path, NULL);
-		worktree->git_dir = strbuf_detach(&gitdir, NULL);
-	}
+	if (parse_ref(path.buf, &head_ref, &is_detached) < 0)
+		goto done;
+
+	worktree = xmalloc(sizeof(struct worktree));
+	worktree->path = strbuf_detach(&worktree_path, NULL);
+	worktree->git_dir = strbuf_detach(&gitdir, NULL);
+	worktree->is_bare = is_bare;
+	worktree->head_ref = NULL;
+	worktree->is_detached = is_detached;
+	add_head_info(&head_ref, worktree);
+
+done:
 	strbuf_release(&path);
 	strbuf_release(&gitdir);
 	strbuf_release(&worktree_path);
@@ -84,6 +111,7 @@ static struct worktree *get_linked_worktree(const char *id)
 	struct strbuf worktree_path = STRBUF_INIT;
 	struct strbuf gitdir = STRBUF_INIT;
 	struct strbuf head_ref = STRBUF_INIT;
+	int is_detached = 0;
 
 	if (!id)
 		die("Missing linked worktree name");
@@ -105,11 +133,16 @@ static struct worktree *get_linked_worktree(const char *id)
 	strbuf_reset(&path);
 	strbuf_addf(&path, "%s/worktrees/%s/HEAD", get_git_common_dir(), id);
 
-	if (parse_ref(path.buf, &head_ref, NULL) >= 0) {
-		worktree = xmalloc(sizeof(struct worktree));
-		worktree->path = strbuf_detach(&worktree_path, NULL);
-		worktree->git_dir = strbuf_detach(&gitdir, NULL);
-	}
+	if (parse_ref(path.buf, &head_ref, &is_detached) < 0)
+		goto done;
+
+	worktree = xmalloc(sizeof(struct worktree));
+	worktree->path = strbuf_detach(&worktree_path, NULL);
+	worktree->git_dir = strbuf_detach(&gitdir, NULL);
+	worktree->is_bare = 0;
+	worktree->head_ref = NULL;
+	worktree->is_detached = is_detached;
+	add_head_info(&head_ref, worktree);
 
 done:
 	strbuf_release(&path);
diff --git a/worktree.h b/worktree.h
index 7022029..b4b3dda 100644
--- a/worktree.h
+++ b/worktree.h
@@ -4,6 +4,10 @@
 struct worktree {
 	char *path;
 	char *git_dir;
+	char *head_ref;
+	unsigned char head_sha1[20];
+	int is_detached;
+	int is_bare;
 };
 
 /* Functions for acting on the information about worktrees. */
-- 
2.6.0

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

* [PATCH v9 5/5] worktree: add 'list' command
  2015-10-02 11:55 [PATCH v9 0/5] worktree: list functions and command Michael Rappazzo
                   ` (3 preceding siblings ...)
  2015-10-02 11:55 ` [PATCH v9 4/5] worktree: add details to the worktree struct Michael Rappazzo
@ 2015-10-02 11:55 ` Michael Rappazzo
  2015-10-02 20:33   ` Junio C Hamano
  4 siblings, 1 reply; 8+ messages in thread
From: Michael Rappazzo @ 2015-10-02 11:55 UTC (permalink / raw)
  To: gitster, sunshine, dturner; +Cc: git, Michael Rappazzo

'git worktree list' iterates through the worktree list, and outputs
details of the worktree including the path to the worktree, the currently
checked out revision and branch, and if the work tree is bare.  There is
also porcelain format option available.

Signed-off-by: Michael Rappazzo <rappazzo@gmail.com>
---
 Documentation/git-worktree.txt | 49 ++++++++++++++++++++++-
 builtin/worktree.c             | 82 ++++++++++++++++++++++++++++++++++++++
 t/t2027-worktree-list.sh       | 89 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 219 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..5b9ad04 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' [--porcelain]
 
 DESCRIPTION
 -----------
@@ -59,6 +60,13 @@ prune::
 
 Prune working tree information in $GIT_DIR/worktrees.
 
+list::
+
+List details of each worktree.  The main worktree is listed first, followed by
+each of the linked worktrees.  The output details include if the worktree is
+bare, the revision currently checked out, and the branch currently checked out
+(or 'detached HEAD' if none).
+
 OPTIONS
 -------
 
@@ -86,6 +94,11 @@ OPTIONS
 	With `prune`, do not remove anything; just report what it would
 	remove.
 
+--porcelain::
+	With `list`, output in an easy-to-parse format for scripts.
+	This format will remain stable across Git versions and regardless of user
+	configuration.  See below for details.
+
 -v::
 --verbose::
 	With `prune`, report all removals.
@@ -134,6 +147,41 @@ to `/path/main/.git/worktrees/test-next` then a file named
 `test-next` entry from being pruned.  See
 linkgit:gitrepository-layout[5] for details.
 
+LIST OUTPUT FORMAT
+------------------
+The worktree list command has two output formats.  The default format shows the
+details on a single line with columns.  For example:
+
+------------
+S git worktree list
+/path/to/bare-source            (bare)
+/path/to/linked-worktree        abcd1234 [master]
+/path/to/other-linked-worktree  1234abc  (detached HEAD)
+------------
+
+Porcelain Format
+~~~~~~~~~~~~~~~~
+The porcelain format has a line per attribute.  Attributes are listed with a
+label and value separated by a single space.  Boolean attributes (like 'bare'
+and 'detached') are listed as a label only, and are only present if and only
+if the value is true.  An empty line indicates the end of a worktree.  For
+example:
+
+------------
+S git worktree list --porcelain
+worktree /path/to/bare-source
+bare
+
+worktree /path/to/linked-worktree
+HEAD abcd1234abcd1234abcd1234abcd1234abcd1234
+branch refs/heads/master
+
+worktree /path/to/other-linked-worktree
+HEAD 1234abc1234abc1234abc1234abc1234abc1234a
+detached
+
+------------
+
 EXAMPLES
 --------
 You are in the middle of a refactoring session and your boss comes in and
@@ -167,7 +215,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 71bb770..268f9bf 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -8,10 +8,13 @@
 #include "run-command.h"
 #include "sigchain.h"
 #include "refs.h"
+#include "utf8.h"
+#include "worktree.h"
 
 static const char * const worktree_usage[] = {
 	N_("git worktree add [<options>] <path> <branch>"),
 	N_("git worktree prune [<options>]"),
+	N_("git worktree list [<options>]"),
 	NULL
 };
 
@@ -359,6 +362,83 @@ static int add(int ac, const char **av, const char *prefix)
 	return add_worktree(path, branch, &opts);
 }
 
+static void show_worktree_porcelain(struct worktree *worktree)
+{
+	printf("worktree %s\n", worktree->path);
+	if (worktree->is_bare)
+		printf("bare\n");
+	else {
+		printf("HEAD %s\n", sha1_to_hex(worktree->head_sha1));
+		if (worktree->is_detached)
+			printf("detached\n");
+		else
+			printf("branch %s\n", worktree->head_ref);
+	}
+	printf("\n");
+}
+static void show_worktree(
+		struct worktree *worktree, int path_maxlen, int abbrev_len)
+{
+	struct strbuf sb = STRBUF_INIT;
+	int cur_path_len = strlen(worktree->path);
+	int path_adj = cur_path_len - utf8_strwidth(worktree->path);
+
+	strbuf_addf(&sb, "%-*s ", 1 + path_maxlen + path_adj, worktree->path);
+	if (worktree->is_bare)
+		strbuf_addstr(&sb, "(bare)");
+	else {
+		strbuf_addf(&sb, "%-*s ", abbrev_len,
+				find_unique_abbrev(worktree->head_sha1, DEFAULT_ABBREV));
+		if (!worktree->is_detached)
+			strbuf_addf(&sb, "[%s]", shorten_unambiguous_ref(worktree->head_ref, 0));
+		else
+			strbuf_addstr(&sb, "(detached HEAD)");
+	}
+	printf("%s\n", sb.buf);
+
+	strbuf_release(&sb);
+}
+
+static int list(int ac, const char **av, const char *prefix)
+{
+	int porcelain = 0;
+
+	struct option options[] = {
+		OPT_BOOL(0, "porcelain", &porcelain, N_("machine-readable output")),
+		OPT_END()
+	};
+
+	ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
+	if (ac)
+		usage_with_options(worktree_usage, options);
+	else {
+		struct worktree **worktrees = get_worktrees();
+		int path_maxlen = 0;
+		int abbrev = 0;
+		int i;
+
+		if (!porcelain) {
+			for (i = 0; worktrees[i]; i++) {
+				int path_len = strlen(worktrees[i]->path);
+				if (path_len > path_maxlen)
+					path_maxlen = path_len;
+				int sha1_len = strlen(
+						find_unique_abbrev(worktrees[i]->head_sha1, DEFAULT_ABBREV));
+				if (sha1_len > abbrev)
+					abbrev = sha1_len;
+			}
+		}
+		for (i = 0; worktrees[i]; i++) {
+			if (porcelain)
+				show_worktree_porcelain(worktrees[i]);
+			else
+				show_worktree(worktrees[i], path_maxlen, abbrev);
+		}
+		free_worktrees(worktrees);
+	}
+	return 0;
+}
+
 int cmd_worktree(int ac, const char **av, const char *prefix)
 {
 	struct option options[] = {
@@ -371,5 +451,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..75ebb1b
--- /dev/null
+++ b/t/t2027-worktree-list.sh
@@ -0,0 +1,89 @@
+#!/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 rev-parse --short HEAD) [$(git symbolic-ref --short HEAD)]" >expect &&
+	test_when_finished "rm -rf here && git worktree prune" &&
+	git worktree add --detach here master &&
+	echo "$(git -C here rev-parse --show-toplevel) $(git rev-parse --short HEAD) (detached HEAD)" >>expect &&
+	git worktree list | sed "s/  */ /g" >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success '"list" all worktrees from linked' '
+	echo "$(git rev-parse --show-toplevel) $(git rev-parse --short HEAD) [$(git symbolic-ref --short HEAD)]" >expect &&
+	test_when_finished "rm -rf here && git worktree prune" &&
+	git worktree add --detach here master &&
+	echo "$(git -C here rev-parse --show-toplevel) $(git rev-parse --short HEAD) (detached HEAD)" >>expect &&
+	git -C here worktree list | sed "s/  */ /g" >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success '"list" all worktrees --porcelain' '
+	echo "worktree $(git rev-parse --show-toplevel)" >expect &&
+	echo "HEAD $(git rev-parse HEAD)" >>expect &&
+	echo "branch $(git symbolic-ref HEAD)" >>expect &&
+	echo >>expect &&
+	test_when_finished "rm -rf here && git worktree prune" &&
+	git worktree add --detach here master &&
+	echo "worktree $(git -C here rev-parse --show-toplevel)" >>expect &&
+	echo "HEAD $(git rev-parse HEAD)" >>expect &&
+	echo "detached" >>expect &&
+	echo >>expect &&
+	git worktree list --porcelain >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'bare repo setup' '
+	git init --bare bare1 &&
+	echo "data" >file1 &&
+	git add file1 &&
+	git commit -m"File1: add data" &&
+	git push bare1 master &&
+	git reset --hard HEAD^
+'
+
+test_expect_success '"list" all worktrees from bare main' '
+	test_when_finished "rm -rf there && git -C bare1 worktree prune" &&
+	git -C bare1 worktree add --detach ../there master &&
+	echo "$(pwd)/bare1 (bare)" >expect &&
+	echo "$(git -C there rev-parse --show-toplevel) $(git -C there rev-parse --short HEAD) (detached HEAD)" >>expect &&
+	git -C bare1 worktree list | sed "s/  */ /g" >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success '"list" all worktrees --porcelain from bare main' '
+	test_when_finished "rm -rf there && git -C bare1 worktree prune" &&
+	git -C bare1 worktree add --detach ../there master &&
+	echo "worktree $(pwd)/bare1" >expect &&
+	echo "bare" >>expect &&
+	echo >>expect &&
+	echo "worktree $(git -C there rev-parse --show-toplevel)" >>expect &&
+	echo "HEAD $(git -C there rev-parse HEAD)" >>expect &&
+	echo "detached" >>expect &&
+	echo >>expect &&
+	git -C bare1 worktree list --porcelain >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success '"list" all worktrees from linked with a bare main' '
+	test_when_finished "rm -rf there && git -C bare1 worktree prune" &&
+	git -C bare1 worktree add --detach ../there master &&
+	echo "$(pwd)/bare1 (bare)" >expect &&
+	echo "$(git -C there rev-parse --show-toplevel) $(git -C there rev-parse --short HEAD) (detached HEAD)" >>expect &&
+	git -C there worktree list | sed "s/  */ /g" >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'bare repo cleanup' '
+	rm -rf bare1
+'
+
+test_done
-- 
2.6.0

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

* Re: [PATCH v9 5/5] worktree: add 'list' command
  2015-10-02 11:55 ` [PATCH v9 5/5] worktree: add 'list' command Michael Rappazzo
@ 2015-10-02 20:33   ` Junio C Hamano
  0 siblings, 0 replies; 8+ messages in thread
From: Junio C Hamano @ 2015-10-02 20:33 UTC (permalink / raw)
  To: Michael Rappazzo; +Cc: sunshine, dturner, git

Michael Rappazzo <rappazzo@gmail.com> writes:

> +		if (!porcelain) {
> +			for (i = 0; worktrees[i]; i++) {
> +				int path_len = strlen(worktrees[i]->path);
> +				if (path_len > path_maxlen)
> +					path_maxlen = path_len;
> +				int sha1_len = strlen(
> +						find_unique_abbrev(worktrees[i]->head_sha1, DEFAULT_ABBREV));

decl-after-stmt.

If I were doing this, I'd probably do something like the attached
using a small helper function to make the primary logic easier to
see.

The first hunk below is unrelated but was to fix an obvious style
breakage I happened to have noticed nearby.

Thanks.


 builtin/worktree.c | 40 +++++++++++++++++++++++-----------------
 1 file changed, 23 insertions(+), 17 deletions(-)

diff --git a/builtin/worktree.c b/builtin/worktree.c
index 268f9bf..3be8ec8 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -376,8 +376,8 @@ static void show_worktree_porcelain(struct worktree *worktree)
 	}
 	printf("\n");
 }
-static void show_worktree(
-		struct worktree *worktree, int path_maxlen, int abbrev_len)
+
+static void show_worktree(struct worktree *worktree, int path_maxlen, int abbrev_len)
 {
 	struct strbuf sb = STRBUF_INIT;
 	int cur_path_len = strlen(worktree->path);
@@ -399,6 +399,22 @@ static void show_worktree(
 	strbuf_release(&sb);
 }
 
+static void measure_widths(struct worktree **wt, int *abbrev, int *maxlen)
+{
+	int i;
+
+	for (i = 0; wt[i]; i++) {
+		int sha1_len;
+		int path_len = strlen(wt[i]->path);
+
+		if (path_len > *maxlen)
+			*maxlen = path_len;
+		sha1_len = strlen(find_unique_abbrev(wt[i]->head_sha1, *abbrev));
+		if (sha1_len > *abbrev)
+			*abbrev = sha1_len;
+	}
+}
+
 static int list(int ac, const char **av, const char *prefix)
 {
 	int porcelain = 0;
@@ -413,21 +429,11 @@ static int list(int ac, const char **av, const char *prefix)
 		usage_with_options(worktree_usage, options);
 	else {
 		struct worktree **worktrees = get_worktrees();
-		int path_maxlen = 0;
-		int abbrev = 0;
-		int i;
-
-		if (!porcelain) {
-			for (i = 0; worktrees[i]; i++) {
-				int path_len = strlen(worktrees[i]->path);
-				if (path_len > path_maxlen)
-					path_maxlen = path_len;
-				int sha1_len = strlen(
-						find_unique_abbrev(worktrees[i]->head_sha1, DEFAULT_ABBREV));
-				if (sha1_len > abbrev)
-					abbrev = sha1_len;
-			}
-		}
+		int path_maxlen = 0, abbrev = DEFAULT_ABBREV, i;
+
+		if (!porcelain)
+			measure_widths(worktrees, &abbrev, &path_maxlen);
+
 		for (i = 0; worktrees[i]; i++) {
 			if (porcelain)
 				show_worktree_porcelain(worktrees[i]);

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

* Re: [PATCH v9 2/5] worktree: refactor find_linked_symref function
  2015-10-02 11:55 ` [PATCH v9 2/5] worktree: refactor find_linked_symref function Michael Rappazzo
@ 2015-10-02 21:16   ` Junio C Hamano
  0 siblings, 0 replies; 8+ messages in thread
From: Junio C Hamano @ 2015-10-02 21:16 UTC (permalink / raw)
  To: Michael Rappazzo; +Cc: sunshine, dturner, git

Michael Rappazzo <rappazzo@gmail.com> writes:

> +static int parse_ref(char *path_to_ref, struct strbuf *ref, int *is_detached)
> +{
> +	if (is_detached)
> +		*is_detached = 0;
> +	if (!strbuf_readlink(ref, path_to_ref, 0))
> +		if (!starts_with(ref->buf, "refs/") ||
> +				check_refname_format(ref->buf, 0))
> +			return -1;
> +	else if (strbuf_read_file(ref, path_to_ref, 0) >= 0) {

Which "if" does this "else if" pair with?  I think you would want to
clarify not with indentation but with a brace here.

	if (!strbuf_readlink(...)) {
		/* HEAD is a symlink */
                if (!starts_with(...) || check_refname_format(...))
			return -1; /* malformed */
	} else if (strbuf_read_file(...) >= 0) {
        	/* textual symref */
                ...

Alternatively, you could do it this way.

	if (!strbuf_readlink(...) &&
	    (!starts_with(...) || check_refname_format(...)))
		return -1;
	else if (strbuf_read_file(...) >= 0) {
		...

I do not know which one is more readable, though.  Probably former,
even though it is a bit more verbose, is easier to follow.

> +		if (!starts_with(ref->buf, "ref:"))
> +			if (is_detached)
> +				*is_detached = 1;
> +		else {

Same here.


 worktree.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/worktree.c b/worktree.c
index c049947..f16c082 100644
--- a/worktree.c
+++ b/worktree.c
@@ -17,22 +17,25 @@ static int parse_ref(char *path_to_ref, struct strbuf *ref, int *is_detached)
 {
 	if (is_detached)
 		*is_detached = 0;
-	if (!strbuf_readlink(ref, path_to_ref, 0))
+	if (!strbuf_readlink(ref, path_to_ref, 0)) {
+		/* HEAD is symbolic link */
 		if (!starts_with(ref->buf, "refs/") ||
 				check_refname_format(ref->buf, 0))
 			return -1;
-	else if (strbuf_read_file(ref, path_to_ref, 0) >= 0) {
-		if (!starts_with(ref->buf, "ref:"))
+	} else if (strbuf_read_file(ref, path_to_ref, 0) >= 0) {
+		/* textual symref or detached */
+		if (!starts_with(ref->buf, "ref:")) {
 			if (is_detached)
 				*is_detached = 1;
-		else {
+		} else {
 			strbuf_remove(ref, 0, strlen("ref:"));
 			strbuf_trim(ref);
 			if (check_refname_format(ref->buf, 0))
 				return -1;
 		}
-	} else
+	} else {
 		return -1;
+	}
 	return 0;
 }
 

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

end of thread, other threads:[~2015-10-02 21:16 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-10-02 11:55 [PATCH v9 0/5] worktree: list functions and command Michael Rappazzo
2015-10-02 11:55 ` [PATCH v9 1/5] worktree: add top-level worktree.c Michael Rappazzo
2015-10-02 11:55 ` [PATCH v9 2/5] worktree: refactor find_linked_symref function Michael Rappazzo
2015-10-02 21:16   ` Junio C Hamano
2015-10-02 11:55 ` [PATCH v9 3/5] worktree: add a function to get worktree details Michael Rappazzo
2015-10-02 11:55 ` [PATCH v9 4/5] worktree: add details to the worktree struct Michael Rappazzo
2015-10-02 11:55 ` [PATCH v9 5/5] worktree: add 'list' command Michael Rappazzo
2015-10-02 20:33   ` Junio C Hamano

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).