git

Форк
0
/
rev-parse.c 
1165 строк · 28.1 Кб
1
/*
2
 * rev-parse.c
3
 *
4
 * Copyright (C) Linus Torvalds, 2005
5
 */
6

7
#include "builtin.h"
8
#include "abspath.h"
9
#include "config.h"
10
#include "commit.h"
11
#include "environment.h"
12
#include "gettext.h"
13
#include "hash.h"
14
#include "hex.h"
15
#include "refs.h"
16
#include "quote.h"
17
#include "object-name.h"
18
#include "parse-options.h"
19
#include "path.h"
20
#include "diff.h"
21
#include "read-cache-ll.h"
22
#include "revision.h"
23
#include "setup.h"
24
#include "split-index.h"
25
#include "submodule.h"
26
#include "commit-reach.h"
27
#include "shallow.h"
28
#include "object-file-convert.h"
29

30
#define DO_REVS		1
31
#define DO_NOREV	2
32
#define DO_FLAGS	4
33
#define DO_NONFLAGS	8
34
static int filter = ~0;
35

36
static const char *def;
37

38
#define NORMAL 0
39
#define REVERSED 1
40
static int show_type = NORMAL;
41

42
#define SHOW_SYMBOLIC_ASIS 1
43
#define SHOW_SYMBOLIC_FULL 2
44
static int symbolic;
45
static int abbrev;
46
static int abbrev_ref;
47
static int abbrev_ref_strict;
48
static int output_sq;
49

50
static int stuck_long;
51
static struct ref_exclusions ref_excludes = REF_EXCLUSIONS_INIT;
52

53
/*
54
 * Some arguments are relevant "revision" arguments,
55
 * others are about output format or other details.
56
 * This sorts it all out.
57
 */
58
static int is_rev_argument(const char *arg)
59
{
60
	static const char *rev_args[] = {
61
		"--all",
62
		"--bisect",
63
		"--dense",
64
		"--branches=",
65
		"--branches",
66
		"--header",
67
		"--ignore-missing",
68
		"--max-age=",
69
		"--max-count=",
70
		"--min-age=",
71
		"--no-merges",
72
		"--min-parents=",
73
		"--no-min-parents",
74
		"--max-parents=",
75
		"--no-max-parents",
76
		"--objects",
77
		"--objects-edge",
78
		"--parents",
79
		"--pretty",
80
		"--remotes=",
81
		"--remotes",
82
		"--glob=",
83
		"--sparse",
84
		"--tags=",
85
		"--tags",
86
		"--topo-order",
87
		"--date-order",
88
		"--unpacked",
89
		NULL
90
	};
91
	const char **p = rev_args;
92

93
	/* accept -<digit>, like traditional "head" */
94
	if ((*arg == '-') && isdigit(arg[1]))
95
		return 1;
96

97
	for (;;) {
98
		const char *str = *p++;
99
		int len;
100
		if (!str)
101
			return 0;
102
		len = strlen(str);
103
		if (!strcmp(arg, str) ||
104
		    (str[len-1] == '=' && !strncmp(arg, str, len)))
105
			return 1;
106
	}
107
}
108

109
/* Output argument as a string, either SQ or normal */
110
static void show(const char *arg)
111
{
112
	if (output_sq) {
113
		int sq = '\'', ch;
114

115
		putchar(sq);
116
		while ((ch = *arg++)) {
117
			if (ch == sq)
118
				fputs("'\\'", stdout);
119
			putchar(ch);
120
		}
121
		putchar(sq);
122
		putchar(' ');
123
	}
124
	else
125
		puts(arg);
126
}
127

128
/* Like show(), but with a negation prefix according to type */
129
static void show_with_type(int type, const char *arg)
130
{
131
	if (type != show_type)
132
		putchar('^');
133
	show(arg);
134
}
135

136
/* Output a revision, only if filter allows it */
137
static void show_rev(int type, const struct object_id *oid, const char *name)
138
{
139
	if (!(filter & DO_REVS))
140
		return;
141
	def = NULL;
142

143
	if ((symbolic || abbrev_ref) && name) {
144
		if (symbolic == SHOW_SYMBOLIC_FULL || abbrev_ref) {
145
			struct object_id discard;
146
			char *full;
147

148
			switch (repo_dwim_ref(the_repository, name,
149
					      strlen(name), &discard, &full,
150
					      0)) {
151
			case 0:
152
				/*
153
				 * Not found -- not a ref.  We could
154
				 * emit "name" here, but symbolic-full
155
				 * users are interested in finding the
156
				 * refs spelled in full, and they would
157
				 * need to filter non-refs if we did so.
158
				 */
159
				break;
160
			case 1: /* happy */
161
				if (abbrev_ref) {
162
					char *old = full;
163
					full = refs_shorten_unambiguous_ref(get_main_ref_store(the_repository),
164
									    full,
165
									    abbrev_ref_strict);
166
					free(old);
167
				}
168
				show_with_type(type, full);
169
				break;
170
			default: /* ambiguous */
171
				error("refname '%s' is ambiguous", name);
172
				break;
173
			}
174
			free(full);
175
		} else {
176
			show_with_type(type, name);
177
		}
178
	}
179
	else if (abbrev)
180
		show_with_type(type,
181
			       repo_find_unique_abbrev(the_repository, oid, abbrev));
182
	else
183
		show_with_type(type, oid_to_hex(oid));
184
}
185

