2006-12-19 23:34:12 +01:00
|
|
|
#include "builtin.h"
|
2006-01-11 03:12:17 +01:00
|
|
|
#include "exec_cmd.h"
|
2006-06-05 19:43:52 +02:00
|
|
|
#include "cache.h"
|
2006-06-25 15:56:18 +02:00
|
|
|
#include "quote.h"
|
2005-11-16 00:31:25 +01:00
|
|
|
|
2006-07-30 23:42:25 +02:00
|
|
|
const char git_usage_string[] =
|
2007-08-19 19:24:36 +02:00
|
|
|
"git [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate|--no-pager] [--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE] [--help] COMMAND [ARGS]";
|
2006-07-30 23:42:25 +02:00
|
|
|
|
2005-11-16 00:31:25 +01:00
|
|
|
static void prepend_to_path(const char *dir, int len)
|
|
|
|
{
|
2006-06-28 11:04:39 +02:00
|
|
|
const char *old_path = getenv("PATH");
|
|
|
|
char *path;
|
2005-11-16 00:31:25 +01:00
|
|
|
int path_len = len;
|
|
|
|
|
|
|
|
if (!old_path)
|
2005-11-16 08:13:30 +01:00
|
|
|
old_path = "/usr/local/bin:/usr/bin:/bin";
|
2005-11-16 00:31:25 +01:00
|
|
|
|
|
|
|
path_len = len + strlen(old_path) + 1;
|
|
|
|
|
2006-09-01 00:32:39 +02:00
|
|
|
path = xmalloc(path_len + 1);
|
2005-11-16 00:31:25 +01:00
|
|
|
|
|
|
|
memcpy(path, dir, len);
|
|
|
|
path[len] = ':';
|
|
|
|
memcpy(path + len + 1, old_path, path_len - len);
|
|
|
|
|
|
|
|
setenv("PATH", path, 1);
|
2006-09-05 08:22:16 +02:00
|
|
|
|
|
|
|
free(path);
|
2005-11-16 00:31:25 +01:00
|
|
|
}
|
|
|
|
|
2007-06-08 22:57:55 +02:00
|
|
|
static int handle_options(const char*** argv, int* argc, int* envchanged)
|
2006-07-24 14:10:45 +02:00
|
|
|
{
|
|
|
|
int handled = 0;
|
|
|
|
|
|
|
|
while (*argc > 0) {
|
|
|
|
const char *cmd = (*argv)[0];
|
|
|
|
if (cmd[0] != '-')
|
|
|
|
break;
|
|
|
|
|
2006-07-25 20:24:22 +02:00
|
|
|
/*
|
|
|
|
* For legacy reasons, the "version" and "help"
|
|
|
|
* commands can be written with "--" prepended
|
|
|
|
* to make them look like flags.
|
|
|
|
*/
|
|
|
|
if (!strcmp(cmd, "--help") || !strcmp(cmd, "--version"))
|
|
|
|
break;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check remaining flags.
|
|
|
|
*/
|
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 10:53:29 +01:00
|
|
|
if (!prefixcmp(cmd, "--exec-path")) {
|
2006-07-25 20:24:22 +02:00
|
|
|
cmd += 11;
|
|
|
|
if (*cmd == '=')
|
|
|
|
git_set_exec_path(cmd + 1);
|
|
|
|
else {
|
|
|
|
puts(git_exec_path());
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
} else if (!strcmp(cmd, "-p") || !strcmp(cmd, "--paginate")) {
|
2006-07-24 14:10:45 +02:00
|
|
|
setup_pager();
|
2007-08-19 19:24:36 +02:00
|
|
|
} else if (!strcmp(cmd, "--no-pager")) {
|
|
|
|
setenv("GIT_PAGER", "cat", 1);
|
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
2006-07-25 20:24:22 +02:00
|
|
|
} else if (!strcmp(cmd, "--git-dir")) {
|
2006-12-22 14:56:25 +01:00
|
|
|
if (*argc < 2) {
|
|
|
|
fprintf(stderr, "No directory given for --git-dir.\n" );
|
|
|
|
usage(git_usage_string);
|
|
|
|
}
|
2006-12-31 05:29:11 +01:00
|
|
|
setenv(GIT_DIR_ENVIRONMENT, (*argv)[1], 1);
|
2007-06-08 22:57:55 +02:00
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
2006-07-25 20:24:22 +02:00
|
|
|
(*argv)++;
|
|
|
|
(*argc)--;
|
2007-04-12 20:52:03 +02:00
|
|
|
handled++;
|
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 10:53:29 +01:00
|
|
|
} else if (!prefixcmp(cmd, "--git-dir=")) {
|
2006-12-31 05:29:11 +01:00
|
|
|
setenv(GIT_DIR_ENVIRONMENT, cmd + 10, 1);
|
2007-06-08 22:57:55 +02:00
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
2007-06-06 09:10:42 +02:00
|
|
|
} else if (!strcmp(cmd, "--work-tree")) {
|
|
|
|
if (*argc < 2) {
|
|
|
|
fprintf(stderr, "No directory given for --work-tree.\n" );
|
|
|
|
usage(git_usage_string);
|
|
|
|
}
|
|
|
|
setenv(GIT_WORK_TREE_ENVIRONMENT, (*argv)[1], 1);
|
2007-06-08 22:57:55 +02:00
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
2007-06-06 09:10:42 +02:00
|
|
|
(*argv)++;
|
|
|
|
(*argc)--;
|
|
|
|
} else if (!prefixcmp(cmd, "--work-tree=")) {
|
|
|
|
setenv(GIT_WORK_TREE_ENVIRONMENT, cmd + 12, 1);
|
2007-06-08 22:57:55 +02:00
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
2006-07-25 20:24:22 +02:00
|
|
|
} else if (!strcmp(cmd, "--bare")) {
|
2006-12-31 05:28:53 +01:00
|
|
|
static char git_dir[PATH_MAX+1];
|
2007-08-27 09:58:06 +02:00
|
|
|
is_bare_repository_cfg = 1;
|
2007-08-28 07:41:23 +02:00
|
|
|
setenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir, sizeof(git_dir)), 0);
|
2007-06-08 22:57:55 +02:00
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
2006-07-25 20:24:22 +02:00
|
|
|
} else {
|
|
|
|
fprintf(stderr, "Unknown option: %s\n", cmd);
|
2006-07-30 23:42:25 +02:00
|
|
|
usage(git_usage_string);
|
2006-07-25 20:24:22 +02:00
|
|
|
}
|
2006-07-24 14:10:45 +02:00
|
|
|
|
|
|
|
(*argv)++;
|
|
|
|
(*argc)--;
|
|
|
|
handled++;
|
|
|
|
}
|
|
|
|
return handled;
|
|
|
|
}
|
|
|
|
|
2006-06-05 19:43:52 +02:00
|
|
|
static const char *alias_command;
|
2006-08-15 19:23:48 +02:00
|
|
|
static char *alias_string;
|
2006-06-05 19:43:52 +02:00
|
|
|
|
|
|
|
static int git_alias_config(const char *var, const char *value)
|
|
|
|
{
|
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 10:53:29 +01:00
|
|
|
if (!prefixcmp(var, "alias.") && !strcmp(var + 6, alias_command)) {
|
2006-09-02 06:16:31 +02:00
|
|
|
alias_string = xstrdup(value);
|
2006-06-05 19:43:52 +02:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int split_cmdline(char *cmdline, const char ***argv)
|
|
|
|
{
|
|
|
|
int src, dst, count = 0, size = 16;
|
|
|
|
char quoted = 0;
|
|
|
|
|
2007-03-26 02:39:36 +02:00
|
|
|
*argv = xmalloc(sizeof(char*) * size);
|
2006-06-05 19:43:52 +02:00
|
|
|
|
|
|
|
/* split alias_string */
|
|
|
|
(*argv)[count++] = cmdline;
|
|
|
|
for (src = dst = 0; cmdline[src];) {
|
|
|
|
char c = cmdline[src];
|
|
|
|
if (!quoted && isspace(c)) {
|
|
|
|
cmdline[dst++] = 0;
|
|
|
|
while (cmdline[++src]
|
|
|
|
&& isspace(cmdline[src]))
|
|
|
|
; /* skip */
|
|
|
|
if (count >= size) {
|
|
|
|
size += 16;
|
2006-08-26 16:16:18 +02:00
|
|
|
*argv = xrealloc(*argv, sizeof(char*) * size);
|
2006-06-05 19:43:52 +02:00
|
|
|
}
|
|
|
|
(*argv)[count++] = cmdline + dst;
|
|
|
|
} else if(!quoted && (c == '\'' || c == '"')) {
|
|
|
|
quoted = c;
|
|
|
|
src++;
|
|
|
|
} else if (c == quoted) {
|
|
|
|
quoted = 0;
|
|
|
|
src++;
|
|
|
|
} else {
|
|
|
|
if (c == '\\' && quoted != '\'') {
|
|
|
|
src++;
|
|
|
|
c = cmdline[src];
|
|
|
|
if (!c) {
|
|
|
|
free(*argv);
|
|
|
|
*argv = NULL;
|
|
|
|
return error("cmdline ends with \\");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cmdline[dst++] = c;
|
|
|
|
src++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cmdline[dst] = 0;
|
|
|
|
|
|
|
|
if (quoted) {
|
|
|
|
free(*argv);
|
|
|
|
*argv = NULL;
|
|
|
|
return error("unclosed quote");
|
|
|
|
}
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int handle_alias(int *argcp, const char ***argv)
|
|
|
|
{
|
2007-06-08 22:57:55 +02:00
|
|
|
int nongit = 0, envchanged = 0, ret = 0, saved_errno = errno;
|
2006-06-05 19:43:52 +02:00
|
|
|
const char *subdir;
|
2006-07-30 03:30:29 +02:00
|
|
|
int count, option_count;
|
|
|
|
const char** new_argv;
|
2006-06-05 19:43:52 +02:00
|
|
|
|
|
|
|
subdir = setup_git_directory_gently(&nongit);
|
2006-07-30 03:30:29 +02:00
|
|
|
|
|
|
|
alias_command = (*argv)[0];
|
|
|
|
git_config(git_alias_config);
|
|
|
|
if (alias_string) {
|
2007-02-11 01:33:58 +01:00
|
|
|
if (alias_string[0] == '!') {
|
2007-07-01 23:51:58 +02:00
|
|
|
if (*argcp > 1) {
|
2007-09-20 00:42:13 +02:00
|
|
|
struct strbuf buf;
|
2007-07-01 23:51:58 +02:00
|
|
|
|
2007-09-20 00:42:13 +02:00
|
|
|
strbuf_init(&buf, PATH_MAX);
|
|
|
|
strbuf_addstr(&buf, alias_string);
|
|
|
|
sq_quote_argv(&buf, (*argv) + 1, *argcp - 1, PATH_MAX);
|
2007-07-01 23:51:58 +02:00
|
|
|
free(alias_string);
|
2007-09-20 00:42:13 +02:00
|
|
|
alias_string = buf.buf;
|
2007-07-01 23:51:58 +02:00
|
|
|
}
|
2007-02-11 01:33:58 +01:00
|
|
|
trace_printf("trace: alias to shell cmd: %s => %s\n",
|
|
|
|
alias_command, alias_string + 1);
|
|
|
|
ret = system(alias_string + 1);
|
|
|
|
if (ret >= 0 && WIFEXITED(ret) &&
|
|
|
|
WEXITSTATUS(ret) != 127)
|
|
|
|
exit(WEXITSTATUS(ret));
|
|
|
|
die("Failed to run '%s' when expanding alias '%s'\n",
|
|
|
|
alias_string + 1, alias_command);
|
|
|
|
}
|
2006-07-30 03:30:29 +02:00
|
|
|
count = split_cmdline(alias_string, &new_argv);
|
2007-06-08 22:57:55 +02:00
|
|
|
option_count = handle_options(&new_argv, &count, &envchanged);
|
|
|
|
if (envchanged)
|
|
|
|
die("alias '%s' changes environment variables\n"
|
|
|
|
"You can use '!git' in the alias to do this.",
|
|
|
|
alias_command);
|
2006-07-30 03:30:29 +02:00
|
|
|
memmove(new_argv - option_count, new_argv,
|
|
|
|
count * sizeof(char *));
|
|
|
|
new_argv -= option_count;
|
|
|
|
|
|
|
|
if (count < 1)
|
|
|
|
die("empty alias for %s", alias_command);
|
|
|
|
|
|
|
|
if (!strcmp(alias_command, new_argv[0]))
|
|
|
|
die("recursive alias: %s", alias_command);
|
|
|
|
|
2006-09-02 18:23:48 +02:00
|
|
|
trace_argv_printf(new_argv, count,
|
|
|
|
"trace: alias expansion: %s =>",
|
|
|
|
alias_command);
|
2006-06-25 15:56:18 +02:00
|
|
|
|
2006-08-26 16:16:18 +02:00
|
|
|
new_argv = xrealloc(new_argv, sizeof(char*) *
|
|
|
|
(count + *argcp + 1));
|
2006-07-30 03:30:29 +02:00
|
|
|
/* insert after command name */
|
|
|
|
memcpy(new_argv + count, *argv + 1, sizeof(char*) * *argcp);
|
|
|
|
new_argv[count+*argcp] = NULL;
|
2006-06-05 19:43:52 +02:00
|
|
|
|
2006-07-30 03:30:29 +02:00
|
|
|
*argv = new_argv;
|
|
|
|
*argcp += count - 1;
|
2006-06-05 19:43:52 +02:00
|
|
|
|
2006-07-30 03:30:29 +02:00
|
|
|
ret = 1;
|
2006-06-05 19:43:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (subdir)
|
|
|
|
chdir(subdir);
|
|
|
|
|
2006-06-28 12:45:27 +02:00
|
|
|
errno = saved_errno;
|
|
|
|
|
2006-06-05 19:43:52 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2006-04-21 19:27:34 +02:00
|
|
|
const char git_version_string[] = GIT_VERSION;
|
2006-04-16 09:07:41 +02:00
|
|
|
|
2006-08-04 11:04:00 +02:00
|
|
|
#define RUN_SETUP (1<<0)
|
|
|
|
#define USE_PAGER (1<<1)
|
2006-12-31 05:32:38 +01:00
|
|
|
/*
|
|
|
|
* require working tree to be present -- anything uses this needs
|
|
|
|
* RUN_SETUP for reading from the configuration file.
|
|
|
|
*/
|
2007-06-03 16:48:16 +02:00
|
|
|
#define NEED_WORK_TREE (1<<2)
|
2006-07-29 07:44:25 +02:00
|
|
|
|
2007-06-24 19:10:40 +02:00
|
|
|
struct cmd_struct {
|
|
|
|
const char *cmd;
|
|
|
|
int (*fn)(int, const char **, const char *);
|
|
|
|
int option;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int run_command(struct cmd_struct *p, int argc, const char **argv)
|
|
|
|
{
|
2007-06-24 19:29:33 +02:00
|
|
|
int status;
|
|
|
|
struct stat st;
|
2007-06-24 19:10:40 +02:00
|
|
|
const char *prefix;
|
|
|
|
|
|
|
|
prefix = NULL;
|
|
|
|
if (p->option & RUN_SETUP)
|
|
|
|
prefix = setup_git_directory();
|
|
|
|
if (p->option & USE_PAGER)
|
|
|
|
setup_pager();
|
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 (p->option & NEED_WORK_TREE) {
|
|
|
|
const char *work_tree = get_git_work_tree();
|
|
|
|
const char *git_dir = get_git_dir();
|
|
|
|
if (!is_absolute_path(git_dir))
|
|
|
|
set_git_dir(make_absolute_path(git_dir));
|
|
|
|
if (!work_tree || chdir(work_tree))
|
|
|
|
die("%s must be run in a work tree", p->cmd);
|
|
|
|
}
|
2007-06-24 19:10:40 +02:00
|
|
|
trace_argv_printf(argv, argc, "trace: built-in: git");
|
|
|
|
|
2007-06-24 19:29:33 +02:00
|
|
|
status = p->fn(argc, argv, prefix);
|
|
|
|
if (status)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
/* Somebody closed stdout? */
|
|
|
|
if (fstat(fileno(stdout), &st))
|
|
|
|
return 0;
|
|
|
|
/* Ignore write errors for pipes and sockets.. */
|
|
|
|
if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Check for ENOSPC and EIO errors.. */
|
git: Try a bit harder not to lose errno in stdio
This switches the checks around upon the exit codepath of the
git wrapper, so that we may recover at least non-transient errors.
It's still not perfect. As I've been harping on, stdio simply isn't very
good for error reporting. For example, if an IO error happened, you'd want
to see EIO, wouldn't you? And yes, that's what the kernel would return.
However, with buffered stdio (and flushing outside of our control), what
would likely happen is that some intermediate error return _does_ return
EIO, but then the kernel might decide to re-mount the filesystem read-only
due to the error, and the actual *report* for us might be
"write failure on standard output: read-only filesystem"
which lost the EIO.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-06-30 20:44:20 +02:00
|
|
|
if (fflush(stdout))
|
2007-06-24 19:29:33 +02:00
|
|
|
die("write failure on standard output: %s", strerror(errno));
|
git: Try a bit harder not to lose errno in stdio
This switches the checks around upon the exit codepath of the
git wrapper, so that we may recover at least non-transient errors.
It's still not perfect. As I've been harping on, stdio simply isn't very
good for error reporting. For example, if an IO error happened, you'd want
to see EIO, wouldn't you? And yes, that's what the kernel would return.
However, with buffered stdio (and flushing outside of our control), what
would likely happen is that some intermediate error return _does_ return
EIO, but then the kernel might decide to re-mount the filesystem read-only
due to the error, and the actual *report* for us might be
"write failure on standard output: read-only filesystem"
which lost the EIO.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-06-30 20:44:20 +02:00
|
|
|
if (ferror(stdout))
|
|
|
|
die("unknown write failure on standard output");
|
|
|
|
if (fclose(stdout))
|
|
|
|
die("close failed on standard output: %s", strerror(errno));
|
2007-06-24 19:29:33 +02:00
|
|
|
return 0;
|
2007-06-24 19:10:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void handle_internal_command(int argc, const char **argv)
|
Teach the "git" command to handle some commands internally
This is another patch in the "prepare to do more in C" series, where the
git wrapper command is taught about the notion of handling some
functionality internally.
Right now, the only internal commands are "version" and "help", but the
point being that we can now easily extend it to handle some of the trivial
scripts internally. Things like "git log" and "git diff" wouldn't need
separate external scripts any more.
This also implies that to support the old "git-log" and "git-diff" syntax,
the "git" wrapper now automatically looks at the name it was executed as,
and if it is "git-xxxx", it will assume that it is to internally do what
"git xxxx" would do.
In other words, you can (once you implement an internal command) soft- or
hard-link that command to the "git" wrapper command, and it will do the
right thing, whether you use the "git xxxx" or the "git-xxxx" format.
There's one other change: the search order for external programs is
modified slightly, so that the first entry remains GIT_EXEC_DIR, but the
second entry is the same directory as the git wrapper itself was executed
out of - if we can figure it out from argv[0], of course.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-26 21:34:51 +01:00
|
|
|
{
|
|
|
|
const char *cmd = argv[0];
|
2007-06-24 19:10:40 +02:00
|
|
|
static struct cmd_struct commands[] = {
|
2007-06-03 16:48:16 +02:00
|
|
|
{ "add", cmd_add, RUN_SETUP | NEED_WORK_TREE },
|
2007-07-05 00:21:49 +02:00
|
|
|
{ "annotate", cmd_annotate, RUN_SETUP },
|
2006-08-04 10:51:04 +02:00
|
|
|
{ "apply", cmd_apply },
|
2007-04-05 22:55:43 +02:00
|
|
|
{ "archive", cmd_archive },
|
2007-01-28 15:25:55 +01:00
|
|
|
{ "blame", cmd_blame, RUN_SETUP },
|
2006-11-01 21:53:13 +01:00
|
|
|
{ "branch", cmd_branch, RUN_SETUP },
|
Add git-bundle: move objects and references by archive
Some workflows require use of repositories on machines that cannot be
connected, preventing use of git-fetch / git-push to transport objects and
references between the repositories.
git-bundle provides an alternate transport mechanism, effectively allowing
git-fetch and git-pull to operate using sneakernet transport. `git-bundle
create` allows the user to create a bundle containing one or more branches
or tags, but with specified basis assumed to exist on the target
repository. At the receiving end, git-bundle acts like git-fetch-pack,
allowing the user to invoke git-fetch or git-pull using the bundle file as
the URL. git-fetch and git-ls-remote determine they have a bundle URL by
checking that the URL points to a file, but are otherwise unchanged in
operation with bundles.
The original patch was done by Mark Levedahl <mdl123@verizon.net>.
It was updated to make git-bundle a builtin, and get rid of the tar
format: now, the first line is supposed to say "# v2 git bundle", the next
lines either contain a prerequisite ("-" followed by the hash of the
needed commit), or a ref (the hash of a commit, followed by the name of
the ref), and finally the pack. As a result, the bundle argument can be
"-" now.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-02-22 01:59:14 +01:00
|
|
|
{ "bundle", cmd_bundle },
|
2006-08-04 11:04:00 +02:00
|
|
|
{ "cat-file", cmd_cat_file, RUN_SETUP },
|
2007-08-05 00:20:07 +02:00
|
|
|
{ "checkout-index", cmd_checkout_index,
|
|
|
|
RUN_SETUP | NEED_WORK_TREE},
|
2006-05-23 14:15:29 +02:00
|
|
|
{ "check-ref-format", cmd_check_ref_format },
|
2007-06-03 16:48:16 +02:00
|
|
|
{ "check-attr", cmd_check_attr, RUN_SETUP | NEED_WORK_TREE },
|
2006-10-24 01:01:57 +02:00
|
|
|
{ "cherry", cmd_cherry, RUN_SETUP },
|
2007-06-03 16:48:16 +02:00
|
|
|
{ "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE },
|
2006-08-04 11:04:00 +02:00
|
|
|
{ "commit-tree", cmd_commit_tree, RUN_SETUP },
|
2007-01-29 01:16:53 +01:00
|
|
|
{ "config", cmd_config },
|
2006-09-14 03:03:59 +02:00
|
|
|
{ "count-objects", cmd_count_objects, RUN_SETUP },
|
2007-01-10 12:36:36 +01:00
|
|
|
{ "describe", cmd_describe, RUN_SETUP },
|
2007-08-12 19:46:55 +02:00
|
|
|
{ "diff", cmd_diff },
|
2007-02-22 21:50:10 +01:00
|
|
|
{ "diff-files", cmd_diff_files },
|
2006-08-04 11:04:00 +02:00
|
|
|
{ "diff-index", cmd_diff_index, RUN_SETUP },
|
|
|
|
{ "diff-tree", cmd_diff_tree, RUN_SETUP },
|
2007-09-11 05:03:25 +02:00
|
|
|
{ "fetch", cmd_fetch, RUN_SETUP },
|
2007-09-11 05:03:00 +02:00
|
|
|
{ "fetch-pack", cmd_fetch_pack, RUN_SETUP },
|
2007-01-16 09:23:24 +01:00
|
|
|
{ "fetch--tool", cmd_fetch__tool, RUN_SETUP },
|
2006-08-04 11:04:00 +02:00
|
|
|
{ "fmt-merge-msg", cmd_fmt_merge_msg, RUN_SETUP },
|
2006-09-15 22:30:02 +02:00
|
|
|
{ "for-each-ref", cmd_for_each_ref, RUN_SETUP },
|
2006-08-04 11:04:00 +02:00
|
|
|
{ "format-patch", cmd_format_patch, RUN_SETUP },
|
2007-01-29 16:48:06 +01:00
|
|
|
{ "fsck", cmd_fsck, RUN_SETUP },
|
|
|
|
{ "fsck-objects", cmd_fsck, RUN_SETUP },
|
2007-03-14 02:58:22 +01:00
|
|
|
{ "gc", cmd_gc, RUN_SETUP },
|
2006-08-04 10:51:04 +02:00
|
|
|
{ "get-tar-commit-id", cmd_get_tar_commit_id },
|
2007-02-19 15:56:04 +01:00
|
|
|
{ "grep", cmd_grep, RUN_SETUP | USE_PAGER },
|
2006-08-04 10:51:04 +02:00
|
|
|
{ "help", cmd_help },
|
2007-09-11 05:02:45 +02:00
|
|
|
#ifndef NO_CURL
|
|
|
|
{ "http-fetch", cmd_http_fetch, RUN_SETUP },
|
|
|
|
#endif
|
2007-01-07 18:31:29 +01:00
|
|
|
{ "init", cmd_init_db },
|
2006-08-04 10:51:04 +02:00
|
|
|
{ "init-db", cmd_init_db },
|
2006-08-04 11:04:00 +02:00
|
|
|
{ "log", cmd_log, RUN_SETUP | USE_PAGER },
|
|
|
|
{ "ls-files", cmd_ls_files, RUN_SETUP },
|
|
|
|
{ "ls-tree", cmd_ls_tree, RUN_SETUP },
|
2006-08-04 10:51:04 +02:00
|
|
|
{ "mailinfo", cmd_mailinfo },
|
|
|
|
{ "mailsplit", cmd_mailsplit },
|
2007-01-09 09:50:02 +01:00
|
|
|
{ "merge-base", cmd_merge_base, RUN_SETUP },
|
2006-12-06 16:26:06 +01:00
|
|
|
{ "merge-file", cmd_merge_file },
|
2007-06-03 16:48:16 +02:00
|
|
|
{ "mv", cmd_mv, RUN_SETUP | NEED_WORK_TREE },
|
2006-08-04 11:04:00 +02:00
|
|
|
{ "name-rev", cmd_name_rev, RUN_SETUP },
|
|
|
|
{ "pack-objects", cmd_pack_objects, RUN_SETUP },
|
2007-07-05 00:21:49 +02:00
|
|
|
{ "pickaxe", cmd_blame, RUN_SETUP },
|
2006-08-04 11:04:00 +02:00
|
|
|
{ "prune", cmd_prune, RUN_SETUP },
|
|
|
|
{ "prune-packed", cmd_prune_packed, RUN_SETUP },
|
2006-08-09 00:42:20 +02:00
|
|
|
{ "push", cmd_push, RUN_SETUP },
|
2006-08-04 11:04:00 +02:00
|
|
|
{ "read-tree", cmd_read_tree, RUN_SETUP },
|
2006-12-19 09:23:12 +01:00
|
|
|
{ "reflog", cmd_reflog, RUN_SETUP },
|
2007-01-29 01:16:53 +01:00
|
|
|
{ "repo-config", cmd_config },
|
2006-12-20 17:39:41 +01:00
|
|
|
{ "rerere", cmd_rerere, RUN_SETUP },
|
2007-09-11 05:19:34 +02:00
|
|
|
{ "reset", cmd_reset, RUN_SETUP },
|
2006-08-04 11:04:00 +02:00
|
|
|
{ "rev-list", cmd_rev_list, RUN_SETUP },
|
|
|
|
{ "rev-parse", cmd_rev_parse, RUN_SETUP },
|
2007-06-03 16:48:16 +02:00
|
|
|
{ "revert", cmd_revert, RUN_SETUP | NEED_WORK_TREE },
|
|
|
|
{ "rm", cmd_rm, RUN_SETUP | NEED_WORK_TREE },
|
|
|
|
{ "runstatus", cmd_runstatus, RUN_SETUP | NEED_WORK_TREE },
|
2006-11-28 00:29:21 +01:00
|
|
|
{ "shortlog", cmd_shortlog, RUN_SETUP | USE_PAGER },
|
2006-08-04 11:04:00 +02:00
|
|
|
{ "show-branch", cmd_show_branch, RUN_SETUP },
|
|
|
|
{ "show", cmd_show, RUN_SETUP | USE_PAGER },
|
2006-08-04 10:51:04 +02:00
|
|
|
{ "stripspace", cmd_stripspace },
|
2006-08-04 11:04:00 +02:00
|
|
|
{ "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
|
2007-07-20 01:42:28 +02:00
|
|
|
{ "tag", cmd_tag, RUN_SETUP },
|
2006-10-08 15:44:50 +02:00
|
|
|
{ "tar-tree", cmd_tar_tree },
|
2006-08-04 11:04:00 +02:00
|
|
|
{ "unpack-objects", cmd_unpack_objects, RUN_SETUP },
|
|
|
|
{ "update-index", cmd_update_index, RUN_SETUP },
|
|
|
|
{ "update-ref", cmd_update_ref, RUN_SETUP },
|
2006-09-07 15:12:05 +02:00
|
|
|
{ "upload-archive", cmd_upload_archive },
|
2007-07-27 06:07:34 +02:00
|
|
|
{ "verify-tag", cmd_verify_tag, RUN_SETUP },
|
2006-08-04 10:51:04 +02:00
|
|
|
{ "version", cmd_version },
|
2006-08-04 11:04:00 +02:00
|
|
|
{ "whatchanged", cmd_whatchanged, RUN_SETUP | USE_PAGER },
|
|
|
|
{ "write-tree", cmd_write_tree, RUN_SETUP },
|
2006-08-10 17:02:38 +02:00
|
|
|
{ "verify-pack", cmd_verify_pack },
|
Add "git show-ref" builtin command
It's kind of like "git peek-remote", but works only locally (and thus
avoids the whole overhead of git_connect()) and has some extra
verification features.
For example, it allows you to filter the results, and to choose whether
you want the tag dereferencing or not. You can also use it to just test
whether a particular ref exists.
For example:
git show-ref master
will show all references called "master", whether tags or heads or
anything else, and regardless of how deep in the reference naming
hierarchy they are (so it would show "refs/heads/master" but also
"refs/remote/other-repo/master").
When using the "--verify" flag, the command requires an exact ref path:
git show-ref --verify refs/heads/master
will only match the exact branch called "master".
If nothing matches, show-ref will return an error code of 1, and in the
case of verification, it will show an error message.
For scripting, you can ask it to be quiet with the "--quiet" flag, which
allows you to do things like
git-show-ref --quiet --verify -- "refs/heads/$headname" ||
echo "$headname is not a valid branch"
to check whether a particular branch exists or not (notice how we don't
actually want to show any results, and we want to use the full refname for
it in order to not trigger the problem with ambiguous partial matches).
To show only tags, or only proper branch heads, use "--tags" and/or
"--heads" respectively (using both means that it shows tags _and_ heads,
but not other random references under the refs/ subdirectory).
To do automatic tag object dereferencing, use the "-d" or "--dereference"
flag, so you can do
git show-ref --tags --dereference
to get a listing of all tags together with what they dereference.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-09-15 20:19:32 +02:00
|
|
|
{ "show-ref", cmd_show_ref, RUN_SETUP },
|
Start handling references internally as a sorted in-memory list
This also adds some very rudimentary support for the notion of packed
refs. HOWEVER! At this point it isn't used to actually look up a ref
yet, only for listing them (ie "for_each_ref()" and friends see the
packed refs, but none of the other single-ref lookup routines).
Note how we keep two separate lists: one for the loose refs, and one for
the packed refs we read. That's so that we can easily keep the two apart,
and read only one set or the other (and still always make sure that the
loose refs take precedence).
[ From this, it's not actually obvious why we'd keep the two separate
lists, but it's important to have the packed refs on their own list
later on, when I add support for looking up a single loose one.
For that case, we will want to read _just_ the packed refs in case the
single-ref lookup fails, yet we may end up needing the other list at
some point in the future, so keeping them separated is important ]
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-09-12 01:37:32 +02:00
|
|
|
{ "pack-refs", cmd_pack_refs, RUN_SETUP },
|
Teach the "git" command to handle some commands internally
This is another patch in the "prepare to do more in C" series, where the
git wrapper command is taught about the notion of handling some
functionality internally.
Right now, the only internal commands are "version" and "help", but the
point being that we can now easily extend it to handle some of the trivial
scripts internally. Things like "git log" and "git diff" wouldn't need
separate external scripts any more.
This also implies that to support the old "git-log" and "git-diff" syntax,
the "git" wrapper now automatically looks at the name it was executed as,
and if it is "git-xxxx", it will assume that it is to internally do what
"git xxxx" would do.
In other words, you can (once you implement an internal command) soft- or
hard-link that command to the "git" wrapper command, and it will do the
right thing, whether you use the "git xxxx" or the "git-xxxx" format.
There's one other change: the search order for external programs is
modified slightly, so that the first entry remains GIT_EXEC_DIR, but the
second entry is the same directory as the git wrapper itself was executed
out of - if we can figure it out from argv[0], of course.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-26 21:34:51 +01:00
|
|
|
};
|
|
|
|
int i;
|
|
|
|
|
2006-04-15 20:13:49 +02:00
|
|
|
/* Turn "git cmd --help" into "git help cmd" */
|
|
|
|
if (argc > 1 && !strcmp(argv[1], "--help")) {
|
|
|
|
argv[1] = argv[0];
|
|
|
|
argv[0] = cmd = "help";
|
|
|
|
}
|
|
|
|
|
Teach the "git" command to handle some commands internally
This is another patch in the "prepare to do more in C" series, where the
git wrapper command is taught about the notion of handling some
functionality internally.
Right now, the only internal commands are "version" and "help", but the
point being that we can now easily extend it to handle some of the trivial
scripts internally. Things like "git log" and "git diff" wouldn't need
separate external scripts any more.
This also implies that to support the old "git-log" and "git-diff" syntax,
the "git" wrapper now automatically looks at the name it was executed as,
and if it is "git-xxxx", it will assume that it is to internally do what
"git xxxx" would do.
In other words, you can (once you implement an internal command) soft- or
hard-link that command to the "git" wrapper command, and it will do the
right thing, whether you use the "git xxxx" or the "git-xxxx" format.
There's one other change: the search order for external programs is
modified slightly, so that the first entry remains GIT_EXEC_DIR, but the
second entry is the same directory as the git wrapper itself was executed
out of - if we can figure it out from argv[0], of course.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-26 21:34:51 +01:00
|
|
|
for (i = 0; i < ARRAY_SIZE(commands); i++) {
|
|
|
|
struct cmd_struct *p = commands+i;
|
|
|
|
if (strcmp(p->cmd, cmd))
|
|
|
|
continue;
|
2007-06-24 19:10:40 +02:00
|
|
|
exit(run_command(p, argc, argv));
|
Teach the "git" command to handle some commands internally
This is another patch in the "prepare to do more in C" series, where the
git wrapper command is taught about the notion of handling some
functionality internally.
Right now, the only internal commands are "version" and "help", but the
point being that we can now easily extend it to handle some of the trivial
scripts internally. Things like "git log" and "git diff" wouldn't need
separate external scripts any more.
This also implies that to support the old "git-log" and "git-diff" syntax,
the "git" wrapper now automatically looks at the name it was executed as,
and if it is "git-xxxx", it will assume that it is to internally do what
"git xxxx" would do.
In other words, you can (once you implement an internal command) soft- or
hard-link that command to the "git" wrapper command, and it will do the
right thing, whether you use the "git xxxx" or the "git-xxxx" format.
There's one other change: the search order for external programs is
modified slightly, so that the first entry remains GIT_EXEC_DIR, but the
second entry is the same directory as the git wrapper itself was executed
out of - if we can figure it out from argv[0], of course.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-26 21:34:51 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-24 19:10:40 +02:00
|
|
|
int main(int argc, const char **argv)
|
2005-11-16 00:31:25 +01:00
|
|
|
{
|
2006-09-14 03:04:09 +02:00
|
|
|
const char *cmd = argv[0] ? argv[0] : "git-help";
|
Teach the "git" command to handle some commands internally
This is another patch in the "prepare to do more in C" series, where the
git wrapper command is taught about the notion of handling some
functionality internally.
Right now, the only internal commands are "version" and "help", but the
point being that we can now easily extend it to handle some of the trivial
scripts internally. Things like "git log" and "git diff" wouldn't need
separate external scripts any more.
This also implies that to support the old "git-log" and "git-diff" syntax,
the "git" wrapper now automatically looks at the name it was executed as,
and if it is "git-xxxx", it will assume that it is to internally do what
"git xxxx" would do.
In other words, you can (once you implement an internal command) soft- or
hard-link that command to the "git" wrapper command, and it will do the
right thing, whether you use the "git xxxx" or the "git-xxxx" format.
There's one other change: the search order for external programs is
modified slightly, so that the first entry remains GIT_EXEC_DIR, but the
second entry is the same directory as the git wrapper itself was executed
out of - if we can figure it out from argv[0], of course.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-26 21:34:51 +01:00
|
|
|
char *slash = strrchr(cmd, '/');
|
|
|
|
const char *exec_path = NULL;
|
2006-06-06 03:09:40 +02:00
|
|
|
int done_alias = 0;
|
Teach the "git" command to handle some commands internally
This is another patch in the "prepare to do more in C" series, where the
git wrapper command is taught about the notion of handling some
functionality internally.
Right now, the only internal commands are "version" and "help", but the
point being that we can now easily extend it to handle some of the trivial
scripts internally. Things like "git log" and "git diff" wouldn't need
separate external scripts any more.
This also implies that to support the old "git-log" and "git-diff" syntax,
the "git" wrapper now automatically looks at the name it was executed as,
and if it is "git-xxxx", it will assume that it is to internally do what
"git xxxx" would do.
In other words, you can (once you implement an internal command) soft- or
hard-link that command to the "git" wrapper command, and it will do the
right thing, whether you use the "git xxxx" or the "git-xxxx" format.
There's one other change: the search order for external programs is
modified slightly, so that the first entry remains GIT_EXEC_DIR, but the
second entry is the same directory as the git wrapper itself was executed
out of - if we can figure it out from argv[0], of course.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-26 21:34:51 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Take the basename of argv[0] as the command
|
|
|
|
* name, and the dirname as the default exec_path
|
|
|
|
* if it's an absolute path and we don't have
|
|
|
|
* anything better.
|
|
|
|
*/
|
|
|
|
if (slash) {
|
|
|
|
*slash++ = 0;
|
|
|
|
if (*cmd == '/')
|
|
|
|
exec_path = cmd;
|
|
|
|
cmd = slash;
|
|
|
|
}
|
2005-11-16 00:31:25 +01:00
|
|
|
|
Teach the "git" command to handle some commands internally
This is another patch in the "prepare to do more in C" series, where the
git wrapper command is taught about the notion of handling some
functionality internally.
Right now, the only internal commands are "version" and "help", but the
point being that we can now easily extend it to handle some of the trivial
scripts internally. Things like "git log" and "git diff" wouldn't need
separate external scripts any more.
This also implies that to support the old "git-log" and "git-diff" syntax,
the "git" wrapper now automatically looks at the name it was executed as,
and if it is "git-xxxx", it will assume that it is to internally do what
"git xxxx" would do.
In other words, you can (once you implement an internal command) soft- or
hard-link that command to the "git" wrapper command, and it will do the
right thing, whether you use the "git xxxx" or the "git-xxxx" format.
There's one other change: the search order for external programs is
modified slightly, so that the first entry remains GIT_EXEC_DIR, but the
second entry is the same directory as the git wrapper itself was executed
out of - if we can figure it out from argv[0], of course.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-26 21:34:51 +01:00
|
|
|
/*
|
|
|
|
* "git-xxxx" is the same as "git xxxx", but we obviously:
|
|
|
|
*
|
|
|
|
* - cannot take flags in between the "git" and the "xxxx".
|
|
|
|
* - cannot execute it externally (since it would just do
|
|
|
|
* the same thing over again)
|
|
|
|
*
|
|
|
|
* So we just directly call the internal command handler, and
|
|
|
|
* die if that one cannot handle it.
|
|
|
|
*/
|
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 10:53:29 +01:00
|
|
|
if (!prefixcmp(cmd, "git-")) {
|
Teach the "git" command to handle some commands internally
This is another patch in the "prepare to do more in C" series, where the
git wrapper command is taught about the notion of handling some
functionality internally.
Right now, the only internal commands are "version" and "help", but the
point being that we can now easily extend it to handle some of the trivial
scripts internally. Things like "git log" and "git diff" wouldn't need
separate external scripts any more.
This also implies that to support the old "git-log" and "git-diff" syntax,
the "git" wrapper now automatically looks at the name it was executed as,
and if it is "git-xxxx", it will assume that it is to internally do what
"git xxxx" would do.
In other words, you can (once you implement an internal command) soft- or
hard-link that command to the "git" wrapper command, and it will do the
right thing, whether you use the "git xxxx" or the "git-xxxx" format.
There's one other change: the search order for external programs is
modified slightly, so that the first entry remains GIT_EXEC_DIR, but the
second entry is the same directory as the git wrapper itself was executed
out of - if we can figure it out from argv[0], of course.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-26 21:34:51 +01:00
|
|
|
cmd += 4;
|
|
|
|
argv[0] = cmd;
|
2007-06-24 19:10:40 +02:00
|
|
|
handle_internal_command(argc, argv);
|
Teach the "git" command to handle some commands internally
This is another patch in the "prepare to do more in C" series, where the
git wrapper command is taught about the notion of handling some
functionality internally.
Right now, the only internal commands are "version" and "help", but the
point being that we can now easily extend it to handle some of the trivial
scripts internally. Things like "git log" and "git diff" wouldn't need
separate external scripts any more.
This also implies that to support the old "git-log" and "git-diff" syntax,
the "git" wrapper now automatically looks at the name it was executed as,
and if it is "git-xxxx", it will assume that it is to internally do what
"git xxxx" would do.
In other words, you can (once you implement an internal command) soft- or
hard-link that command to the "git" wrapper command, and it will do the
right thing, whether you use the "git xxxx" or the "git-xxxx" format.
There's one other change: the search order for external programs is
modified slightly, so that the first entry remains GIT_EXEC_DIR, but the
second entry is the same directory as the git wrapper itself was executed
out of - if we can figure it out from argv[0], of course.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-26 21:34:51 +01:00
|
|
|
die("cannot handle %s internally", cmd);
|
|
|
|
}
|
2005-11-16 00:31:25 +01:00
|
|
|
|
Teach the "git" command to handle some commands internally
This is another patch in the "prepare to do more in C" series, where the
git wrapper command is taught about the notion of handling some
functionality internally.
Right now, the only internal commands are "version" and "help", but the
point being that we can now easily extend it to handle some of the trivial
scripts internally. Things like "git log" and "git diff" wouldn't need
separate external scripts any more.
This also implies that to support the old "git-log" and "git-diff" syntax,
the "git" wrapper now automatically looks at the name it was executed as,
and if it is "git-xxxx", it will assume that it is to internally do what
"git xxxx" would do.
In other words, you can (once you implement an internal command) soft- or
hard-link that command to the "git" wrapper command, and it will do the
right thing, whether you use the "git xxxx" or the "git-xxxx" format.
There's one other change: the search order for external programs is
modified slightly, so that the first entry remains GIT_EXEC_DIR, but the
second entry is the same directory as the git wrapper itself was executed
out of - if we can figure it out from argv[0], of course.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-26 21:34:51 +01:00
|
|
|
/* Look for flags.. */
|
2006-07-25 20:24:22 +02:00
|
|
|
argv++;
|
|
|
|
argc--;
|
2007-06-08 22:57:55 +02:00
|
|
|
handle_options(&argv, &argc, NULL);
|
2006-07-25 20:24:22 +02:00
|
|
|
if (argc > 0) {
|
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 10:53:29 +01:00
|
|
|
if (!prefixcmp(argv[0], "--"))
|
2006-07-25 20:24:22 +02:00
|
|
|
argv[0] += 2;
|
|
|
|
} else {
|
|
|
|
/* Default command: "help" */
|
|
|
|
argv[0] = "help";
|
|
|
|
argc = 1;
|
2005-11-16 00:31:25 +01:00
|
|
|
}
|
2006-07-25 20:24:22 +02:00
|
|
|
cmd = argv[0];
|
Teach the "git" command to handle some commands internally
This is another patch in the "prepare to do more in C" series, where the
git wrapper command is taught about the notion of handling some
functionality internally.
Right now, the only internal commands are "version" and "help", but the
point being that we can now easily extend it to handle some of the trivial
scripts internally. Things like "git log" and "git diff" wouldn't need
separate external scripts any more.
This also implies that to support the old "git-log" and "git-diff" syntax,
the "git" wrapper now automatically looks at the name it was executed as,
and if it is "git-xxxx", it will assume that it is to internally do what
"git xxxx" would do.
In other words, you can (once you implement an internal command) soft- or
hard-link that command to the "git" wrapper command, and it will do the
right thing, whether you use the "git xxxx" or the "git-xxxx" format.
There's one other change: the search order for external programs is
modified slightly, so that the first entry remains GIT_EXEC_DIR, but the
second entry is the same directory as the git wrapper itself was executed
out of - if we can figure it out from argv[0], of course.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-26 21:34:51 +01:00
|
|
|
|
|
|
|
/*
|
2007-07-31 11:06:14 +02:00
|
|
|
* We execute external git command via execv_git_cmd(),
|
|
|
|
* which looks at "--exec-path" option, GIT_EXEC_PATH
|
|
|
|
* environment, and $(gitexecdir) in Makefile while built,
|
|
|
|
* in this order. For scripted commands, we prepend
|
|
|
|
* the value of the exec_path variable to the PATH.
|
Teach the "git" command to handle some commands internally
This is another patch in the "prepare to do more in C" series, where the
git wrapper command is taught about the notion of handling some
functionality internally.
Right now, the only internal commands are "version" and "help", but the
point being that we can now easily extend it to handle some of the trivial
scripts internally. Things like "git log" and "git diff" wouldn't need
separate external scripts any more.
This also implies that to support the old "git-log" and "git-diff" syntax,
the "git" wrapper now automatically looks at the name it was executed as,
and if it is "git-xxxx", it will assume that it is to internally do what
"git xxxx" would do.
In other words, you can (once you implement an internal command) soft- or
hard-link that command to the "git" wrapper command, and it will do the
right thing, whether you use the "git xxxx" or the "git-xxxx" format.
There's one other change: the search order for external programs is
modified slightly, so that the first entry remains GIT_EXEC_DIR, but the
second entry is the same directory as the git wrapper itself was executed
out of - if we can figure it out from argv[0], of course.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-26 21:34:51 +01:00
|
|
|
*/
|
|
|
|
if (exec_path)
|
|
|
|
prepend_to_path(exec_path, strlen(exec_path));
|
2006-01-11 03:12:17 +01:00
|
|
|
exec_path = git_exec_path();
|
|
|
|
prepend_to_path(exec_path, strlen(exec_path));
|
2005-11-16 00:31:25 +01:00
|
|
|
|
2006-06-06 03:09:40 +02:00
|
|
|
while (1) {
|
|
|
|
/* See if it's an internal command */
|
2007-06-24 19:10:40 +02:00
|
|
|
handle_internal_command(argc, argv);
|
2006-06-05 19:43:52 +02:00
|
|
|
|
2006-06-06 03:09:40 +02:00
|
|
|
/* .. then try the external ones */
|
|
|
|
execv_git_cmd(argv);
|
Teach the "git" command to handle some commands internally
This is another patch in the "prepare to do more in C" series, where the
git wrapper command is taught about the notion of handling some
functionality internally.
Right now, the only internal commands are "version" and "help", but the
point being that we can now easily extend it to handle some of the trivial
scripts internally. Things like "git log" and "git diff" wouldn't need
separate external scripts any more.
This also implies that to support the old "git-log" and "git-diff" syntax,
the "git" wrapper now automatically looks at the name it was executed as,
and if it is "git-xxxx", it will assume that it is to internally do what
"git xxxx" would do.
In other words, you can (once you implement an internal command) soft- or
hard-link that command to the "git" wrapper command, and it will do the
right thing, whether you use the "git xxxx" or the "git-xxxx" format.
There's one other change: the search order for external programs is
modified slightly, so that the first entry remains GIT_EXEC_DIR, but the
second entry is the same directory as the git wrapper itself was executed
out of - if we can figure it out from argv[0], of course.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-26 21:34:51 +01:00
|
|
|
|
2006-06-06 03:09:40 +02:00
|
|
|
/* It could be an alias -- this works around the insanity
|
|
|
|
* of overriding "git log" with "git show" by having
|
|
|
|
* alias.log = show
|
|
|
|
*/
|
|
|
|
if (done_alias || !handle_alias(&argc, &argv))
|
|
|
|
break;
|
|
|
|
done_alias = 1;
|
|
|
|
}
|
2005-12-01 13:48:35 +01:00
|
|
|
|
2007-02-11 01:33:57 +01:00
|
|
|
if (errno == ENOENT) {
|
|
|
|
if (done_alias) {
|
|
|
|
fprintf(stderr, "Expansion of alias '%s' failed; "
|
|
|
|
"'%s' is not a git-command\n",
|
|
|
|
cmd, argv[0]);
|
|
|
|
exit(1);
|
|
|
|
}
|
2006-07-30 23:42:25 +02:00
|
|
|
help_unknown_cmd(cmd);
|
2007-02-11 01:33:57 +01:00
|
|
|
}
|
2005-12-01 13:48:35 +01:00
|
|
|
|
|
|
|
fprintf(stderr, "Failed to run command '%s': %s\n",
|
2006-06-28 11:17:21 +02:00
|
|
|
cmd, strerror(errno));
|
2005-11-16 00:31:25 +01:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|