2 * GIT - The information manager from hell
4 * Copyright (C) Linus Torvalds, 2005
12 #include "parse-options.h"
15 static int line_termination
= '\n';
16 #define LS_RECURSIVE 1
17 #define LS_TREE_ONLY 2
18 #define LS_SHOW_TREES 4
19 #define LS_NAME_ONLY 8
20 #define LS_SHOW_SIZE 16
22 static int ls_options
;
23 static struct pathspec pathspec
;
24 static int chomp_prefix
;
25 static const char *ls_tree_prefix
;
27 static const char * const ls_tree_usage
[] = {
28 N_("git ls-tree [<options>] <tree-ish> [<path>...]"),
32 static int show_recursive(const char *base
, int baselen
, const char *pathname
)
36 if (ls_options
& LS_RECURSIVE
)
44 const char *spec
= *s
++;
49 if (strncmp(base
, spec
, baselen
))
51 len
= strlen(pathname
);
53 speclen
= strlen(spec
);
56 if (spec
[len
] && spec
[len
] != '/')
58 if (memcmp(pathname
, spec
, len
))
64 static int show_tree(const unsigned char *sha1
, const char *base
, int baselen
,
65 const char *pathname
, unsigned mode
, int stage
, void *context
)
68 const char *type
= blob_type
;
70 if (S_ISGITLINK(mode
)) {
72 * Maybe we want to have some recursive version here?
74 * Something similar to this incomplete example:
76 if (show_subprojects(base, baselen, pathname))
77 retval = READ_TREE_RECURSIVE;
81 } else if (S_ISDIR(mode
)) {
82 if (show_recursive(base
, baselen
, pathname
)) {
83 retval
= READ_TREE_RECURSIVE
;
84 if (!(ls_options
& LS_SHOW_TREES
))
89 else if (ls_options
& LS_TREE_ONLY
)
93 (baselen
< chomp_prefix
|| memcmp(ls_tree_prefix
, base
, chomp_prefix
)))
96 if (!(ls_options
& LS_NAME_ONLY
)) {
97 if (ls_options
& LS_SHOW_SIZE
) {
99 if (!strcmp(type
, blob_type
)) {
101 if (sha1_object_info(sha1
, &size
) == OBJ_BAD
)
102 strcpy(size_text
, "BAD");
104 snprintf(size_text
, sizeof(size_text
),
107 strcpy(size_text
, "-");
108 printf("%06o %s %s %7s\t", mode
, type
,
109 find_unique_abbrev(sha1
, abbrev
),
112 printf("%06o %s %s\t", mode
, type
,
113 find_unique_abbrev(sha1
, abbrev
));
115 write_name_quotedpfx(base
+ chomp_prefix
, baselen
- chomp_prefix
,
116 pathname
, stdout
, line_termination
);
120 int cmd_ls_tree(int argc
, const char **argv
, const char *prefix
)
122 unsigned char sha1
[20];
124 int i
, full_tree
= 0;
125 const struct option ls_tree_options
[] = {
126 OPT_BIT('d', NULL
, &ls_options
, N_("only show trees"),
128 OPT_BIT('r', NULL
, &ls_options
, N_("recurse into subtrees"),
130 OPT_BIT('t', NULL
, &ls_options
, N_("show trees when recursing"),
132 OPT_SET_INT('z', NULL
, &line_termination
,
133 N_("terminate entries with NUL byte"), 0),
134 OPT_BIT('l', "long", &ls_options
, N_("include object size"),
136 OPT_BIT(0, "name-only", &ls_options
, N_("list only filenames"),
138 OPT_BIT(0, "name-status", &ls_options
, N_("list only filenames"),
140 OPT_SET_INT(0, "full-name", &chomp_prefix
,
141 N_("use full path names"), 0),
142 OPT_BOOL(0, "full-tree", &full_tree
,
143 N_("list entire tree; not just current directory "
144 "(implies --full-name)")),
145 OPT__ABBREV(&abbrev
),
149 git_config(git_default_config
, NULL
);
150 ls_tree_prefix
= prefix
;
151 if (prefix
&& *prefix
)
152 chomp_prefix
= strlen(prefix
);
154 argc
= parse_options(argc
, argv
, prefix
, ls_tree_options
,
157 ls_tree_prefix
= prefix
= NULL
;
160 /* -d -r should imply -t, but -d by itself should not have to. */
161 if ( (LS_TREE_ONLY
|LS_RECURSIVE
) ==
162 ((LS_TREE_ONLY
|LS_RECURSIVE
) & ls_options
))
163 ls_options
|= LS_SHOW_TREES
;
166 usage_with_options(ls_tree_usage
, ls_tree_options
);
167 if (get_sha1(argv
[0], sha1
))
168 die("Not a valid object name %s", argv
[0]);
171 * show_recursive() rolls its own matching code and is
172 * generally ignorant of 'struct pathspec'. The magic mask
173 * cannot be lifted until it is converted to use
174 * match_pathspec_depth() or tree_entry_interesting()
176 parse_pathspec(&pathspec
, PATHSPEC_GLOB
| PATHSPEC_ICASE
,
179 for (i
= 0; i
< pathspec
.nr
; i
++)
180 pathspec
.items
[i
].nowildcard_len
= pathspec
.items
[i
].len
;
181 pathspec
.has_wildcard
= 0;
182 tree
= parse_tree_indirect(sha1
);
184 die("not a tree object");
185 return !!read_tree_recursive(tree
, "", 0, 0, &pathspec
, show_tree
, NULL
);