t / t4100 / t-apply-3.patchon commit Merge git://git.kernel.org/pub/scm/gitk/gitk (a549e11)
   16af1f0192ff8740fe77db7cf02c739ccfbdf119c (from 2bc2564145835996734d6ed5d1880f85b17233d6)
   2diff --git a/Documentation/git-ls-tree.txt b/Documentation/git-ls-tree.txt
   3--- a/Documentation/git-ls-tree.txt
   4+++ b/Documentation/git-ls-tree.txt
   5@@ -4,23 +4,26 @@ v0.1, May 2005
   6 
   7 NAME
   8 ----
   9-git-ls-tree - Displays a tree object in human readable form
  10+git-ls-tree - Lists the contents of a tree object.
  11 
  12 
  13 SYNOPSIS
  14 --------
  15-'git-ls-tree' [-r] [-z] <tree-ish> [paths...]
  16+'git-ls-tree' [-d] [-r] [-z] <tree-ish> [paths...]
  17 
  18 DESCRIPTION
  19 -----------
  20-Converts the tree object to a human readable (and script processable)
  21-form.
  22+Lists the contents of a tree object, like what "/bin/ls -a" does
  23+in the current working directory.
  24 
  25 OPTIONS
  26 -------
  27 <tree-ish>::
  28        Id of a tree.
  29 
  30+-d::
  31+       show only the named tree entry itself, not its children
  32+
  33 -r::
  34        recurse into sub-trees
  35 
  36@@ -28,18 +31,19 @@ OPTIONS
  37        \0 line termination on output
  38 
  39 paths::
  40-       Optionally, restrict the output of git-ls-tree to specific
  41-       paths. Directories will only list their tree blob ids.
  42-       Implies -r.
  43+       When paths are given, shows them.  Otherwise implicitly
  44+       uses the root level of the tree as the sole path argument.
  45+
  46 
  47 Output Format
  48 -------------
  49-        <mode>\t       <type>\t        <object>\t      <file>
  50+        <mode> SP <type> SP <object> TAB <file>
  51 
  52 
  53 Author
  54 ------
  55 Written by Linus Torvalds <torvalds@osdl.org>
  56+Completely rewritten from scratch by Junio C Hamano <junkio@cox.net>
  57 
  58 Documentation
  59 --------------
  60diff --git a/ls-tree.c b/ls-tree.c
  61dissimilarity index 82%
  62--- ls-tree.c
  63+++ ls-tree.c
  64@@ -1,212 +1,247 @@
  65-/*
  66- * GIT - The information manager from hell
  67- *
  68- * Copyright (C) Linus Torvalds, 2005
  69- */
  70-#include "cache.h"
  71-
  72-static int line_termination = '\n';
  73-static int recursive = 0;
  74-
  75-struct path_prefix {
  76-       struct path_prefix *prev;
  77-       const char *name;
  78-};
  79-
  80-#define DEBUG(fmt, ...)        
  81-
  82-static int string_path_prefix(char *buff, size_t blen, struct path_prefix *prefix)
  83-{
  84-       int len = 0;
  85-       if (prefix) {
  86-               if (prefix->prev) {
  87-                       len = string_path_prefix(buff,blen,prefix->prev);
  88-                       buff += len;
  89-                       blen -= len;
  90-                       if (blen > 0) {
  91-                               *buff = '/';
  92-                               len++;
  93-                               buff++;
  94-                               blen--;
  95-                       }
  96-               }
  97-               strncpy(buff,prefix->name,blen);
  98-               return len + strlen(prefix->name);
  99-       }
 100-
 101-       return 0;
 102-}
 103-
 104-static void print_path_prefix(struct path_prefix *prefix)
 105-{
 106-       if (prefix) {
 107-               if (prefix->prev) {
 108-                       print_path_prefix(prefix->prev);
 109-                       putchar('/');
 110-               }
 111-               fputs(prefix->name, stdout);
 112-       }
 113-}
 114-
 115-/*
 116- * return:
 117- *     -1 if prefix is *not* a subset of path
 118- *      0 if prefix == path
 119- *      1 if prefix is a subset of path
 120- */
 121-static int pathcmp(const char *path, struct path_prefix *prefix)
 122-{
 123-       char buff[PATH_MAX];
 124-       int len,slen;
 125-
 126-       if (prefix == NULL)
 127-               return 1;
 128-
 129-       len = string_path_prefix(buff, sizeof buff, prefix);
 130-       slen = strlen(path);
 131-
 132-       if (slen < len)
 133-               return -1;
 134-
 135-       if (strncmp(path,buff,len) == 0) {
 136-               if (slen == len)
 137-                       return 0;
 138-               else
 139-                       return 1;
 140-       }
 141-
 142-       return -1;
 143-}      
 144-
 145-/*
 146- * match may be NULL, or a *sorted* list of paths
 147- */
 148-static void list_recursive(void *buffer,
 149-                          const char *type,
 150-                          unsigned long size,
 151-                          struct path_prefix *prefix,
 152-                          char **match, int matches)
 153-{
 154-       struct path_prefix this_prefix;
 155-       this_prefix.prev = prefix;
 156-
 157-       if (strcmp(type, "tree"))
 158-               die("expected a 'tree' node");
 159-
 160-       if (matches)
 161-               recursive = 1;
 162-
 163-       while (size) {
 164-               int namelen = strlen(buffer)+1;
 165-               void *eltbuf = NULL;
 166-               char elttype[20];
 167-               unsigned long eltsize;
 168-               unsigned char *sha1 = buffer + namelen;
 169-               char *path = strchr(buffer, ' ') + 1;
 170-               unsigned int mode;
 171-               const char *matched = NULL;
 172-               int mtype = -1;
 173-               int mindex;
 174-
 175-               if (size < namelen + 20 || sscanf(buffer, "%o", &mode) != 1)
 176-                       die("corrupt 'tree' file");
 177-               buffer = sha1 + 20;
 178-               size -= namelen + 20;
 179-
 180-               this_prefix.name = path;
 181-               for ( mindex = 0; mindex < matches; mindex++) {
 182-                       mtype = pathcmp(match[mindex],&this_prefix);
 183-                       if (mtype >= 0) {
 184-                               matched = match[mindex];
 185-                               break;
 186-                       }
 187-               }
 188-
 189-               /*
 190-                * If we're not matching, or if this is an exact match,
 191-                * print out the info
 192-                */
 193-               if (!matches || (matched != NULL && mtype == 0)) {
 194-                       printf("%06o %s %s\t", mode,
 195-                              S_ISDIR(mode) ? "tree" : "blob",
 196-                              sha1_to_hex(sha1));
 197-                       print_path_prefix(&this_prefix);
 198-                       putchar(line_termination);
 199-               }
 200-
 201-               if (! recursive || ! S_ISDIR(mode))
 202-                       continue;
 203-
 204-               if (matches && ! matched)
 205-                       continue;
 206-
 207-               if (! (eltbuf = read_sha1_file(sha1, elttype, &eltsize)) ) {
 208-                       error("cannot read %s", sha1_to_hex(sha1));
 209-                       continue;
 210-               }
 211-
 212-               /* If this is an exact directory match, we may have
 213-                * directory files following this path. Match on them.
 214-                * Otherwise, we're at a pach subcomponent, and we need
 215-                * to try to match again.
 216-                */
 217-               if (mtype == 0)
 218-                       mindex++;
 219-
 220-               list_recursive(eltbuf, elttype, eltsize, &this_prefix, &match[mindex], matches-mindex);
 221-               free(eltbuf);
 222-       }
 223-}
 224-
 225-static int qcmp(const void *a, const void *b)
 226-{
 227-       return strcmp(*(char **)a, *(char **)b);
 228-}
 229-
 230-static int list(unsigned char *sha1,char **path)
 231-{
 232-       void *buffer;
 233-       unsigned long size;
 234-       int npaths;
 235-
 236-       for (npaths = 0; path[npaths] != NULL; npaths++)
 237-               ;
 238-
 239-       qsort(path,npaths,sizeof(char *),qcmp);
 240-
 241-       buffer = read_object_with_reference(sha1, "tree", &size, NULL);
 242-       if (!buffer)
 243-               die("unable to read sha1 file");
 244-       list_recursive(buffer, "tree", size, NULL, path, npaths);
 245-       free(buffer);
 246-       return 0;
 247-}
 248-
 249-static const char *ls_tree_usage = "git-ls-tree [-r] [-z] <key> [paths...]";
 250-
 251-int main(int argc, char **argv)
 252-{
 253-       unsigned char sha1[20];
 254-
 255-       while (1 < argc && argv[1][0] == '-') {
 256-               switch (argv[1][1]) {
 257-               case 'z':
 258-                       line_termination = 0;
 259-                       break;
 260-               case 'r':
 261-                       recursive = 1;
 262-                       break;
 263-               default:
 264-                       usage(ls_tree_usage);
 265-               }
 266-               argc--; argv++;
 267-       }
 268-
 269-       if (argc < 2)
 270-               usage(ls_tree_usage);
 271-       if (get_sha1(argv[1], sha1) < 0)
 272-               usage(ls_tree_usage);
 273-       if (list(sha1, &argv[2]) < 0)
 274-               die("list failed");
 275-       return 0;
 276-}
 277+/*
 278+ * GIT - The information manager from hell
 279+ *
 280+ * Copyright (C) Linus Torvalds, 2005
 281+ */
 282+#include "cache.h"
 283+#include "blob.h"
 284+#include "tree.h"
 285+
 286+static int line_termination = '\n';
 287+#define LS_RECURSIVE 1
 288+#define LS_TREE_ONLY 2
 289+static int ls_options = 0;
 290+
 291+static struct tree_entry_list root_entry;
 292+
 293+static void prepare_root(unsigned char *sha1)
 294+{
 295+       unsigned char rsha[20];
 296+       unsigned long size;
 297+       void *buf;
 298+       struct tree *root_tree;
 299+
 300+       buf = read_object_with_reference(sha1, "tree", &size, rsha);
 301+       free(buf);
 302+       if (!buf)
 303+               die("Could not read %s", sha1_to_hex(sha1));
 304+
 305+       root_tree = lookup_tree(rsha);
 306+       if (!root_tree)
 307+               die("Could not read %s", sha1_to_hex(sha1));
 308+
 309+       /* Prepare a fake entry */
 310+       root_entry.directory = 1;
 311+       root_entry.executable = root_entry.symlink = 0;
 312+       root_entry.mode = S_IFDIR;
 313+       root_entry.name = "";
 314+       root_entry.item.tree = root_tree;
 315+       root_entry.parent = NULL;
 316+}
 317+
 318+static int prepare_children(struct tree_entry_list *elem)
 319+{
 320+       if (!elem->directory)
 321+               return -1;
 322+       if (!elem->item.tree->object.parsed) {
 323+               struct tree_entry_list *e;
 324+               if (parse_tree(elem->item.tree))
 325+                       return -1;
 326+               /* Set up the parent link */
 327+               for (e = elem->item.tree->entries; e; e = e->next)
 328+                       e->parent = elem;
 329+       }
 330+       return 0;
 331+}
 332+
 333+static struct tree_entry_list *find_entry_0(struct tree_entry_list *elem,
 334+                                           const char *path,
 335+                                           const char *path_end)
 336+{
 337+       const char *ep;
 338+       int len;
 339+
 340+       while (path < path_end) {
 341+               if (prepare_children(elem))
 342+                       return NULL;
 343+
 344+               /* In elem->tree->entries, find the one that has name
 345+                * that matches what is between path and ep.
 346+                */
 347+               elem = elem->item.tree->entries;
 348+
 349+               ep = strchr(path, '/');
 350+               if (!ep || path_end <= ep)
 351+                       ep = path_end;
 352+               len = ep - path;
 353+
 354+               while (elem) {
 355+                       if ((strlen(elem->name) == len) &&
 356+                           !strncmp(elem->name, path, len))
 357+                               break;
 358+                       elem = elem->next;
 359+               }
 360+               if (path_end <= ep || !elem)
 361+                       return elem;
 362+               while (*ep == '/' && ep < path_end)
 363+                       ep++;
 364+               path = ep;
 365+       }
 366+       return NULL;
 367+}
 368+
 369+static struct tree_entry_list *find_entry(const char *path,
 370+                                         const char *path_end)
 371+{
 372+       /* Find tree element, descending from root, that
 373+        * corresponds to the named path, lazily expanding
 374+        * the tree if possible.
 375+        */
 376+       if (path == path_end) {
 377+               /* Special.  This is the root level */
 378+               return &root_entry;
 379+       }
 380+       return find_entry_0(&root_entry, path, path_end);
 381+}
 382+
 383+static void show_entry_name(struct tree_entry_list *e)
 384+{
 385+       /* This is yucky.  The root level is there for
 386+        * our convenience but we really want to do a
 387+        * forest.
 388+        */
 389+       if (e->parent && e->parent != &root_entry) {
 390+               show_entry_name(e->parent);
 391+               putchar('/');
 392+       }
 393+       printf("%s", e->name);
 394+}
 395+
 396+static const char *entry_type(struct tree_entry_list *e)
 397+{
 398+       return (e->directory ? "tree" : "blob");
 399+}
 400+
 401+static const char *entry_hex(struct tree_entry_list *e)
 402+{
 403+       return sha1_to_hex(e->directory
 404+                          ? e->item.tree->object.sha1
 405+                          : e->item.blob->object.sha1);
 406+}
 407+
 408+/* forward declaration for mutually recursive routines */
 409+static int show_entry(struct tree_entry_list *, int);
 410+
 411+static int show_children(struct tree_entry_list *e, int level)
 412+{
 413+       if (prepare_children(e))
 414+               die("internal error: ls-tree show_children called with non tree");
 415+       e = e->item.tree->entries;
 416+       while (e) {
 417+               show_entry(e, level);
 418+               e = e->next;
 419+       }
 420+       return 0;
 421+}
 422+
 423+static int show_entry(struct tree_entry_list *e, int level)
 424+{
 425+       int err = 0; 
 426+
 427+       if (e != &root_entry) {
 428+               printf("%06o %s %s      ", e->mode, entry_type(e),
 429+                      entry_hex(e));
 430+               show_entry_name(e);
 431+               putchar(line_termination);
 432+       }
 433+
 434+       if (e->directory) {
 435+               /* If this is a directory, we have the following cases:
 436+                * (1) This is the top-level request (explicit path from the
 437+                *     command line, or "root" if there is no command line).
 438+                *  a. Without any flag.  We show direct children.  We do not 
 439+                *     recurse into them.
 440+                *  b. With -r.  We do recurse into children.
 441+                *  c. With -d.  We do not recurse into children.
 442+                * (2) We came here because our caller is either (1-a) or
 443+                *     (1-b).
 444+                *  a. Without any flag.  We do not show our children (which
 445+                *     are grandchildren for the original request).
 446+                *  b. With -r.  We continue to recurse into our children.
 447+                *  c. With -d.  We should not have come here to begin with.
 448+                */
 449+               if (level == 0 && !(ls_options & LS_TREE_ONLY))
 450+                       /* case (1)-a and (1)-b */
 451+                       err = err | show_children(e, level+1);
 452+               else if (level && ls_options & LS_RECURSIVE)
 453+                       /* case (2)-b */
 454+                       err = err | show_children(e, level+1);
 455+       }
 456+       return err;
 457+}
 458+
 459+static int list_one(const char *path, const char *path_end)
 460+{
 461+       int err = 0;
 462+       struct tree_entry_list *e = find_entry(path, path_end);
 463+       if (!e) {
 464+               /* traditionally ls-tree does not complain about
 465+                * missing path.  We may change this later to match
 466+                * what "/bin/ls -a" does, which is to complain.
 467+                */
 468+               return err;
 469+       }
 470+       err = err | show_entry(e, 0);
 471+       return err;
 472+}
 473+
 474+static int list(char **path)
 475+{
 476+       int i;
 477+       int err = 0;
 478+       for (i = 0; path[i]; i++) {
 479+               int len = strlen(path[i]);
 480+               while (0 <= len && path[i][len] == '/')
 481+                       len--;
 482+               err = err | list_one(path[i], path[i] + len);
 483+       }
 484+       return err;
 485+}
 486+
 487+static const char *ls_tree_usage =
 488+       "git-ls-tree [-d] [-r] [-z] <tree-ish> [path...]";
 489+
 490+int main(int argc, char **argv)
 491+{
 492+       static char *path0[] = { "", NULL };
 493+       char **path;
 494+       unsigned char sha1[20];
 495+
 496+       while (1 < argc && argv[1][0] == '-') {
 497+               switch (argv[1][1]) {
 498+               case 'z':
 499+                       line_termination = 0;
 500+                       break;
 501+               case 'r':
 502+                       ls_options |= LS_RECURSIVE;
 503+                       break;
 504+               case 'd':
 505+                       ls_options |= LS_TREE_ONLY;
 506+                       break;
 507+               default:
 508+                       usage(ls_tree_usage);
 509+               }
 510+               argc--; argv++;
 511+       }
 512+
 513+       if (argc < 2)
 514+               usage(ls_tree_usage);
 515+       if (get_sha1(argv[1], sha1) < 0)
 516+               usage(ls_tree_usage);
 517+
 518+       path = (argc == 2) ? path0 : (argv + 2);
 519+       prepare_root(sha1);
 520+       if (list(path) < 0)
 521+               die("list failed");
 522+       return 0;
 523+}
 524diff --git a/t/t3100-ls-tree-restrict.sh b/t/t3100-ls-tree-restrict.sh
 525--- a/t/t3100-ls-tree-restrict.sh
 526+++ b/t/t3100-ls-tree-restrict.sh
 527@@ -74,8 +74,8 @@ test_expect_success \
 528     'ls-tree filtered' \
 529     'git-ls-tree $tree path1 path0 >current &&
 530      cat >expected <<\EOF &&
 531-100644 blob X  path0
 532 120000 blob X  path1
 533+100644 blob X  path0
 534 EOF
 535      test_output'
 536 
 537@@ -85,7 +85,6 @@ test_expect_success \
 538      cat >expected <<\EOF &&
 539 040000 tree X  path2
 540 040000 tree X  path2/baz
 541-100644 blob X  path2/baz/b
 542 120000 blob X  path2/bazbo
 543 100644 blob X  path2/foo
 544 EOF
 545diff --git a/tree.c b/tree.c
 546--- a/tree.c
 547+++ b/tree.c
 548@@ -133,7 +133,7 @@ int parse_tree_buffer(struct tree *item,
 549                }
 550                if (obj)
 551                        add_ref(&item->object, obj);
 552-
 553+               entry->parent = NULL; /* needs to be filled by the user */
 554                *list_p = entry;
 555                list_p = &entry->next;
 556        }
 557diff --git a/tree.h b/tree.h
 558--- a/tree.h
 559+++ b/tree.h
 560@@ -16,6 +16,7 @@ struct tree_entry_list {
 561                struct tree *tree;
 562                struct blob *blob;
 563        } item;
 564+       struct tree_entry_list *parent;
 565 };
 566 
 567 struct tree {