11
#include "environment.h"
17
#include "object-name.h"
18
#include "parse-options.h"
21
#include "read-cache-ll.h"
24
#include "split-index.h"
26
#include "commit-reach.h"
28
#include "object-file-convert.h"
34
static int filter = ~0;
36
static const char *def;
40
static int show_type = NORMAL;
42
#define SHOW_SYMBOLIC_ASIS 1
43
#define SHOW_SYMBOLIC_FULL 2
47
static int abbrev_ref_strict;
51
static struct ref_exclusions ref_excludes = REF_EXCLUSIONS_INIT;
58
static int is_rev_argument(const char *arg)
60
static const char *rev_args[] = {
91
const char **p = rev_args;
94
if ((*arg == '-') && isdigit(arg[1]))
98
const char *str = *p++;
103
if (!strcmp(arg, str) ||
104
(str[len-1] == '=' && !strncmp(arg, str, len)))
110
static void show(const char *arg)
116
while ((ch = *arg++)) {
118
fputs("'\\'", stdout);
129
static void show_with_type(int type, const char *arg)
131
if (type != show_type)
137
static void show_rev(int type, const struct object_id *oid, const char *name)
139
if (!(filter & DO_REVS))
143
if ((symbolic || abbrev_ref) && name) {
144
if (symbolic == SHOW_SYMBOLIC_FULL || abbrev_ref) {
145
struct object_id discard;
148
switch (repo_dwim_ref(the_repository, name,
149
strlen(name), &discard, &full,
163
full = refs_shorten_unambiguous_ref(get_main_ref_store(the_repository),
168
show_with_type(type, full);
171
error("refname '%s' is ambiguous", name);
176
show_with_type(type, name);
181
repo_find_unique_abbrev(the_repository, oid, abbrev));
183
show_with_type(type, oid_to_hex(oid));
187
static int show_flag(const char *arg)
189
if (!(filter & DO_FLAGS))
191
if (filter & (is_rev_argument(arg) ? DO_REVS : DO_NOREV)) {
198
static int show_default(void)
203
struct object_id oid;
206
if (!repo_get_oid(the_repository, s, &oid)) {
207
show_rev(NORMAL, &oid, s);
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)
217
if (ref_excluded(&ref_excludes, refname))
219
show_rev(NORMAL, oid, refname);
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)
226
show_rev(REVERSED, oid, refname);
230
static int show_abbrev(const struct object_id *oid, void *cb_data UNUSED)
232
show_rev(NORMAL, oid, NULL);
236
static void show_datestring(const char *flag, const char *datestr)
241
if ((filter & (DO_FLAGS | DO_REVS)) != (DO_FLAGS | DO_REVS))
243
buffer = xstrfmt("%s%"PRItime, flag, approxidate(datestr));
248
static int show_file(const char *arg, int output_prefix)
251
if ((filter & (DO_NONFLAGS|DO_NOREV)) == (DO_NONFLAGS|DO_NOREV)) {
253
const char *prefix = startup_info->prefix;
254
char *fname = prefix_filename(prefix, arg);
264
static int try_difference(const char *arg)
267
struct object_id start_oid;
268
struct object_id end_oid;
272
static const char head_by_default[] = "HEAD";
274
if (!(dotdot = strstr(arg, "..")))
278
symmetric = (*end == '.');
284
end = head_by_default;
286
start = head_by_default;
288
if (start == head_by_default && end == head_by_default &&
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);
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);
310
if (repo_get_merge_bases(the_repository, a, b, &exclude) < 0)
313
struct commit *commit = pop_commit(&exclude);
314
show_rev(REVERSED, &commit->object.oid, NULL);
324
static int try_parent_shorthands(const char *arg)
327
struct object_id oid;
328
struct commit *commit;
329
struct commit_list *parents;
332
int include_parents = 0;
333
int exclude_parent = 0;
335
if ((dotdot = strstr(arg, "^!"))) {
339
} else if ((dotdot = strstr(arg, "^@"))) {
343
} else if ((dotdot = strstr(arg, "^-"))) {
349
exclude_parent = strtoul(dotdot + 2, &end, 10);
350
if (*end != '\0' || !exclude_parent)
357
if (repo_get_oid_committish(the_repository, arg, &oid) ||
358
!(commit = lookup_commit_reference(the_repository, &oid))) {
363
if (exclude_parent &&
364
exclude_parent > commit_list_count(commit->parents)) {
370
show_rev(NORMAL, &oid, arg);
371
for (parents = commit->parents, parent_number = 1;
373
parents = parents->next, parent_number++) {
376
if (exclude_parent && parent_number != exclude_parent)
380
name = xstrfmt("%s^%d", arg, parent_number);
381
show_rev(include_parents ? NORMAL : REVERSED,
382
&parents->item->object.oid, name);
390
static int parseopt_dump(const struct option *o, const char *arg, int unset)
392
struct strbuf *parsed = o->value;
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);
398
strbuf_addf(parsed, " --%s", o->long_name);
401
strbuf_addch(parsed, ' ');
402
else if (o->long_name)
403
strbuf_addch(parsed, '=');
404
sq_quote_buf(parsed, arg);
409
static const char *skipspaces(const char *s)
416
static char *findspace(const char *s)
424
static int cmd_parseopt(int argc, const char **argv, const char *prefix)
426
int keep_dashdash = 0, stop_at_non_option = 0;
427
char const * const parseopt_usage[] = {
428
N_("git rev-parse --parseopt [<options>] -- [<args>...]"),
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")),
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;
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);
456
if (strbuf_getline(&sb, stdin) == EOF)
457
die(_("premature end of input"));
458
if (!strcmp("--", sb.buf)) {
460
die(_("no usage string given before the `--' separator"));
464
strvec_push(&usage, sb.buf);
468
while (strbuf_getline(&sb, stdin) != EOF) {
476
ALLOC_GROW(opts, opts_nr + 1, opts_alloc);
477
memset(opts + opts_nr, 0, sizeof(*opts));
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));
489
o->type = OPTION_CALLBACK;
490
o->help = xstrdup(skipspaces(help+1));
492
o->flags = PARSE_OPT_NOARG;
493
o->callback = &parseopt_dump;
496
s = strpbrk(sb.buf, "*=?!");
501
die(_("missing opt-spec before option flags"));
503
if (s - sb.buf == 1) {
504
o->short_name = *sb.buf;
505
} else if (sb.buf[1] != ',') {
506
o->long_name = strvec_pushf(&longnames, "%.*s",
507
(int)(s - sb.buf), sb.buf);
509
o->short_name = *sb.buf;
510
o->long_name = strvec_pushf(&longnames, "%.*s",
511
(int)(s - sb.buf - 2), sb.buf + 2);
518
o->flags &= ~PARSE_OPT_NOARG;
521
o->flags &= ~PARSE_OPT_NOARG;
522
o->flags |= PARSE_OPT_OPTARG;
525
o->flags |= PARSE_OPT_NONEG;
528
o->flags |= PARSE_OPT_HIDDEN;
536
o->argh = xmemdupz(s, help - s);
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);
548
strbuf_addstr(&parsed, " --");
549
sq_quote_argv(&parsed, argv);
552
strbuf_release(&parsed);
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);
564
static int cmd_sq_quote(int argc, const char **argv)
566
struct strbuf buf = STRBUF_INIT;
569
sq_quote_argv(&buf, argv);
570
printf("%s\n", buf.buf);
571
strbuf_release(&buf);
576
static void die_no_single_rev(int quiet)
581
die(_("Needed a single revision"));
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"
589
"Run \"git rev-parse --parseopt -h\" for more information on the first usage.");
595
static int opt_with_value(const char *arg, const char *opt, const char **value)
597
if (skip_prefix(arg, opt, &arg)) {
610
static void handle_ref_opt(const char *pattern, const char *prefix)
613
refs_for_each_glob_ref_in(get_main_ref_store(the_repository),
614
show_reference, pattern, prefix,
617
refs_for_each_ref_in(get_main_ref_store(the_repository),
618
prefix, show_reference, NULL);
619
clear_ref_exclusions(&ref_excludes);
635
DEFAULT_RELATIVE_IF_SHARED,
642
static void print_path(const char *path, const char *prefix, enum format_type format, enum default_type def)
653
if (!prefix && (format != FORMAT_DEFAULT || def != DEFAULT_RELATIVE_IF_SHARED))
654
prefix = cwd = xgetcwd();
655
if (format == FORMAT_DEFAULT && def == DEFAULT_UNMODIFIED) {
657
} else if (format == FORMAT_RELATIVE ||
658
(format == FORMAT_DEFAULT && def == DEFAULT_RELATIVE)) {
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);
670
if (!is_absolute_path(prefix)) {
671
strbuf_realpath_forgiving(&prefixbuf, prefix, 1);
672
prefix = prefixbuf.buf;
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);
683
struct strbuf buf = STRBUF_INIT;
684
strbuf_realpath_forgiving(&buf, path, 1);
686
strbuf_release(&buf);
691
int cmd_rev_parse(int argc, const char **argv, const char *prefix)
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;
707
if (argc > 1 && !strcmp("--parseopt", argv[1]))
708
return cmd_parseopt(argc - 1, argv + 1, prefix);
710
if (argc > 1 && !strcmp("--sq-quote", argv[1]))
711
return cmd_sq_quote(argc - 2, argv + 2);
713
if (argc > 1 && !strcmp("-h", argv[1]))
714
usage(builtin_rev_parse_usage);
716
for (i = 1; i < argc; i++) {
717
if (!strcmp(argv[i], "--")) {
725
setup_git_directory();
726
git_config(git_default_config, NULL);
730
for (i = 1; i < argc; i++) {
731
const char *arg = argv[i];
734
if (show_file(arg, output_prefix) && as_is < 2)
735
verify_filename(prefix, arg, 0);
739
if (!seen_end_of_options) {
740
if (!strcmp(arg, "--local-env-vars")) {
742
for (i = 0; local_repo_env[i]; i++)
743
printf("%s\n", local_repo_env[i]);
746
if (!strcmp(arg, "--resolve-git-dir")) {
747
const char *gitdir = argv[++i];
749
die(_("--resolve-git-dir requires an argument"));
750
gitdir = resolve_gitdir(gitdir);
752
die(_("not a gitdir '%s'"), argv[i]);
759
if (!did_repo_setup) {
760
prefix = setup_git_directory();
761
git_config(git_default_config, NULL);
764
prepare_repo_settings(the_repository);
765
the_repository->settings.command_requires_full_index = 0;
766
compat = the_repository->compat_hash_algo;
769
if (!strcmp(arg, "--")) {
772
if (filter & (DO_FLAGS | DO_REVS))
777
if (!seen_end_of_options && *arg == '-') {
778
if (!strcmp(arg, "--git-path")) {
780
die(_("--git-path requires an argument"));
782
print_path(git_path("%s", argv[i + 1]), prefix,
784
DEFAULT_RELATIVE_IF_SHARED);
788
if (!strcmp(arg,"-n")) {
790
die(_("-n requires an argument"));
791
if ((filter & DO_FLAGS) && (filter & DO_REVS)) {
797
if (starts_with(arg, "-n")) {
798
if ((filter & DO_FLAGS) && (filter & DO_REVS))
802
if (opt_with_value(arg, "--path-format", &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;
810
die(_("unknown argument to --path-format: %s"), arg);
814
if (!strcmp(arg, "--default")) {
817
die(_("--default requires an argument"));
820
if (!strcmp(arg, "--prefix")) {
823
die(_("--prefix requires an argument"));
824
startup_info->prefix = prefix;
828
if (!strcmp(arg, "--revs-only")) {
832
if (!strcmp(arg, "--no-revs")) {
836
if (!strcmp(arg, "--flags")) {
837
filter &= ~DO_NONFLAGS;
840
if (!strcmp(arg, "--no-flags")) {
844
if (!strcmp(arg, "--verify")) {
845
filter &= ~(DO_FLAGS|DO_NOREV);
849
if (!strcmp(arg, "--quiet") || !strcmp(arg, "-q")) {
851
flags |= GET_OID_QUIETLY;
854
if (opt_with_value(arg, "--output-object-format", &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;
863
else if (compat && !strcmp(arg, compat->name)) {
864
flags |= GET_OID_HASH_ANY;
865
output_algo = compat;
868
else die(_("unsupported object format: %s"), arg);
870
if (opt_with_value(arg, "--short", &arg)) {
871
filter &= ~(DO_FLAGS|DO_NOREV);
873
abbrev = DEFAULT_ABBREV;
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;
883
if (!strcmp(arg, "--sq")) {
887
if (!strcmp(arg, "--not")) {
888
show_type ^= REVERSED;
891
if (!strcmp(arg, "--symbolic")) {
892
symbolic = SHOW_SYMBOLIC_ASIS;
895
if (!strcmp(arg, "--symbolic-full-name")) {
896
symbolic = SHOW_SYMBOLIC_FULL;
899
if (opt_with_value(arg, "--abbrev-ref", &arg)) {
901
abbrev_ref_strict = warn_ambiguous_refs;
903
if (!strcmp(arg, "strict"))
904
abbrev_ref_strict = 1;
905
else if (!strcmp(arg, "loose"))
906
abbrev_ref_strict = 0;
908
die(_("unknown mode for --abbrev-ref: %s"),
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);
919
if (skip_prefix(arg, "--disambiguate=", &arg)) {
920
repo_for_each_abbrev(the_repository, arg, the_hash_algo,
924
if (!strcmp(arg, "--bisect")) {
925
refs_for_each_fullref_in(get_main_ref_store(the_repository),
927
NULL, show_reference,
929
refs_for_each_fullref_in(get_main_ref_store(the_repository),
931
NULL, anti_reference,
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/");
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/");
949
if (skip_prefix(arg, "--glob=", &arg)) {
950
handle_ref_opt(arg, NULL);
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/");
960
if (skip_prefix(arg, "--exclude=", &arg)) {
961
add_ref_exclusion(&ref_excludes, arg);
964
if (skip_prefix(arg, "--exclude-hidden=", &arg)) {
965
exclude_hidden_refs(&ref_excludes, arg);
968
if (!strcmp(arg, "--show-toplevel")) {
969
const char *work_tree = get_git_work_tree();
971
print_path(work_tree, prefix, format, DEFAULT_UNMODIFIED);
973
die(_("this operation must be run in a work tree"));
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);
983
if (!strcmp(arg, "--show-prefix")) {
990
if (!strcmp(arg, "--show-cdup")) {
991
const char *pfx = prefix;
992
if (!is_inside_work_tree()) {
993
const char *work_tree =
996
printf("%s\n", work_tree);
1000
pfx = strchr(pfx, '/');
1009
if (!strcmp(arg, "--git-dir") ||
1010
!strcmp(arg, "--absolute-git-dir")) {
1011
const char *gitdir = getenv(GIT_DIR_ENVIRONMENT);
1014
enum format_type wanted = format;
1015
if (arg[2] == 'g') {
1017
print_path(gitdir, prefix, format, DEFAULT_UNMODIFIED);
1021
print_path(".git", prefix, format, DEFAULT_UNMODIFIED);
1025
wanted = FORMAT_CANONICAL;
1026
if (!gitdir && !prefix)
1029
struct strbuf realpath = STRBUF_INIT;
1030
strbuf_realpath(&realpath, gitdir, 1);
1032
strbuf_release(&realpath);
1039
strbuf_addf(&buf, "%s%s.git", cwd, len && cwd[len-1] != '/' ? "/" : "");
1041
print_path(buf.buf, prefix, wanted, DEFAULT_CANONICAL);
1044
if (!strcmp(arg, "--git-common-dir")) {
1045
print_path(get_git_common_dir(), prefix, format, DEFAULT_RELATIVE_IF_SHARED);
1048
if (!strcmp(arg, "--is-inside-git-dir")) {
1049
printf("%s\n", is_inside_git_dir() ? "true"
1053
if (!strcmp(arg, "--is-inside-work-tree")) {
1054
printf("%s\n", is_inside_work_tree() ? "true"
1058
if (!strcmp(arg, "--is-bare-repository")) {
1059
printf("%s\n", is_bare_repository() ? "true"
1063
if (!strcmp(arg, "--is-shallow-repository")) {
1065
is_repository_shallow(the_repository) ? "true"
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);
1079
if (skip_prefix(arg, "--since=", &arg)) {
1080
show_datestring("--max-age=", arg);
1083
if (skip_prefix(arg, "--after=", &arg)) {
1084
show_datestring("--max-age=", arg);
1087
if (skip_prefix(arg, "--before=", &arg)) {
1088
show_datestring("--min-age=", arg);
1091
if (skip_prefix(arg, "--until=", &arg)) {
1092
show_datestring("--min-age=", arg);
1095
if (opt_with_value(arg, "--show-object-format", &arg)) {
1096
const char *val = arg ? arg : "storage";
1098
if (strcmp(val, "storage") &&
1099
strcmp(val, "input") &&
1100
strcmp(val, "output"))
1101
die(_("unknown mode for --show-object-format: %s"),
1103
puts(the_hash_algo->name);
1106
if (!strcmp(arg, "--show-ref-format")) {
1107
puts(ref_storage_format_to_name(the_repository->ref_storage_format));
1110
if (!strcmp(arg, "--end-of-options")) {
1111
seen_end_of_options = 1;
1112
if (filter & (DO_FLAGS | DO_REVS))
1116
if (show_flag(arg) && verify)
1117
die_no_single_rev(quiet);
1122
if (try_difference(arg))
1124
if (try_parent_shorthands(arg))
1132
if (!get_oid_with_context(the_repository, name,
1133
flags, &oid, &unused)) {
1134
object_context_release(&unused);
1136
repo_oid_to_algop(the_repository, &oid,
1141
show_rev(type, &oid, name);
1144
object_context_release(&unused);
1146
die_no_single_rev(quiet);
1148
die(_("bad revision '%s'"), arg);
1150
if (!show_file(arg, output_prefix))
1152
verify_filename(prefix, arg, 1);
1154
strbuf_release(&buf);
1156
if (revs_count == 1) {
1157
show_rev(type, &oid, name);
1159
} else if (revs_count == 0 && show_default())
1161
die_no_single_rev(quiet);