186
/* Output a flag, only if filter allows it. */
187
static int show_flag(const char *arg)
188
{
189
	if (!(filter & DO_FLAGS))
190
		return 0;
191
	if (filter & (is_rev_argument(arg) ? DO_REVS : DO_NOREV)) {
192
		show(arg);
193
		return 1;
194
	}
195
	return 0;
196
}
197

198
static int show_default(void)
199
{
200
	const char *s = def;
201

202
	if (s) {
203
		struct object_id oid;
204

205
		def = NULL;
206
		if (!repo_get_oid(the_repository, s, &oid)) {
207
			show_rev(NORMAL, &oid, s);
208
			return 1;
209
		}
210
	}
211
	return 0;
212
}
213

214
static int show_reference(const char *refname, const char *referent UNUSED, const struct object_id *oid,
215
			  int flag UNUSED, void *cb_data UNUSED)
216
{
217
	if (ref_excluded(&ref_excludes, refname))
218
		return 0;
219
	show_rev(NORMAL, oid, refname);
220
	return 0;
221
}
222

223
static int anti_reference(const char *refname, const char *referent UNUSED, const struct object_id *oid,
224
			  int flag UNUSED, void *cb_data UNUSED)
225
{
226
	show_rev(REVERSED, oid, refname);
227
	return 0;
228
}
229

230
static int show_abbrev(const struct object_id *oid, void *cb_data UNUSED)
231
{
232
	show_rev(NORMAL, oid, NULL);
233
	return 0;
234
}
235

236
static void show_datestring(const char *flag, const char *datestr)
237
{
238
	char *buffer;
239

240
	/* date handling requires both flags and revs */
241
	if ((filter & (DO_FLAGS | DO_REVS)) != (DO_FLAGS | DO_REVS))
242
		return;
243
	buffer = xstrfmt("%s%"PRItime, flag, approxidate(datestr));
244
	show(buffer);
245
	free(buffer);
246
}
247

248
static int show_file(const char *arg, int output_prefix)
249
{
250
	show_default();
251
	if ((filter & (DO_NONFLAGS|DO_NOREV)) == (DO_NONFLAGS|DO_NOREV)) {
252
		if (output_prefix) {
253
			const char *prefix = startup_info->prefix;
254
			char *fname = prefix_filename(prefix, arg);
255
			show(fname);
256
			free(fname);
257
		} else
258
			show(arg);
259
		return 1;
260
	}
261
	return 0;
262
}
263

264
static int try_difference(const char *arg)
265
{
266
	char *dotdot;
267
	struct object_id start_oid;
268
	struct object_id end_oid;
269
	const char *end;
270
	const char *start;
271
	int symmetric;
272
	static const char head_by_default[] = "HEAD";
273

274
	if (!(dotdot = strstr(arg, "..")))
275
		return 0;
276
	end = dotdot + 2;
277
	start = arg;
278
	symmetric = (*end == '.');
279

280
	*dotdot = 0;
281
	end += symmetric;
282

283
	if (!*end)
284
		end = head_by_default;
285
	if (dotdot == arg)
286
		start = head_by_default;
287

288
	if (start == head_by_default && end == head_by_default &&
289
	    !symmetric) {
290
		/*
291
		 * Just ".."?  That is not a range but the
292
		 * pathspec for the parent directory.
293
		 */
294
		*dotdot = '.';
295
		return 0;
296
	}
297

298
	if (!repo_get_oid_committish(the_repository, start, &start_oid) && !repo_get_oid_committish(the_repository, end, &end_oid)) {
299
		show_rev(NORMAL, &end_oid, end);
300
		show_rev(symmetric ? NORMAL : REVERSED, &start_oid, start);
301
		if (symmetric) {
302
			struct commit_list *exclude = NULL;
303
			struct commit *a, *b;
304
			a = lookup_commit_reference(the_repository, &start_oid);
305
			b = lookup_commit_reference(the_repository, &end_oid);
306
			if (!a || !b) {
307
				*dotdot = '.';
308
				return 0;
309
			}
310
			if (repo_get_merge_bases(the_repository, a, b, &exclude) < 0)
311
				exit(128);
312
			while (exclude) {
313
				struct commit *commit = pop_commit(&exclude);
314
				show_rev(REVERSED, &commit->object.oid, NULL);
315
			}
316
		}
317
		*dotdot = '.';
318
		return 1;
319
	}
320
	*dotdot = '.';
321
	return 0;
322
}
323

