git

Форк
0
/t
/
t-apply-3.patch 
567 строк · 12.8 Кб
1
6af1f0192ff8740fe77db7cf02c739ccfbdf119c (from 2bc2564145835996734d6ed5d1880f85b17233d6)
2
diff --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
 --------------
60
diff --git a/ls-tree.c b/ls-tree.c
61
dissimilarity 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 patch 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
+}
524
diff --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
545
diff --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
 	}
557
diff --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 {
568

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.