2005-06-14 01:06:50 +08:00
|
|
|
/*
|
|
|
|
* rev-parse.c
|
|
|
|
*
|
|
|
|
* Copyright (C) Linus Torvalds, 2005
|
|
|
|
*/
|
2022-11-19 21:07:38 +08:00
|
|
|
#define USE_THE_INDEX_VARIABLE
|
2023-05-16 14:33:57 +08:00
|
|
|
#include "builtin.h"
|
2023-03-21 14:25:58 +08:00
|
|
|
#include "abspath.h"
|
2017-06-15 02:07:36 +08:00
|
|
|
#include "config.h"
|
2005-06-21 11:28:09 +08:00
|
|
|
#include "commit.h"
|
2023-03-21 14:26:03 +08:00
|
|
|
#include "environment.h"
|
2023-03-21 14:25:54 +08:00
|
|
|
#include "gettext.h"
|
2023-05-16 14:34:00 +08:00
|
|
|
#include "hash.h"
|
2023-02-24 08:09:27 +08:00
|
|
|
#include "hex.h"
|
2005-07-04 04:07:52 +08:00
|
|
|
#include "refs.h"
|
2005-09-21 05:13:24 +08:00
|
|
|
#include "quote.h"
|
2023-04-11 15:41:49 +08:00
|
|
|
#include "object-name.h"
|
2007-11-04 18:30:53 +08:00
|
|
|
#include "parse-options.h"
|
2023-05-16 14:33:59 +08:00
|
|
|
#include "path.h"
|
2013-11-02 03:13:01 +08:00
|
|
|
#include "diff.h"
|
2023-05-16 14:33:56 +08:00
|
|
|
#include "read-cache-ll.h"
|
2013-11-02 03:13:01 +08:00
|
|
|
#include "revision.h"
|
2023-03-21 14:26:05 +08:00
|
|
|
#include "setup.h"
|
2014-06-13 20:19:46 +08:00
|
|
|
#include "split-index.h"
|
2017-03-09 07:07:42 +08:00
|
|
|
#include "submodule.h"
|
2018-07-21 00:33:04 +08:00
|
|
|
#include "commit-reach.h"
|
2020-05-01 03:48:50 +08:00
|
|
|
#include "shallow.h"
|
2005-06-21 11:28:09 +08:00
|
|
|
|
2005-08-25 05:30:04 +08:00
|
|
|
#define DO_REVS 1
|
|
|
|
#define DO_NOREV 2
|
|
|
|
#define DO_FLAGS 4
|
|
|
|
#define DO_NONFLAGS 8
|
|
|
|
static int filter = ~0;
|
|
|
|
|
2006-08-16 01:23:48 +08:00
|
|
|
static const char *def;
|
2005-06-25 01:12:55 +08:00
|
|
|
|
2005-06-27 02:34:30 +08:00
|
|
|
#define NORMAL 0
|
|
|
|
#define REVERSED 1
|
|
|
|
static int show_type = NORMAL;
|
2008-01-06 04:09:55 +08:00
|
|
|
|
|
|
|
#define SHOW_SYMBOLIC_ASIS 1
|
|
|
|
#define SHOW_SYMBOLIC_FULL 2
|
2006-08-16 01:23:48 +08:00
|
|
|
static int symbolic;
|
|
|
|
static int abbrev;
|
2009-04-13 19:20:26 +08:00
|
|
|
static int abbrev_ref;
|
|
|
|
static int abbrev_ref_strict;
|
2006-08-16 01:23:48 +08:00
|
|
|
static int output_sq;
|
2005-08-25 05:30:04 +08:00
|
|
|
|
2013-10-31 19:08:29 +08:00
|
|
|
static int stuck_long;
|
2022-11-17 13:46:51 +08:00
|
|
|
static struct ref_exclusions ref_excludes = REF_EXCLUSIONS_INIT;
|
2013-10-31 19:08:29 +08:00
|
|
|
|
2005-06-14 02:14:20 +08:00
|
|
|
/*
|
|
|
|
* Some arguments are relevant "revision" arguments,
|
|
|
|
* others are about output format or other details.
|
|
|
|
* This sorts it all out.
|
|
|
|
*/
|
|
|
|
static int is_rev_argument(const char *arg)
|
|
|
|
{
|
|
|
|
static const char *rev_args[] = {
|
2005-10-06 05:49:54 +08:00
|
|
|
"--all",
|
2005-08-25 05:30:04 +08:00
|
|
|
"--bisect",
|
2005-10-30 17:08:35 +08:00
|
|
|
"--dense",
|
2010-01-20 17:48:26 +08:00
|
|
|
"--branches=",
|
2006-05-14 09:43:00 +08:00
|
|
|
"--branches",
|
2005-08-25 05:30:04 +08:00
|
|
|
"--header",
|
2011-05-19 09:08:09 +08:00
|
|
|
"--ignore-missing",
|
2005-06-14 02:14:20 +08:00
|
|
|
"--max-age=",
|
2005-08-25 05:30:04 +08:00
|
|
|
"--max-count=",
|
|
|
|
"--min-age=",
|
2005-08-09 10:31:37 +08:00
|
|
|
"--no-merges",
|
2011-03-21 18:14:06 +08:00
|
|
|
"--min-parents=",
|
|
|
|
"--no-min-parents",
|
|
|
|
"--max-parents=",
|
|
|
|
"--no-max-parents",
|
2005-08-25 05:30:04 +08:00
|
|
|
"--objects",
|
2006-02-19 19:32:31 +08:00
|
|
|
"--objects-edge",
|
2005-08-25 05:30:04 +08:00
|
|
|
"--parents",
|
|
|
|
"--pretty",
|
2010-01-20 17:48:26 +08:00
|
|
|
"--remotes=",
|
2006-05-14 09:43:00 +08:00
|
|
|
"--remotes",
|
2010-01-20 17:48:25 +08:00
|
|
|
"--glob=",
|
2005-10-30 17:08:35 +08:00
|
|
|
"--sparse",
|
2010-01-20 17:48:26 +08:00
|
|
|
"--tags=",
|
2006-05-14 09:43:00 +08:00
|
|
|
"--tags",
|
2005-08-25 05:30:04 +08:00
|
|
|
"--topo-order",
|
2006-02-16 14:05:33 +08:00
|
|
|
"--date-order",
|
2005-08-25 05:30:04 +08:00
|
|
|
"--unpacked",
|
2005-06-14 02:14:20 +08:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
const char **p = rev_args;
|
|
|
|
|
2006-01-30 08:28:02 +08:00
|
|
|
/* accept -<digit>, like traditional "head" */
|
|
|
|
if ((*arg == '-') && isdigit(arg[1]))
|
|
|
|
return 1;
|
|
|
|
|
2005-06-14 02:14:20 +08:00
|
|
|
for (;;) {
|
|
|
|
const char *str = *p++;
|
|
|
|
int len;
|
|
|
|
if (!str)
|
|
|
|
return 0;
|
|
|
|
len = strlen(str);
|
2005-08-25 05:30:04 +08:00
|
|
|
if (!strcmp(arg, str) ||
|
|
|
|
(str[len-1] == '=' && !strncmp(arg, str, len)))
|
2005-06-14 02:14:20 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-08-25 05:30:04 +08:00
|
|
|
/* Output argument as a string, either SQ or normal */
|
[PATCH] Help scripts that use git-rev-parse to grok args with SP/TAB/LF
The git-rev-parse command uses LF to separate each argument it
parses, so its users at least need to set IFS to LF to be able
to handle filenames with embedded SPs and TABs. Some commands,
however, can take and do expect arguments with embedded LF,
notably, "-S" (pickaxe) of diff family, so even this workaround
does not work for them.
When --sq flag to git-rev-parse is given, instead of showing one
argument per line, it outputs arguments quoted for consumption
with "eval" by the caller, to remedy this situation.
As an example, this patch converts git-whatchanged to use this
new feature.
Signed-off-by: Junio C Hamano <junkio@cox.net>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-07-23 10:08:32 +08:00
|
|
|
static void show(const char *arg)
|
|
|
|
{
|
|
|
|
if (output_sq) {
|
|
|
|
int sq = '\'', ch;
|
|
|
|
|
|
|
|
putchar(sq);
|
|
|
|
while ((ch = *arg++)) {
|
|
|
|
if (ch == sq)
|
|
|
|
fputs("'\\'", stdout);
|
|
|
|
putchar(ch);
|
|
|
|
}
|
|
|
|
putchar(sq);
|
|
|
|
putchar(' ');
|
|
|
|
}
|
|
|
|
else
|
|
|
|
puts(arg);
|
|
|
|
}
|
|
|
|
|
2008-05-23 22:13:05 +08:00
|
|
|
/* Like show(), but with a negation prefix according to type */
|
|
|
|
static void show_with_type(int type, const char *arg)
|
|
|
|
{
|
|
|
|
if (type != show_type)
|
|
|
|
putchar('^');
|
|
|
|
show(arg);
|
|
|
|
}
|
|
|
|
|
2005-08-25 05:30:04 +08:00
|
|
|
/* Output a revision, only if filter allows it */
|
2017-05-01 10:29:02 +08:00
|
|
|
static void show_rev(int type, const struct object_id *oid, const char *name)
|
2005-06-25 01:12:55 +08:00
|
|
|
{
|
2005-08-25 05:30:04 +08:00
|
|
|
if (!(filter & DO_REVS))
|
2005-06-25 01:12:55 +08:00
|
|
|
return;
|
2005-08-25 05:30:04 +08:00
|
|
|
def = NULL;
|
[PATCH] Help scripts that use git-rev-parse to grok args with SP/TAB/LF
The git-rev-parse command uses LF to separate each argument it
parses, so its users at least need to set IFS to LF to be able
to handle filenames with embedded SPs and TABs. Some commands,
however, can take and do expect arguments with embedded LF,
notably, "-S" (pickaxe) of diff family, so even this workaround
does not work for them.
When --sq flag to git-rev-parse is given, instead of showing one
argument per line, it outputs arguments quoted for consumption
with "eval" by the caller, to remedy this situation.
As an example, this patch converts git-whatchanged to use this
new feature.
Signed-off-by: Junio C Hamano <junkio@cox.net>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-07-23 10:08:32 +08:00
|
|
|
|
2009-04-13 19:20:26 +08:00
|
|
|
if ((symbolic || abbrev_ref) && name) {
|
|
|
|
if (symbolic == SHOW_SYMBOLIC_FULL || abbrev_ref) {
|
2017-05-01 10:29:02 +08:00
|
|
|
struct object_id discard;
|
2008-01-06 04:09:55 +08:00
|
|
|
char *full;
|
|
|
|
|
2023-03-28 21:58:54 +08:00
|
|
|
switch (repo_dwim_ref(the_repository, name,
|
|
|
|
strlen(name), &discard, &full,
|
|
|
|
0)) {
|
2008-01-06 04:09:55 +08:00
|
|
|
case 0:
|
|
|
|
/*
|
|
|
|
* Not found -- not a ref. We could
|
|
|
|
* emit "name" here, but symbolic-full
|
|
|
|
* users are interested in finding the
|
|
|
|
* refs spelled in full, and they would
|
|
|
|
* need to filter non-refs if we did so.
|
|
|
|
*/
|
|
|
|
break;
|
|
|
|
case 1: /* happy */
|
2023-06-17 14:40:43 +08:00
|
|
|
if (abbrev_ref) {
|
|
|
|
char *old = full;
|
2009-04-13 19:20:26 +08:00
|
|
|
full = shorten_unambiguous_ref(full,
|
|
|
|
abbrev_ref_strict);
|
2023-06-17 14:40:43 +08:00
|
|
|
free(old);
|
|
|
|
}
|
2008-05-23 22:13:05 +08:00
|
|
|
show_with_type(type, full);
|
2008-01-06 04:09:55 +08:00
|
|
|
break;
|
|
|
|
default: /* ambiguous */
|
|
|
|
error("refname '%s' is ambiguous", name);
|
|
|
|
break;
|
|
|
|
}
|
2014-07-24 12:41:11 +08:00
|
|
|
free(full);
|
2008-01-06 04:09:55 +08:00
|
|
|
} else {
|
2008-05-23 22:13:05 +08:00
|
|
|
show_with_type(type, name);
|
2008-01-06 04:09:55 +08:00
|
|
|
}
|
|
|
|
}
|
2006-01-25 17:35:38 +08:00
|
|
|
else if (abbrev)
|
2023-03-28 21:58:46 +08:00
|
|
|
show_with_type(type,
|
|
|
|
repo_find_unique_abbrev(the_repository, oid, abbrev));
|
2005-08-17 03:36:46 +08:00
|
|
|
else
|
2017-05-01 10:29:02 +08:00
|
|
|
show_with_type(type, oid_to_hex(oid));
|
2005-06-25 01:12:55 +08:00
|
|
|
}
|
|
|
|
|
2005-08-25 05:30:04 +08:00
|
|
|
/* Output a flag, only if filter allows it. */
|
2006-06-06 13:36:21 +08:00
|
|
|
static int show_flag(const char *arg)
|
2005-06-25 01:12:55 +08:00
|
|
|
{
|
2005-08-25 05:30:04 +08:00
|
|
|
if (!(filter & DO_FLAGS))
|
2006-02-06 03:58:34 +08:00
|
|
|
return 0;
|
|
|
|
if (filter & (is_rev_argument(arg) ? DO_REVS : DO_NOREV)) {
|
2005-08-24 01:47:54 +08:00
|
|
|
show(arg);
|
2006-02-06 03:58:34 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
2005-06-25 01:12:55 +08:00
|
|
|
}
|
|
|
|
|
2008-05-12 00:28:25 +08:00
|
|
|
static int show_default(void)
|
2005-06-25 01:12:55 +08:00
|
|
|
{
|
2006-06-06 13:36:21 +08:00
|
|
|
const char *s = def;
|
2005-06-25 01:12:55 +08:00
|
|
|
|
|
|
|
if (s) {
|
2017-05-01 10:29:02 +08:00
|
|
|
struct object_id oid;
|
2005-06-25 01:12:55 +08:00
|
|
|
|
|
|
|
def = NULL;
|
2023-03-28 21:58:46 +08:00
|
|
|
if (!repo_get_oid(the_repository, s, &oid)) {
|
2017-05-01 10:29:02 +08:00
|
|
|
show_rev(NORMAL, &oid, s);
|
2008-05-12 00:28:25 +08:00
|
|
|
return 1;
|
2005-06-25 01:12:55 +08:00
|
|
|
}
|
|
|
|
}
|
2008-05-12 00:28:25 +08:00
|
|
|
return 0;
|
2005-06-25 01:12:55 +08:00
|
|
|
}
|
|
|
|
|
2022-08-19 18:08:32 +08:00
|
|
|
static int show_reference(const char *refname, const struct object_id *oid,
|
2022-08-26 01:09:48 +08:00
|
|
|
int flag UNUSED, void *cb_data UNUSED)
|
2005-07-04 04:07:52 +08:00
|
|
|
{
|
2022-11-17 13:46:51 +08:00
|
|
|
if (ref_excluded(&ref_excludes, refname))
|
2013-11-02 03:13:01 +08:00
|
|
|
return 0;
|
2017-05-01 10:29:02 +08:00
|
|
|
show_rev(NORMAL, oid, refname);
|
2005-07-04 04:07:52 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-08-19 18:08:32 +08:00
|
|
|
static int anti_reference(const char *refname, const struct object_id *oid,
|
2022-08-26 01:09:48 +08:00
|
|
|
int flag UNUSED, void *cb_data UNUSED)
|
2009-10-28 02:28:07 +08:00
|
|
|
{
|
2017-05-01 10:29:02 +08:00
|
|
|
show_rev(REVERSED, oid, refname);
|
2009-10-28 02:28:07 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-07-03 14:44:31 +08:00
|
|
|
static int show_abbrev(const struct object_id *oid, void *cb_data UNUSED)
|
2012-07-04 05:21:59 +08:00
|
|
|
{
|
2017-05-01 10:29:02 +08:00
|
|
|
show_rev(NORMAL, oid, NULL);
|
2012-07-04 05:21:59 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-09-21 05:13:24 +08:00
|
|
|
static void show_datestring(const char *flag, const char *datestr)
|
|
|
|
{
|
2017-03-29 03:46:50 +08:00
|
|
|
char *buffer;
|
2005-09-21 05:13:24 +08:00
|
|
|
|
|
|
|
/* date handling requires both flags and revs */
|
|
|
|
if ((filter & (DO_FLAGS | DO_REVS)) != (DO_FLAGS | DO_REVS))
|
|
|
|
return;
|
2017-04-21 18:45:48 +08:00
|
|
|
buffer = xstrfmt("%s%"PRItime, flag, approxidate(datestr));
|
2005-09-21 05:13:24 +08:00
|
|
|
show(buffer);
|
2017-03-29 03:46:50 +08:00
|
|
|
free(buffer);
|
2005-09-21 05:13:24 +08:00
|
|
|
}
|
|
|
|
|
2013-06-16 22:18:17 +08:00
|
|
|
static int show_file(const char *arg, int output_prefix)
|
2005-10-18 15:16:45 +08:00
|
|
|
{
|
2005-10-26 06:24:55 +08:00
|
|
|
show_default();
|
2006-02-06 13:41:47 +08:00
|
|
|
if ((filter & (DO_NONFLAGS|DO_NOREV)) == (DO_NONFLAGS|DO_NOREV)) {
|
2013-06-16 22:18:17 +08:00
|
|
|
if (output_prefix) {
|
|
|
|
const char *prefix = startup_info->prefix;
|
2017-03-21 09:28:49 +08:00
|
|
|
char *fname = prefix_filename(prefix, arg);
|
|
|
|
show(fname);
|
|
|
|
free(fname);
|
2013-06-16 22:18:17 +08:00
|
|
|
} else
|
|
|
|
show(arg);
|
2006-02-06 13:41:47 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
2005-10-18 15:16:45 +08:00
|
|
|
}
|
|
|
|
|
2006-07-06 15:16:35 +08:00
|
|
|
static int try_difference(const char *arg)
|
2006-07-04 17:02:22 +08:00
|
|
|
{
|
|
|
|
char *dotdot;
|
2018-02-15 02:59:27 +08:00
|
|
|
struct object_id start_oid;
|
|
|
|
struct object_id end_oid;
|
|
|
|
const char *end;
|
|
|
|
const char *start;
|
2006-07-04 17:02:22 +08:00
|
|
|
int symmetric;
|
2011-05-03 04:39:16 +08:00
|
|
|
static const char head_by_default[] = "HEAD";
|
2006-07-04 17:02:22 +08:00
|
|
|
|
|
|
|
if (!(dotdot = strstr(arg, "..")))
|
|
|
|
return 0;
|
2018-02-15 02:59:27 +08:00
|
|
|
end = dotdot + 2;
|
|
|
|
start = arg;
|
|
|
|
symmetric = (*end == '.');
|
2006-07-04 17:02:22 +08:00
|
|
|
|
|
|
|
*dotdot = 0;
|
2018-02-15 02:59:27 +08:00
|
|
|
end += symmetric;
|
2006-07-04 17:02:22 +08:00
|
|
|
|
2018-02-15 02:59:27 +08:00
|
|
|
if (!*end)
|
|
|
|
end = head_by_default;
|
2006-07-04 17:02:22 +08:00
|
|
|
if (dotdot == arg)
|
2018-02-15 02:59:27 +08:00
|
|
|
start = head_by_default;
|
2011-05-03 04:39:16 +08:00
|
|
|
|
2018-02-15 02:59:27 +08:00
|
|
|
if (start == head_by_default && end == head_by_default &&
|
2011-05-03 04:39:16 +08:00
|
|
|
!symmetric) {
|
|
|
|
/*
|
|
|
|
* Just ".."? That is not a range but the
|
|
|
|
* pathspec for the parent directory.
|
|
|
|
*/
|
|
|
|
*dotdot = '.';
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-03-28 21:58:46 +08:00
|
|
|
if (!repo_get_oid_committish(the_repository, start, &start_oid) && !repo_get_oid_committish(the_repository, end, &end_oid)) {
|
2018-02-15 02:59:27 +08:00
|
|
|
show_rev(NORMAL, &end_oid, end);
|
|
|
|
show_rev(symmetric ? NORMAL : REVERSED, &start_oid, start);
|
2006-07-04 17:02:22 +08:00
|
|
|
if (symmetric) {
|
|
|
|
struct commit_list *exclude;
|
|
|
|
struct commit *a, *b;
|
2018-06-29 09:21:58 +08:00
|
|
|
a = lookup_commit_reference(the_repository, &start_oid);
|
|
|
|
b = lookup_commit_reference(the_repository, &end_oid);
|
2018-05-24 14:27:33 +08:00
|
|
|
if (!a || !b) {
|
|
|
|
*dotdot = '.';
|
|
|
|
return 0;
|
|
|
|
}
|
2023-03-28 21:58:47 +08:00
|
|
|
exclude = repo_get_merge_bases(the_repository, a, b);
|
2006-07-04 17:02:22 +08:00
|
|
|
while (exclude) {
|
2015-10-25 00:21:31 +08:00
|
|
|
struct commit *commit = pop_commit(&exclude);
|
2017-05-01 10:29:02 +08:00
|
|
|
show_rev(REVERSED, &commit->object.oid, NULL);
|
2006-07-04 17:02:22 +08:00
|
|
|
}
|
|
|
|
}
|
rev-parse: be more careful with munging arguments
When rev-parse looks at whether an argument like "foo..bar" or
"foobar^@" is a difference or parent-shorthand, it internally
munges the arguments so that it can pass the individual rev
arguments to get_sha1(). However, we do not consistently un-munge
the result.
For cases where we do not match (e.g., "doesnotexist..HEAD"), we
would then want to try to treat the argument as a filename.
try_difference gets() this right, and always unmunges in this case.
However, try_parent_shorthand() never unmunges, leading to incorrect
error messages, or even incorrect results:
$ git rev-parse foobar^@
foobar
fatal: ambiguous argument 'foobar': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'
$ >foobar
$ git rev-parse foobar^@
foobar
For cases where we do match, neither function unmunges. This does
not currently matter, since we are done with the argument. However,
a future patch will do further processing, and this prepares for
it. In addition, it's simply a confusing interface for some cases to
modify the const argument, and others not to.
Signed-off-by: Jeff King <peff@peff.net>
Reviewed-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-12-07 06:07:52 +08:00
|
|
|
*dotdot = '.';
|
2006-07-04 17:02:22 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
*dotdot = '.';
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-07-27 00:37:56 +08:00
|
|
|
static int try_parent_shorthands(const char *arg)
|
|
|
|
{
|
|
|
|
char *dotdot;
|
2017-05-01 10:29:02 +08:00
|
|
|
struct object_id oid;
|
2008-07-27 00:37:56 +08:00
|
|
|
struct commit *commit;
|
|
|
|
struct commit_list *parents;
|
2016-09-27 16:32:49 +08:00
|
|
|
int parent_number;
|
|
|
|
int include_rev = 0;
|
|
|
|
int include_parents = 0;
|
|
|
|
int exclude_parent = 0;
|
|
|
|
|
|
|
|
if ((dotdot = strstr(arg, "^!"))) {
|
|
|
|
include_rev = 1;
|
|
|
|
if (dotdot[2])
|
|
|
|
return 0;
|
|
|
|
} else if ((dotdot = strstr(arg, "^@"))) {
|
|
|
|
include_parents = 1;
|
|
|
|
if (dotdot[2])
|
|
|
|
return 0;
|
|
|
|
} else if ((dotdot = strstr(arg, "^-"))) {
|
|
|
|
include_rev = 1;
|
|
|
|
exclude_parent = 1;
|
|
|
|
|
|
|
|
if (dotdot[2]) {
|
|
|
|
char *end;
|
|
|
|
exclude_parent = strtoul(dotdot + 2, &end, 10);
|
|
|
|
if (*end != '\0' || !exclude_parent)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else
|
2008-07-27 00:37:56 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
*dotdot = 0;
|
2023-03-28 21:58:46 +08:00
|
|
|
if (repo_get_oid_committish(the_repository, arg, &oid) ||
|
2018-06-29 09:21:58 +08:00
|
|
|
!(commit = lookup_commit_reference(the_repository, &oid))) {
|
rev-parse: be more careful with munging arguments
When rev-parse looks at whether an argument like "foo..bar" or
"foobar^@" is a difference or parent-shorthand, it internally
munges the arguments so that it can pass the individual rev
arguments to get_sha1(). However, we do not consistently un-munge
the result.
For cases where we do not match (e.g., "doesnotexist..HEAD"), we
would then want to try to treat the argument as a filename.
try_difference gets() this right, and always unmunges in this case.
However, try_parent_shorthand() never unmunges, leading to incorrect
error messages, or even incorrect results:
$ git rev-parse foobar^@
foobar
fatal: ambiguous argument 'foobar': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'
$ >foobar
$ git rev-parse foobar^@
foobar
For cases where we do match, neither function unmunges. This does
not currently matter, since we are done with the argument. However,
a future patch will do further processing, and this prepares for
it. In addition, it's simply a confusing interface for some cases to
modify the const argument, and others not to.
Signed-off-by: Jeff King <peff@peff.net>
Reviewed-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-12-07 06:07:52 +08:00
|
|
|
*dotdot = '^';
|
2008-07-27 00:37:56 +08:00
|
|
|
return 0;
|
rev-parse: be more careful with munging arguments
When rev-parse looks at whether an argument like "foo..bar" or
"foobar^@" is a difference or parent-shorthand, it internally
munges the arguments so that it can pass the individual rev
arguments to get_sha1(). However, we do not consistently un-munge
the result.
For cases where we do not match (e.g., "doesnotexist..HEAD"), we
would then want to try to treat the argument as a filename.
try_difference gets() this right, and always unmunges in this case.
However, try_parent_shorthand() never unmunges, leading to incorrect
error messages, or even incorrect results:
$ git rev-parse foobar^@
foobar
fatal: ambiguous argument 'foobar': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'
$ >foobar
$ git rev-parse foobar^@
foobar
For cases where we do match, neither function unmunges. This does
not currently matter, since we are done with the argument. However,
a future patch will do further processing, and this prepares for
it. In addition, it's simply a confusing interface for some cases to
modify the const argument, and others not to.
Signed-off-by: Jeff King <peff@peff.net>
Reviewed-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-12-07 06:07:52 +08:00
|
|
|
}
|
2008-07-27 00:37:56 +08:00
|
|
|
|
2016-09-27 16:32:49 +08:00
|
|
|
if (exclude_parent &&
|
|
|
|
exclude_parent > commit_list_count(commit->parents)) {
|
|
|
|
*dotdot = '^';
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (include_rev)
|
2017-05-01 10:29:02 +08:00
|
|
|
show_rev(NORMAL, &oid, arg);
|
2016-09-27 16:32:49 +08:00
|
|
|
for (parents = commit->parents, parent_number = 1;
|
|
|
|
parents;
|
|
|
|
parents = parents->next, parent_number++) {
|
2016-11-16 16:46:26 +08:00
|
|
|
char *name = NULL;
|
|
|
|
|
2016-09-27 16:32:49 +08:00
|
|
|
if (exclude_parent && parent_number != exclude_parent)
|
|
|
|
continue;
|
|
|
|
|
2016-11-16 16:46:26 +08:00
|
|
|
if (symbolic)
|
|
|
|
name = xstrfmt("%s^%d", arg, parent_number);
|
2016-09-27 16:32:49 +08:00
|
|
|
show_rev(include_parents ? NORMAL : REVERSED,
|
2017-05-01 10:29:02 +08:00
|
|
|
&parents->item->object.oid, name);
|
2016-11-16 16:46:26 +08:00
|
|
|
free(name);
|
2016-09-27 16:32:49 +08:00
|
|
|
}
|
2008-07-27 00:37:56 +08:00
|
|
|
|
rev-parse: be more careful with munging arguments
When rev-parse looks at whether an argument like "foo..bar" or
"foobar^@" is a difference or parent-shorthand, it internally
munges the arguments so that it can pass the individual rev
arguments to get_sha1(). However, we do not consistently un-munge
the result.
For cases where we do not match (e.g., "doesnotexist..HEAD"), we
would then want to try to treat the argument as a filename.
try_difference gets() this right, and always unmunges in this case.
However, try_parent_shorthand() never unmunges, leading to incorrect
error messages, or even incorrect results:
$ git rev-parse foobar^@
foobar
fatal: ambiguous argument 'foobar': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'
$ >foobar
$ git rev-parse foobar^@
foobar
For cases where we do match, neither function unmunges. This does
not currently matter, since we are done with the argument. However,
a future patch will do further processing, and this prepares for
it. In addition, it's simply a confusing interface for some cases to
modify the const argument, and others not to.
Signed-off-by: Jeff King <peff@peff.net>
Reviewed-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-12-07 06:07:52 +08:00
|
|
|
*dotdot = '^';
|
2008-07-27 00:37:56 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2007-11-04 18:30:53 +08:00
|
|
|
static int parseopt_dump(const struct option *o, const char *arg, int unset)
|
|
|
|
{
|
|
|
|
struct strbuf *parsed = o->value;
|
|
|
|
if (unset)
|
|
|
|
strbuf_addf(parsed, " --no-%s", o->long_name);
|
2013-10-31 19:08:29 +08:00
|
|
|
else if (o->short_name && (o->long_name == NULL || !stuck_long))
|
2007-11-04 18:30:53 +08:00
|
|
|
strbuf_addf(parsed, " -%c", o->short_name);
|
|
|
|
else
|
|
|
|
strbuf_addf(parsed, " --%s", o->long_name);
|
|
|
|
if (arg) {
|
2013-10-31 19:08:29 +08:00
|
|
|
if (!stuck_long)
|
|
|
|
strbuf_addch(parsed, ' ');
|
|
|
|
else if (o->long_name)
|
|
|
|
strbuf_addch(parsed, '=');
|
2007-11-04 18:30:53 +08:00
|
|
|
sq_quote_buf(parsed, arg);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *skipspaces(const char *s)
|
|
|
|
{
|
|
|
|
while (isspace(*s))
|
|
|
|
s++;
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2017-09-18 06:28:16 +08:00
|
|
|
static char *findspace(const char *s)
|
|
|
|
{
|
|
|
|
for (; *s; s++)
|
|
|
|
if (isspace(*s))
|
|
|
|
return (char*)s;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-11-04 18:30:53 +08:00
|
|
|
static int cmd_parseopt(int argc, const char **argv, const char *prefix)
|
|
|
|
{
|
2009-06-14 07:58:43 +08:00
|
|
|
static int keep_dashdash = 0, stop_at_non_option = 0;
|
2007-11-04 18:30:53 +08:00
|
|
|
static char const * const parseopt_usage[] = {
|
2015-01-13 15:44:47 +08:00
|
|
|
N_("git rev-parse --parseopt [<options>] -- [<args>...]"),
|
2007-11-04 18:30:53 +08:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
static struct option parseopt_opts[] = {
|
2013-08-03 19:51:19 +08:00
|
|
|
OPT_BOOL(0, "keep-dashdash", &keep_dashdash,
|
2012-08-20 20:32:40 +08:00
|
|
|
N_("keep the `--` passed as an arg")),
|
2013-08-03 19:51:19 +08:00
|
|
|
OPT_BOOL(0, "stop-at-non-option", &stop_at_non_option,
|
2012-08-20 20:32:40 +08:00
|
|
|
N_("stop parsing after the "
|
|
|
|
"first non-option argument")),
|
2013-10-31 19:08:29 +08:00
|
|
|
OPT_BOOL(0, "stuck-long", &stuck_long,
|
|
|
|
N_("output in stuck long form")),
|
2007-11-04 18:30:53 +08:00
|
|
|
OPT_END(),
|
|
|
|
};
|
2015-07-14 16:17:44 +08:00
|
|
|
static const char * const flag_chars = "*=?!";
|
2007-11-04 18:30:53 +08:00
|
|
|
|
2008-10-10 03:12:12 +08:00
|
|
|
struct strbuf sb = STRBUF_INIT, parsed = STRBUF_INIT;
|
2007-11-04 18:30:53 +08:00
|
|
|
const char **usage = NULL;
|
|
|
|
struct option *opts = NULL;
|
|
|
|
int onb = 0, osz = 0, unb = 0, usz = 0;
|
|
|
|
|
|
|
|
strbuf_addstr(&parsed, "set --");
|
2009-05-24 02:53:12 +08:00
|
|
|
argc = parse_options(argc, argv, prefix, parseopt_opts, parseopt_usage,
|
2007-11-04 18:30:53 +08:00
|
|
|
PARSE_OPT_KEEP_DASHDASH);
|
|
|
|
if (argc < 1 || strcmp(argv[0], "--"))
|
|
|
|
usage_with_options(parseopt_usage, parseopt_opts);
|
|
|
|
|
|
|
|
/* get the usage up to the first line with a -- on it */
|
|
|
|
for (;;) {
|
2015-10-29 04:59:44 +08:00
|
|
|
if (strbuf_getline(&sb, stdin) == EOF)
|
2021-05-17 16:02:43 +08:00
|
|
|
die(_("premature end of input"));
|
2007-11-04 18:30:53 +08:00
|
|
|
ALLOC_GROW(usage, unb + 1, usz);
|
|
|
|
if (!strcmp("--", sb.buf)) {
|
|
|
|
if (unb < 1)
|
2021-05-17 16:02:43 +08:00
|
|
|
die(_("no usage string given before the `--' separator"));
|
2007-11-04 18:30:53 +08:00
|
|
|
usage[unb] = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
usage[unb++] = strbuf_detach(&sb, NULL);
|
|
|
|
}
|
|
|
|
|
2014-03-22 17:47:34 +08:00
|
|
|
/* parse: (<short>|<short>,<long>|<long>)[*=?!]*<arghint>? SP+ <help> */
|
2015-10-29 04:59:44 +08:00
|
|
|
while (strbuf_getline(&sb, stdin) != EOF) {
|
2007-11-04 18:30:53 +08:00
|
|
|
const char *s;
|
2017-09-18 06:28:15 +08:00
|
|
|
char *help;
|
2007-11-04 18:30:53 +08:00
|
|
|
struct option *o;
|
|
|
|
|
|
|
|
if (!sb.len)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
ALLOC_GROW(opts, onb + 1, osz);
|
|
|
|
memset(opts + onb, 0, sizeof(opts[onb]));
|
|
|
|
|
|
|
|
o = &opts[onb++];
|
2017-09-18 06:28:16 +08:00
|
|
|
help = findspace(sb.buf);
|
|
|
|
if (!help || sb.buf == help) {
|
2007-11-04 18:30:53 +08:00
|
|
|
o->type = OPTION_GROUP;
|
2008-02-26 12:07:39 +08:00
|
|
|
o->help = xstrdup(skipspaces(sb.buf));
|
2007-11-04 18:30:53 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-09-18 06:28:15 +08:00
|
|
|
*help = '\0';
|
|
|
|
|
2007-11-04 18:30:53 +08:00
|
|
|
o->type = OPTION_CALLBACK;
|
2017-09-18 06:28:15 +08:00
|
|
|
o->help = xstrdup(skipspaces(help+1));
|
2007-11-04 18:30:53 +08:00
|
|
|
o->value = &parsed;
|
2008-03-02 16:21:38 +08:00
|
|
|
o->flags = PARSE_OPT_NOARG;
|
2007-11-04 18:30:53 +08:00
|
|
|
o->callback = &parseopt_dump;
|
2014-03-22 17:47:34 +08:00
|
|
|
|
2015-07-14 16:17:44 +08:00
|
|
|
/* name(s) */
|
|
|
|
s = strpbrk(sb.buf, flag_chars);
|
2022-05-03 00:50:37 +08:00
|
|
|
if (!s)
|
2015-07-14 16:17:44 +08:00
|
|
|
s = help;
|
|
|
|
|
2022-09-03 01:59:02 +08:00
|
|
|
if (s == sb.buf)
|
|
|
|
die(_("missing opt-spec before option flags"));
|
|
|
|
|
2015-07-14 16:17:44 +08:00
|
|
|
if (s - sb.buf == 1) /* short option only */
|
|
|
|
o->short_name = *sb.buf;
|
|
|
|
else if (sb.buf[1] != ',') /* long option only */
|
|
|
|
o->long_name = xmemdupz(sb.buf, s - sb.buf);
|
|
|
|
else {
|
|
|
|
o->short_name = *sb.buf;
|
|
|
|
o->long_name = xmemdupz(sb.buf + 2, s - sb.buf - 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
while (s < help) {
|
|
|
|
switch (*s++) {
|
2008-03-02 16:21:38 +08:00
|
|
|
case '=':
|
|
|
|
o->flags &= ~PARSE_OPT_NOARG;
|
2015-07-14 16:17:44 +08:00
|
|
|
continue;
|
2008-03-02 16:21:38 +08:00
|
|
|
case '?':
|
|
|
|
o->flags &= ~PARSE_OPT_NOARG;
|
|
|
|
o->flags |= PARSE_OPT_OPTARG;
|
2015-07-14 16:17:44 +08:00
|
|
|
continue;
|
2008-03-02 16:21:38 +08:00
|
|
|
case '!':
|
|
|
|
o->flags |= PARSE_OPT_NONEG;
|
2015-07-14 16:17:44 +08:00
|
|
|
continue;
|
2008-03-02 16:21:38 +08:00
|
|
|
case '*':
|
|
|
|
o->flags |= PARSE_OPT_HIDDEN;
|
2015-07-14 16:17:44 +08:00
|
|
|
continue;
|
2008-03-02 16:21:38 +08:00
|
|
|
}
|
2015-07-14 16:17:44 +08:00
|
|
|
s--;
|
|
|
|
break;
|
2007-11-04 18:30:53 +08:00
|
|
|
}
|
|
|
|
|
2015-07-14 16:17:44 +08:00
|
|
|
if (s < help)
|
|
|
|
o->argh = xmemdupz(s, help - s);
|
2007-11-04 18:30:53 +08:00
|
|
|
}
|
|
|
|
strbuf_release(&sb);
|
|
|
|
|
|
|
|
/* put an OPT_END() */
|
|
|
|
ALLOC_GROW(opts, onb + 1, osz);
|
|
|
|
memset(opts + onb, 0, sizeof(opts[onb]));
|
2009-05-24 02:53:12 +08:00
|
|
|
argc = parse_options(argc, argv, prefix, opts, usage,
|
2010-07-06 22:46:05 +08:00
|
|
|
(keep_dashdash ? PARSE_OPT_KEEP_DASHDASH : 0) |
|
2010-07-08 02:18:26 +08:00
|
|
|
(stop_at_non_option ? PARSE_OPT_STOP_AT_NON_OPTION : 0) |
|
2010-06-12 20:57:39 +08:00
|
|
|
PARSE_OPT_SHELL_EVAL);
|
2007-11-04 18:30:53 +08:00
|
|
|
|
2016-07-31 01:36:23 +08:00
|
|
|
strbuf_addstr(&parsed, " --");
|
2018-01-15 18:59:43 +08:00
|
|
|
sq_quote_argv(&parsed, argv);
|
2007-11-04 18:30:53 +08:00
|
|
|
puts(parsed.buf);
|
built-ins & libs & helpers: add/move destructors, fix leaks
Fix various leaks in built-ins, libraries and a test helper here we
were missing a call to strbuf_release(), string_list_clear() etc, or
were calling them after a potential "return".
Comments on individual changes:
- builtin/checkout.c: Fix a memory leak that was introduced in [1]. A
sibling leak introduced in [2] was recently fixed in [3]. As with [3]
we should be using the wt_status_state_free_buffers() API introduced
in [4].
- builtin/repack.c: Fix a leak that's been here since this use of
"strbuf_release()" was added in a1bbc6c0176 (repack: rewrite the shell
script in C, 2013-09-15). We don't use the variable for anything
except this loop, so we can instead free it right afterwards.
- builtin/rev-parse: Fix a leak that's been here since this code was
added in 21d47835386 (Add a parseopt mode to git-rev-parse to bring
parse-options to shell scripts., 2007-11-04).
- builtin/stash.c: Fix a couple of leaks that have been here since
this code was added in d4788af875c (stash: convert create to builtin,
2019-02-25), we strbuf_release()'d only some of the "struct strbuf" we
allocated earlier in the function, let's release all of them.
- ref-filter.c: Fix a leak in 482c1191869 (gpg-interface: improve
interface for parsing tags, 2021-02-11), we don't use the "payload"
variable that we ask parse_signature() to populate for us, so let's
free it.
- t/helper/test-fake-ssh.c: Fix a leak that's been here since this
code was added in 3064d5a38c7 (mingw: fix t5601-clone.sh,
2016-01-27). Let's free the "struct strbuf" as soon as we don't need
it anymore.
1. c45f0f525de (switch: reject if some operation is in progress,
2019-03-29)
2. 2708ce62d21 (branch: sort detached HEAD based on a flag,
2021-01-07)
3. abcac2e19fa (ref-filter.c: fix a leak in get_head_description,
2022-09-25)
4. 962dd7ebc3e (wt-status: introduce wt_status_state_free_buffers(),
2020-09-27).
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
2022-11-09 02:17:42 +08:00
|
|
|
strbuf_release(&parsed);
|
2007-11-04 18:30:53 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-04-25 12:55:26 +08:00
|
|
|
static int cmd_sq_quote(int argc, const char **argv)
|
|
|
|
{
|
|
|
|
struct strbuf buf = STRBUF_INIT;
|
|
|
|
|
|
|
|
if (argc)
|
2018-01-15 18:59:43 +08:00
|
|
|
sq_quote_argv(&buf, argv);
|
2009-04-25 12:55:26 +08:00
|
|
|
printf("%s\n", buf.buf);
|
|
|
|
strbuf_release(&buf);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-04-26 19:57:23 +08:00
|
|
|
static void die_no_single_rev(int quiet)
|
|
|
|
{
|
|
|
|
if (quiet)
|
|
|
|
exit(1);
|
|
|
|
else
|
2021-05-17 16:02:43 +08:00
|
|
|
die(_("Needed a single revision"));
|
2008-04-26 19:57:23 +08:00
|
|
|
}
|
|
|
|
|
2009-11-09 23:04:54 +08:00
|
|
|
static const char builtin_rev_parse_usage[] =
|
2015-01-13 15:44:47 +08:00
|
|
|
N_("git rev-parse --parseopt [<options>] -- [<args>...]\n"
|
2012-08-20 20:32:40 +08:00
|
|
|
" or: git rev-parse --sq-quote [<arg>...]\n"
|
2015-01-13 15:44:47 +08:00
|
|
|
" or: git rev-parse [<options>] [<arg>...]\n"
|
2012-08-20 20:32:40 +08:00
|
|
|
"\n"
|
|
|
|
"Run \"git rev-parse --parseopt -h\" for more information on the first usage.");
|
2009-11-09 23:04:54 +08:00
|
|
|
|
2017-03-16 04:06:53 +08:00
|
|
|
/*
|
|
|
|
* Parse "opt" or "opt=<value>", setting value respectively to either
|
|
|
|
* NULL or the string after "=".
|
|
|
|
*/
|
|
|
|
static int opt_with_value(const char *arg, const char *opt, const char **value)
|
|
|
|
{
|
|
|
|
if (skip_prefix(arg, opt, &arg)) {
|
|
|
|
if (!*arg) {
|
|
|
|
*value = NULL;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if (*arg++ == '=') {
|
|
|
|
*value = arg;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-03-16 04:08:02 +08:00
|
|
|
static void handle_ref_opt(const char *pattern, const char *prefix)
|
|
|
|
{
|
|
|
|
if (pattern)
|
|
|
|
for_each_glob_ref_in(show_reference, pattern, prefix, NULL);
|
|
|
|
else
|
|
|
|
for_each_ref_in(prefix, show_reference, NULL);
|
2022-11-17 13:46:51 +08:00
|
|
|
clear_ref_exclusions(&ref_excludes);
|
2017-03-16 04:08:02 +08:00
|
|
|
}
|
|
|
|
|
2020-12-13 08:25:29 +08:00
|
|
|
enum format_type {
|
|
|
|
/* We would like a relative path. */
|
|
|
|
FORMAT_RELATIVE,
|
|
|
|
/* We would like a canonical absolute path. */
|
|
|
|
FORMAT_CANONICAL,
|
|
|
|
/* We would like the default behavior. */
|
|
|
|
FORMAT_DEFAULT,
|
|
|
|
};
|
|
|
|
|
|
|
|
enum default_type {
|
|
|
|
/* Our default is a relative path. */
|
|
|
|
DEFAULT_RELATIVE,
|
|
|
|
/* Our default is a relative path if there's a shared root. */
|
|
|
|
DEFAULT_RELATIVE_IF_SHARED,
|
|
|
|
/* Our default is a canonical absolute path. */
|
|
|
|
DEFAULT_CANONICAL,
|
|
|
|
/* Our default is not to modify the item. */
|
|
|
|
DEFAULT_UNMODIFIED,
|
|
|
|
};
|
|
|
|
|
|
|
|
static void print_path(const char *path, const char *prefix, enum format_type format, enum default_type def)
|
|
|
|
{
|
|
|
|
char *cwd = NULL;
|
|
|
|
/*
|
|
|
|
* We don't ever produce a relative path if prefix is NULL, so set the
|
|
|
|
* prefix to the current directory so that we can produce a relative
|
|
|
|
* path whenever possible. If we're using RELATIVE_IF_SHARED mode, then
|
|
|
|
* we want an absolute path unless the two share a common prefix, so don't
|
|
|
|
* set it in that case, since doing so causes a relative path to always
|
|
|
|
* be produced if possible.
|
|
|
|
*/
|
|
|
|
if (!prefix && (format != FORMAT_DEFAULT || def != DEFAULT_RELATIVE_IF_SHARED))
|
|
|
|
prefix = cwd = xgetcwd();
|
|
|
|
if (format == FORMAT_DEFAULT && def == DEFAULT_UNMODIFIED) {
|
|
|
|
puts(path);
|
|
|
|
} else if (format == FORMAT_RELATIVE ||
|
|
|
|
(format == FORMAT_DEFAULT && def == DEFAULT_RELATIVE)) {
|
|
|
|
/*
|
|
|
|
* In order for relative_path to work as expected, we need to
|
|
|
|
* make sure that both paths are absolute paths. If we don't,
|
|
|
|
* we can end up with an unexpected absolute path that the user
|
|
|
|
* didn't want.
|
|
|
|
*/
|
|
|
|
struct strbuf buf = STRBUF_INIT, realbuf = STRBUF_INIT, prefixbuf = STRBUF_INIT;
|
|
|
|
if (!is_absolute_path(path)) {
|
|
|
|
strbuf_realpath_forgiving(&realbuf, path, 1);
|
|
|
|
path = realbuf.buf;
|
|
|
|
}
|
|
|
|
if (!is_absolute_path(prefix)) {
|
|
|
|
strbuf_realpath_forgiving(&prefixbuf, prefix, 1);
|
|
|
|
prefix = prefixbuf.buf;
|
|
|
|
}
|
|
|
|
puts(relative_path(path, prefix, &buf));
|
|
|
|
strbuf_release(&buf);
|
|
|
|
strbuf_release(&realbuf);
|
|
|
|
strbuf_release(&prefixbuf);
|
|
|
|
} else if (format == FORMAT_DEFAULT && def == DEFAULT_RELATIVE_IF_SHARED) {
|
|
|
|
struct strbuf buf = STRBUF_INIT;
|
|
|
|
puts(relative_path(path, prefix, &buf));
|
|
|
|
strbuf_release(&buf);
|
|
|
|
} else {
|
|
|
|
struct strbuf buf = STRBUF_INIT;
|
|
|
|
strbuf_realpath_forgiving(&buf, path, 1);
|
|
|
|
puts(buf.buf);
|
|
|
|
strbuf_release(&buf);
|
|
|
|
}
|
|
|
|
free(cwd);
|
|
|
|
}
|
|
|
|
|
2006-07-29 13:44:25 +08:00
|
|
|
int cmd_rev_parse(int argc, const char **argv, const char *prefix)
|
2005-06-14 01:06:50 +08:00
|
|
|
{
|
2008-05-12 00:28:25 +08:00
|
|
|
int i, as_is = 0, verify = 0, quiet = 0, revs_count = 0, type = 0;
|
2016-02-29 19:01:56 +08:00
|
|
|
int did_repo_setup = 0;
|
rev-parse: correctly diagnose revision errors before "--"
Rev-parse understands that a "--" may separate revisions and
filenames, and that anything after the "--" is taken as-is.
However, it does not understand that anything before the
token must be a revision (which is the usual rule
implemented by the setup_revisions parser).
Since rev-parse prefers revisions to files when parsing
before the "--", we end up with the correct result (if such
an argument is a revision, we parse it as one, and if it is
not, it is an error either way). However, we misdiagnose
the errors:
$ git rev-parse foobar -- >/dev/null
fatal: ambiguous argument 'foobar': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'
$ >foobar
$ git rev-parse foobar -- >/dev/null
fatal: bad flag '--' used after filename
In both cases, we should know that the real error is that
"foobar" is meant to be a revision, but could not be
resolved.
Signed-off-by: Jeff King <peff@peff.net>
Reviewed-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-12-07 06:05:48 +08:00
|
|
|
int has_dashdash = 0;
|
2013-06-16 22:18:17 +08:00
|
|
|
int output_prefix = 0;
|
2017-05-01 10:29:02 +08:00
|
|
|
struct object_id oid;
|
2014-09-19 11:45:37 +08:00
|
|
|
unsigned int flags = 0;
|
2008-05-12 00:28:25 +08:00
|
|
|
const char *name = NULL;
|
2014-09-19 11:45:37 +08:00
|
|
|
struct object_context unused;
|
rev-parse: fix several options when running in a subdirectory
In addition to making git_path() aware of certain file names that need
to be handled differently e.g. when running in worktrees, the commit
557bd833bb (git_path(): be aware of file relocation in $GIT_DIR,
2014-11-30) also snuck in a new option for `git rev-parse`:
`--git-path`.
On the face of it, there is no obvious bug in that commit's diff: it
faithfully calls git_path() on the argument and prints it out, i.e. `git
rev-parse --git-path <filename>` has the same precise behavior as
calling `git_path("<filename>")` in C.
The problem lies deeper, much deeper. In hindsight (which is always
unfair), implementing the .git/ directory discovery in
`setup_git_directory()` by changing the working directory may have
allowed us to avoid passing around a struct that contains information
about the current repository, but it bought us many, many problems.
In this case, when being called in a subdirectory, `git rev-parse`
changes the working directory to the top-level directory before calling
`git_path()`. In the new working directory, the result is correct. But
in the working directory of the calling script, it is incorrect.
Example: when calling `git rev-parse --git-path HEAD` in, say, the
Documentation/ subdirectory of Git's own source code, the string
`.git/HEAD` is printed.
Side note: that bug is hidden when running in a subdirectory of a
worktree that was added by the `git worktree` command: in that case, the
(correct) absolute path of the `HEAD` file is printed.
In the interest of time, this patch does not go the "correct" route to
introduce a struct with repository information (and removing global
state in the process), instead this patch chooses to detect when the
command was called in a subdirectory and forces the result to be an
absolute path.
While at it, we are also fixing the output of --git-common-dir and
--shared-index-path.
Lastly, please note that we reuse the same strbuf for all of the
relative_path() calls; this avoids frequent allocation (and duplicated
code), and it does not risk memory leaks, for two reasons: 1) the
cmd_rev_parse() function does not return anywhere between the use of
the new strbuf instance and its final release, and 2) git-rev-parse is
one of these "one-shot" programs in Git, i.e. it exits after running
for a very short time, meaning that all allocated memory is released
with the exit() call anyway.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-18 00:59:06 +08:00
|
|
|
struct strbuf buf = STRBUF_INIT;
|
2019-08-19 04:04:07 +08:00
|
|
|
const int hexsz = the_hash_algo->hexsz;
|
rev-parse: handle --end-of-options
We taught rev-list a new way to separate options from revisions in
19e8789b23 (revision: allow --end-of-options to end option parsing,
2019-08-06), but rev-parse uses its own parser. It should know about
--end-of-options not only for consistency, but because it may be
presented with similarly ambiguous cases. E.g., if a caller does:
git rev-parse "$rev" -- "$path"
to parse an untrusted input, then it will get confused if $rev contains
an option-like string like "--local-env-vars". Or even "--not-real",
which we'd keep as an option to pass along to rev-list.
Or even more importantly:
git rev-parse --verify "$rev"
can be confused by options, even though its purpose is safely parsing
untrusted input. On the plus side, it will always fail the --verify
part, as it will not have parsed a revision, so the caller will
generally "fail closed" rather than continue to use the untrusted
string. But it will still trigger whatever option was in "$rev"; this
should be mostly harmless, since rev-parse options are all read-only,
but I didn't carefully audit all paths.
This patch lets callers write:
git rev-parse --end-of-options "$rev" -- "$path"
and:
git rev-parse --verify --end-of-options "$rev"
which will both treat "$rev" always as a revision parameter. The latter
is a bit clunky. It would be nicer if we had defined "--verify" to
require that its next argument be the revision. But we have not
historically done so, and:
git rev-parse --verify -q "$rev"
does currently work. I added a test here to confirm that we didn't break
that.
A few implementation notes:
- We don't document --end-of-options explicitly in commands, but rather
in gitcli(7). So I didn't give it its own section in git-rev-parse(1).
But I did call it out specifically in the --verify section, and
include it in the examples, which should show best practices.
- We don't have to re-indent the main option-parsing block, because we
can combine our "did we see end of options" check with "does it start
with a dash". The exception is the pre-setup options, which need
their own block.
- We do however have to pull the "--" parsing out of the "does it start
with dash" block, because we want to parse it even if we've seen
--end-of-options.
- We'll leave "--end-of-options" in the output. This is probably not
technically necessary, as a careful caller will do:
git rev-parse --end-of-options $revs -- $paths
and anything in $revs will be resolved to an object id. However, it
does help a slightly less careful caller like:
git rev-parse --end-of-options $revs_or_paths
where a path "--foo" will remain in the output as long as it also
exists on disk. In that case, it's helpful to retain --end-of-options
to get passed along to rev-list, s it would otherwise see just
"--foo".
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-11-11 05:40:19 +08:00
|
|
|
int seen_end_of_options = 0;
|
2020-12-13 08:25:29 +08:00
|
|
|
enum format_type format = FORMAT_DEFAULT;
|
2006-05-14 09:43:00 +08:00
|
|
|
|
2007-11-04 18:30:53 +08:00
|
|
|
if (argc > 1 && !strcmp("--parseopt", argv[1]))
|
|
|
|
return cmd_parseopt(argc - 1, argv + 1, prefix);
|
|
|
|
|
2009-04-25 12:55:26 +08:00
|
|
|
if (argc > 1 && !strcmp("--sq-quote", argv[1]))
|
|
|
|
return cmd_sq_quote(argc - 2, argv + 2);
|
|
|
|
|
2009-11-09 23:04:54 +08:00
|
|
|
if (argc > 1 && !strcmp("-h", argv[1]))
|
|
|
|
usage(builtin_rev_parse_usage);
|
|
|
|
|
rev-parse: correctly diagnose revision errors before "--"
Rev-parse understands that a "--" may separate revisions and
filenames, and that anything after the "--" is taken as-is.
However, it does not understand that anything before the
token must be a revision (which is the usual rule
implemented by the setup_revisions parser).
Since rev-parse prefers revisions to files when parsing
before the "--", we end up with the correct result (if such
an argument is a revision, we parse it as one, and if it is
not, it is an error either way). However, we misdiagnose
the errors:
$ git rev-parse foobar -- >/dev/null
fatal: ambiguous argument 'foobar': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'
$ >foobar
$ git rev-parse foobar -- >/dev/null
fatal: bad flag '--' used after filename
In both cases, we should know that the real error is that
"foobar" is meant to be a revision, but could not be
resolved.
Signed-off-by: Jeff King <peff@peff.net>
Reviewed-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-12-07 06:05:48 +08:00
|
|
|
for (i = 1; i < argc; i++) {
|
|
|
|
if (!strcmp(argv[i], "--")) {
|
|
|
|
has_dashdash = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-29 19:01:56 +08:00
|
|
|
/* No options; just report on whether we're in a git repo or not. */
|
|
|
|
if (argc == 1) {
|
|
|
|
setup_git_directory();
|
|
|
|
git_config(git_default_config, NULL);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-06-14 01:06:50 +08:00
|
|
|
for (i = 1; i < argc; i++) {
|
2006-06-06 13:36:21 +08:00
|
|
|
const char *arg = argv[i];
|
2006-03-27 08:28:20 +08:00
|
|
|
|
2020-11-11 05:37:27 +08:00
|
|
|
if (as_is) {
|
|
|
|
if (show_file(arg, output_prefix) && as_is < 2)
|
|
|
|
verify_filename(prefix, arg, 0);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
rev-parse: handle --end-of-options
We taught rev-list a new way to separate options from revisions in
19e8789b23 (revision: allow --end-of-options to end option parsing,
2019-08-06), but rev-parse uses its own parser. It should know about
--end-of-options not only for consistency, but because it may be
presented with similarly ambiguous cases. E.g., if a caller does:
git rev-parse "$rev" -- "$path"
to parse an untrusted input, then it will get confused if $rev contains
an option-like string like "--local-env-vars". Or even "--not-real",
which we'd keep as an option to pass along to rev-list.
Or even more importantly:
git rev-parse --verify "$rev"
can be confused by options, even though its purpose is safely parsing
untrusted input. On the plus side, it will always fail the --verify
part, as it will not have parsed a revision, so the caller will
generally "fail closed" rather than continue to use the untrusted
string. But it will still trigger whatever option was in "$rev"; this
should be mostly harmless, since rev-parse options are all read-only,
but I didn't carefully audit all paths.
This patch lets callers write:
git rev-parse --end-of-options "$rev" -- "$path"
and:
git rev-parse --verify --end-of-options "$rev"
which will both treat "$rev" always as a revision parameter. The latter
is a bit clunky. It would be nicer if we had defined "--verify" to
require that its next argument be the revision. But we have not
historically done so, and:
git rev-parse --verify -q "$rev"
does currently work. I added a test here to confirm that we didn't break
that.
A few implementation notes:
- We don't document --end-of-options explicitly in commands, but rather
in gitcli(7). So I didn't give it its own section in git-rev-parse(1).
But I did call it out specifically in the --verify section, and
include it in the examples, which should show best practices.
- We don't have to re-indent the main option-parsing block, because we
can combine our "did we see end of options" check with "does it start
with a dash". The exception is the pre-setup options, which need
their own block.
- We do however have to pull the "--" parsing out of the "does it start
with dash" block, because we want to parse it even if we've seen
--end-of-options.
- We'll leave "--end-of-options" in the output. This is probably not
technically necessary, as a careful caller will do:
git rev-parse --end-of-options $revs -- $paths
and anything in $revs will be resolved to an object id. However, it
does help a slightly less careful caller like:
git rev-parse --end-of-options $revs_or_paths
where a path "--foo" will remain in the output as long as it also
exists on disk. In that case, it's helpful to retain --end-of-options
to get passed along to rev-list, s it would otherwise see just
"--foo".
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-11-11 05:40:19 +08:00
|
|
|
if (!seen_end_of_options) {
|
|
|
|
if (!strcmp(arg, "--local-env-vars")) {
|
|
|
|
int i;
|
|
|
|
for (i = 0; local_repo_env[i]; i++)
|
|
|
|
printf("%s\n", local_repo_env[i]);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!strcmp(arg, "--resolve-git-dir")) {
|
|
|
|
const char *gitdir = argv[++i];
|
|
|
|
if (!gitdir)
|
2021-05-17 16:02:43 +08:00
|
|
|
die(_("--resolve-git-dir requires an argument"));
|
rev-parse: handle --end-of-options
We taught rev-list a new way to separate options from revisions in
19e8789b23 (revision: allow --end-of-options to end option parsing,
2019-08-06), but rev-parse uses its own parser. It should know about
--end-of-options not only for consistency, but because it may be
presented with similarly ambiguous cases. E.g., if a caller does:
git rev-parse "$rev" -- "$path"
to parse an untrusted input, then it will get confused if $rev contains
an option-like string like "--local-env-vars". Or even "--not-real",
which we'd keep as an option to pass along to rev-list.
Or even more importantly:
git rev-parse --verify "$rev"
can be confused by options, even though its purpose is safely parsing
untrusted input. On the plus side, it will always fail the --verify
part, as it will not have parsed a revision, so the caller will
generally "fail closed" rather than continue to use the untrusted
string. But it will still trigger whatever option was in "$rev"; this
should be mostly harmless, since rev-parse options are all read-only,
but I didn't carefully audit all paths.
This patch lets callers write:
git rev-parse --end-of-options "$rev" -- "$path"
and:
git rev-parse --verify --end-of-options "$rev"
which will both treat "$rev" always as a revision parameter. The latter
is a bit clunky. It would be nicer if we had defined "--verify" to
require that its next argument be the revision. But we have not
historically done so, and:
git rev-parse --verify -q "$rev"
does currently work. I added a test here to confirm that we didn't break
that.
A few implementation notes:
- We don't document --end-of-options explicitly in commands, but rather
in gitcli(7). So I didn't give it its own section in git-rev-parse(1).
But I did call it out specifically in the --verify section, and
include it in the examples, which should show best practices.
- We don't have to re-indent the main option-parsing block, because we
can combine our "did we see end of options" check with "does it start
with a dash". The exception is the pre-setup options, which need
their own block.
- We do however have to pull the "--" parsing out of the "does it start
with dash" block, because we want to parse it even if we've seen
--end-of-options.
- We'll leave "--end-of-options" in the output. This is probably not
technically necessary, as a careful caller will do:
git rev-parse --end-of-options $revs -- $paths
and anything in $revs will be resolved to an object id. However, it
does help a slightly less careful caller like:
git rev-parse --end-of-options $revs_or_paths
where a path "--foo" will remain in the output as long as it also
exists on disk. In that case, it's helpful to retain --end-of-options
to get passed along to rev-list, s it would otherwise see just
"--foo".
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-11-11 05:40:19 +08:00
|
|
|
gitdir = resolve_gitdir(gitdir);
|
|
|
|
if (!gitdir)
|
2021-05-17 16:02:43 +08:00
|
|
|
die(_("not a gitdir '%s'"), argv[i]);
|
rev-parse: handle --end-of-options
We taught rev-list a new way to separate options from revisions in
19e8789b23 (revision: allow --end-of-options to end option parsing,
2019-08-06), but rev-parse uses its own parser. It should know about
--end-of-options not only for consistency, but because it may be
presented with similarly ambiguous cases. E.g., if a caller does:
git rev-parse "$rev" -- "$path"
to parse an untrusted input, then it will get confused if $rev contains
an option-like string like "--local-env-vars". Or even "--not-real",
which we'd keep as an option to pass along to rev-list.
Or even more importantly:
git rev-parse --verify "$rev"
can be confused by options, even though its purpose is safely parsing
untrusted input. On the plus side, it will always fail the --verify
part, as it will not have parsed a revision, so the caller will
generally "fail closed" rather than continue to use the untrusted
string. But it will still trigger whatever option was in "$rev"; this
should be mostly harmless, since rev-parse options are all read-only,
but I didn't carefully audit all paths.
This patch lets callers write:
git rev-parse --end-of-options "$rev" -- "$path"
and:
git rev-parse --verify --end-of-options "$rev"
which will both treat "$rev" always as a revision parameter. The latter
is a bit clunky. It would be nicer if we had defined "--verify" to
require that its next argument be the revision. But we have not
historically done so, and:
git rev-parse --verify -q "$rev"
does currently work. I added a test here to confirm that we didn't break
that.
A few implementation notes:
- We don't document --end-of-options explicitly in commands, but rather
in gitcli(7). So I didn't give it its own section in git-rev-parse(1).
But I did call it out specifically in the --verify section, and
include it in the examples, which should show best practices.
- We don't have to re-indent the main option-parsing block, because we
can combine our "did we see end of options" check with "does it start
with a dash". The exception is the pre-setup options, which need
their own block.
- We do however have to pull the "--" parsing out of the "does it start
with dash" block, because we want to parse it even if we've seen
--end-of-options.
- We'll leave "--end-of-options" in the output. This is probably not
technically necessary, as a careful caller will do:
git rev-parse --end-of-options $revs -- $paths
and anything in $revs will be resolved to an object id. However, it
does help a slightly less careful caller like:
git rev-parse --end-of-options $revs_or_paths
where a path "--foo" will remain in the output as long as it also
exists on disk. In that case, it's helpful to retain --end-of-options
to get passed along to rev-list, s it would otherwise see just
"--foo".
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-11-11 05:40:19 +08:00
|
|
|
puts(gitdir);
|
|
|
|
continue;
|
|
|
|
}
|
2016-02-29 19:01:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* The rest of the options require a git repository. */
|
|
|
|
if (!did_repo_setup) {
|
|
|
|
prefix = setup_git_directory();
|
|
|
|
git_config(git_default_config, NULL);
|
|
|
|
did_repo_setup = 1;
|
2022-04-27 04:43:20 +08:00
|
|
|
|
|
|
|
prepare_repo_settings(the_repository);
|
|
|
|
the_repository->settings.command_requires_full_index = 0;
|
2016-02-29 19:01:56 +08:00
|
|
|
}
|
|
|
|
|
rev-parse: handle --end-of-options
We taught rev-list a new way to separate options from revisions in
19e8789b23 (revision: allow --end-of-options to end option parsing,
2019-08-06), but rev-parse uses its own parser. It should know about
--end-of-options not only for consistency, but because it may be
presented with similarly ambiguous cases. E.g., if a caller does:
git rev-parse "$rev" -- "$path"
to parse an untrusted input, then it will get confused if $rev contains
an option-like string like "--local-env-vars". Or even "--not-real",
which we'd keep as an option to pass along to rev-list.
Or even more importantly:
git rev-parse --verify "$rev"
can be confused by options, even though its purpose is safely parsing
untrusted input. On the plus side, it will always fail the --verify
part, as it will not have parsed a revision, so the caller will
generally "fail closed" rather than continue to use the untrusted
string. But it will still trigger whatever option was in "$rev"; this
should be mostly harmless, since rev-parse options are all read-only,
but I didn't carefully audit all paths.
This patch lets callers write:
git rev-parse --end-of-options "$rev" -- "$path"
and:
git rev-parse --verify --end-of-options "$rev"
which will both treat "$rev" always as a revision parameter. The latter
is a bit clunky. It would be nicer if we had defined "--verify" to
require that its next argument be the revision. But we have not
historically done so, and:
git rev-parse --verify -q "$rev"
does currently work. I added a test here to confirm that we didn't break
that.
A few implementation notes:
- We don't document --end-of-options explicitly in commands, but rather
in gitcli(7). So I didn't give it its own section in git-rev-parse(1).
But I did call it out specifically in the --verify section, and
include it in the examples, which should show best practices.
- We don't have to re-indent the main option-parsing block, because we
can combine our "did we see end of options" check with "does it start
with a dash". The exception is the pre-setup options, which need
their own block.
- We do however have to pull the "--" parsing out of the "does it start
with dash" block, because we want to parse it even if we've seen
--end-of-options.
- We'll leave "--end-of-options" in the output. This is probably not
technically necessary, as a careful caller will do:
git rev-parse --end-of-options $revs -- $paths
and anything in $revs will be resolved to an object id. However, it
does help a slightly less careful caller like:
git rev-parse --end-of-options $revs_or_paths
where a path "--foo" will remain in the output as long as it also
exists on disk. In that case, it's helpful to retain --end-of-options
to get passed along to rev-list, s it would otherwise see just
"--foo".
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-11-11 05:40:19 +08:00
|
|
|
if (!strcmp(arg, "--")) {
|
|
|
|
as_is = 2;
|
|
|
|
/* Pass on the "--" if we show anything but files.. */
|
|
|
|
if (filter & (DO_FLAGS | DO_REVS))
|
|
|
|
show_file(arg, 0);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!seen_end_of_options && *arg == '-') {
|
2020-11-11 05:38:03 +08:00
|
|
|
if (!strcmp(arg, "--git-path")) {
|
|
|
|
if (!argv[i + 1])
|
2021-05-17 16:02:43 +08:00
|
|
|
die(_("--git-path requires an argument"));
|
2020-11-11 05:38:03 +08:00
|
|
|
strbuf_reset(&buf);
|
2020-12-13 08:25:29 +08:00
|
|
|
print_path(git_path("%s", argv[i + 1]), prefix,
|
|
|
|
format,
|
|
|
|
DEFAULT_RELATIVE_IF_SHARED);
|
2020-11-11 05:38:03 +08:00
|
|
|
i++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!strcmp(arg,"-n")) {
|
|
|
|
if (++i >= argc)
|
2021-05-17 16:02:43 +08:00
|
|
|
die(_("-n requires an argument"));
|
2020-11-11 05:38:03 +08:00
|
|
|
if ((filter & DO_FLAGS) && (filter & DO_REVS)) {
|
|
|
|
show(arg);
|
|
|
|
show(argv[i]);
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (starts_with(arg, "-n")) {
|
|
|
|
if ((filter & DO_FLAGS) && (filter & DO_REVS))
|
|
|
|
show(arg);
|
|
|
|
continue;
|
|
|
|
}
|
2020-12-13 08:25:29 +08:00
|
|
|
if (opt_with_value(arg, "--path-format", &arg)) {
|
2021-05-17 16:02:42 +08:00
|
|
|
if (!arg)
|
2021-05-17 16:02:43 +08:00
|
|
|
die(_("--path-format requires an argument"));
|
2020-12-13 08:25:29 +08:00
|
|
|
if (!strcmp(arg, "absolute")) {
|
|
|
|
format = FORMAT_CANONICAL;
|
|
|
|
} else if (!strcmp(arg, "relative")) {
|
|
|
|
format = FORMAT_RELATIVE;
|
|
|
|
} else {
|
2021-05-17 16:02:43 +08:00
|
|
|
die(_("unknown argument to --path-format: %s"), arg);
|
2020-12-13 08:25:29 +08:00
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
2005-06-14 01:06:50 +08:00
|
|
|
if (!strcmp(arg, "--default")) {
|
2014-01-29 05:21:00 +08:00
|
|
|
def = argv[++i];
|
|
|
|
if (!def)
|
2021-05-17 16:02:43 +08:00
|
|
|
die(_("--default requires an argument"));
|
2005-06-14 01:06:50 +08:00
|
|
|
continue;
|
|
|
|
}
|
2013-06-16 22:18:17 +08:00
|
|
|
if (!strcmp(arg, "--prefix")) {
|
2014-01-29 05:21:00 +08:00
|
|
|
prefix = argv[++i];
|
|
|
|
if (!prefix)
|
2021-05-17 16:02:43 +08:00
|
|
|
die(_("--prefix requires an argument"));
|
2013-06-16 22:18:17 +08:00
|
|
|
startup_info->prefix = prefix;
|
|
|
|
output_prefix = 1;
|
|
|
|
continue;
|
|
|
|
}
|
2005-06-14 01:21:11 +08:00
|
|
|
if (!strcmp(arg, "--revs-only")) {
|
2005-08-25 05:30:04 +08:00
|
|
|
filter &= ~DO_NOREV;
|
2005-06-14 01:21:11 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!strcmp(arg, "--no-revs")) {
|
2005-08-25 05:30:04 +08:00
|
|
|
filter &= ~DO_REVS;
|
2005-06-14 01:21:11 +08:00
|
|
|
continue;
|
|
|
|
}
|
2005-07-07 01:08:08 +08:00
|
|
|
if (!strcmp(arg, "--flags")) {
|
2005-08-25 05:30:04 +08:00
|
|
|
filter &= ~DO_NONFLAGS;
|
2005-07-07 01:08:08 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!strcmp(arg, "--no-flags")) {
|
2005-08-25 05:30:04 +08:00
|
|
|
filter &= ~DO_FLAGS;
|
2005-07-07 01:08:08 +08:00
|
|
|
continue;
|
|
|
|
}
|
2005-06-25 01:12:55 +08:00
|
|
|
if (!strcmp(arg, "--verify")) {
|
2005-08-25 05:30:04 +08:00
|
|
|
filter &= ~(DO_FLAGS|DO_NOREV);
|
|
|
|
verify = 1;
|
2005-06-25 01:12:55 +08:00
|
|
|
continue;
|
2005-06-14 02:14:20 +08:00
|
|
|
}
|
2008-04-26 19:57:23 +08:00
|
|
|
if (!strcmp(arg, "--quiet") || !strcmp(arg, "-q")) {
|
|
|
|
quiet = 1;
|
2017-07-14 07:49:29 +08:00
|
|
|
flags |= GET_OID_QUIETLY;
|
2008-04-26 19:57:23 +08:00
|
|
|
continue;
|
|
|
|
}
|
2017-03-16 04:06:53 +08:00
|
|
|
if (opt_with_value(arg, "--short", &arg)) {
|
2006-01-25 17:35:38 +08:00
|
|
|
filter &= ~(DO_FLAGS|DO_NOREV);
|
|
|
|
verify = 1;
|
|
|
|
abbrev = DEFAULT_ABBREV;
|
2017-03-16 04:06:53 +08:00
|
|
|
if (!arg)
|
abbrev: prepare for new world order
The code that sets custom abbreviation length, in response to
command line argument, often does something like this:
if (skip_prefix(arg, "--abbrev=", &arg))
abbrev = atoi(arg);
else if (!strcmp("--abbrev", &arg))
abbrev = DEFAULT_ABBREV;
/* make the value sane */
if (abbrev < 0 || 40 < abbrev)
abbrev = ... some sane value ...
However, it is pointless to sanity-check and tweak the value
obtained from DEFAULT_ABBREV. We are going to allow it to be
initially set to -1 to signal that the default abbreviation length
must be auto sized upon the first request to abbreviate, based on
the number of objects in the repository, and when that happens,
rejecting or tweaking a negative value to a "saner" one will
negatively interfere with the auto sizing. The codepaths for
git rev-parse --short <object>
git diff --raw --abbrev
do exactly that; allow them to pass possibly negative abbrevs
intact, that will come from DEFAULT_ABBREV in the future.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-10-01 08:19:36 +08:00
|
|
|
continue;
|
2017-03-16 04:06:53 +08:00
|
|
|
abbrev = strtoul(arg, NULL, 10);
|
2006-01-26 16:48:19 +08:00
|
|
|
if (abbrev < MINIMUM_ABBREV)
|
|
|
|
abbrev = MINIMUM_ABBREV;
|
2019-08-19 04:04:07 +08:00
|
|
|
else if (hexsz <= abbrev)
|
|
|
|
abbrev = hexsz;
|
2006-01-25 17:35:38 +08:00
|
|
|
continue;
|
|
|
|
}
|
[PATCH] Help scripts that use git-rev-parse to grok args with SP/TAB/LF
The git-rev-parse command uses LF to separate each argument it
parses, so its users at least need to set IFS to LF to be able
to handle filenames with embedded SPs and TABs. Some commands,
however, can take and do expect arguments with embedded LF,
notably, "-S" (pickaxe) of diff family, so even this workaround
does not work for them.
When --sq flag to git-rev-parse is given, instead of showing one
argument per line, it outputs arguments quoted for consumption
with "eval" by the caller, to remedy this situation.
As an example, this patch converts git-whatchanged to use this
new feature.
Signed-off-by: Junio C Hamano <junkio@cox.net>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-07-23 10:08:32 +08:00
|
|
|
if (!strcmp(arg, "--sq")) {
|
|
|
|
output_sq = 1;
|
|
|
|
continue;
|
|
|
|
}
|
2005-06-27 02:34:30 +08:00
|
|
|
if (!strcmp(arg, "--not")) {
|
|
|
|
show_type ^= REVERSED;
|
|
|
|
continue;
|
|
|
|
}
|
2005-08-17 03:36:46 +08:00
|
|
|
if (!strcmp(arg, "--symbolic")) {
|
2008-01-06 04:09:55 +08:00
|
|
|
symbolic = SHOW_SYMBOLIC_ASIS;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!strcmp(arg, "--symbolic-full-name")) {
|
|
|
|
symbolic = SHOW_SYMBOLIC_FULL;
|
2005-08-17 03:36:46 +08:00
|
|
|
continue;
|
|
|
|
}
|
2017-03-16 04:06:53 +08:00
|
|
|
if (opt_with_value(arg, "--abbrev-ref", &arg)) {
|
2009-04-13 19:20:26 +08:00
|
|
|
abbrev_ref = 1;
|
|
|
|
abbrev_ref_strict = warn_ambiguous_refs;
|
2017-03-16 04:06:53 +08:00
|
|
|
if (arg) {
|
|
|
|
if (!strcmp(arg, "strict"))
|
2009-04-13 19:20:26 +08:00
|
|
|
abbrev_ref_strict = 1;
|
2017-03-16 04:06:53 +08:00
|
|
|
else if (!strcmp(arg, "loose"))
|
2009-04-13 19:20:26 +08:00
|
|
|
abbrev_ref_strict = 0;
|
|
|
|
else
|
2021-05-17 16:02:43 +08:00
|
|
|
die(_("unknown mode for --abbrev-ref: %s"),
|
2017-03-16 04:06:53 +08:00
|
|
|
arg);
|
2009-04-13 19:20:26 +08:00
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
2005-07-04 04:07:52 +08:00
|
|
|
if (!strcmp(arg, "--all")) {
|
2015-05-26 02:38:29 +08:00
|
|
|
for_each_ref(show_reference, NULL);
|
2022-11-17 13:46:51 +08:00
|
|
|
clear_ref_exclusions(&ref_excludes);
|
2005-07-04 04:07:52 +08:00
|
|
|
continue;
|
|
|
|
}
|
2017-03-16 04:05:36 +08:00
|
|
|
if (skip_prefix(arg, "--disambiguate=", &arg)) {
|
2023-03-28 21:58:46 +08:00
|
|
|
repo_for_each_abbrev(the_repository, arg,
|
|
|
|
show_abbrev, NULL);
|
2012-07-04 05:21:59 +08:00
|
|
|
continue;
|
|
|
|
}
|
2009-10-28 02:28:07 +08:00
|
|
|
if (!strcmp(arg, "--bisect")) {
|
2021-09-25 02:48:48 +08:00
|
|
|
for_each_fullref_in("refs/bisect/bad", show_reference, NULL);
|
|
|
|
for_each_fullref_in("refs/bisect/good", anti_reference, NULL);
|
2009-10-28 02:28:07 +08:00
|
|
|
continue;
|
|
|
|
}
|
2017-03-16 04:08:02 +08:00
|
|
|
if (opt_with_value(arg, "--branches", &arg)) {
|
2022-11-17 13:47:00 +08:00
|
|
|
if (ref_excludes.hidden_refs_configured)
|
2023-12-06 19:51:58 +08:00
|
|
|
return error(_("options '%s' and '%s' cannot be used together"),
|
|
|
|
"--exclude-hidden", "--branches");
|
2017-03-16 04:08:02 +08:00
|
|
|
handle_ref_opt(arg, "refs/heads/");
|
2006-05-14 09:43:00 +08:00
|
|
|
continue;
|
|
|
|
}
|
2017-03-16 04:08:02 +08:00
|
|
|
if (opt_with_value(arg, "--tags", &arg)) {
|
2022-11-17 13:47:00 +08:00
|
|
|
if (ref_excludes.hidden_refs_configured)
|
2023-12-06 19:51:58 +08:00
|
|
|
return error(_("options '%s' and '%s' cannot be used together"),
|
|
|
|
"--exclude-hidden", "--tags");
|
2017-03-16 04:08:02 +08:00
|
|
|
handle_ref_opt(arg, "refs/tags/");
|
2010-01-20 17:48:25 +08:00
|
|
|
continue;
|
|
|
|
}
|
2017-03-16 04:05:36 +08:00
|
|
|
if (skip_prefix(arg, "--glob=", &arg)) {
|
2017-03-16 04:08:02 +08:00
|
|
|
handle_ref_opt(arg, NULL);
|
2010-01-20 17:48:26 +08:00
|
|
|
continue;
|
|
|
|
}
|
2017-03-16 04:08:02 +08:00
|
|
|
if (opt_with_value(arg, "--remotes", &arg)) {
|
2022-11-17 13:47:00 +08:00
|
|
|
if (ref_excludes.hidden_refs_configured)
|
2023-12-06 19:51:58 +08:00
|
|
|
return error(_("options '%s' and '%s' cannot be used together"),
|
|
|
|
"--exclude-hidden", "--remotes");
|
2017-03-16 04:08:02 +08:00
|
|
|
handle_ref_opt(arg, "refs/remotes/");
|
2013-11-02 03:13:01 +08:00
|
|
|
continue;
|
|
|
|
}
|
2017-03-16 04:05:36 +08:00
|
|
|
if (skip_prefix(arg, "--exclude=", &arg)) {
|
|
|
|
add_ref_exclusion(&ref_excludes, arg);
|
2006-05-14 09:43:00 +08:00
|
|
|
continue;
|
|
|
|
}
|
2022-11-17 13:47:00 +08:00
|
|
|
if (skip_prefix(arg, "--exclude-hidden=", &arg)) {
|
|
|
|
exclude_hidden_refs(&ref_excludes, arg);
|
|
|
|
continue;
|
|
|
|
}
|
2010-01-12 06:33:48 +08:00
|
|
|
if (!strcmp(arg, "--show-toplevel")) {
|
|
|
|
const char *work_tree = get_git_work_tree();
|
|
|
|
if (work_tree)
|
2020-12-13 08:25:29 +08:00
|
|
|
print_path(work_tree, prefix, format, DEFAULT_UNMODIFIED);
|
2019-11-19 16:05:43 +08:00
|
|
|
else
|
2021-05-17 16:02:43 +08:00
|
|
|
die(_("this operation must be run in a work tree"));
|
2010-01-12 06:33:48 +08:00
|
|
|
continue;
|
|
|
|
}
|
2017-03-09 07:07:42 +08:00
|
|
|
if (!strcmp(arg, "--show-superproject-working-tree")) {
|
2020-03-10 21:11:24 +08:00
|
|
|
struct strbuf superproject = STRBUF_INIT;
|
|
|
|
if (get_superproject_working_tree(&superproject))
|
2020-12-13 08:25:29 +08:00
|
|
|
print_path(superproject.buf, prefix, format, DEFAULT_UNMODIFIED);
|
2020-03-10 21:11:24 +08:00
|
|
|
strbuf_release(&superproject);
|
2017-03-09 07:07:42 +08:00
|
|
|
continue;
|
|
|
|
}
|
2005-08-17 09:06:34 +08:00
|
|
|
if (!strcmp(arg, "--show-prefix")) {
|
2005-08-25 05:30:04 +08:00
|
|
|
if (prefix)
|
|
|
|
puts(prefix);
|
2012-04-09 21:27:56 +08:00
|
|
|
else
|
|
|
|
putchar('\n');
|
2005-08-17 09:06:34 +08:00
|
|
|
continue;
|
|
|
|
}
|
2005-12-23 14:35:38 +08:00
|
|
|
if (!strcmp(arg, "--show-cdup")) {
|
|
|
|
const char *pfx = prefix;
|
Clean up work-tree handling
The old version of work-tree support was an unholy mess, barely readable,
and not to the point.
For example, why do you have to provide a worktree, when it is not used?
As in "git status". Now it works.
Another riddle was: if you can have work trees inside the git dir, why
are some programs complaining that they need a work tree?
IOW it is allowed to call
$ git --git-dir=../ --work-tree=. bla
when you really want to. In this case, you are both in the git directory
and in the working tree. So, programs have to actually test for the right
thing, namely if they are inside a working tree, and not if they are
inside a git directory.
Also, GIT_DIR=../.git should behave the same as if no GIT_DIR was
specified, unless there is a repository in the current working directory.
It does now.
The logic to determine if a repository is bare, or has a work tree
(tertium non datur), is this:
--work-tree=bla overrides GIT_WORK_TREE, which overrides core.bare = true,
which overrides core.worktree, which overrides GIT_DIR/.. when GIT_DIR
ends in /.git, which overrides the directory in which .git/ was found.
In related news, a long standing bug was fixed: when in .git/bla/x.git/,
which is a bare repository, git formerly assumed ../.. to be the
appropriate git dir. This problem was reported by Shawn Pearce to have
caused much pain, where a colleague mistakenly ran "git init" in "/" a
long time ago, and bare repositories just would not work.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-08-01 08:30:14 +08:00
|
|
|
if (!is_inside_work_tree()) {
|
|
|
|
const char *work_tree =
|
|
|
|
get_git_work_tree();
|
|
|
|
if (work_tree)
|
|
|
|
printf("%s\n", work_tree);
|
|
|
|
continue;
|
|
|
|
}
|
2005-12-23 14:35:38 +08:00
|
|
|
while (pfx) {
|
|
|
|
pfx = strchr(pfx, '/');
|
|
|
|
if (pfx) {
|
|
|
|
pfx++;
|
|
|
|
printf("../");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
putchar('\n');
|
|
|
|
continue;
|
|
|
|
}
|
rev-parse: add '--absolute-git-dir' option
The output of 'git rev-parse --git-dir' can be either a relative or an
absolute path, depending on whether the current working directory is
at the top of the worktree or the .git directory or not, or how the
path to the repository is specified via the '--git-dir=<path>' option
or the $GIT_DIR environment variable. And if that output is a
relative path, then it is relative to the directory where any 'git
-C <path>' options might have led us.
This doesn't matter at all for regular scripts, because the git
wrapper automatically takes care of changing directories according to
the '-C <path>' options, and the scripts can then simply follow any
path returned by 'git rev-parse --git-dir', even if it's a relative
path.
Our Bash completion script, however, is unique in that it must run
directly in the user's interactive shell environment. This means that
it's not executed through the git wrapper and would have to take care
of any '-C <path> options on its own, and it can't just change
directories as it pleases. Consequently, adding support for taking
any '-C <path>' options on the command line into account during
completion turned out to be considerably more difficult, error prone
and required more subshells and git processes when it had to cope with
a relative path to the .git directory.
Help this rather special use case and teach 'git rev-parse' a new
'--absolute-git-dir' option which always outputs a canonicalized
absolute path to the .git directory, regardless of whether the path is
discovered automatically or is specified via $GIT_DIR or 'git
--git-dir=<path>'.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 10:48:23 +08:00
|
|
|
if (!strcmp(arg, "--git-dir") ||
|
|
|
|
!strcmp(arg, "--absolute-git-dir")) {
|
2005-09-19 02:18:30 +08:00
|
|
|
const char *gitdir = getenv(GIT_DIR_ENVIRONMENT);
|
2014-07-29 02:30:39 +08:00
|
|
|
char *cwd;
|
2010-02-14 23:44:42 +08:00
|
|
|
int len;
|
2020-12-13 08:25:29 +08:00
|
|
|
enum format_type wanted = format;
|
rev-parse: add '--absolute-git-dir' option
The output of 'git rev-parse --git-dir' can be either a relative or an
absolute path, depending on whether the current working directory is
at the top of the worktree or the .git directory or not, or how the
path to the repository is specified via the '--git-dir=<path>' option
or the $GIT_DIR environment variable. And if that output is a
relative path, then it is relative to the directory where any 'git
-C <path>' options might have led us.
This doesn't matter at all for regular scripts, because the git
wrapper automatically takes care of changing directories according to
the '-C <path>' options, and the scripts can then simply follow any
path returned by 'git rev-parse --git-dir', even if it's a relative
path.
Our Bash completion script, however, is unique in that it must run
directly in the user's interactive shell environment. This means that
it's not executed through the git wrapper and would have to take care
of any '-C <path> options on its own, and it can't just change
directories as it pleases. Consequently, adding support for taking
any '-C <path>' options on the command line into account during
completion turned out to be considerably more difficult, error prone
and required more subshells and git processes when it had to cope with
a relative path to the .git directory.
Help this rather special use case and teach 'git rev-parse' a new
'--absolute-git-dir' option which always outputs a canonicalized
absolute path to the .git directory, regardless of whether the path is
discovered automatically or is specified via $GIT_DIR or 'git
--git-dir=<path>'.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 10:48:23 +08:00
|
|
|
if (arg[2] == 'g') { /* --git-dir */
|
|
|
|
if (gitdir) {
|
2020-12-13 08:25:29 +08:00
|
|
|
print_path(gitdir, prefix, format, DEFAULT_UNMODIFIED);
|
rev-parse: add '--absolute-git-dir' option
The output of 'git rev-parse --git-dir' can be either a relative or an
absolute path, depending on whether the current working directory is
at the top of the worktree or the .git directory or not, or how the
path to the repository is specified via the '--git-dir=<path>' option
or the $GIT_DIR environment variable. And if that output is a
relative path, then it is relative to the directory where any 'git
-C <path>' options might have led us.
This doesn't matter at all for regular scripts, because the git
wrapper automatically takes care of changing directories according to
the '-C <path>' options, and the scripts can then simply follow any
path returned by 'git rev-parse --git-dir', even if it's a relative
path.
Our Bash completion script, however, is unique in that it must run
directly in the user's interactive shell environment. This means that
it's not executed through the git wrapper and would have to take care
of any '-C <path> options on its own, and it can't just change
directories as it pleases. Consequently, adding support for taking
any '-C <path>' options on the command line into account during
completion turned out to be considerably more difficult, error prone
and required more subshells and git processes when it had to cope with
a relative path to the .git directory.
Help this rather special use case and teach 'git rev-parse' a new
'--absolute-git-dir' option which always outputs a canonicalized
absolute path to the .git directory, regardless of whether the path is
discovered automatically or is specified via $GIT_DIR or 'git
--git-dir=<path>'.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 10:48:23 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!prefix) {
|
2020-12-13 08:25:29 +08:00
|
|
|
print_path(".git", prefix, format, DEFAULT_UNMODIFIED);
|
rev-parse: add '--absolute-git-dir' option
The output of 'git rev-parse --git-dir' can be either a relative or an
absolute path, depending on whether the current working directory is
at the top of the worktree or the .git directory or not, or how the
path to the repository is specified via the '--git-dir=<path>' option
or the $GIT_DIR environment variable. And if that output is a
relative path, then it is relative to the directory where any 'git
-C <path>' options might have led us.
This doesn't matter at all for regular scripts, because the git
wrapper automatically takes care of changing directories according to
the '-C <path>' options, and the scripts can then simply follow any
path returned by 'git rev-parse --git-dir', even if it's a relative
path.
Our Bash completion script, however, is unique in that it must run
directly in the user's interactive shell environment. This means that
it's not executed through the git wrapper and would have to take care
of any '-C <path> options on its own, and it can't just change
directories as it pleases. Consequently, adding support for taking
any '-C <path>' options on the command line into account during
completion turned out to be considerably more difficult, error prone
and required more subshells and git processes when it had to cope with
a relative path to the .git directory.
Help this rather special use case and teach 'git rev-parse' a new
'--absolute-git-dir' option which always outputs a canonicalized
absolute path to the .git directory, regardless of whether the path is
discovered automatically or is specified via $GIT_DIR or 'git
--git-dir=<path>'.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 10:48:23 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} else { /* --absolute-git-dir */
|
2020-12-13 08:25:29 +08:00
|
|
|
wanted = FORMAT_CANONICAL;
|
rev-parse: add '--absolute-git-dir' option
The output of 'git rev-parse --git-dir' can be either a relative or an
absolute path, depending on whether the current working directory is
at the top of the worktree or the .git directory or not, or how the
path to the repository is specified via the '--git-dir=<path>' option
or the $GIT_DIR environment variable. And if that output is a
relative path, then it is relative to the directory where any 'git
-C <path>' options might have led us.
This doesn't matter at all for regular scripts, because the git
wrapper automatically takes care of changing directories according to
the '-C <path>' options, and the scripts can then simply follow any
path returned by 'git rev-parse --git-dir', even if it's a relative
path.
Our Bash completion script, however, is unique in that it must run
directly in the user's interactive shell environment. This means that
it's not executed through the git wrapper and would have to take care
of any '-C <path> options on its own, and it can't just change
directories as it pleases. Consequently, adding support for taking
any '-C <path>' options on the command line into account during
completion turned out to be considerably more difficult, error prone
and required more subshells and git processes when it had to cope with
a relative path to the .git directory.
Help this rather special use case and teach 'git rev-parse' a new
'--absolute-git-dir' option which always outputs a canonicalized
absolute path to the .git directory, regardless of whether the path is
discovered automatically or is specified via $GIT_DIR or 'git
--git-dir=<path>'.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 10:48:23 +08:00
|
|
|
if (!gitdir && !prefix)
|
|
|
|
gitdir = ".git";
|
|
|
|
if (gitdir) {
|
2020-03-10 21:11:22 +08:00
|
|
|
struct strbuf realpath = STRBUF_INIT;
|
|
|
|
strbuf_realpath(&realpath, gitdir, 1);
|
|
|
|
puts(realpath.buf);
|
|
|
|
strbuf_release(&realpath);
|
rev-parse: add '--absolute-git-dir' option
The output of 'git rev-parse --git-dir' can be either a relative or an
absolute path, depending on whether the current working directory is
at the top of the worktree or the .git directory or not, or how the
path to the repository is specified via the '--git-dir=<path>' option
or the $GIT_DIR environment variable. And if that output is a
relative path, then it is relative to the directory where any 'git
-C <path>' options might have led us.
This doesn't matter at all for regular scripts, because the git
wrapper automatically takes care of changing directories according to
the '-C <path>' options, and the scripts can then simply follow any
path returned by 'git rev-parse --git-dir', even if it's a relative
path.
Our Bash completion script, however, is unique in that it must run
directly in the user's interactive shell environment. This means that
it's not executed through the git wrapper and would have to take care
of any '-C <path> options on its own, and it can't just change
directories as it pleases. Consequently, adding support for taking
any '-C <path>' options on the command line into account during
completion turned out to be considerably more difficult, error prone
and required more subshells and git processes when it had to cope with
a relative path to the .git directory.
Help this rather special use case and teach 'git rev-parse' a new
'--absolute-git-dir' option which always outputs a canonicalized
absolute path to the .git directory, regardless of whether the path is
discovered automatically or is specified via $GIT_DIR or 'git
--git-dir=<path>'.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 10:48:23 +08:00
|
|
|
continue;
|
|
|
|
}
|
2005-09-19 02:18:30 +08:00
|
|
|
}
|
2014-07-29 02:30:39 +08:00
|
|
|
cwd = xgetcwd();
|
2010-02-14 23:44:42 +08:00
|
|
|
len = strlen(cwd);
|
2020-12-13 08:25:29 +08:00
|
|
|
strbuf_reset(&buf);
|
|
|
|
strbuf_addf(&buf, "%s%s.git", cwd, len && cwd[len-1] != '/' ? "/" : "");
|
2014-07-29 02:30:39 +08:00
|
|
|
free(cwd);
|
2020-12-13 08:25:29 +08:00
|
|
|
print_path(buf.buf, prefix, wanted, DEFAULT_CANONICAL);
|
2005-09-19 02:18:30 +08:00
|
|
|
continue;
|
|
|
|
}
|
2014-11-30 16:24:44 +08:00
|
|
|
if (!strcmp(arg, "--git-common-dir")) {
|
2020-12-13 08:25:29 +08:00
|
|
|
print_path(get_git_common_dir(), prefix, format, DEFAULT_RELATIVE_IF_SHARED);
|
2014-11-30 16:24:44 +08:00
|
|
|
continue;
|
|
|
|
}
|
2007-01-23 20:30:20 +08:00
|
|
|
if (!strcmp(arg, "--is-inside-git-dir")) {
|
|
|
|
printf("%s\n", is_inside_git_dir() ? "true"
|
|
|
|
: "false");
|
|
|
|
continue;
|
|
|
|
}
|
2007-06-06 15:10:42 +08:00
|
|
|
if (!strcmp(arg, "--is-inside-work-tree")) {
|
|
|
|
printf("%s\n", is_inside_work_tree() ? "true"
|
|
|
|
: "false");
|
|
|
|
continue;
|
|
|
|
}
|
2007-06-03 22:46:36 +08:00
|
|
|
if (!strcmp(arg, "--is-bare-repository")) {
|
|
|
|
printf("%s\n", is_bare_repository() ? "true"
|
|
|
|
: "false");
|
|
|
|
continue;
|
|
|
|
}
|
2017-09-19 01:04:29 +08:00
|
|
|
if (!strcmp(arg, "--is-shallow-repository")) {
|
2018-05-18 06:51:46 +08:00
|
|
|
printf("%s\n",
|
|
|
|
is_repository_shallow(the_repository) ? "true"
|
2017-09-19 01:04:29 +08:00
|
|
|
: "false");
|
|
|
|
continue;
|
|
|
|
}
|
2014-06-13 20:19:46 +08:00
|
|
|
if (!strcmp(arg, "--shared-index-path")) {
|
2022-11-19 21:07:38 +08:00
|
|
|
if (repo_read_index(the_repository) < 0)
|
2014-06-13 20:19:46 +08:00
|
|
|
die(_("Could not read the index"));
|
|
|
|
if (the_index.split_index) {
|
2018-05-02 08:25:43 +08:00
|
|
|
const struct object_id *oid = &the_index.split_index->base_oid;
|
|
|
|
const char *path = git_path("sharedindex.%s", oid_to_hex(oid));
|
2020-12-13 08:25:29 +08:00
|
|
|
print_path(path, prefix, format, DEFAULT_RELATIVE);
|
2014-06-13 20:19:46 +08:00
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
2017-03-16 04:05:36 +08:00
|
|
|
if (skip_prefix(arg, "--since=", &arg)) {
|
|
|
|
show_datestring("--max-age=", arg);
|
2005-09-21 05:13:24 +08:00
|
|
|
continue;
|
|
|
|
}
|
2017-03-16 04:05:36 +08:00
|
|
|
if (skip_prefix(arg, "--after=", &arg)) {
|
|
|
|
show_datestring("--max-age=", arg);
|
2005-09-21 05:13:24 +08:00
|
|
|
continue;
|
|
|
|
}
|
2017-03-16 04:05:36 +08:00
|
|
|
if (skip_prefix(arg, "--before=", &arg)) {
|
|
|
|
show_datestring("--min-age=", arg);
|
2005-09-21 05:13:24 +08:00
|
|
|
continue;
|
|
|
|
}
|
2017-03-16 04:05:36 +08:00
|
|
|
if (skip_prefix(arg, "--until=", &arg)) {
|
|
|
|
show_datestring("--min-age=", arg);
|
2005-09-21 05:13:24 +08:00
|
|
|
continue;
|
|
|
|
}
|
2019-10-28 08:58:55 +08:00
|
|
|
if (opt_with_value(arg, "--show-object-format", &arg)) {
|
|
|
|
const char *val = arg ? arg : "storage";
|
|
|
|
|
|
|
|
if (strcmp(val, "storage") &&
|
|
|
|
strcmp(val, "input") &&
|
|
|
|
strcmp(val, "output"))
|
2021-05-17 16:02:43 +08:00
|
|
|
die(_("unknown mode for --show-object-format: %s"),
|
2019-10-28 08:58:55 +08:00
|
|
|
arg);
|
|
|
|
puts(the_hash_algo->name);
|
|
|
|
continue;
|
|
|
|
}
|
rev-parse: handle --end-of-options
We taught rev-list a new way to separate options from revisions in
19e8789b23 (revision: allow --end-of-options to end option parsing,
2019-08-06), but rev-parse uses its own parser. It should know about
--end-of-options not only for consistency, but because it may be
presented with similarly ambiguous cases. E.g., if a caller does:
git rev-parse "$rev" -- "$path"
to parse an untrusted input, then it will get confused if $rev contains
an option-like string like "--local-env-vars". Or even "--not-real",
which we'd keep as an option to pass along to rev-list.
Or even more importantly:
git rev-parse --verify "$rev"
can be confused by options, even though its purpose is safely parsing
untrusted input. On the plus side, it will always fail the --verify
part, as it will not have parsed a revision, so the caller will
generally "fail closed" rather than continue to use the untrusted
string. But it will still trigger whatever option was in "$rev"; this
should be mostly harmless, since rev-parse options are all read-only,
but I didn't carefully audit all paths.
This patch lets callers write:
git rev-parse --end-of-options "$rev" -- "$path"
and:
git rev-parse --verify --end-of-options "$rev"
which will both treat "$rev" always as a revision parameter. The latter
is a bit clunky. It would be nicer if we had defined "--verify" to
require that its next argument be the revision. But we have not
historically done so, and:
git rev-parse --verify -q "$rev"
does currently work. I added a test here to confirm that we didn't break
that.
A few implementation notes:
- We don't document --end-of-options explicitly in commands, but rather
in gitcli(7). So I didn't give it its own section in git-rev-parse(1).
But I did call it out specifically in the --verify section, and
include it in the examples, which should show best practices.
- We don't have to re-indent the main option-parsing block, because we
can combine our "did we see end of options" check with "does it start
with a dash". The exception is the pre-setup options, which need
their own block.
- We do however have to pull the "--" parsing out of the "does it start
with dash" block, because we want to parse it even if we've seen
--end-of-options.
- We'll leave "--end-of-options" in the output. This is probably not
technically necessary, as a careful caller will do:
git rev-parse --end-of-options $revs -- $paths
and anything in $revs will be resolved to an object id. However, it
does help a slightly less careful caller like:
git rev-parse --end-of-options $revs_or_paths
where a path "--foo" will remain in the output as long as it also
exists on disk. In that case, it's helpful to retain --end-of-options
to get passed along to rev-list, s it would otherwise see just
"--foo".
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-11-11 05:40:19 +08:00
|
|
|
if (!strcmp(arg, "--end-of-options")) {
|
|
|
|
seen_end_of_options = 1;
|
|
|
|
if (filter & (DO_FLAGS | DO_REVS))
|
|
|
|
show_file(arg, 0);
|
|
|
|
continue;
|
|
|
|
}
|
2006-02-06 03:58:34 +08:00
|
|
|
if (show_flag(arg) && verify)
|
2008-04-26 19:57:23 +08:00
|
|
|
die_no_single_rev(quiet);
|
2005-06-14 01:06:50 +08:00
|
|
|
continue;
|
|
|
|
}
|
2005-08-25 05:30:04 +08:00
|
|
|
|
|
|
|
/* Not a flag argument */
|
2006-07-04 17:02:22 +08:00
|
|
|
if (try_difference(arg))
|
|
|
|
continue;
|
2008-07-27 00:37:56 +08:00
|
|
|
if (try_parent_shorthands(arg))
|
|
|
|
continue;
|
2008-05-12 00:28:25 +08:00
|
|
|
name = arg;
|
|
|
|
type = NORMAL;
|
|
|
|
if (*arg == '^') {
|
|
|
|
name++;
|
|
|
|
type = REVERSED;
|
2005-06-20 23:29:13 +08:00
|
|
|
}
|
2019-01-12 10:13:28 +08:00
|
|
|
if (!get_oid_with_context(the_repository, name,
|
|
|
|
flags, &oid, &unused)) {
|
2008-05-12 00:28:25 +08:00
|
|
|
if (verify)
|
|
|
|
revs_count++;
|
|
|
|
else
|
2017-05-01 10:29:02 +08:00
|
|
|
show_rev(type, &oid, name);
|
2005-06-20 23:29:13 +08:00
|
|
|
continue;
|
|
|
|
}
|
2008-04-26 21:19:29 +08:00
|
|
|
if (verify)
|
|
|
|
die_no_single_rev(quiet);
|
rev-parse: correctly diagnose revision errors before "--"
Rev-parse understands that a "--" may separate revisions and
filenames, and that anything after the "--" is taken as-is.
However, it does not understand that anything before the
token must be a revision (which is the usual rule
implemented by the setup_revisions parser).
Since rev-parse prefers revisions to files when parsing
before the "--", we end up with the correct result (if such
an argument is a revision, we parse it as one, and if it is
not, it is an error either way). However, we misdiagnose
the errors:
$ git rev-parse foobar -- >/dev/null
fatal: ambiguous argument 'foobar': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'
$ >foobar
$ git rev-parse foobar -- >/dev/null
fatal: bad flag '--' used after filename
In both cases, we should know that the real error is that
"foobar" is meant to be a revision, but could not be
resolved.
Signed-off-by: Jeff King <peff@peff.net>
Reviewed-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-12-07 06:05:48 +08:00
|
|
|
if (has_dashdash)
|
2021-05-17 16:02:43 +08:00
|
|
|
die(_("bad revision '%s'"), arg);
|
2006-02-06 13:41:47 +08:00
|
|
|
as_is = 1;
|
2013-06-16 22:18:17 +08:00
|
|
|
if (!show_file(arg, output_prefix))
|
2006-02-06 13:41:47 +08:00
|
|
|
continue;
|
2012-06-19 02:18:21 +08:00
|
|
|
verify_filename(prefix, arg, 1);
|
2005-06-25 01:12:55 +08:00
|
|
|
}
|
rev-parse: fix several options when running in a subdirectory
In addition to making git_path() aware of certain file names that need
to be handled differently e.g. when running in worktrees, the commit
557bd833bb (git_path(): be aware of file relocation in $GIT_DIR,
2014-11-30) also snuck in a new option for `git rev-parse`:
`--git-path`.
On the face of it, there is no obvious bug in that commit's diff: it
faithfully calls git_path() on the argument and prints it out, i.e. `git
rev-parse --git-path <filename>` has the same precise behavior as
calling `git_path("<filename>")` in C.
The problem lies deeper, much deeper. In hindsight (which is always
unfair), implementing the .git/ directory discovery in
`setup_git_directory()` by changing the working directory may have
allowed us to avoid passing around a struct that contains information
about the current repository, but it bought us many, many problems.
In this case, when being called in a subdirectory, `git rev-parse`
changes the working directory to the top-level directory before calling
`git_path()`. In the new working directory, the result is correct. But
in the working directory of the calling script, it is incorrect.
Example: when calling `git rev-parse --git-path HEAD` in, say, the
Documentation/ subdirectory of Git's own source code, the string
`.git/HEAD` is printed.
Side note: that bug is hidden when running in a subdirectory of a
worktree that was added by the `git worktree` command: in that case, the
(correct) absolute path of the `HEAD` file is printed.
In the interest of time, this patch does not go the "correct" route to
introduce a struct with repository information (and removing global
state in the process), instead this patch chooses to detect when the
command was called in a subdirectory and forces the result to be an
absolute path.
While at it, we are also fixing the output of --git-common-dir and
--shared-index-path.
Lastly, please note that we reuse the same strbuf for all of the
relative_path() calls; this avoids frequent allocation (and duplicated
code), and it does not risk memory leaks, for two reasons: 1) the
cmd_rev_parse() function does not return anywhere between the use of
the new strbuf instance and its final release, and 2) git-rev-parse is
one of these "one-shot" programs in Git, i.e. it exits after running
for a very short time, meaning that all allocated memory is released
with the exit() call anyway.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-18 00:59:06 +08:00
|
|
|
strbuf_release(&buf);
|
2008-05-12 00:28:25 +08:00
|
|
|
if (verify) {
|
|
|
|
if (revs_count == 1) {
|
2017-05-01 10:29:02 +08:00
|
|
|
show_rev(type, &oid, name);
|
2008-05-12 00:28:25 +08:00
|
|
|
return 0;
|
|
|
|
} else if (revs_count == 0 && show_default())
|
|
|
|
return 0;
|
2008-04-26 19:57:23 +08:00
|
|
|
die_no_single_rev(quiet);
|
2008-05-12 00:28:25 +08:00
|
|
|
} else
|
|
|
|
show_default();
|
2005-06-14 01:06:50 +08:00
|
|
|
return 0;
|
|
|
|
}
|