324
static int try_parent_shorthands(const char *arg)
325
{
326
	char *dotdot;
327
	struct object_id oid;
328
	struct commit *commit;
329
	struct commit_list *parents;
330
	int parent_number;
331
	int include_rev = 0;
332
	int include_parents = 0;
333
	int exclude_parent = 0;
334

335
	if ((dotdot = strstr(arg, "^!"))) {
336
		include_rev = 1;
337
		if (dotdot[2])
338
			return 0;
339
	} else if ((dotdot = strstr(arg, "^@"))) {
340
		include_parents = 1;
341
		if (dotdot[2])
342
			return 0;
343
	} else if ((dotdot = strstr(arg, "^-"))) {
344
		include_rev = 1;
345
		exclude_parent = 1;
346

347
		if (dotdot[2]) {
348
			char *end;
349
			exclude_parent = strtoul(dotdot + 2, &end, 10);
350
			if (*end != '\0' || !exclude_parent)
351
				return 0;
352
		}
353
	} else
354
		return 0;
355

356
	*dotdot = 0;
357
	if (repo_get_oid_committish(the_repository, arg, &oid) ||
358
	    !(commit = lookup_commit_reference(the_repository, &oid))) {
359
		*dotdot = '^';
360
		return 0;
361
	}
362

363
	if (exclude_parent &&
364
	    exclude_parent > commit_list_count(commit->parents)) {
365
		*dotdot = '^';
366
		return 0;
367
	}
368

369
	if (include_rev)
370
		show_rev(NORMAL, &oid, arg);
371
	for (parents = commit->parents, parent_number = 1;
372
	     parents;
373
	     parents = parents->next, parent_number++) {
374
		char *name = NULL;
375

376
		if (exclude_parent && parent_number != exclude_parent)
377
			continue;
378

379
		if (symbolic)
380
			name = xstrfmt("%s^%d", arg, parent_number);
381
		show_rev(include_parents ? NORMAL : REVERSED,
382
			 &parents->item->object.oid, name);
383
		free(name);
384
	}
385

386
	*dotdot = '^';
387
	return 1;
388
}
389

390
static int parseopt_dump(const struct option *o, const char *arg, int unset)
391
{
392
	struct strbuf *parsed = o->value;
393
	if (unset)
394
		strbuf_addf(parsed, " --no-%s", o->long_name);
395
	else if (o->short_name && (o->long_name == NULL || !stuck_long))
396
		strbuf_addf(parsed, " -%c", o->short_name);
397
	else
398
		strbuf_addf(parsed, " --%s", o->long_name);
399
	if (arg) {
400
		if (!stuck_long)
401
			strbuf_addch(parsed, ' ');
402
		else if (o->long_name)
403
			strbuf_addch(parsed, '=');
404
		sq_quote_buf(parsed, arg);
405
	}
406
	return 0;
407
}
408

409
static const char *skipspaces(const char *s)
410
{
411
	while (isspace(*s))
412
		s++;
413
	return s;
414
}
415

416
static char *findspace(const char *s)
417
{
418
	for (; *s; s++)
419
		if (isspace(*s))
420
			return (char*)s;
421
	return NULL;
422
}
423

424
static int cmd_parseopt(int argc, const char **argv, const char *prefix)
425
{
426
	int keep_dashdash = 0, stop_at_non_option = 0;
427
	char const * const parseopt_usage[] = {
428
		N_("git rev-parse --parseopt [<options>] -- [<args>...]"),
429
		NULL
430
	};
431
	struct option parseopt_opts[] = {
432
		OPT_BOOL(0, "keep-dashdash", &keep_dashdash,
433
					N_("keep the `--` passed as an arg")),
434
		OPT_BOOL(0, "stop-at-non-option", &stop_at_non_option,
435
					N_("stop parsing after the "
436
					   "first non-option argument")),
437
		OPT_BOOL(0, "stuck-long", &stuck_long,
438
					N_("output in stuck long form")),
439
		OPT_END(),
440
	};
441
	struct strbuf sb = STRBUF_INIT, parsed = STRBUF_INIT;
442
	struct strvec longnames = STRVEC_INIT;
443
	struct strvec usage = STRVEC_INIT;
444
	struct option *opts = NULL;
445
	size_t opts_nr = 0, opts_alloc = 0;
446

447
	strbuf_addstr(&parsed, "set --");
448
	argc = parse_options(argc, argv, prefix, parseopt_opts, parseopt_usage,
449
	                     PARSE_OPT_KEEP_DASHDASH);
450
	if (argc < 1 || strcmp(argv[0], "--"))
451
		usage_with_options(parseopt_usage, parseopt_opts);
452

453
	/* get the usage up to the first line with a -- on it */
454
	for (;;) {
455
		strbuf_reset(&sb);
456
		if (strbuf_getline(&sb, stdin) == EOF)
457
			die(_("premature end of input"));
458
		if (!strcmp("--", sb.buf)) {
459
			if (!usage.nr)
460
				die(_("no usage string given before the `--' separator"));
461
			break;
462
		}
463

464
		strvec_push(&usage, sb.buf);
465
	}
466

467
	/* parse: (<short>|<short>,<long>|<long>)[*=?!]*<arghint>? SP+ <help> */
468
	while (strbuf_getline(&sb, stdin) != EOF) {
469
		const char *s;
470
		char *help;
471
		struct option *o;
472

473
		if (!sb.len)
474
			continue;
475

476
		ALLOC_GROW(opts, opts_nr + 1, opts_alloc);
477
		memset(opts + opts_nr, 0, sizeof(*opts));
478

479
		o = &opts[opts_nr++];
480
		help = findspace(sb.buf);
481
		if (!help || sb.buf == help) {
482
			o->type = OPTION_GROUP;
483
			o->help = xstrdup(skipspaces(sb.buf));
484
			continue;
485
		}
486

487
		*help = '\0';
488

489
		o->type = OPTION_CALLBACK;
490
		o->help = xstrdup(skipspaces(help+1));
491
		o->value = &parsed;
492
		o->flags = PARSE_OPT_NOARG;
493
		o->callback = &parseopt_dump;
494

495
		/* name(s) */
496
		s = strpbrk(sb.buf, "*=?!");
497
		if (!s)
498
			s = help;
499

500
		if (s == sb.buf)
501
			die(_("missing opt-spec before option flags"));
502

503
		if (s - sb.buf == 1) { /* short option only */
504
			o->short_name = *sb.buf;
505
		} else if (sb.buf[1] != ',') { /* long option only */
506
			o->long_name = strvec_pushf(&longnames, "%.*s",
507
						    (int)(s - sb.buf), sb.buf);
508
		} else {
509
			o->short_name = *sb.buf;
510
			o->long_name = strvec_pushf(&longnames, "%.*s",
511
						    (int)(s - sb.buf - 2), sb.buf + 2);
512
		}
513

514
		/* flags */
515
		while (s < help) {
516
			switch (*s++) {
517
			case '=':
518
				o->flags &= ~PARSE_OPT_NOARG;
519
				continue;
520
			case '?':
521
				o->flags &= ~PARSE_OPT_NOARG;
522
				o->flags |= PARSE_OPT_OPTARG;
523
				continue;
524
			case '!':
525
				o->flags |= PARSE_OPT_NONEG;
526
				continue;
527
			case '*':
528
				o->flags |= PARSE_OPT_HIDDEN;
529
				continue;
530
			}
531
			s--;
532
			break;
533
		}
534

535
		if (s < help)
536
			o->argh = xmemdupz(s, help - s);
537
	}
538
	strbuf_release(&sb);
539

540
	/* put an OPT_END() */
541
	ALLOC_GROW(opts, opts_nr + 1, opts_alloc);
542
	memset(opts + opts_nr, 0, sizeof(*opts));
543
	argc = parse_options(argc, argv, prefix, opts, usage.v,
544
			(keep_dashdash ? PARSE_OPT_KEEP_DASHDASH : 0) |
545
			(stop_at_non_option ? PARSE_OPT_STOP_AT_NON_OPTION : 0) |
546
			PARSE_OPT_SHELL_EVAL);
547

548
	strbuf_addstr(&parsed, " --");
549
	sq_quote_argv(&parsed, argv);
550
	puts(parsed.buf);
551

552
	strbuf_release(&parsed);
553
	strbuf_release(&sb);
554
	strvec_clear(&longnames);
555
	strvec_clear(&usage);
556
	for (size_t i = 0; i < opts_nr; i++) {
557
		free((char *) opts[i].help);
558
		free((char *) opts[i].argh);
559
	}
560
	free(opts);
561
	return 0;
562
}
563

