2005-06-13 21:06:50 +04:00
|
|
|
/*
|
|
|
|
* rev-parse.c
|
|
|
|
*
|
|
|
|
* Copyright (C) Linus Torvalds, 2005
|
|
|
|
*/
|
|
|
|
#include "cache.h"
|
2005-06-21 07:28:09 +04:00
|
|
|
#include "commit.h"
|
2005-07-04 00:07:52 +04:00
|
|
|
#include "refs.h"
|
2005-09-21 01:13:24 +04:00
|
|
|
#include "quote.h"
|
2006-06-03 20:45:43 +04:00
|
|
|
#include "builtin.h"
|
2007-11-04 13:30:53 +03:00
|
|
|
#include "parse-options.h"
|
2005-06-21 07:28:09 +04:00
|
|
|
|
2005-08-25 01:30:04 +04:00
|
|
|
#define DO_REVS 1
|
|
|
|
#define DO_NOREV 2
|
|
|
|
#define DO_FLAGS 4
|
|
|
|
#define DO_NONFLAGS 8
|
|
|
|
static int filter = ~0;
|
|
|
|
|
2006-08-15 21:23:48 +04:00
|
|
|
static const char *def;
|
2005-06-24 21:12:55 +04:00
|
|
|
|
2005-06-26 22:34:30 +04:00
|
|
|
#define NORMAL 0
|
|
|
|
#define REVERSED 1
|
|
|
|
static int show_type = NORMAL;
|
2008-01-05 23:09:55 +03:00
|
|
|
|
|
|
|
#define SHOW_SYMBOLIC_ASIS 1
|
|
|
|
#define SHOW_SYMBOLIC_FULL 2
|
2006-08-15 21:23:48 +04:00
|
|
|
static int symbolic;
|
|
|
|
static int abbrev;
|
|
|
|
static int output_sq;
|
2005-08-25 01:30:04 +04:00
|
|
|
|
2005-06-13 22:14:20 +04: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 01:49:54 +04:00
|
|
|
"--all",
|
2005-08-25 01:30:04 +04:00
|
|
|
"--bisect",
|
2005-10-30 12:08:35 +03:00
|
|
|
"--dense",
|
2006-05-14 05:43:00 +04:00
|
|
|
"--branches",
|
2005-08-25 01:30:04 +04:00
|
|
|
"--header",
|
2005-06-13 22:14:20 +04:00
|
|
|
"--max-age=",
|
2005-08-25 01:30:04 +04:00
|
|
|
"--max-count=",
|
|
|
|
"--min-age=",
|
2005-08-09 06:31:37 +04:00
|
|
|
"--no-merges",
|
2005-08-25 01:30:04 +04:00
|
|
|
"--objects",
|
2006-02-19 14:32:31 +03:00
|
|
|
"--objects-edge",
|
2005-08-25 01:30:04 +04:00
|
|
|
"--parents",
|
|
|
|
"--pretty",
|
2006-05-14 05:43:00 +04:00
|
|
|
"--remotes",
|
2005-10-30 12:08:35 +03:00
|
|
|
"--sparse",
|
2006-05-14 05:43:00 +04:00
|
|
|
"--tags",
|
2005-08-25 01:30:04 +04:00
|
|
|
"--topo-order",
|
2006-02-16 09:05:33 +03:00
|
|
|
"--date-order",
|
2005-08-25 01:30:04 +04:00
|
|
|
"--unpacked",
|
2005-06-13 22:14:20 +04:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
const char **p = rev_args;
|
|
|
|
|
2006-01-30 03:28:02 +03:00
|
|
|
/* accept -<digit>, like traditional "head" */
|
|
|
|
if ((*arg == '-') && isdigit(arg[1]))
|
|
|
|
return 1;
|
|
|
|
|
2005-06-13 22:14:20 +04:00
|
|
|
for (;;) {
|
|
|
|
const char *str = *p++;
|
|
|
|
int len;
|
|
|
|
if (!str)
|
|
|
|
return 0;
|
|
|
|
len = strlen(str);
|
2005-08-25 01:30:04 +04:00
|
|
|
if (!strcmp(arg, str) ||
|
|
|
|
(str[len-1] == '=' && !strncmp(arg, str, len)))
|
2005-06-13 22:14:20 +04:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-08-25 01:30:04 +04: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 06:08:32 +04: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 18:13:05 +04: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 01:30:04 +04:00
|
|
|
/* Output a revision, only if filter allows it */
|
2005-08-16 23:36:46 +04:00
|
|
|
static void show_rev(int type, const unsigned char *sha1, const char *name)
|
2005-06-24 21:12:55 +04:00
|
|
|
{
|
2005-08-25 01:30:04 +04:00
|
|
|
if (!(filter & DO_REVS))
|
2005-06-24 21:12:55 +04:00
|
|
|
return;
|
2005-08-25 01:30:04 +04: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 06:08:32 +04:00
|
|
|
|
2008-01-05 23:09:55 +03:00
|
|
|
if (symbolic && name) {
|
|
|
|
if (symbolic == SHOW_SYMBOLIC_FULL) {
|
|
|
|
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 */
|
2008-05-23 18:13:05 +04:00
|
|
|
show_with_type(type, full);
|
2008-01-05 23:09:55 +03:00
|
|
|
break;
|
|
|
|
default: /* ambiguous */
|
|
|
|
error("refname '%s' is ambiguous", name);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
2008-05-23 18:13:05 +04:00
|
|
|
show_with_type(type, name);
|
2008-01-05 23:09:55 +03:00
|
|
|
}
|
|
|
|
}
|
2006-01-25 12:35:38 +03:00
|
|
|
else if (abbrev)
|
2008-05-23 18:13:05 +04:00
|
|
|
show_with_type(type, find_unique_abbrev(sha1, abbrev));
|
2005-08-16 23:36:46 +04:00
|
|
|
else
|
2008-05-23 18:13:05 +04:00
|
|
|
show_with_type(type, sha1_to_hex(sha1));
|
2005-06-24 21:12:55 +04:00
|
|
|
}
|
|
|
|
|
2005-08-25 01:30:04 +04:00
|
|
|
/* Output a flag, only if filter allows it. */
|
2006-06-06 09:36:21 +04:00
|
|
|
static int show_flag(const char *arg)
|
2005-06-24 21:12:55 +04:00
|
|
|
{
|
2005-08-25 01:30:04 +04:00
|
|
|
if (!(filter & DO_FLAGS))
|
2006-02-05 22:58:34 +03:00
|
|
|
return 0;
|
|
|
|
if (filter & (is_rev_argument(arg) ? DO_REVS : DO_NOREV)) {
|
2005-08-23 21:47:54 +04:00
|
|
|
show(arg);
|
2006-02-05 22:58:34 +03:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
2005-06-24 21:12:55 +04:00
|
|
|
}
|
|
|
|
|
2008-05-11 20:28:25 +04:00
|
|
|
static int show_default(void)
|
2005-06-24 21:12:55 +04:00
|
|
|
{
|
2006-06-06 09:36:21 +04:00
|
|
|
const char *s = def;
|
2005-06-24 21:12:55 +04:00
|
|
|
|
|
|
|
if (s) {
|
|
|
|
unsigned char sha1[20];
|
|
|
|
|
|
|
|
def = NULL;
|
2005-08-04 09:15:49 +04:00
|
|
|
if (!get_sha1(s, sha1)) {
|
2005-08-16 23:36:46 +04:00
|
|
|
show_rev(NORMAL, sha1, s);
|
2008-05-11 20:28:25 +04:00
|
|
|
return 1;
|
2005-06-24 21:12:55 +04:00
|
|
|
}
|
|
|
|
}
|
2008-05-11 20:28:25 +04:00
|
|
|
return 0;
|
2005-06-24 21:12:55 +04:00
|
|
|
}
|
|
|
|
|
2006-09-21 09:02:01 +04:00
|
|
|
static int show_reference(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
|
2005-07-04 00:07:52 +04:00
|
|
|
{
|
2005-08-16 23:36:46 +04:00
|
|
|
show_rev(NORMAL, sha1, refname);
|
2005-07-04 00:07:52 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-09-21 01:13:24 +04: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 06:29:06 +03:00
|
|
|
snprintf(buffer, sizeof(buffer), "%s%lu", flag, approxidate(datestr));
|
2005-09-21 01:13:24 +04:00
|
|
|
show(buffer);
|
|
|
|
}
|
|
|
|
|
2006-02-06 08:41:47 +03:00
|
|
|
static int show_file(const char *arg)
|
2005-10-18 11:16:45 +04:00
|
|
|
{
|
2005-10-26 02:24:55 +04:00
|
|
|
show_default();
|
2006-02-06 08:41:47 +03:00
|
|
|
if ((filter & (DO_NONFLAGS|DO_NOREV)) == (DO_NONFLAGS|DO_NOREV)) {
|
2005-10-18 11:16:45 +04:00
|
|
|
show(arg);
|
2006-02-06 08:41:47 +03:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
2005-10-18 11:16:45 +04:00
|
|
|
}
|
|
|
|
|
2006-07-06 11:16:35 +04:00
|
|
|
static int try_difference(const char *arg)
|
2006-07-04 13:02:22 +04:00
|
|
|
{
|
|
|
|
char *dotdot;
|
|
|
|
unsigned char sha1[20];
|
|
|
|
unsigned char end[20];
|
|
|
|
const char *next;
|
|
|
|
const char *this;
|
|
|
|
int symmetric;
|
|
|
|
|
|
|
|
if (!(dotdot = strstr(arg, "..")))
|
|
|
|
return 0;
|
|
|
|
next = dotdot + 2;
|
|
|
|
this = arg;
|
|
|
|
symmetric = (*next == '.');
|
|
|
|
|
|
|
|
*dotdot = 0;
|
|
|
|
next += symmetric;
|
|
|
|
|
|
|
|
if (!*next)
|
|
|
|
next = "HEAD";
|
|
|
|
if (dotdot == arg)
|
|
|
|
this = "HEAD";
|
|
|
|
if (!get_sha1(this, sha1) && !get_sha1(next, end)) {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
*dotdot = '.';
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-11-04 13:30:53 +03: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);
|
|
|
|
else if (o->short_name)
|
|
|
|
strbuf_addf(parsed, " -%c", o->short_name);
|
|
|
|
else
|
|
|
|
strbuf_addf(parsed, " --%s", o->long_name);
|
|
|
|
if (arg) {
|
|
|
|
strbuf_addch(parsed, ' ');
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
static int keep_dashdash = 0;
|
|
|
|
static char const * const parseopt_usage[] = {
|
|
|
|
"git-rev-parse --parseopt [options] -- [<args>...]",
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
static struct option parseopt_opts[] = {
|
|
|
|
OPT_BOOLEAN(0, "keep-dashdash", &keep_dashdash,
|
|
|
|
"keep the `--` passed as an arg"),
|
|
|
|
OPT_END(),
|
|
|
|
};
|
|
|
|
|
|
|
|
struct strbuf sb, parsed;
|
|
|
|
const char **usage = NULL;
|
|
|
|
struct option *opts = NULL;
|
|
|
|
int onb = 0, osz = 0, unb = 0, usz = 0;
|
|
|
|
|
|
|
|
strbuf_init(&parsed, 0);
|
|
|
|
strbuf_addstr(&parsed, "set --");
|
|
|
|
argc = parse_options(argc, argv, parseopt_opts, parseopt_usage,
|
|
|
|
PARSE_OPT_KEEP_DASHDASH);
|
|
|
|
if (argc < 1 || strcmp(argv[0], "--"))
|
|
|
|
usage_with_options(parseopt_usage, parseopt_opts);
|
|
|
|
|
|
|
|
strbuf_init(&sb, 0);
|
|
|
|
/* 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* parse: (<short>|<short>,<long>|<long>)[=?]? SP+ <help> */
|
|
|
|
while (strbuf_getline(&sb, stdin, '\n') != EOF) {
|
|
|
|
const char *s;
|
|
|
|
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 07:07:39 +03:00
|
|
|
o->help = xstrdup(skipspaces(sb.buf));
|
2007-11-04 13:30:53 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
o->type = OPTION_CALLBACK;
|
|
|
|
o->help = xstrdup(skipspaces(s));
|
|
|
|
o->value = &parsed;
|
2008-03-02 11:21:38 +03:00
|
|
|
o->flags = PARSE_OPT_NOARG;
|
2007-11-04 13:30:53 +03:00
|
|
|
o->callback = &parseopt_dump;
|
2008-03-02 11:21:38 +03: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 13:30:53 +03: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]));
|
|
|
|
argc = parse_options(argc, argv, opts, usage,
|
|
|
|
keep_dashdash ? PARSE_OPT_KEEP_DASHDASH : 0);
|
|
|
|
|
|
|
|
strbuf_addf(&parsed, " --");
|
2007-12-03 07:51:50 +03:00
|
|
|
sq_quote_argv(&parsed, argv, 0);
|
2007-11-04 13:30:53 +03:00
|
|
|
puts(parsed.buf);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-04-26 15:57:23 +04:00
|
|
|
static void die_no_single_rev(int quiet)
|
|
|
|
{
|
|
|
|
if (quiet)
|
|
|
|
exit(1);
|
|
|
|
else
|
|
|
|
die("Needed a single revision");
|
|
|
|
}
|
|
|
|
|
2006-07-29 09:44:25 +04:00
|
|
|
int cmd_rev_parse(int argc, const char **argv, const char *prefix)
|
2005-06-13 21:06:50 +04:00
|
|
|
{
|
2008-05-11 20:28:25 +04:00
|
|
|
int i, as_is = 0, verify = 0, quiet = 0, revs_count = 0, type = 0;
|
2005-06-13 21:06:50 +04:00
|
|
|
unsigned char sha1[20];
|
2008-05-11 20:28:25 +04:00
|
|
|
const char *name = NULL;
|
2006-05-14 05:43:00 +04:00
|
|
|
|
2007-11-04 13:30:53 +03:00
|
|
|
if (argc > 1 && !strcmp("--parseopt", argv[1]))
|
|
|
|
return cmd_parseopt(argc - 1, argv + 1, prefix);
|
|
|
|
|
2007-11-06 23:23:14 +03:00
|
|
|
prefix = setup_git_directory();
|
2008-05-14 21:46:53 +04:00
|
|
|
git_config(git_default_config, NULL);
|
2005-06-13 21:06:50 +04:00
|
|
|
for (i = 1; i < argc; i++) {
|
2006-06-06 09:36:21 +04:00
|
|
|
const char *arg = argv[i];
|
2006-03-27 04:28:20 +04:00
|
|
|
|
2005-06-13 21:06:50 +04:00
|
|
|
if (as_is) {
|
2006-03-27 04:28:20 +04:00
|
|
|
if (show_file(arg) && as_is < 2)
|
2006-04-26 21:15:54 +04:00
|
|
|
verify_filename(prefix, arg);
|
2005-06-13 21:06:50 +04:00
|
|
|
continue;
|
|
|
|
}
|
2006-01-30 03:26:40 +03: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;
|
|
|
|
}
|
2007-02-20 12:55:07 +03:00
|
|
|
if (!prefixcmp(arg, "-n")) {
|
2006-01-30 03:26:40 +03:00
|
|
|
if ((filter & DO_FLAGS) && (filter & DO_REVS))
|
|
|
|
show(arg);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2005-06-13 21:06:50 +04:00
|
|
|
if (*arg == '-') {
|
|
|
|
if (!strcmp(arg, "--")) {
|
2006-03-27 04:28:20 +04:00
|
|
|
as_is = 2;
|
2005-10-21 04:16:30 +04:00
|
|
|
/* Pass on the "--" if we show anything but files.. */
|
|
|
|
if (filter & (DO_FLAGS | DO_REVS))
|
|
|
|
show_file(arg);
|
2005-08-25 01:30:04 +04:00
|
|
|
continue;
|
2005-06-13 21:06:50 +04:00
|
|
|
}
|
|
|
|
if (!strcmp(arg, "--default")) {
|
|
|
|
def = argv[i+1];
|
|
|
|
i++;
|
|
|
|
continue;
|
|
|
|
}
|
2005-06-13 21:21:11 +04:00
|
|
|
if (!strcmp(arg, "--revs-only")) {
|
2005-08-25 01:30:04 +04:00
|
|
|
filter &= ~DO_NOREV;
|
2005-06-13 21:21:11 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!strcmp(arg, "--no-revs")) {
|
2005-08-25 01:30:04 +04:00
|
|
|
filter &= ~DO_REVS;
|
2005-06-13 21:21:11 +04:00
|
|
|
continue;
|
|
|
|
}
|
2005-07-06 21:08:08 +04:00
|
|
|
if (!strcmp(arg, "--flags")) {
|
2005-08-25 01:30:04 +04:00
|
|
|
filter &= ~DO_NONFLAGS;
|
2005-07-06 21:08:08 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!strcmp(arg, "--no-flags")) {
|
2005-08-25 01:30:04 +04:00
|
|
|
filter &= ~DO_FLAGS;
|
2005-07-06 21:08:08 +04:00
|
|
|
continue;
|
|
|
|
}
|
2005-06-24 21:12:55 +04:00
|
|
|
if (!strcmp(arg, "--verify")) {
|
2005-08-25 01:30:04 +04:00
|
|
|
filter &= ~(DO_FLAGS|DO_NOREV);
|
|
|
|
verify = 1;
|
2005-06-24 21:12:55 +04:00
|
|
|
continue;
|
2005-06-13 22:14:20 +04:00
|
|
|
}
|
2008-04-26 15:57:23 +04:00
|
|
|
if (!strcmp(arg, "--quiet") || !strcmp(arg, "-q")) {
|
|
|
|
quiet = 1;
|
|
|
|
continue;
|
|
|
|
}
|
2006-01-27 04:02:07 +03:00
|
|
|
if (!strcmp(arg, "--short") ||
|
Mechanical conversion to use prefixcmp()
This mechanically converts strncmp() to use prefixcmp(), but only when
the parameters match specific patterns, so that they can be verified
easily. Leftover from this will be fixed in a separate step, including
idiotic conversions like
if (!strncmp("foo", arg, 3))
=>
if (!(-prefixcmp(arg, "foo")))
This was done by using this script in px.perl
#!/usr/bin/perl -i.bak -p
if (/strncmp\(([^,]+), "([^\\"]*)", (\d+)\)/ && (length($2) == $3)) {
s|strncmp\(([^,]+), "([^\\"]*)", (\d+)\)|prefixcmp($1, "$2")|;
}
if (/strncmp\("([^\\"]*)", ([^,]+), (\d+)\)/ && (length($1) == $3)) {
s|strncmp\("([^\\"]*)", ([^,]+), (\d+)\)|(-prefixcmp($2, "$1"))|;
}
and running:
$ git grep -l strncmp -- '*.c' | xargs perl px.perl
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-20 12:53:29 +03:00
|
|
|
!prefixcmp(arg, "--short=")) {
|
2006-01-25 12:35:38 +03:00
|
|
|
filter &= ~(DO_FLAGS|DO_NOREV);
|
|
|
|
verify = 1;
|
|
|
|
abbrev = DEFAULT_ABBREV;
|
2006-02-18 04:10:53 +03:00
|
|
|
if (arg[7] == '=')
|
|
|
|
abbrev = strtoul(arg + 8, NULL, 10);
|
2006-01-26 11:48:19 +03:00
|
|
|
if (abbrev < MINIMUM_ABBREV)
|
|
|
|
abbrev = MINIMUM_ABBREV;
|
|
|
|
else if (40 <= abbrev)
|
|
|
|
abbrev = 40;
|
2006-01-25 12:35:38 +03: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 06:08:32 +04:00
|
|
|
if (!strcmp(arg, "--sq")) {
|
|
|
|
output_sq = 1;
|
|
|
|
continue;
|
|
|
|
}
|
2005-06-26 22:34:30 +04:00
|
|
|
if (!strcmp(arg, "--not")) {
|
|
|
|
show_type ^= REVERSED;
|
|
|
|
continue;
|
|
|
|
}
|
2005-08-16 23:36:46 +04:00
|
|
|
if (!strcmp(arg, "--symbolic")) {
|
2008-01-05 23:09:55 +03:00
|
|
|
symbolic = SHOW_SYMBOLIC_ASIS;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!strcmp(arg, "--symbolic-full-name")) {
|
|
|
|
symbolic = SHOW_SYMBOLIC_FULL;
|
2005-08-16 23:36:46 +04:00
|
|
|
continue;
|
|
|
|
}
|
2005-07-04 00:07:52 +04:00
|
|
|
if (!strcmp(arg, "--all")) {
|
2006-09-21 08:47:42 +04:00
|
|
|
for_each_ref(show_reference, NULL);
|
2005-07-04 00:07:52 +04:00
|
|
|
continue;
|
|
|
|
}
|
2006-05-14 05:43:00 +04:00
|
|
|
if (!strcmp(arg, "--branches")) {
|
2006-09-21 08:47:42 +04:00
|
|
|
for_each_branch_ref(show_reference, NULL);
|
2006-05-14 05:43:00 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!strcmp(arg, "--tags")) {
|
2006-09-21 08:47:42 +04:00
|
|
|
for_each_tag_ref(show_reference, NULL);
|
2006-05-14 05:43:00 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!strcmp(arg, "--remotes")) {
|
2006-09-21 08:47:42 +04:00
|
|
|
for_each_remote_ref(show_reference, NULL);
|
2006-05-14 05:43:00 +04:00
|
|
|
continue;
|
|
|
|
}
|
2005-08-17 05:06:34 +04:00
|
|
|
if (!strcmp(arg, "--show-prefix")) {
|
2005-08-25 01:30:04 +04:00
|
|
|
if (prefix)
|
|
|
|
puts(prefix);
|
2005-08-17 05:06:34 +04:00
|
|
|
continue;
|
|
|
|
}
|
2005-12-23 09:35:38 +03: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 04:30:14 +04: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 09:35:38 +03:00
|
|
|
while (pfx) {
|
|
|
|
pfx = strchr(pfx, '/');
|
|
|
|
if (pfx) {
|
|
|
|
pfx++;
|
|
|
|
printf("../");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
putchar('\n');
|
|
|
|
continue;
|
|
|
|
}
|
2005-09-18 22:18:30 +04:00
|
|
|
if (!strcmp(arg, "--git-dir")) {
|
|
|
|
const char *gitdir = getenv(GIT_DIR_ENVIRONMENT);
|
|
|
|
static char cwd[PATH_MAX];
|
|
|
|
if (gitdir) {
|
|
|
|
puts(gitdir);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!prefix) {
|
|
|
|
puts(".git");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!getcwd(cwd, PATH_MAX))
|
|
|
|
die("unable to get current working directory");
|
|
|
|
printf("%s/.git\n", cwd);
|
|
|
|
continue;
|
|
|
|
}
|
2007-01-23 15:30:20 +03:00
|
|
|
if (!strcmp(arg, "--is-inside-git-dir")) {
|
|
|
|
printf("%s\n", is_inside_git_dir() ? "true"
|
|
|
|
: "false");
|
|
|
|
continue;
|
|
|
|
}
|
2007-06-06 11:10:42 +04:00
|
|
|
if (!strcmp(arg, "--is-inside-work-tree")) {
|
|
|
|
printf("%s\n", is_inside_work_tree() ? "true"
|
|
|
|
: "false");
|
|
|
|
continue;
|
|
|
|
}
|
2007-06-03 18:46:36 +04:00
|
|
|
if (!strcmp(arg, "--is-bare-repository")) {
|
|
|
|
printf("%s\n", is_bare_repository() ? "true"
|
|
|
|
: "false");
|
|
|
|
continue;
|
|
|
|
}
|
Mechanical conversion to use prefixcmp()
This mechanically converts strncmp() to use prefixcmp(), but only when
the parameters match specific patterns, so that they can be verified
easily. Leftover from this will be fixed in a separate step, including
idiotic conversions like
if (!strncmp("foo", arg, 3))
=>
if (!(-prefixcmp(arg, "foo")))
This was done by using this script in px.perl
#!/usr/bin/perl -i.bak -p
if (/strncmp\(([^,]+), "([^\\"]*)", (\d+)\)/ && (length($2) == $3)) {
s|strncmp\(([^,]+), "([^\\"]*)", (\d+)\)|prefixcmp($1, "$2")|;
}
if (/strncmp\("([^\\"]*)", ([^,]+), (\d+)\)/ && (length($1) == $3)) {
s|strncmp\("([^\\"]*)", ([^,]+), (\d+)\)|(-prefixcmp($2, "$1"))|;
}
and running:
$ git grep -l strncmp -- '*.c' | xargs perl px.perl
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-20 12:53:29 +03:00
|
|
|
if (!prefixcmp(arg, "--since=")) {
|
2005-09-21 01:13:24 +04:00
|
|
|
show_datestring("--max-age=", arg+8);
|
|
|
|
continue;
|
|
|
|
}
|
Mechanical conversion to use prefixcmp()
This mechanically converts strncmp() to use prefixcmp(), but only when
the parameters match specific patterns, so that they can be verified
easily. Leftover from this will be fixed in a separate step, including
idiotic conversions like
if (!strncmp("foo", arg, 3))
=>
if (!(-prefixcmp(arg, "foo")))
This was done by using this script in px.perl
#!/usr/bin/perl -i.bak -p
if (/strncmp\(([^,]+), "([^\\"]*)", (\d+)\)/ && (length($2) == $3)) {
s|strncmp\(([^,]+), "([^\\"]*)", (\d+)\)|prefixcmp($1, "$2")|;
}
if (/strncmp\("([^\\"]*)", ([^,]+), (\d+)\)/ && (length($1) == $3)) {
s|strncmp\("([^\\"]*)", ([^,]+), (\d+)\)|(-prefixcmp($2, "$1"))|;
}
and running:
$ git grep -l strncmp -- '*.c' | xargs perl px.perl
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-20 12:53:29 +03:00
|
|
|
if (!prefixcmp(arg, "--after=")) {
|
2005-09-21 01:13:24 +04:00
|
|
|
show_datestring("--max-age=", arg+8);
|
|
|
|
continue;
|
|
|
|
}
|
Mechanical conversion to use prefixcmp()
This mechanically converts strncmp() to use prefixcmp(), but only when
the parameters match specific patterns, so that they can be verified
easily. Leftover from this will be fixed in a separate step, including
idiotic conversions like
if (!strncmp("foo", arg, 3))
=>
if (!(-prefixcmp(arg, "foo")))
This was done by using this script in px.perl
#!/usr/bin/perl -i.bak -p
if (/strncmp\(([^,]+), "([^\\"]*)", (\d+)\)/ && (length($2) == $3)) {
s|strncmp\(([^,]+), "([^\\"]*)", (\d+)\)|prefixcmp($1, "$2")|;
}
if (/strncmp\("([^\\"]*)", ([^,]+), (\d+)\)/ && (length($1) == $3)) {
s|strncmp\("([^\\"]*)", ([^,]+), (\d+)\)|(-prefixcmp($2, "$1"))|;
}
and running:
$ git grep -l strncmp -- '*.c' | xargs perl px.perl
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-20 12:53:29 +03:00
|
|
|
if (!prefixcmp(arg, "--before=")) {
|
2005-09-21 01:13:24 +04:00
|
|
|
show_datestring("--min-age=", arg+9);
|
|
|
|
continue;
|
|
|
|
}
|
Mechanical conversion to use prefixcmp()
This mechanically converts strncmp() to use prefixcmp(), but only when
the parameters match specific patterns, so that they can be verified
easily. Leftover from this will be fixed in a separate step, including
idiotic conversions like
if (!strncmp("foo", arg, 3))
=>
if (!(-prefixcmp(arg, "foo")))
This was done by using this script in px.perl
#!/usr/bin/perl -i.bak -p
if (/strncmp\(([^,]+), "([^\\"]*)", (\d+)\)/ && (length($2) == $3)) {
s|strncmp\(([^,]+), "([^\\"]*)", (\d+)\)|prefixcmp($1, "$2")|;
}
if (/strncmp\("([^\\"]*)", ([^,]+), (\d+)\)/ && (length($1) == $3)) {
s|strncmp\("([^\\"]*)", ([^,]+), (\d+)\)|(-prefixcmp($2, "$1"))|;
}
and running:
$ git grep -l strncmp -- '*.c' | xargs perl px.perl
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-20 12:53:29 +03:00
|
|
|
if (!prefixcmp(arg, "--until=")) {
|
2005-09-21 01:13:24 +04:00
|
|
|
show_datestring("--min-age=", arg+8);
|
|
|
|
continue;
|
|
|
|
}
|
2006-02-05 22:58:34 +03:00
|
|
|
if (show_flag(arg) && verify)
|
2008-04-26 15:57:23 +04:00
|
|
|
die_no_single_rev(quiet);
|
2005-06-13 21:06:50 +04:00
|
|
|
continue;
|
|
|
|
}
|
2005-08-25 01:30:04 +04:00
|
|
|
|
|
|
|
/* Not a flag argument */
|
2006-07-04 13:02:22 +04:00
|
|
|
if (try_difference(arg))
|
|
|
|
continue;
|
2008-05-11 20:28:25 +04:00
|
|
|
name = arg;
|
|
|
|
type = NORMAL;
|
|
|
|
if (*arg == '^') {
|
|
|
|
name++;
|
|
|
|
type = REVERSED;
|
2005-06-20 19:29:13 +04:00
|
|
|
}
|
2008-05-11 20:28:25 +04:00
|
|
|
if (!get_sha1(name, sha1)) {
|
|
|
|
if (verify)
|
|
|
|
revs_count++;
|
|
|
|
else
|
|
|
|
show_rev(type, sha1, name);
|
2005-06-20 19:29:13 +04:00
|
|
|
continue;
|
|
|
|
}
|
2008-04-26 17:19:29 +04:00
|
|
|
if (verify)
|
|
|
|
die_no_single_rev(quiet);
|
2006-02-06 08:41:47 +03:00
|
|
|
as_is = 1;
|
|
|
|
if (!show_file(arg))
|
|
|
|
continue;
|
2006-04-26 21:15:54 +04:00
|
|
|
verify_filename(prefix, arg);
|
2005-06-24 21:12:55 +04:00
|
|
|
}
|
2008-05-11 20:28:25 +04: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 15:57:23 +04:00
|
|
|
die_no_single_rev(quiet);
|
2008-05-11 20:28:25 +04:00
|
|
|
} else
|
|
|
|
show_default();
|
2005-06-13 21:06:50 +04:00
|
|
|
return 0;
|
|
|
|
}
|