[PATCH v9 5/5] worktree: add 'list' command

2015-10-02 Thread 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 
---
 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 ]  []
 'git worktree prune' [-n] [-v] [--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-worktreeabcd1234 [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 []  "),
N_("git worktree prune []"),
+   N_("git worktree list []"),
NULL
 };
 
@@ -359,6 +362,83 @@ static int add(int ac, const char **av, const char *prefix)
return add_worktree(path, branch, );
 }
 
+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(, "%-*s ", 1 + path_maxlen + path_adj, worktree->path);
+   if (worktree->is_bare)
+   strbuf_addstr(, "(bare)");
+   else {
+   

Re: [PATCH v9 5/5] worktree: add 'list' command

2015-10-02 Thread Junio C Hamano
Michael Rappazzo  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();
 }
 
+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, , _maxlen);
+
for (i = 0; worktrees[i]; i++) {
if (porcelain)
show_worktree_porcelain(worktrees[i]);
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html