564
static int cmd_sq_quote(int argc, const char **argv)
565
{
566
	struct strbuf buf = STRBUF_INIT;
567

568
	if (argc)
569
		sq_quote_argv(&buf, argv);
570
	printf("%s\n", buf.buf);
571
	strbuf_release(&buf);
572

573
	return 0;
574
}
575

576
static void die_no_single_rev(int quiet)
577
{
578
	if (quiet)
579
		exit(1);
580
	else
581
		die(_("Needed a single revision"));
582
}
583

584
static const char builtin_rev_parse_usage[] =
585
N_("git rev-parse --parseopt [<options>] -- [<args>...]\n"
586
   "   or: git rev-parse --sq-quote [<arg>...]\n"
587
   "   or: git rev-parse [<options>] [<arg>...]\n"
588
   "\n"
589
   "Run \"git rev-parse --parseopt -h\" for more information on the first usage.");
590

591
/*
592
 * Parse "opt" or "opt=<value>", setting value respectively to either
593
 * NULL or the string after "=".
594
 */
595
static int opt_with_value(const char *arg, const char *opt, const char **value)
596
{
597
	if (skip_prefix(arg, opt, &arg)) {
598
		if (!*arg) {
599
			*value = NULL;
600
			return 1;
601
		}
602
		if (*arg++ == '=') {
603
			*value = arg;
604
			return 1;
605
		}
606
	}
607
	return 0;
608
}
609

610
static void handle_ref_opt(const char *pattern, const char *prefix)
611
{
612
	if (pattern)
613
		refs_for_each_glob_ref_in(get_main_ref_store(the_repository),
614
					  show_reference, pattern, prefix,
615
					  NULL);
616
	else
617
		refs_for_each_ref_in(get_main_ref_store(the_repository),
618
				     prefix, show_reference, NULL);
619
	clear_ref_exclusions(&ref_excludes);
620
}
621

622
enum format_type {
623
	/* We would like a relative path. */
624
	FORMAT_RELATIVE,
625
	/* We would like a canonical absolute path. */
626
	FORMAT_CANONICAL,
627
	/* We would like the default behavior. */
628
	FORMAT_DEFAULT,
629
};
630

631
enum default_type {
632
	/* Our default is a relative path. */
633
	DEFAULT_RELATIVE,
634
	/* Our default is a relative path if there's a shared root. */
635
	DEFAULT_RELATIVE_IF_SHARED,
636
	/* Our default is a canonical absolute path. */
637
	DEFAULT_CANONICAL,
638
	/* Our default is not to modify the item. */
639
	DEFAULT_UNMODIFIED,
640
};
641

