2005-06-13 19:06:50 +02:00
|
|
|
/*
|
|
|
|
* rev-parse.c
|
|
|
|
*
|
|
|
|
* Copyright (C) Linus Torvalds, 2005
|
|
|
|
*/
|
|
|
|
#include "cache.h"
|
2005-06-21 05:28:09 +02:00
|
|
|
#include "commit.h"
|
2005-07-03 22:07:52 +02:00
|
|
|
#include "refs.h"
|
2005-09-20 23:13:24 +02:00
|
|
|
#include "quote.h"
|
2006-06-03 18:45:43 +02:00
|
|
|
#include "builtin.h"
|
2007-11-04 11:30:53 +01:00
|
|
|
#include "parse-options.h"
|
2013-11-01 20:13:01 +01:00
|
|
|
#include "diff.h"
|
|
|
|
#include "revision.h"
|
2014-06-13 14:19:46 +02:00
|
|
|
#include "split-index.h"
|
2005-06-21 05:28:09 +02:00
|
|
|
|
2005-08-24 23:30:04 +02:00
|
|
|
#define DO_REVS 1
|
|
|
|
#define DO_NOREV 2
|
|
|
|
#define DO_FLAGS 4
|
|
|
|
#define DO_NONFLAGS 8
|
|
|
|
static int filter = ~0;
|
|
|
|
|
2006-08-15 19:23:48 +02:00
|
|
|
static const char *def;
|
2005-06-24 19:12:55 +02:00
|
|
|
|
2005-06-26 20:34:30 +02:00
|
|
|
#define NORMAL 0
|
|
|
|
#define REVERSED 1
|
|
|
|
static int show_type = NORMAL;
|
2008-01-05 21:09:55 +01:00
|
|
|
|
|
|
|
#define SHOW_SYMBOLIC_ASIS 1
|
|
|
|
#define SHOW_SYMBOLIC_FULL 2
|
2006-08-15 19:23:48 +02:00
|
|
|
static int symbolic;
|
|
|
|
static int abbrev;
|
2009-04-13 13:20:26 +02:00
|
|
|
static int abbrev_ref;
|
|
|
|
static int abbrev_ref_strict;
|
2006-08-15 19:23:48 +02:00
|
|
|
static int output_sq;
|
2005-08-24 23:30:04 +02:00
|
|
|
|
2013-10-31 12:08:29 +01:00
|
|
|
static int stuck_long;
|
2013-11-01 20:13:01 +01:00
|
|
|
static struct string_list *ref_excludes;
|
2013-10-31 12:08:29 +01:00
|
|
|
|
2005-06-13 20:14:20 +02: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-05 23:49:54 +02:00
|
|
|
"--all",
|
2005-08-24 23:30:04 +02:00
|
|
|
"--bisect",
|
2005-10-30 10:08:35 +01:00
|
|
|
"--dense",
|
2010-01-20 10:48:26 +01:00
|
|
|
"--branches=",
|
2006-05-14 03:43:00 +02:00
|
|
|
"--branches",
|
2005-08-24 23:30:04 +02:00
|
|
|
"--header",
|
2011-05-19 03:08:09 +02:00
|
|
|
"--ignore-missing",
|
2005-06-13 20:14:20 +02:00
|
|
|
"--max-age=",
|
2005-08-24 23:30:04 +02:00
|
|
|
"--max-count=",
|
|
|
|
"--min-age=",
|
2005-08-09 04:31:37 +02:00
|
|
|
"--no-merges",
|
2011-03-21 11:14:06 +01:00
|
|
|
"--min-parents=",
|
|
|
|
"--no-min-parents",
|
|
|
|
"--max-parents=",
|
|
|
|
"--no-max-parents",
|
2005-08-24 23:30:04 +02:00
|
|
|
"--objects",
|
2006-02-19 12:32:31 +01:00
|
|
|
"--objects-edge",
|
2005-08-24 23:30:04 +02:00
|
|
|
"--parents",
|
|
|
|
"--pretty",
|
2010-01-20 10:48:26 +01:00
|
|
|
"--remotes=",
|
2006-05-14 03:43:00 +02:00
|
|
|
"--remotes",
|
2010-01-20 10:48:25 +01:00
|
|
|
"--glob=",
|
2005-10-30 10:08:35 +01:00
|
|
|
"--sparse",
|
2010-01-20 10:48:26 +01:00
|
|
|
"--tags=",
|
2006-05-14 03:43:00 +02:00
|
|
|
"--tags",
|
2005-08-24 23:30:04 +02:00
|
|
|
"--topo-order",
|
2006-02-16 07:05:33 +01:00
|
|
|
"--date-order",
|
2005-08-24 23:30:04 +02:00
|
|
|
"--unpacked",
|
2005-06-13 20:14:20 +02:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
const char **p = rev_args;
|
|
|
|
|
2006-01-30 01:28:02 +01:00
|
|
|
/* accept -<digit>, like traditional "head" */
|
|
|
|
if ((*arg == '-') && isdigit(arg[1]))
|
|
|
|
return 1;
|
|
|
|
|
2005-06-13 20:14:20 +02:00
|
|
|
for (;;) {
|
|
|
|
const char *str = *p++;
|
|
|
|
int len;
|
|
|
|
if (!str)
|
|
|
|
return 0;
|
|
|
|
len = strlen(str);
|
2005-08-24 23:30:04 +02:00
|
|
|
if (!strcmp(arg, str) ||
|
|
|
|
(str[len-1] == '=' && !strncmp(arg, str, len)))
|
2005-06-13 20:14:20 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-08-24 23:30:04 +02: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 04:08:32 +02: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 16:13:05 +02: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-24 23:30:04 +02:00
|
|
|
/* Output a revision, only if filter allows it */
|
2005-08-16 21:36:46 +02:00
|
|
|
static void show_rev(int type, const unsigned char *sha1, const char *name)
|
2005-06-24 19:12:55 +02:00
|
|
|
{
|
2005-08-24 23:30:04 +02:00
|
|
|
if (!(filter & DO_REVS))
|
2005-06-24 19:12:55 +02:00
|
|
|
return;
|
2005-08-24 23:30:04 +02: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 04:08:32 +02:00
|
|
|
|
2009-04-13 13:20:26 +02:00
|
|
|
if ((symbolic || abbrev_ref) && name) {
|
|
|
|
if (symbolic == SHOW_SYMBOLIC_FULL || abbrev_ref) {
|
2008-01-05 21:09:55 +01:00
|
|
|
unsigned char discard[20];
|
|
|
|
char *full;
|
|
|
|
|
|
|
|
switch (dwim_ref(name, strlen(name), discard, &full)) {
|
|
|
|
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 13:20:26 +02:00
|
|
|
if (abbrev_ref)
|
|
|
|
full = shorten_unambiguous_ref(full,
|
|
|
|
abbrev_ref_strict);
|
2008-05-23 16:13:05 +02:00
|
|
|
show_with_type(type, full);
|
2008-01-05 21:09:55 +01:00
|
|
|
break;
|
|
|
|
default: /* ambiguous */
|
|
|
|
error("refname '%s' is ambiguous", name);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
2008-05-23 16:13:05 +02:00
|
|
|
show_with_type(type, name);
|
2008-01-05 21:09:55 +01:00
|
|
|
}
|
|
|
|
}
|
2006-01-25 10:35:38 +01:00
|
|
|
else if (abbrev)
|
2008-05-23 16:13:05 +02:00
|
|
|
show_with_type(type, find_unique_abbrev(sha1, abbrev));
|
2005-08-16 21:36:46 +02:00
|
|
|
else
|
2008-05-23 16:13:05 +02:00
|
|
|
show_with_type(type, sha1_to_hex(sha1));
|
2005-06-24 19:12:55 +02:00
|
|
|
}
|
|
|
|
|
2005-08-24 23:30:04 +02:00
|
|
|
/* Output a flag, only if filter allows it. */
|
2006-06-06 07:36:21 +02:00
|
|
|
static int show_flag(const char *arg)
|
2005-06-24 19:12:55 +02:00
|
|
|
{
|
2005-08-24 23:30:04 +02:00
|
|
|
if (!(filter & DO_FLAGS))
|
2006-02-05 20:58:34 +01:00
|
|
|
return 0;
|
|
|
|
if (filter & (is_rev_argument(arg) ? DO_REVS : DO_NOREV)) {
|
2005-08-23 19:47:54 +02:00
|
|
|
show(arg);
|
2006-02-05 20:58:34 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
2005-06-24 19:12:55 +02:00
|
|
|
}
|
|
|
|
|
2008-05-11 18:28:25 +02:00
|
|
|
static int show_default(void)
|
2005-06-24 19:12:55 +02:00
|
|
|
{
|
2006-06-06 07:36:21 +02:00
|
|
|
const char *s = def;
|
2005-06-24 19:12:55 +02:00
|
|
|
|
|
|
|
if (s) {
|
|
|
|
unsigned char sha1[20];
|
|
|
|
|
|
|
|
def = NULL;
|
2005-08-04 07:15:49 +02:00
|
|
|
if (!get_sha1(s, sha1)) {
|
2005-08-16 21:36:46 +02:00
|
|
|
show_rev(NORMAL, sha1, s);
|
2008-05-11 18:28:25 +02:00
|
|
|
return 1;
|
2005-06-24 19:12:55 +02:00
|
|
|
}
|
|
|
|
}
|
2008-05-11 18:28:25 +02:00
|
|
|
return 0;
|
2005-06-24 19:12:55 +02:00
|
|
|
}
|
|
|
|
|
2006-09-21 07:02:01 +02:00
|
|
|
static int show_reference(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
|
2005-07-03 22:07:52 +02:00
|
|
|
{
|
2013-11-01 20:13:01 +01:00
|
|
|
if (ref_excluded(ref_excludes, refname))
|
|
|
|
return 0;
|
2005-08-16 21:36:46 +02:00
|
|
|
show_rev(NORMAL, sha1, refname);
|
2005-07-03 22:07:52 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-10-27 19:28:07 +01:00
|
|
|
static int anti_reference(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
|
|
|
|
{
|
|
|
|
show_rev(REVERSED, sha1, refname);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-07-03 23:21:59 +02:00
|
|
|
static int show_abbrev(const unsigned char *sha1, void *cb_data)
|
|
|
|
{
|
|
|
|
show_rev(NORMAL, sha1, NULL);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-09-20 23:13:24 +02:00
|
|
|
static void show_datestring(const char *flag, const char *datestr)
|
|
|
|
{
|
|
|
|
static char buffer[100];
|
|
|
|
|
|
|
|
/* date handling requires both flags and revs */
|
|
|
|
if ((filter & (DO_FLAGS | DO_REVS)) != (DO_FLAGS | DO_REVS))
|
|
|
|
return;
|
git's rev-parse.c function show_datestring presumes gnu date
Ok. This is the insane patch to do this.
It really isn't very careful, and the reason I call it "approxidate()"
will become obvious when you look at the code. It is very liberal in what
it accepts, to the point where sometimes the results may not make a whole
lot of sense.
It accepts "last week" as a date string, by virtue of "last" parsing as
the number 1, and it totally ignoring superfluous fluff like "ago", so
"last week" ends up being exactly the same thing as "1 week ago". Fine so
far.
It has strange side effects: "last december" will actually parse as "Dec
1", which actually _does_ turn out right, because it will then notice that
it's not December yet, so it will decide that you must be talking about a
date last year. So it actually gets it right, but it's kind of for the
"wrong" reasons.
It also accepts the numbers 1..10 in string format ("one" .. "ten"), so
you can do "ten weeks ago" or "ten hours ago" and it will do the right
thing.
But it will do some really strange thigns too: the string "this will last
forever", will not recognize anyting but "last", which is recognized as
"1", which since it doesn't understand anything else it will think is the
day of the month. So if you do
gitk --since="this will last forever"
the date will actually parse as the first day of the current month.
And it will parse the string "now" as "now", but only because it doesn't
understand it at all, and it makes everything relative to "now".
Similarly, it doesn't actually parse the "ago" or "from now", so "2 weeks
ago" is exactly the same as "2 weeks from now". It's the current date
minus 14 days.
But hey, it's probably better (and certainly faster) than depending on GNU
date. So now you can portably do things like
gitk --since="two weeks and three days ago"
git log --since="July 5"
git-whatchanged --since="10 hours ago"
git log --since="last october"
and it will actually do exactly what you thought it would do (I think). It
will count 17 days backwards, and it will do so even if you don't have GNU
date installed.
(I don't do "last monday" or similar yet, but I can extend it to that too
if people want).
It was kind of fun trying to write code that uses such totally relaxed
"understanding" of dates yet tries to get it right for the trivial cases.
The result should be mixed with a few strange preprocessor tricks, and be
submitted for the IOCCC ;)
Feel free to try it out, and see how many strange dates it gets right. Or
wrong.
And if you find some interesting (and valid - not "interesting" as in
"strange", but "interesting" as in "I'd be interested in actually doing
this) thing it gets wrong - usually by not understanding it and silently
just doing some strange things - please holler.
Now, as usual this certainly hasn't been getting a lot of testing. But my
code always works, no?
Linus
Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-11-15 04:29:06 +01:00
|
|
|
snprintf(buffer, sizeof(buffer), "%s%lu", flag, approxidate(datestr));
|
2005-09-20 23:13:24 +02:00
|
|
|
show(buffer);
|
|
|
|
}
|
|
|
|
|
2013-06-16 16:18:17 +02:00
|
|
|
static int show_file(const char *arg, int output_prefix)
|
2005-10-18 09:16:45 +02:00
|
|
|
{
|
2005-10-26 00:24:55 +02:00
|
|
|
show_default();
|
2006-02-06 06:41:47 +01:00
|
|
|
if ((filter & (DO_NONFLAGS|DO_NOREV)) == (DO_NONFLAGS|DO_NOREV)) {
|
2013-06-16 16:18:17 +02:00
|
|
|
if (output_prefix) {
|
|
|
|
const char *prefix = startup_info->prefix;
|
|
|
|
show(prefix_filename(prefix,
|
|
|
|
prefix ? strlen(prefix) : 0,
|
|
|
|
arg));
|
|
|
|
} else
|
|
|
|
show(arg);
|
2006-02-06 06:41:47 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
2005-10-18 09:16:45 +02:00
|
|
|
}
|
|
|
|
|
2006-07-06 09:16:35 +02:00
|
|
|
static int try_difference(const char *arg)
|
2006-07-04 11:02:22 +02:00
|
|
|
{
|
|
|
|
char *dotdot;
|
|
|
|
unsigned char sha1[20];
|
|
|
|
unsigned char end[20];
|
|
|
|
const char *next;
|
|
|
|
const char *this;
|
|
|
|
int symmetric;
|
2011-05-02 22:39:16 +02:00
|
|
|
static const char head_by_default[] = "HEAD";
|
2006-07-04 11:02:22 +02:00
|
|
|
|
|
|
|
if (!(dotdot = strstr(arg, "..")))
|
|
|
|
return 0;
|
|
|
|
next = dotdot + 2;
|
|
|
|
this = arg;
|
|
|
|
symmetric = (*next == '.');
|
|
|
|
|
|
|
|
*dotdot = 0;
|
|
|
|
next += symmetric;
|
|
|
|
|
|
|
|
if (!*next)
|
2011-05-02 22:39:16 +02:00
|
|
|
next = head_by_default;
|
2006-07-04 11:02:22 +02:00
|
|
|
if (dotdot == arg)
|
2011-05-02 22:39:16 +02:00
|
|
|
this = head_by_default;
|
|
|
|
|
|
|
|
if (this == head_by_default && next == head_by_default &&
|
|
|
|
!symmetric) {
|
|
|
|
/*
|
|
|
|
* Just ".."? That is not a range but the
|
|
|
|
* pathspec for the parent directory.
|
|
|
|
*/
|
|
|
|
*dotdot = '.';
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-07-03 22:45:12 +02:00
|
|
|
if (!get_sha1_committish(this, sha1) && !get_sha1_committish(next, end)) {
|
2006-07-04 11:02:22 +02:00
|
|
|
show_rev(NORMAL, end, next);
|
|
|
|
show_rev(symmetric ? NORMAL : REVERSED, sha1, this);
|
|
|
|
if (symmetric) {
|
|
|
|
struct commit_list *exclude;
|
|
|
|
struct commit *a, *b;
|
|
|
|
a = lookup_commit_reference(sha1);
|
|
|
|
b = lookup_commit_reference(end);
|
|
|
|
exclude = get_merge_bases(a, b, 1);
|
|
|
|
while (exclude) {
|
|
|
|
struct commit_list *n = exclude->next;
|
|
|
|
show_rev(REVERSED,
|
|
|
|
exclude->item->object.sha1,NULL);
|
|
|
|
free(exclude);
|
|
|
|
exclude = n;
|
|
|
|
}
|
|
|
|
}
|
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-06 23:07:52 +01:00
|
|
|
*dotdot = '.';
|
2006-07-04 11:02:22 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
*dotdot = '.';
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-07-26 18:37:56 +02:00
|
|
|
static int try_parent_shorthands(const char *arg)
|
|
|
|
{
|
|
|
|
char *dotdot;
|
|
|
|
unsigned char sha1[20];
|
|
|
|
struct commit *commit;
|
|
|
|
struct commit_list *parents;
|
|
|
|
int parents_only;
|
|
|
|
|
|
|
|
if ((dotdot = strstr(arg, "^!")))
|
|
|
|
parents_only = 0;
|
|
|
|
else if ((dotdot = strstr(arg, "^@")))
|
|
|
|
parents_only = 1;
|
|
|
|
|
|
|
|
if (!dotdot || dotdot[2])
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
*dotdot = 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-06 23:07:52 +01:00
|
|
|
if (get_sha1_committish(arg, sha1)) {
|
|
|
|
*dotdot = '^';
|
2008-07-26 18:37:56 +02: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-06 23:07:52 +01:00
|
|
|
}
|
2008-07-26 18:37:56 +02:00
|
|
|
|
|
|
|
if (!parents_only)
|
|
|
|
show_rev(NORMAL, sha1, arg);
|
|
|
|
commit = lookup_commit_reference(sha1);
|
|
|
|
for (parents = commit->parents; parents; parents = parents->next)
|
|
|
|
show_rev(parents_only ? NORMAL : REVERSED,
|
|
|
|
parents->item->object.sha1, arg);
|
|
|
|
|
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-06 23:07:52 +01:00
|
|
|
*dotdot = '^';
|
2008-07-26 18:37:56 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2007-11-04 11:30:53 +01: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 12:08:29 +01:00
|
|
|
else if (o->short_name && (o->long_name == NULL || !stuck_long))
|
2007-11-04 11:30:53 +01:00
|
|
|
strbuf_addf(parsed, " -%c", o->short_name);
|
|
|
|
else
|
|
|
|
strbuf_addf(parsed, " --%s", o->long_name);
|
|
|
|
if (arg) {
|
2013-10-31 12:08:29 +01:00
|
|
|
if (!stuck_long)
|
|
|
|
strbuf_addch(parsed, ' ');
|
|
|
|
else if (o->long_name)
|
|
|
|
strbuf_addch(parsed, '=');
|
2007-11-04 11:30:53 +01:00
|
|
|
sq_quote_buf(parsed, arg);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *skipspaces(const char *s)
|
|
|
|
{
|
|
|
|
while (isspace(*s))
|
|
|
|
s++;
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cmd_parseopt(int argc, const char **argv, const char *prefix)
|
|
|
|
{
|
2009-06-14 01:58:43 +02:00
|
|
|
static int keep_dashdash = 0, stop_at_non_option = 0;
|
2007-11-04 11:30:53 +01:00
|
|
|
static char const * const parseopt_usage[] = {
|
2012-08-20 14:32:40 +02:00
|
|
|
N_("git rev-parse --parseopt [options] -- [<args>...]"),
|
2007-11-04 11:30:53 +01:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
static struct option parseopt_opts[] = {
|
2013-08-03 13:51:19 +02:00
|
|
|
OPT_BOOL(0, "keep-dashdash", &keep_dashdash,
|
2012-08-20 14:32:40 +02:00
|
|
|
N_("keep the `--` passed as an arg")),
|
2013-08-03 13:51:19 +02:00
|
|
|
OPT_BOOL(0, "stop-at-non-option", &stop_at_non_option,
|
2012-08-20 14:32:40 +02:00
|
|
|
N_("stop parsing after the "
|
|
|
|
"first non-option argument")),
|
2013-10-31 12:08:29 +01:00
|
|
|
OPT_BOOL(0, "stuck-long", &stuck_long,
|
|
|
|
N_("output in stuck long form")),
|
2007-11-04 11:30:53 +01:00
|
|
|
OPT_END(),
|
|
|
|
};
|
|
|
|
|
2008-10-09 21:12:12 +02:00
|
|
|
struct strbuf sb = STRBUF_INIT, parsed = STRBUF_INIT;
|
2007-11-04 11:30:53 +01:00
|
|
|
const char **usage = NULL;
|
|
|
|
struct option *opts = NULL;
|
|
|
|
int onb = 0, osz = 0, unb = 0, usz = 0;
|
|
|
|
|
|
|
|
strbuf_addstr(&parsed, "set --");
|
2009-05-23 20:53:12 +02:00
|
|
|
argc = parse_options(argc, argv, prefix, parseopt_opts, parseopt_usage,
|
2007-11-04 11:30:53 +01: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 (;;) {
|
|
|
|
if (strbuf_getline(&sb, stdin, '\n') == EOF)
|
|
|
|
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 10:47:34 +01:00
|
|
|
/* parse: (<short>|<short>,<long>|<long>)[*=?!]*<arghint>? SP+ <help> */
|
2007-11-04 11:30:53 +01:00
|
|
|
while (strbuf_getline(&sb, stdin, '\n') != EOF) {
|
|
|
|
const char *s;
|
2014-03-22 10:47:34 +01:00
|
|
|
const char *end;
|
2007-11-04 11:30:53 +01:00
|
|
|
struct option *o;
|
|
|
|
|
|
|
|
if (!sb.len)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
ALLOC_GROW(opts, onb + 1, osz);
|
|
|
|
memset(opts + onb, 0, sizeof(opts[onb]));
|
|
|
|
|
|
|
|
o = &opts[onb++];
|
|
|
|
s = strchr(sb.buf, ' ');
|
|
|
|
if (!s || *sb.buf == ' ') {
|
|
|
|
o->type = OPTION_GROUP;
|
2008-02-26 05:07:39 +01:00
|
|
|
o->help = xstrdup(skipspaces(sb.buf));
|
2007-11-04 11:30:53 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
o->type = OPTION_CALLBACK;
|
|
|
|
o->help = xstrdup(skipspaces(s));
|
|
|
|
o->value = &parsed;
|
2008-03-02 09:21:38 +01:00
|
|
|
o->flags = PARSE_OPT_NOARG;
|
2007-11-04 11:30:53 +01:00
|
|
|
o->callback = &parseopt_dump;
|
2014-03-22 10:47:34 +01:00
|
|
|
|
|
|
|
/* Possible argument name hint */
|
|
|
|
end = s;
|
|
|
|
while (s > sb.buf && strchr("*=?!", s[-1]) == NULL)
|
|
|
|
--s;
|
|
|
|
if (s != sb.buf && s != end)
|
|
|
|
o->argh = xmemdupz(s, end - s);
|
|
|
|
if (s == sb.buf)
|
|
|
|
s = end;
|
|
|
|
|
2008-03-02 09:21:38 +01:00
|
|
|
while (s > sb.buf && strchr("*=?!", s[-1])) {
|
|
|
|
switch (*--s) {
|
|
|
|
case '=':
|
|
|
|
o->flags &= ~PARSE_OPT_NOARG;
|
|
|
|
break;
|
|
|
|
case '?':
|
|
|
|
o->flags &= ~PARSE_OPT_NOARG;
|
|
|
|
o->flags |= PARSE_OPT_OPTARG;
|
|
|
|
break;
|
|
|
|
case '!':
|
|
|
|
o->flags |= PARSE_OPT_NONEG;
|
|
|
|
break;
|
|
|
|
case '*':
|
|
|
|
o->flags |= PARSE_OPT_HIDDEN;
|
|
|
|
break;
|
|
|
|
}
|
2007-11-04 11:30:53 +01: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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
strbuf_release(&sb);
|
|
|
|
|
|
|
|
/* put an OPT_END() */
|
|
|
|
ALLOC_GROW(opts, onb + 1, osz);
|
|
|
|
memset(opts + onb, 0, sizeof(opts[onb]));
|
2009-05-23 20:53:12 +02:00
|
|
|
argc = parse_options(argc, argv, prefix, opts, usage,
|
2010-07-06 16:46:05 +02:00
|
|
|
(keep_dashdash ? PARSE_OPT_KEEP_DASHDASH : 0) |
|
2010-07-07 20:18:26 +02:00
|
|
|
(stop_at_non_option ? PARSE_OPT_STOP_AT_NON_OPTION : 0) |
|
2010-06-12 14:57:39 +02:00
|
|
|
PARSE_OPT_SHELL_EVAL);
|
2007-11-04 11:30:53 +01:00
|
|
|
|
|
|
|
strbuf_addf(&parsed, " --");
|
2007-12-03 05:51:50 +01:00
|
|
|
sq_quote_argv(&parsed, argv, 0);
|
2007-11-04 11:30:53 +01:00
|
|
|
puts(parsed.buf);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-04-25 06:55:26 +02:00
|
|
|
static int cmd_sq_quote(int argc, const char **argv)
|
|
|
|
{
|
|
|
|
struct strbuf buf = STRBUF_INIT;
|
|
|
|
|
|
|
|
if (argc)
|
|
|
|
sq_quote_argv(&buf, argv, 0);
|
|
|
|
printf("%s\n", buf.buf);
|
|
|
|
strbuf_release(&buf);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-04-26 13:57:23 +02:00
|
|
|
static void die_no_single_rev(int quiet)
|
|
|
|
{
|
|
|
|
if (quiet)
|
|
|
|
exit(1);
|
|
|
|
else
|
|
|
|
die("Needed a single revision");
|
|
|
|
}
|
|
|
|
|
2009-11-09 16:04:54 +01:00
|
|
|
static const char builtin_rev_parse_usage[] =
|
2012-08-20 14:32:40 +02:00
|
|
|
N_("git rev-parse --parseopt [options] -- [<args>...]\n"
|
|
|
|
" or: git rev-parse --sq-quote [<arg>...]\n"
|
|
|
|
" or: git rev-parse [options] [<arg>...]\n"
|
|
|
|
"\n"
|
|
|
|
"Run \"git rev-parse --parseopt -h\" for more information on the first usage.");
|
2009-11-09 16:04:54 +01:00
|
|
|
|
2006-07-29 07:44:25 +02:00
|
|
|
int cmd_rev_parse(int argc, const char **argv, const char *prefix)
|
2005-06-13 19:06:50 +02:00
|
|
|
{
|
2008-05-11 18:28:25 +02:00
|
|
|
int i, as_is = 0, verify = 0, quiet = 0, revs_count = 0, type = 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-06 23:05:48 +01:00
|
|
|
int has_dashdash = 0;
|
2013-06-16 16:18:17 +02:00
|
|
|
int output_prefix = 0;
|
2005-06-13 19:06:50 +02:00
|
|
|
unsigned char sha1[20];
|
2008-05-11 18:28:25 +02:00
|
|
|
const char *name = NULL;
|
2006-05-14 03:43:00 +02:00
|
|
|
|
2007-11-04 11:30:53 +01:00
|
|
|
if (argc > 1 && !strcmp("--parseopt", argv[1]))
|
|
|
|
return cmd_parseopt(argc - 1, argv + 1, prefix);
|
|
|
|
|
2009-04-25 06:55:26 +02:00
|
|
|
if (argc > 1 && !strcmp("--sq-quote", argv[1]))
|
|
|
|
return cmd_sq_quote(argc - 2, argv + 2);
|
|
|
|
|
2009-11-09 16:04:54 +01: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-06 23:05:48 +01:00
|
|
|
for (i = 1; i < argc; i++) {
|
|
|
|
if (!strcmp(argv[i], "--")) {
|
|
|
|
has_dashdash = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-11-06 21:23:14 +01:00
|
|
|
prefix = setup_git_directory();
|
2008-05-14 19:46:53 +02:00
|
|
|
git_config(git_default_config, NULL);
|
2005-06-13 19:06:50 +02:00
|
|
|
for (i = 1; i < argc; i++) {
|
2006-06-06 07:36:21 +02:00
|
|
|
const char *arg = argv[i];
|
2006-03-27 02:28:20 +02:00
|
|
|
|
2005-06-13 19:06:50 +02:00
|
|
|
if (as_is) {
|
2013-06-16 16:18:17 +02:00
|
|
|
if (show_file(arg, output_prefix) && as_is < 2)
|
2012-06-18 20:18:21 +02:00
|
|
|
verify_filename(prefix, arg, 0);
|
2005-06-13 19:06:50 +02:00
|
|
|
continue;
|
|
|
|
}
|
2006-01-30 01:26:40 +01: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-11-30 21:55:40 +01:00
|
|
|
if (starts_with(arg, "-n")) {
|
2006-01-30 01:26:40 +01:00
|
|
|
if ((filter & DO_FLAGS) && (filter & DO_REVS))
|
|
|
|
show(arg);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2005-06-13 19:06:50 +02:00
|
|
|
if (*arg == '-') {
|
|
|
|
if (!strcmp(arg, "--")) {
|
2006-03-27 02:28:20 +02:00
|
|
|
as_is = 2;
|
2005-10-21 02:16:30 +02:00
|
|
|
/* Pass on the "--" if we show anything but files.. */
|
|
|
|
if (filter & (DO_FLAGS | DO_REVS))
|
2013-06-16 16:18:17 +02:00
|
|
|
show_file(arg, 0);
|
2005-08-24 23:30:04 +02:00
|
|
|
continue;
|
2005-06-13 19:06:50 +02:00
|
|
|
}
|
|
|
|
if (!strcmp(arg, "--default")) {
|
2014-01-28 22:21:00 +01:00
|
|
|
def = argv[++i];
|
|
|
|
if (!def)
|
|
|
|
die("--default requires an argument");
|
2005-06-13 19:06:50 +02:00
|
|
|
continue;
|
|
|
|
}
|
2013-06-16 16:18:17 +02:00
|
|
|
if (!strcmp(arg, "--prefix")) {
|
2014-01-28 22:21:00 +01:00
|
|
|
prefix = argv[++i];
|
|
|
|
if (!prefix)
|
|
|
|
die("--prefix requires an argument");
|
2013-06-16 16:18:17 +02:00
|
|
|
startup_info->prefix = prefix;
|
|
|
|
output_prefix = 1;
|
|
|
|
continue;
|
|
|
|
}
|
2005-06-13 19:21:11 +02:00
|
|
|
if (!strcmp(arg, "--revs-only")) {
|
2005-08-24 23:30:04 +02:00
|
|
|
filter &= ~DO_NOREV;
|
2005-06-13 19:21:11 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!strcmp(arg, "--no-revs")) {
|
2005-08-24 23:30:04 +02:00
|
|
|
filter &= ~DO_REVS;
|
2005-06-13 19:21:11 +02:00
|
|
|
continue;
|
|
|
|
}
|
2005-07-06 19:08:08 +02:00
|
|
|
if (!strcmp(arg, "--flags")) {
|
2005-08-24 23:30:04 +02:00
|
|
|
filter &= ~DO_NONFLAGS;
|
2005-07-06 19:08:08 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!strcmp(arg, "--no-flags")) {
|
2005-08-24 23:30:04 +02:00
|
|
|
filter &= ~DO_FLAGS;
|
2005-07-06 19:08:08 +02:00
|
|
|
continue;
|
|
|
|
}
|
2005-06-24 19:12:55 +02:00
|
|
|
if (!strcmp(arg, "--verify")) {
|
2005-08-24 23:30:04 +02:00
|
|
|
filter &= ~(DO_FLAGS|DO_NOREV);
|
|
|
|
verify = 1;
|
2005-06-24 19:12:55 +02:00
|
|
|
continue;
|
2005-06-13 20:14:20 +02:00
|
|
|
}
|
2008-04-26 13:57:23 +02:00
|
|
|
if (!strcmp(arg, "--quiet") || !strcmp(arg, "-q")) {
|
|
|
|
quiet = 1;
|
|
|
|
continue;
|
|
|
|
}
|
2006-01-27 02:02:07 +01:00
|
|
|
if (!strcmp(arg, "--short") ||
|
2013-11-30 21:55:40 +01:00
|
|
|
starts_with(arg, "--short=")) {
|
2006-01-25 10:35:38 +01:00
|
|
|
filter &= ~(DO_FLAGS|DO_NOREV);
|
|
|
|
verify = 1;
|
|
|
|
abbrev = DEFAULT_ABBREV;
|
2006-02-18 02:10:53 +01:00
|
|
|
if (arg[7] == '=')
|
|
|
|
abbrev = strtoul(arg + 8, NULL, 10);
|
2006-01-26 09:48:19 +01:00
|
|
|
if (abbrev < MINIMUM_ABBREV)
|
|
|
|
abbrev = MINIMUM_ABBREV;
|
|
|
|
else if (40 <= abbrev)
|
|
|
|
abbrev = 40;
|
2006-01-25 10:35:38 +01: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 04:08:32 +02:00
|
|
|
if (!strcmp(arg, "--sq")) {
|
|
|
|
output_sq = 1;
|
|
|
|
continue;
|
|
|
|
}
|
2005-06-26 20:34:30 +02:00
|
|
|
if (!strcmp(arg, "--not")) {
|
|
|
|
show_type ^= REVERSED;
|
|
|
|
continue;
|
|
|
|
}
|
2005-08-16 21:36:46 +02:00
|
|
|
if (!strcmp(arg, "--symbolic")) {
|
2008-01-05 21:09:55 +01:00
|
|
|
symbolic = SHOW_SYMBOLIC_ASIS;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!strcmp(arg, "--symbolic-full-name")) {
|
|
|
|
symbolic = SHOW_SYMBOLIC_FULL;
|
2005-08-16 21:36:46 +02:00
|
|
|
continue;
|
|
|
|
}
|
2013-11-30 21:55:40 +01:00
|
|
|
if (starts_with(arg, "--abbrev-ref") &&
|
2009-04-13 13:20:26 +02:00
|
|
|
(!arg[12] || arg[12] == '=')) {
|
|
|
|
abbrev_ref = 1;
|
|
|
|
abbrev_ref_strict = warn_ambiguous_refs;
|
|
|
|
if (arg[12] == '=') {
|
|
|
|
if (!strcmp(arg + 13, "strict"))
|
|
|
|
abbrev_ref_strict = 1;
|
|
|
|
else if (!strcmp(arg + 13, "loose"))
|
|
|
|
abbrev_ref_strict = 0;
|
|
|
|
else
|
|
|
|
die("unknown mode for %s", arg);
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
2005-07-03 22:07:52 +02:00
|
|
|
if (!strcmp(arg, "--all")) {
|
2006-09-21 06:47:42 +02:00
|
|
|
for_each_ref(show_reference, NULL);
|
2005-07-03 22:07:52 +02:00
|
|
|
continue;
|
|
|
|
}
|
2013-11-30 21:55:40 +01:00
|
|
|
if (starts_with(arg, "--disambiguate=")) {
|
2012-07-03 23:21:59 +02:00
|
|
|
for_each_abbrev(arg + 15, show_abbrev, NULL);
|
|
|
|
continue;
|
|
|
|
}
|
2009-10-27 19:28:07 +01:00
|
|
|
if (!strcmp(arg, "--bisect")) {
|
|
|
|
for_each_ref_in("refs/bisect/bad", show_reference, NULL);
|
|
|
|
for_each_ref_in("refs/bisect/good", anti_reference, NULL);
|
|
|
|
continue;
|
|
|
|
}
|
2013-11-30 21:55:40 +01:00
|
|
|
if (starts_with(arg, "--branches=")) {
|
2010-01-20 10:48:26 +01:00
|
|
|
for_each_glob_ref_in(show_reference, arg + 11,
|
|
|
|
"refs/heads/", NULL);
|
2013-11-01 20:13:01 +01:00
|
|
|
clear_ref_exclusion(&ref_excludes);
|
2010-01-20 10:48:26 +01:00
|
|
|
continue;
|
|
|
|
}
|
2006-05-14 03:43:00 +02:00
|
|
|
if (!strcmp(arg, "--branches")) {
|
2006-09-21 06:47:42 +02:00
|
|
|
for_each_branch_ref(show_reference, NULL);
|
2013-11-01 20:13:01 +01:00
|
|
|
clear_ref_exclusion(&ref_excludes);
|
2006-05-14 03:43:00 +02:00
|
|
|
continue;
|
|
|
|
}
|
2013-11-30 21:55:40 +01:00
|
|
|
if (starts_with(arg, "--tags=")) {
|
2010-01-20 10:48:26 +01:00
|
|
|
for_each_glob_ref_in(show_reference, arg + 7,
|
|
|
|
"refs/tags/", NULL);
|
2013-11-01 20:13:01 +01:00
|
|
|
clear_ref_exclusion(&ref_excludes);
|
2010-01-20 10:48:26 +01:00
|
|
|
continue;
|
|
|
|
}
|
2006-05-14 03:43:00 +02:00
|
|
|
if (!strcmp(arg, "--tags")) {
|
2006-09-21 06:47:42 +02:00
|
|
|
for_each_tag_ref(show_reference, NULL);
|
2013-11-01 20:13:01 +01:00
|
|
|
clear_ref_exclusion(&ref_excludes);
|
2006-05-14 03:43:00 +02:00
|
|
|
continue;
|
|
|
|
}
|
2013-11-30 21:55:40 +01:00
|
|
|
if (starts_with(arg, "--glob=")) {
|
2010-01-20 10:48:25 +01:00
|
|
|
for_each_glob_ref(show_reference, arg + 7, NULL);
|
2013-11-01 20:13:01 +01:00
|
|
|
clear_ref_exclusion(&ref_excludes);
|
2010-01-20 10:48:25 +01:00
|
|
|
continue;
|
|
|
|
}
|
2013-11-30 21:55:40 +01:00
|
|
|
if (starts_with(arg, "--remotes=")) {
|
2010-01-20 10:48:26 +01:00
|
|
|
for_each_glob_ref_in(show_reference, arg + 10,
|
|
|
|
"refs/remotes/", NULL);
|
2013-11-01 20:13:01 +01:00
|
|
|
clear_ref_exclusion(&ref_excludes);
|
2010-01-20 10:48:26 +01:00
|
|
|
continue;
|
|
|
|
}
|
2006-05-14 03:43:00 +02:00
|
|
|
if (!strcmp(arg, "--remotes")) {
|
2006-09-21 06:47:42 +02:00
|
|
|
for_each_remote_ref(show_reference, NULL);
|
2013-11-01 20:13:01 +01:00
|
|
|
clear_ref_exclusion(&ref_excludes);
|
|
|
|
continue;
|
|
|
|
}
|
2013-12-17 20:47:35 +01:00
|
|
|
if (starts_with(arg, "--exclude=")) {
|
2013-11-01 20:13:01 +01:00
|
|
|
add_ref_exclusion(&ref_excludes, arg + 10);
|
2006-05-14 03:43:00 +02:00
|
|
|
continue;
|
|
|
|
}
|
2013-07-21 14:49:26 +02: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;
|
|
|
|
}
|
2010-01-11 23:33:48 +01:00
|
|
|
if (!strcmp(arg, "--show-toplevel")) {
|
|
|
|
const char *work_tree = get_git_work_tree();
|
|
|
|
if (work_tree)
|
|
|
|
puts(work_tree);
|
|
|
|
continue;
|
|
|
|
}
|
2005-08-17 03:06:34 +02:00
|
|
|
if (!strcmp(arg, "--show-prefix")) {
|
2005-08-24 23:30:04 +02:00
|
|
|
if (prefix)
|
|
|
|
puts(prefix);
|
2012-04-09 15:27:56 +02:00
|
|
|
else
|
|
|
|
putchar('\n');
|
2005-08-17 03:06:34 +02:00
|
|
|
continue;
|
|
|
|
}
|
2005-12-23 07:35:38 +01: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 02:30:14 +02: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 07:35:38 +01:00
|
|
|
while (pfx) {
|
|
|
|
pfx = strchr(pfx, '/');
|
|
|
|
if (pfx) {
|
|
|
|
pfx++;
|
|
|
|
printf("../");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
putchar('\n');
|
|
|
|
continue;
|
|
|
|
}
|
2005-09-18 20:18:30 +02:00
|
|
|
if (!strcmp(arg, "--git-dir")) {
|
|
|
|
const char *gitdir = getenv(GIT_DIR_ENVIRONMENT);
|
|
|
|
static char cwd[PATH_MAX];
|
2010-02-14 16:44:42 +01:00
|
|
|
int len;
|
2005-09-18 20:18:30 +02:00
|
|
|
if (gitdir) {
|
|
|
|
puts(gitdir);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!prefix) {
|
|
|
|
puts(".git");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!getcwd(cwd, PATH_MAX))
|
2009-06-27 17:58:47 +02:00
|
|
|
die_errno("unable to get current working directory");
|
2010-02-14 16:44:42 +01:00
|
|
|
len = strlen(cwd);
|
|
|
|
printf("%s%s.git\n", cwd, len && cwd[len-1] != '/' ? "/" : "");
|
2005-09-18 20:18:30 +02:00
|
|
|
continue;
|
|
|
|
}
|
2013-07-21 14:49:26 +02:00
|
|
|
if (!strcmp(arg, "--resolve-git-dir")) {
|
2014-01-28 22:21:00 +01:00
|
|
|
const char *gitdir = argv[++i];
|
2013-07-21 14:49:26 +02:00
|
|
|
if (!gitdir)
|
2014-01-28 22:21:00 +01:00
|
|
|
die("--resolve-git-dir requires an argument");
|
|
|
|
gitdir = resolve_gitdir(gitdir);
|
|
|
|
if (!gitdir)
|
|
|
|
die("not a gitdir '%s'", argv[i]);
|
2013-07-21 14:49:26 +02:00
|
|
|
puts(gitdir);
|
|
|
|
continue;
|
|
|
|
}
|
2007-01-23 13:30:20 +01:00
|
|
|
if (!strcmp(arg, "--is-inside-git-dir")) {
|
|
|
|
printf("%s\n", is_inside_git_dir() ? "true"
|
|
|
|
: "false");
|
|
|
|
continue;
|
|
|
|
}
|
2007-06-06 09:10:42 +02:00
|
|
|
if (!strcmp(arg, "--is-inside-work-tree")) {
|
|
|
|
printf("%s\n", is_inside_work_tree() ? "true"
|
|
|
|
: "false");
|
|
|
|
continue;
|
|
|
|
}
|
2007-06-03 16:46:36 +02:00
|
|
|
if (!strcmp(arg, "--is-bare-repository")) {
|
|
|
|
printf("%s\n", is_bare_repository() ? "true"
|
|
|
|
: "false");
|
|
|
|
continue;
|
|
|
|
}
|
2014-06-13 14:19:46 +02:00
|
|
|
if (!strcmp(arg, "--shared-index-path")) {
|
|
|
|
if (read_cache() < 0)
|
|
|
|
die(_("Could not read the index"));
|
|
|
|
if (the_index.split_index) {
|
|
|
|
const unsigned char *sha1 = the_index.split_index->base_sha1;
|
|
|
|
puts(git_path("sharedindex.%s", sha1_to_hex(sha1)));
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
2013-11-30 21:55:40 +01:00
|
|
|
if (starts_with(arg, "--since=")) {
|
2005-09-20 23:13:24 +02:00
|
|
|
show_datestring("--max-age=", arg+8);
|
|
|
|
continue;
|
|
|
|
}
|
2013-11-30 21:55:40 +01:00
|
|
|
if (starts_with(arg, "--after=")) {
|
2005-09-20 23:13:24 +02:00
|
|
|
show_datestring("--max-age=", arg+8);
|
|
|
|
continue;
|
|
|
|
}
|
2013-11-30 21:55:40 +01:00
|
|
|
if (starts_with(arg, "--before=")) {
|
2005-09-20 23:13:24 +02:00
|
|
|
show_datestring("--min-age=", arg+9);
|
|
|
|
continue;
|
|
|
|
}
|
2013-11-30 21:55:40 +01:00
|
|
|
if (starts_with(arg, "--until=")) {
|
2005-09-20 23:13:24 +02:00
|
|
|
show_datestring("--min-age=", arg+8);
|
|
|
|
continue;
|
|
|
|
}
|
2006-02-05 20:58:34 +01:00
|
|
|
if (show_flag(arg) && verify)
|
2008-04-26 13:57:23 +02:00
|
|
|
die_no_single_rev(quiet);
|
2005-06-13 19:06:50 +02:00
|
|
|
continue;
|
|
|
|
}
|
2005-08-24 23:30:04 +02:00
|
|
|
|
|
|
|
/* Not a flag argument */
|
2006-07-04 11:02:22 +02:00
|
|
|
if (try_difference(arg))
|
|
|
|
continue;
|
2008-07-26 18:37:56 +02:00
|
|
|
if (try_parent_shorthands(arg))
|
|
|
|
continue;
|
2008-05-11 18:28:25 +02:00
|
|
|
name = arg;
|
|
|
|
type = NORMAL;
|
|
|
|
if (*arg == '^') {
|
|
|
|
name++;
|
|
|
|
type = REVERSED;
|
2005-06-20 17:29:13 +02:00
|
|
|
}
|
2008-05-11 18:28:25 +02:00
|
|
|
if (!get_sha1(name, sha1)) {
|
|
|
|
if (verify)
|
|
|
|
revs_count++;
|
|
|
|
else
|
|
|
|
show_rev(type, sha1, name);
|
2005-06-20 17:29:13 +02:00
|
|
|
continue;
|
|
|
|
}
|
2008-04-26 15:19:29 +02: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-06 23:05:48 +01:00
|
|
|
if (has_dashdash)
|
|
|
|
die("bad revision '%s'", arg);
|
2006-02-06 06:41:47 +01:00
|
|
|
as_is = 1;
|
2013-06-16 16:18:17 +02:00
|
|
|
if (!show_file(arg, output_prefix))
|
2006-02-06 06:41:47 +01:00
|
|
|
continue;
|
2012-06-18 20:18:21 +02:00
|
|
|
verify_filename(prefix, arg, 1);
|
2005-06-24 19:12:55 +02:00
|
|
|
}
|
2008-05-11 18:28:25 +02:00
|
|
|
if (verify) {
|
|
|
|
if (revs_count == 1) {
|
|
|
|
show_rev(type, sha1, name);
|
|
|
|
return 0;
|
|
|
|
} else if (revs_count == 0 && show_default())
|
|
|
|
return 0;
|
2008-04-26 13:57:23 +02:00
|
|
|
die_no_single_rev(quiet);
|
2008-05-11 18:28:25 +02:00
|
|
|
} else
|
|
|
|
show_default();
|
2005-06-13 19:06:50 +02:00
|
|
|
return 0;
|
|
|
|
}
|