2005-06-14 01:06:50 +08:00
|
|
|
/*
|
|
|
|
* rev-parse.c
|
|
|
|
*
|
|
|
|
* Copyright (C) Linus Torvalds, 2005
|
|
|
|
*/
|
|
|
|
#include "cache.h"
|
2017-06-15 02:07:36 +08:00
|
|
|
#include "config.h"
|
2005-06-21 11:28:09 +08:00
|
|
|
#include "commit.h"
|
2005-07-04 04:07:52 +08:00
|
|
|
#include "refs.h"
|
2005-09-21 05:13:24 +08:00
|
|
|
#include "quote.h"
|
2006-06-04 00:45:43 +08:00
|
|
|
#include "builtin.h"
|
2007-11-04 18:30:53 +08:00
|
|
|
#include "parse-options.h"
|
2013-11-02 03:13:01 +08:00
|
|
|
#include "diff.h"
|
|
|
|
#include "revision.h"
|
2014-06-13 20:19:46 +08:00
|
|
|
#include "split-index.h"
|
2017-03-09 07:07:42 +08:00
|
|
|
#include "submodule.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;
|
2013-11-02 03:13:01 +08:00
|
|
|
static struct string_list *ref_excludes;
|
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;
|
|
|
|
|
2017-10-16 06:06:57 +08:00
|
|
|
switch (dwim_ref(name, strlen(name), &discard, &full)) {
|
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 */
|
2009-04-13 19:20:26 +08:00
|
|
|
if (abbrev_ref)
|
|
|
|
full = shorten_unambiguous_ref(full,
|
|
|
|
abbrev_ref_strict);
|
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)
|
2018-03-12 10:27:30 +08:00
|
|
|
show_with_type(type, find_unique_abbrev(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;
|
2017-05-01 10:29:02 +08:00
|
|
|
if (!get_oid(s, &oid)) {
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2015-05-26 02:38:29 +08:00
|
|
|
static int show_reference(const char *refname, const struct object_id *oid, int flag, void *cb_data)
|
2005-07-04 04:07:52 +08:00
|
|
|
{
|
2013-11-02 03:13:01 +08:00
|
|
|
if (ref_excluded(ref_excludes, refname))
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-05-26 02:38:29 +08:00
|
|
|
static int anti_reference(const char *refname, const struct object_id *oid, int flag, void *cb_data)
|
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;
|
|
|
|
}
|
|
|
|
|
2017-03-31 09:39:59 +08:00
|
|
|
static int show_abbrev(const struct object_id *oid, void *cb_data)
|
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;
|
|
|
|
}
|
|
|
|
|
2018-02-15 02:59:27 +08:00
|
|
|
if (!get_oid_committish(start, &start_oid) && !get_oid_committish(end, &end_oid)) {
|
|
|
|
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;
|
|
|
|
}
|
2014-10-31 03:20:44 +08:00
|
|
|
exclude = get_merge_bases(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;
|
2018-05-24 14:27:33 +08:00
|
|
|
if (get_oid_committish(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)
|
2007-11-04 18:30:53 +08:00
|
|
|
die("premature end of input");
|
|
|
|
ALLOC_GROW(usage, unb + 1, usz);
|
|
|
|
if (!strcmp("--", sb.buf)) {
|
|
|
|
if (unb < 1)
|
|
|
|
die("no usage string given before the `--' separator");
|
|
|
|
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);
|
|
|
|
if (s == NULL)
|
|
|
|
s = help;
|
|
|
|
|
|
|
|
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);
|
|
|
|
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
|
|
|
|
die("Needed a single revision");
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
clear_ref_exclusion(&ref_excludes);
|
|
|
|
}
|
|
|
|
|
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;
|
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
|
|
|
|
2016-02-29 19:01:56 +08:00
|
|
|
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)
|
|
|
|
die("--resolve-git-dir requires an argument");
|
|
|
|
gitdir = resolve_gitdir(gitdir);
|
|
|
|
if (!gitdir)
|
|
|
|
die("not a gitdir '%s'", argv[i]);
|
|
|
|
puts(gitdir);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
|
2014-11-30 16:24:31 +08:00
|
|
|
if (!strcmp(arg, "--git-path")) {
|
|
|
|
if (!argv[i + 1])
|
|
|
|
die("--git-path requires an argument");
|
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_reset(&buf);
|
|
|
|
puts(relative_path(git_path("%s", argv[i + 1]),
|
|
|
|
prefix, &buf));
|
2014-11-30 16:24:31 +08:00
|
|
|
i++;
|
|
|
|
continue;
|
|
|
|
}
|
2005-06-14 01:06:50 +08:00
|
|
|
if (as_is) {
|
2013-06-16 22:18:17 +08:00
|
|
|
if (show_file(arg, output_prefix) && as_is < 2)
|
2012-06-19 02:18:21 +08:00
|
|
|
verify_filename(prefix, arg, 0);
|
2005-06-14 01:06:50 +08:00
|
|
|
continue;
|
|
|
|
}
|
2006-01-30 08:26:40 +08:00
|
|
|
if (!strcmp(arg,"-n")) {
|
|
|
|
if (++i >= argc)
|
|
|
|
die("-n requires an argument");
|
|
|
|
if ((filter & DO_FLAGS) && (filter & DO_REVS)) {
|
|
|
|
show(arg);
|
|
|
|
show(argv[i]);
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
2013-12-01 04:55:40 +08:00
|
|
|
if (starts_with(arg, "-n")) {
|
2006-01-30 08:26:40 +08:00
|
|
|
if ((filter & DO_FLAGS) && (filter & DO_REVS))
|
|
|
|
show(arg);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2005-06-14 01:06:50 +08:00
|
|
|
if (*arg == '-') {
|
|
|
|
if (!strcmp(arg, "--")) {
|
2006-03-27 08:28:20 +08:00
|
|
|
as_is = 2;
|
2005-10-21 08:16:30 +08:00
|
|
|
/* Pass on the "--" if we show anything but files.. */
|
|
|
|
if (filter & (DO_FLAGS | DO_REVS))
|
2013-06-16 22:18:17 +08:00
|
|
|
show_file(arg, 0);
|
2005-08-25 05:30:04 +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)
|
|
|
|
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)
|
|
|
|
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;
|
|
|
|
else if (40 <= abbrev)
|
|
|
|
abbrev = 40;
|
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
|
2017-03-16 04:06:53 +08:00
|
|
|
die("unknown mode for --abbrev-ref: %s",
|
|
|
|
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);
|
2005-07-04 04:07:52 +08:00
|
|
|
continue;
|
|
|
|
}
|
2017-03-16 04:05:36 +08:00
|
|
|
if (skip_prefix(arg, "--disambiguate=", &arg)) {
|
|
|
|
for_each_abbrev(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")) {
|
2017-09-06 19:53:10 +08:00
|
|
|
for_each_fullref_in("refs/bisect/bad", show_reference, NULL, 0);
|
|
|
|
for_each_fullref_in("refs/bisect/good", anti_reference, NULL, 0);
|
2009-10-28 02:28:07 +08:00
|
|
|
continue;
|
|
|
|
}
|
2017-03-16 04:08:02 +08:00
|
|
|
if (opt_with_value(arg, "--branches", &arg)) {
|
|
|
|
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)) {
|
|
|
|
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)) {
|
|
|
|
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;
|
|
|
|
}
|
2010-01-12 06:33:48 +08:00
|
|
|
if (!strcmp(arg, "--show-toplevel")) {
|
|
|
|
const char *work_tree = get_git_work_tree();
|
|
|
|
if (work_tree)
|
|
|
|
puts(work_tree);
|
|
|
|
continue;
|
|
|
|
}
|
2017-03-09 07:07:42 +08:00
|
|
|
if (!strcmp(arg, "--show-superproject-working-tree")) {
|
|
|
|
const char *superproject = get_superproject_working_tree();
|
|
|
|
if (superproject)
|
|
|
|
puts(superproject);
|
|
|
|
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;
|
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) {
|
|
|
|
puts(gitdir);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!prefix) {
|
|
|
|
puts(".git");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} else { /* --absolute-git-dir */
|
|
|
|
if (!gitdir && !prefix)
|
|
|
|
gitdir = ".git";
|
|
|
|
if (gitdir) {
|
|
|
|
puts(real_path(gitdir));
|
|
|
|
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);
|
|
|
|
printf("%s%s.git\n", cwd, len && cwd[len-1] != '/' ? "/" : "");
|
2014-07-29 02:30:39 +08:00
|
|
|
free(cwd);
|
2005-09-19 02:18:30 +08:00
|
|
|
continue;
|
|
|
|
}
|
2014-11-30 16:24:44 +08:00
|
|
|
if (!strcmp(arg, "--git-common-dir")) {
|
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_reset(&buf);
|
|
|
|
puts(relative_path(get_git_common_dir(),
|
|
|
|
prefix, &buf));
|
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")) {
|
|
|
|
if (read_cache() < 0)
|
|
|
|
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));
|
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_reset(&buf);
|
|
|
|
puts(relative_path(path, prefix, &buf));
|
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;
|
|
|
|
}
|
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
|
|
|
}
|
sha1_name: convert get_sha1* to get_oid*
Now that all the callers of get_sha1 directly or indirectly use struct
object_id, rename the functions starting with get_sha1 to start with
get_oid. Convert the internals in sha1_name.c to use struct object_id
as well, and eliminate explicit length checks where possible. Convert a
use of 40 in get_oid_basic to GIT_SHA1_HEXSZ.
Outside of sha1_name.c and cache.h, this transition was made with the
following semantic patch:
@@
expression E1, E2;
@@
- get_sha1(E1, E2.hash)
+ get_oid(E1, &E2)
@@
expression E1, E2;
@@
- get_sha1(E1, E2->hash)
+ get_oid(E1, E2)
@@
expression E1, E2;
@@
- get_sha1_committish(E1, E2.hash)
+ get_oid_committish(E1, &E2)
@@
expression E1, E2;
@@
- get_sha1_committish(E1, E2->hash)
+ get_oid_committish(E1, E2)
@@
expression E1, E2;
@@
- get_sha1_treeish(E1, E2.hash)
+ get_oid_treeish(E1, &E2)
@@
expression E1, E2;
@@
- get_sha1_treeish(E1, E2->hash)
+ get_oid_treeish(E1, E2)
@@
expression E1, E2;
@@
- get_sha1_commit(E1, E2.hash)
+ get_oid_commit(E1, &E2)
@@
expression E1, E2;
@@
- get_sha1_commit(E1, E2->hash)
+ get_oid_commit(E1, E2)
@@
expression E1, E2;
@@
- get_sha1_tree(E1, E2.hash)
+ get_oid_tree(E1, &E2)
@@
expression E1, E2;
@@
- get_sha1_tree(E1, E2->hash)
+ get_oid_tree(E1, E2)
@@
expression E1, E2;
@@
- get_sha1_blob(E1, E2.hash)
+ get_oid_blob(E1, &E2)
@@
expression E1, E2;
@@
- get_sha1_blob(E1, E2->hash)
+ get_oid_blob(E1, E2)
@@
expression E1, E2, E3, E4;
@@
- get_sha1_with_context(E1, E2, E3.hash, E4)
+ get_oid_with_context(E1, E2, &E3, E4)
@@
expression E1, E2, E3, E4;
@@
- get_sha1_with_context(E1, E2, E3->hash, E4)
+ get_oid_with_context(E1, E2, E3, E4)
Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-07-14 07:49:28 +08:00
|
|
|
if (!get_oid_with_context(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)
|
|
|
|
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;
|
|
|
|
}
|