642
static void print_path(const char *path, const char *prefix, enum format_type format, enum default_type def)
643
{
644
	char *cwd = NULL;
645
	/*
646
	 * We don't ever produce a relative path if prefix is NULL, so set the
647
	 * prefix to the current directory so that we can produce a relative
648
	 * path whenever possible.  If we're using RELATIVE_IF_SHARED mode, then
649
	 * we want an absolute path unless the two share a common prefix, so don't
650
	 * set it in that case, since doing so causes a relative path to always
651
	 * be produced if possible.
652
	 */
653
	if (!prefix && (format != FORMAT_DEFAULT || def != DEFAULT_RELATIVE_IF_SHARED))
654
		prefix = cwd = xgetcwd();
655
	if (format == FORMAT_DEFAULT && def == DEFAULT_UNMODIFIED) {
656
		puts(path);
657
	} else if (format == FORMAT_RELATIVE ||
658
		  (format == FORMAT_DEFAULT && def == DEFAULT_RELATIVE)) {
659
		/*
660
		 * In order for relative_path to work as expected, we need to
661
		 * make sure that both paths are absolute paths.  If we don't,
662
		 * we can end up with an unexpected absolute path that the user
663
		 * didn't want.
664
		 */
665
		struct strbuf buf = STRBUF_INIT, realbuf = STRBUF_INIT, prefixbuf = STRBUF_INIT;
666
		if (!is_absolute_path(path)) {
667
			strbuf_realpath_forgiving(&realbuf, path,  1);
668
			path = realbuf.buf;
669
		}
670
		if (!is_absolute_path(prefix)) {
671
			strbuf_realpath_forgiving(&prefixbuf, prefix, 1);
672
			prefix = prefixbuf.buf;
673
		}
674
		puts(relative_path(path, prefix, &buf));
675
		strbuf_release(&buf);
676
		strbuf_release(&realbuf);
677
		strbuf_release(&prefixbuf);
678
	} else if (format == FORMAT_DEFAULT && def == DEFAULT_RELATIVE_IF_SHARED) {
679
		struct strbuf buf = STRBUF_INIT;
680
		puts(relative_path(path, prefix, &buf));
681
		strbuf_release(&buf);
682
	} else {
683
		struct strbuf buf = STRBUF_INIT;
684
		strbuf_realpath_forgiving(&buf, path, 1);
685
		puts(buf.buf);
686
		strbuf_release(&buf);
687
	}
688
	free(cwd);
689
}
690

