2 * GIT - The information manager from hell
4 * Copyright (C) Linus Torvalds, 2005
12 #include "parse-options.h"
14 static int line_termination
= '\n';
15 #define LS_RECURSIVE 1
16 #define LS_TREE_ONLY 2
17 #define LS_SHOW_TREES 4
18 #define LS_NAME_ONLY 8
19 #define LS_SHOW_SIZE 16
21 static int ls_options
;
22 static struct pathspec pathspec
;
23 static int chomp_prefix
;
24 static const char *ls_tree_prefix
;
26 static const char * const ls_tree_usage
[] = {
27 N_("git ls-tree [<options>] <tree-ish> [<path>...]"),
31 static int show_recursive(const char *base
, int baselen
, const char *pathname
)
35 if (ls_options
& LS_RECURSIVE
)
43 const char *spec
= *s
++;
48 if (strncmp(base
, spec
, baselen
))
50 len
= strlen(pathname
);
52 speclen
= strlen(spec
);
55 if (spec
[len
] && spec
[len
] != '/')
57 if (memcmp(pathname
, spec
, len
))
63 static int show_tree(const unsigned char *sha1
, const char *base
, int baselen
,
64 const char *pathname
, unsigned mode
, int stage
, void *context
)
67 const char *type
= blob_type
;
69 if (S_ISGITLINK(mode
)) {
71 * Maybe we want to have some recursive version here?
73 * Something similar to this incomplete example:
75 if (show_subprojects(base, baselen, pathname))
76 retval = READ_TREE_RECURSIVE;
80 } else if (S_ISDIR(mode
)) {
81 if (show_recursive(base
, baselen
, pathname
)) {
82 retval
= READ_TREE_RECURSIVE
;
83 if (!(ls_options
& LS_SHOW_TREES
))
88 else if (ls_options
& LS_TREE_ONLY
)
92 (baselen
< chomp_prefix
|| memcmp(ls_tree_prefix
, base
, chomp_prefix
)))
95 if (!(ls_options
& LS_NAME_ONLY
)) {
96 if (ls_options
& LS_SHOW_SIZE
) {
98 if (!strcmp(type
, blob_type
)) {
100 if (sha1_object_info(sha1
, &size
) == OBJ_BAD
)
101 strcpy(size_text
, "BAD");
103 snprintf(size_text
, sizeof(size_text
),
106 strcpy(size_text
, "-");
107 printf("%06o %s %s %7s\t", mode
, type
,
108 find_unique_abbrev(sha1
, abbrev
),
111 printf("%06o %s %s\t", mode
, type
,
112 find_unique_abbrev(sha1
, abbrev
));
114 write_name_quotedpfx(base
+ chomp_prefix
, baselen
- chomp_prefix
,
115 pathname
, stdout
, line_termination
);
119 int cmd_ls_tree(int argc
, const char **argv
, const char *prefix
)
121 unsigned char sha1
[20];
123 int i
, full_tree
= 0;
124 const struct option ls_tree_options
[] = {
125 OPT_BIT('d', NULL
, &ls_options
, N_("only show trees"),
127 OPT_BIT('r', NULL
, &ls_options
, N_("recurse into subtrees"),
129 OPT_BIT('t', NULL
, &ls_options
, N_("show trees when recursing"),
131 OPT_SET_INT('z', NULL
, &line_termination
,
132 N_("terminate entries with NUL byte"), 0),
133 OPT_BIT('l', "long", &ls_options
, N_("include object size"),
135 OPT_BIT(0, "name-only", &ls_options
, N_("list only filenames"),
137 OPT_BIT(0, "name-status", &ls_options
, N_("list only filenames"),
139 OPT_SET_INT(0, "full-name", &chomp_prefix
,
140 N_("use full path names"), 0),
141 OPT_BOOLEAN(0, "full-tree", &full_tree
,
142 N_("list entire tree; not just current directory "
143 "(implies --full-name)")),
144 OPT__ABBREV(&abbrev
),
148 git_config(git_default_config
, NULL
);
149 ls_tree_prefix
= prefix
;
150 if (prefix
&& *prefix
)
151 chomp_prefix
= strlen(prefix
);
153 argc
= parse_options(argc
, argv
, prefix
, ls_tree_options
,
156 ls_tree_prefix
= prefix
= NULL
;
159 /* -d -r should imply -t, but -d by itself should not have to. */
160 if ( (LS_TREE_ONLY
|LS_RECURSIVE
) ==
161 ((LS_TREE_ONLY
|LS_RECURSIVE
) & ls_options
))
162 ls_options
|= LS_SHOW_TREES
;
165 usage_with_options(ls_tree_usage
, ls_tree_options
);
166 if (get_sha1(argv
[0], sha1
))
167 die("Not a valid object name %s", argv
[0]);
169 init_pathspec(&pathspec
, get_pathspec(prefix
, argv
+ 1));
170 for (i
= 0; i
< pathspec
.nr
; i
++)
171 pathspec
.items
[i
].use_wildcard
= 0;
172 pathspec
.has_wildcard
= 0;
173 tree
= parse_tree_indirect(sha1
);
175 die("not a tree object");
176 return !!read_tree_recursive(tree
, "", 0, 0, &pathspec
, show_tree
, NULL
);