691
int cmd_rev_parse(int argc, const char **argv, const char *prefix)
692
{
693
	int i, as_is = 0, verify = 0, quiet = 0, revs_count = 0, type = 0;
694
	const struct git_hash_algo *output_algo = NULL;
695
	const struct git_hash_algo *compat = NULL;
696
	int did_repo_setup = 0;
697
	int has_dashdash = 0;
698
	int output_prefix = 0;
699
	struct object_id oid;
700
	unsigned int flags = 0;
701
	const char *name = NULL;
702
	struct object_context unused;
703
	struct strbuf buf = STRBUF_INIT;
704
	int seen_end_of_options = 0;
705
	enum format_type format = FORMAT_DEFAULT;
706

707
	if (argc > 1 && !strcmp("--parseopt", argv[1]))
708
		return cmd_parseopt(argc - 1, argv + 1, prefix);
709

710
	if (argc > 1 && !strcmp("--sq-quote", argv[1]))
711
		return cmd_sq_quote(argc - 2, argv + 2);
712

713
	if (argc > 1 && !strcmp("-h", argv[1]))
714
		usage(builtin_rev_parse_usage);
715

716
	for (i = 1; i < argc; i++) {
717
		if (!strcmp(argv[i], "--")) {
718
			has_dashdash = 1;
719
			break;
720
		}
721
	}
722

723
	/* No options; just report on whether we're in a git repo or not. */
724
	if (argc == 1) {
725
		setup_git_directory();
726
		git_config(git_default_config, NULL);
727
		return 0;
728
	}
729

730
	for (i = 1; i < argc; i++) {
731
		const char *arg = argv[i];
732

733
		if (as_is) {
734
			if (show_file(arg, output_prefix) && as_is < 2)
735
				verify_filename(prefix, arg, 0);
736
			continue;
737
		}
738

739
		if (!seen_end_of_options) {
740
			if (!strcmp(arg, "--local-env-vars")) {
741
				int i;
742
				for (i = 0; local_repo_env[i]; i++)
743
					printf("%s\n", local_repo_env[i]);
744
				continue;
745
			}
746
			if (!strcmp(arg, "--resolve-git-dir")) {
747
				const char *gitdir = argv[++i];
748
				if (!gitdir)
749
					die(_("--resolve-git-dir requires an argument"));
750
				gitdir = resolve_gitdir(gitdir);
751
				if (!gitdir)
752
					die(_("not a gitdir '%s'"), argv[i]);
753
				puts(gitdir);
754
				continue;
755
			}
756
		}
757

758
		/* The rest of the options require a git repository. */
759
		if (!did_repo_setup) {
760
			prefix = setup_git_directory();
761
			git_config(git_default_config, NULL);
762
			did_repo_setup = 1;
763

764
			prepare_repo_settings(the_repository);
765
			the_repository->settings.command_requires_full_index = 0;
766
			compat = the_repository->compat_hash_algo;
767
		}
768

769
		if (!strcmp(arg, "--")) {
770
			as_is = 2;
771
			/* Pass on the "--" if we show anything but files.. */
772
			if (filter & (DO_FLAGS | DO_REVS))
773
				show_file(arg, 0);
774
			continue;
775
		}
776

777
		if (!seen_end_of_options && *arg == '-') {
778
			if (!strcmp(arg, "--git-path")) {
779
				if (!argv[i + 1])
780
					die(_("--git-path requires an argument"));
781
				strbuf_reset(&buf);
782
				print_path(git_path("%s", argv[i + 1]), prefix,
783
						format,
784
						DEFAULT_RELATIVE_IF_SHARED);
785
				i++;
786
				continue;
787
			}
788
			if (!strcmp(arg,"-n")) {
789
				if (++i >= argc)
790
					die(_("-n requires an argument"));
791
				if ((filter & DO_FLAGS) && (filter & DO_REVS)) {
792
					show(arg);
793
					show(argv[i]);
794
				}
795
				continue;
796
			}
797
			if (starts_with(arg, "-n")) {
798
				if ((filter & DO_FLAGS) && (filter & DO_REVS))
799
					show(arg);
800
				continue;
801
			}
802
			if (opt_with_value(arg, "--path-format", &arg)) {
803
				if (!arg)
804
					die(_("--path-format requires an argument"));
805
				if (!strcmp(arg, "absolute")) {
806
					format = FORMAT_CANONICAL;
807
				} else if (!strcmp(arg, "relative")) {
808
					format = FORMAT_RELATIVE;
809
				} else {
810
					die(_("unknown argument to --path-format: %s"), arg);
811
				}
812
				continue;
813
			}
814
			if (!strcmp(arg, "--default")) {
815
				def = argv[++i];
816
				if (!def)
817
					die(_("--default requires an argument"));
818
				continue;
819
			}
820
			if (!strcmp(arg, "--prefix")) {
821
				prefix = argv[++i];
822
				if (!prefix)
823
					die(_("--prefix requires an argument"));
824
				startup_info->prefix = prefix;
825
				output_prefix = 1;
826
				continue;
827
			}
828
			if (!strcmp(arg, "--revs-only")) {
829
				filter &= ~DO_NOREV;
830
				continue;
831
			}
832
			if (!strcmp(arg, "--no-revs")) {
833
				filter &= ~DO_REVS;
834
				continue;
835
			}
836
			if (!strcmp(arg, "--flags")) {
837
				filter &= ~DO_NONFLAGS;
838
				continue;
839
			}
840
			if (!strcmp(arg, "--no-flags")) {
841
				filter &= ~DO_FLAGS;
842
				continue;
843
			}
844
			if (!strcmp(arg, "--verify")) {
845
				filter &= ~(DO_FLAGS|DO_NOREV);
846
				verify = 1;
847
				continue;
848
			}
849
			if (!strcmp(arg, "--quiet") || !strcmp(arg, "-q")) {
850
				quiet = 1;
851
				flags |= GET_OID_QUIETLY;
852
				continue;
853
			}
854
			if (opt_with_value(arg, "--output-object-format", &arg)) {
855
				if (!arg)
856
					die(_("no object format specified"));
857
				if (!strcmp(arg, the_hash_algo->name) ||
858
				    !strcmp(arg, "storage")) {
859
					flags |= GET_OID_HASH_ANY;
860
					output_algo = the_hash_algo;
861
					continue;
862
				}
863
				else if (compat && !strcmp(arg, compat->name)) {
864
					flags |= GET_OID_HASH_ANY;
865
					output_algo = compat;
866
					continue;
867
				}
868
				else die(_("unsupported object format: %s"), arg);
869
			}
870
			if (opt_with_value(arg, "--short", &arg)) {
871
				filter &= ~(DO_FLAGS|DO_NOREV);
872
				verify = 1;
873
				abbrev = DEFAULT_ABBREV;
874
				if (!arg)
875
					continue;
876
				abbrev = strtoul(arg, NULL, 10);
877
				if (abbrev < MINIMUM_ABBREV)
878
					abbrev = MINIMUM_ABBREV;
879
				else if ((int)the_hash_algo->hexsz <= abbrev)
880
					abbrev = the_hash_algo->hexsz;
881
				continue;
882
			}
883
			if (!strcmp(arg, "--sq")) {
884
				output_sq = 1;
885
				continue;
886
			}
887
			if (!strcmp(arg, "--not")) {
888
				show_type ^= REVERSED;
889
				continue;
890
			}
891
			if (!strcmp(arg, "--symbolic")) {
892
				symbolic = SHOW_SYMBOLIC_ASIS;
893
				continue;
894
			}
895
			if (!strcmp(arg, "--symbolic-full-name")) {
896
				symbolic = SHOW_SYMBOLIC_FULL;
897
				continue;
898
			}
899
			if (opt_with_value(arg, "--abbrev-ref", &arg)) {
900
				abbrev_ref = 1;
901
				abbrev_ref_strict = warn_ambiguous_refs;
902
				if (arg) {
903
					if (!strcmp(arg, "strict"))
904
						abbrev_ref_strict = 1;
905
					else if (!strcmp(arg, "loose"))
906
						abbrev_ref_strict = 0;
907
					else
908
						die(_("unknown mode for --abbrev-ref: %s"),
909
						    arg);
910
				}
911
				continue;
912
			}
913
			if (!strcmp(arg, "--all")) {
914
				refs_for_each_ref(get_main_ref_store(the_repository),
915
						  show_reference, NULL);
916
				clear_ref_exclusions(&ref_excludes);
917
				continue;
918
			}
919
			if (skip_prefix(arg, "--disambiguate=", &arg)) {
920
				repo_for_each_abbrev(the_repository, arg, the_hash_algo,
921
						     show_abbrev, NULL);
922
				continue;
923
			}
924
			if (!strcmp(arg, "--bisect")) {
925
				refs_for_each_fullref_in(get_main_ref_store(the_repository),
926
							 "refs/bisect/bad",
927
							 NULL, show_reference,
928
							 NULL);
929
				refs_for_each_fullref_in(get_main_ref_store(the_repository),
930
							 "refs/bisect/good",
931
							 NULL, anti_reference,
932
							 NULL);
933
				continue;
934
			}
935
			if (opt_with_value(arg, "--branches", &arg)) {
936
				if (ref_excludes.hidden_refs_configured)
937
					return error(_("options '%s' and '%s' cannot be used together"),
938
						     "--exclude-hidden", "--branches");
939
				handle_ref_opt(arg, "refs/heads/");
940
				continue;
941
			}
942
			if (opt_with_value(arg, "--tags", &arg)) {
943
				if (ref_excludes.hidden_refs_configured)
944
					return error(_("options '%s' and '%s' cannot be used together"),
945
						     "--exclude-hidden", "--tags");
946
				handle_ref_opt(arg, "refs/tags/");
947
				continue;
948
			}
949
			if (skip_prefix(arg, "--glob=", &arg)) {
950
				handle_ref_opt(arg, NULL);
951
				continue;
952
			}
953
			if (opt_with_value(arg, "--remotes", &arg)) {
954
				if (ref_excludes.hidden_refs_configured)
955
					return error(_("options '%s' and '%s' cannot be used together"),
956
						     "--exclude-hidden", "--remotes");
957
				handle_ref_opt(arg, "refs/remotes/");
958
				continue;
959
			}
960
			if (skip_prefix(arg, "--exclude=", &arg)) {
961
				add_ref_exclusion(&ref_excludes, arg);
962
				continue;
963
			}
964
			if (skip_prefix(arg, "--exclude-hidden=", &arg)) {
965
				exclude_hidden_refs(&ref_excludes, arg);
966
				continue;
967
			}
968
			if (!strcmp(arg, "--show-toplevel")) {
969
				const char *work_tree = get_git_work_tree();
970
				if (work_tree)
971
					print_path(work_tree, prefix, format, DEFAULT_UNMODIFIED);
972
				else
973
					die(_("this operation must be run in a work tree"));
974
				continue;
975
			}
976
			if (!strcmp(arg, "--show-superproject-working-tree")) {
977
				struct strbuf superproject = STRBUF_INIT;
978
				if (get_superproject_working_tree(&superproject))
979
					print_path(superproject.buf, prefix, format, DEFAULT_UNMODIFIED);
980
				strbuf_release(&superproject);
981
				continue;
982
			}
983
			if (!strcmp(arg, "--show-prefix")) {
984
				if (prefix)
985
					puts(prefix);
986
				else
987
					putchar('\n');
988
				continue;
989
			}
990
			if (!strcmp(arg, "--show-cdup")) {
991
				const char *pfx = prefix;
992
				if (!is_inside_work_tree()) {
993
					const char *work_tree =
994
						get_git_work_tree();
995
					if (work_tree)
996
						printf("%s\n", work_tree);
997
					continue;
998
				}
999
				while (pfx) {
1000
					pfx = strchr(pfx, '/');
1001
					if (pfx) {
1002
						pfx++;
1003
						printf("../");
1004
					}
1005
				}
1006
				putchar('\n');
1007
				continue;
1008
			}
1009
			if (!strcmp(arg, "--git-dir") ||
1010
			    !strcmp(arg, "--absolute-git-dir")) {
1011
				const char *gitdir = getenv(GIT_DIR_ENVIRONMENT);
1012
				char *cwd;
1013
				int len;
1014
				enum format_type wanted = format;
1015
				if (arg[2] == 'g') {	/* --git-dir */
1016
					if (gitdir) {
1017
						print_path(gitdir, prefix, format, DEFAULT_UNMODIFIED);
1018
						continue;
1019
					}
1020
					if (!prefix) {
1021
						print_path(".git", prefix, format, DEFAULT_UNMODIFIED);
1022
						continue;
1023
					}
1024
				} else {		/* --absolute-git-dir */
1025
					wanted = FORMAT_CANONICAL;
1026
					if (!gitdir && !prefix)
1027
						gitdir = ".git";
1028
					if (gitdir) {
1029
						struct strbuf realpath = STRBUF_INIT;
1030
						strbuf_realpath(&realpath, gitdir, 1);
1031
						puts(realpath.buf);
1032
						strbuf_release(&realpath);
1033
						continue;
1034
					}
1035
				}
1036
				cwd = xgetcwd();
1037
				len = strlen(cwd);
1038
				strbuf_reset(&buf);
1039
				strbuf_addf(&buf, "%s%s.git", cwd, len && cwd[len-1] != '/' ? "/" : "");
1040
				free(cwd);
1041
				print_path(buf.buf, prefix, wanted, DEFAULT_CANONICAL);
1042
				continue;
1043
			}
1044
			if (!strcmp(arg, "--git-common-dir")) {
1045
				print_path(get_git_common_dir(), prefix, format, DEFAULT_RELATIVE_IF_SHARED);
1046
				continue;
1047
			}
1048
			if (!strcmp(arg, "--is-inside-git-dir")) {
1049
				printf("%s\n", is_inside_git_dir() ? "true"
1050
						: "false");
1051
				continue;
1052
			}
1053
			if (!strcmp(arg, "--is-inside-work-tree")) {
1054
				printf("%s\n", is_inside_work_tree() ? "true"
1055
						: "false");
1056
				continue;
1057
			}
1058
			if (!strcmp(arg, "--is-bare-repository")) {
1059
				printf("%s\n", is_bare_repository() ? "true"
1060
						: "false");
1061
				continue;
1062
			}
1063
			if (!strcmp(arg, "--is-shallow-repository")) {
1064
				printf("%s\n",
1065
						is_repository_shallow(the_repository) ? "true"
1066
						: "false");
1067
				continue;
1068
			}
1069
			if (!strcmp(arg, "--shared-index-path")) {
1070
				if (repo_read_index(the_repository) < 0)
1071
					die(_("Could not read the index"));
1072
				if (the_repository->index->split_index) {
1073
					const struct object_id *oid = &the_repository->index->split_index->base_oid;
1074
					const char *path = git_path("sharedindex.%s", oid_to_hex(oid));
1075
					print_path(path, prefix, format, DEFAULT_RELATIVE);
1076
				}
1077
				continue;
1078
			}
1079
			if (skip_prefix(arg, "--since=", &arg)) {
1080
				show_datestring("--max-age=", arg);
1081
				continue;
1082
			}
1083
			if (skip_prefix(arg, "--after=", &arg)) {
1084
				show_datestring("--max-age=", arg);
1085
				continue;
1086
			}
1087
			if (skip_prefix(arg, "--before=", &arg)) {
1088
				show_datestring("--min-age=", arg);
1089
				continue;
1090
			}
1091
			if (skip_prefix(arg, "--until=", &arg)) {
1092
				show_datestring("--min-age=", arg);
1093
				continue;
1094
			}
1095
			if (opt_with_value(arg, "--show-object-format", &arg)) {
1096
				const char *val = arg ? arg : "storage";
1097

1098
				if (strcmp(val, "storage") &&
1099
				    strcmp(val, "input") &&
1100
				    strcmp(val, "output"))
1101
					die(_("unknown mode for --show-object-format: %s"),
1102
					    arg);
1103
				puts(the_hash_algo->name);
1104
				continue;
1105
			}
1106
			if (!strcmp(arg, "--show-ref-format")) {
1107
				puts(ref_storage_format_to_name(the_repository->ref_storage_format));
1108
				continue;
1109
			}
1110
			if (!strcmp(arg, "--end-of-options")) {
1111
				seen_end_of_options = 1;
1112
				if (filter & (DO_FLAGS | DO_REVS))
1113
					show_file(arg, 0);
1114
				continue;
1115
			}
1116
			if (show_flag(arg) && verify)
1117
				die_no_single_rev(quiet);
1118
			continue;
1119
		}
1120

1121
		/* Not a flag argument */
1122
		if (try_difference(arg))
1123
			continue;
1124
		if (try_parent_shorthands(arg))
1125
			continue;
1126
		name = arg;
1127
		type = NORMAL;
1128
		if (*arg == '^') {
1129
			name++;
1130
			type = REVERSED;
1131
		}
1132
		if (!get_oid_with_context(the_repository, name,
1133
					  flags, &oid, &unused)) {
1134
			object_context_release(&unused);
1135
			if (output_algo)
1136
				repo_oid_to_algop(the_repository, &oid,
1137
						  output_algo, &oid);
1138
			if (verify)
1139
				revs_count++;
1140
			else
1141
				show_rev(type, &oid, name);
1142
			continue;
1143
		}
1144
		object_context_release(&unused);
1145
		if (verify)
1146
			die_no_single_rev(quiet);
1147
		if (has_dashdash)
1148
			die(_("bad revision '%s'"), arg);
1149
		as_is = 1;
1150
		if (!show_file(arg, output_prefix))
1151
			continue;
1152
		verify_filename(prefix, arg, 1);
1153
	}
1154
	strbuf_release(&buf);
1155
	if (verify) {
1156
		if (revs_count == 1) {
1157
			show_rev(type, &oid, name);
1158
			return 0;
1159
		} else if (revs_count == 0 && show_default())
1160
			return 0;
1161
		die_no_single_rev(quiet);
1162
	} else
1163
		show_default();
1164
	return 0;
1165
}
1166

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

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

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

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