2006-12-20 06:34:12 +08:00
|
|
|
#include "builtin.h"
|
2006-01-11 10:12:17 +08:00
|
|
|
#include "exec_cmd.h"
|
2006-06-06 01:43:52 +08:00
|
|
|
#include "cache.h"
|
2006-06-25 21:56:18 +08:00
|
|
|
#include "quote.h"
|
2009-01-28 15:38:14 +08:00
|
|
|
#include "run-command.h"
|
2005-11-16 07:31:25 +08:00
|
|
|
|
2006-07-31 05:42:25 +08:00
|
|
|
const char git_usage_string[] =
|
2009-09-12 18:39:30 +08:00
|
|
|
"git [--version] [--exec-path[=GIT_EXEC_PATH]] [--html-path]\n"
|
2009-10-13 04:30:32 +08:00
|
|
|
" [-p|--paginate|--no-pager] [--no-replace-objects]\n"
|
2009-09-12 18:39:30 +08:00
|
|
|
" [--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE]\n"
|
2010-07-26 16:36:24 +08:00
|
|
|
" [-c name=value] [--help]\n"
|
|
|
|
" COMMAND [ARGS]";
|
2006-07-31 05:42:25 +08:00
|
|
|
|
2008-06-06 05:15:36 +08:00
|
|
|
const char git_more_info_string[] =
|
|
|
|
"See 'git help COMMAND' for more information on a specific command.";
|
|
|
|
|
2010-08-06 10:40:35 +08:00
|
|
|
static struct startup_info git_startup_info;
|
Allow per-command pager config
There is great debate over whether some commands should set
up a pager automatically. This patch allows individuals to
set their own pager preferences for each command, overriding
the default. For example, to disable the pager for git
status:
git config pager.status false
If "--pager" or "--no-pager" is specified on the command
line, it takes precedence over the config option.
There are two caveats:
- you can turn on the pager for plumbing commands.
Combined with "core.pager = always", this will probably
break a lot of things. Don't do it.
- This only works for builtin commands. The reason is
somewhat complex:
Calling git_config before we do setup_git_directory
has bad side effects, because it wants to know where
the git_dir is to find ".git/config". Unfortunately,
we cannot call setup_git_directory indiscriminately,
because some builtins (like "init") break if we do.
For builtins, this is OK, since we can just wait until
after we call setup_git_directory. But for aliases, we
don't know until we expand (recursively) which command
we're doing. This should not be a huge problem for
aliases, which can simply use "--pager" or "--no-pager"
in the alias as appropriate.
For external commands, however, we don't know we even
have an external command until we exec it, and by then
it is too late to check the config.
An alternative approach would be to have a config mode
where we don't bother looking at .git/config, but only
at the user and system config files. This would make the
behavior consistent across builtins, aliases, and
external commands, at the cost of not allowing per-repo
pager config for at all.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-07-03 19:46:57 +08:00
|
|
|
static int use_pager = -1;
|
|
|
|
struct pager_config {
|
|
|
|
const char *cmd;
|
|
|
|
int val;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int pager_command_config(const char *var, const char *value, void *data)
|
|
|
|
{
|
|
|
|
struct pager_config *c = data;
|
|
|
|
if (!prefixcmp(var, "pager.") && !strcmp(var + 6, c->cmd))
|
|
|
|
c->val = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */
|
|
|
|
int check_pager_config(const char *cmd)
|
|
|
|
{
|
|
|
|
struct pager_config c;
|
|
|
|
c.cmd = cmd;
|
|
|
|
c.val = -1;
|
|
|
|
git_config(pager_command_config, &c);
|
|
|
|
return c.val;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void commit_pager_choice(void) {
|
|
|
|
switch (use_pager) {
|
|
|
|
case 0:
|
|
|
|
setenv("GIT_PAGER", "cat", 1);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
setup_pager();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-01 17:06:36 +08:00
|
|
|
static int handle_options(const char ***argv, int *argc, int *envchanged)
|
2006-07-24 20:10:45 +08:00
|
|
|
{
|
|
|
|
int handled = 0;
|
|
|
|
|
2010-03-02 19:52:11 +08:00
|
|
|
if (!getenv("GIT_ASKPASS") && getenv("SSH_ASKPASS"))
|
|
|
|
setenv("GIT_ASKPASS", getenv("SSH_ASKPASS"), 1);
|
|
|
|
|
2006-07-24 20:10:45 +08:00
|
|
|
while (*argc > 0) {
|
|
|
|
const char *cmd = (*argv)[0];
|
|
|
|
if (cmd[0] != '-')
|
|
|
|
break;
|
|
|
|
|
2006-07-26 02:24:22 +08: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 17:53:29 +08:00
|
|
|
if (!prefixcmp(cmd, "--exec-path")) {
|
2006-07-26 02:24:22 +08:00
|
|
|
cmd += 11;
|
|
|
|
if (*cmd == '=')
|
2007-10-27 16:36:51 +08:00
|
|
|
git_set_argv_exec_path(cmd + 1);
|
2006-07-26 02:24:22 +08:00
|
|
|
else {
|
|
|
|
puts(git_exec_path());
|
|
|
|
exit(0);
|
|
|
|
}
|
2009-04-05 10:15:16 +08:00
|
|
|
} else if (!strcmp(cmd, "--html-path")) {
|
|
|
|
puts(system_path(GIT_HTML_PATH));
|
|
|
|
exit(0);
|
2006-07-26 02:24:22 +08:00
|
|
|
} else if (!strcmp(cmd, "-p") || !strcmp(cmd, "--paginate")) {
|
Allow per-command pager config
There is great debate over whether some commands should set
up a pager automatically. This patch allows individuals to
set their own pager preferences for each command, overriding
the default. For example, to disable the pager for git
status:
git config pager.status false
If "--pager" or "--no-pager" is specified on the command
line, it takes precedence over the config option.
There are two caveats:
- you can turn on the pager for plumbing commands.
Combined with "core.pager = always", this will probably
break a lot of things. Don't do it.
- This only works for builtin commands. The reason is
somewhat complex:
Calling git_config before we do setup_git_directory
has bad side effects, because it wants to know where
the git_dir is to find ".git/config". Unfortunately,
we cannot call setup_git_directory indiscriminately,
because some builtins (like "init") break if we do.
For builtins, this is OK, since we can just wait until
after we call setup_git_directory. But for aliases, we
don't know until we expand (recursively) which command
we're doing. This should not be a huge problem for
aliases, which can simply use "--pager" or "--no-pager"
in the alias as appropriate.
For external commands, however, we don't know we even
have an external command until we exec it, and by then
it is too late to check the config.
An alternative approach would be to have a config mode
where we don't bother looking at .git/config, but only
at the user and system config files. This would make the
behavior consistent across builtins, aliases, and
external commands, at the cost of not allowing per-repo
pager config for at all.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-07-03 19:46:57 +08:00
|
|
|
use_pager = 1;
|
2007-08-20 01:24:36 +08:00
|
|
|
} else if (!strcmp(cmd, "--no-pager")) {
|
Allow per-command pager config
There is great debate over whether some commands should set
up a pager automatically. This patch allows individuals to
set their own pager preferences for each command, overriding
the default. For example, to disable the pager for git
status:
git config pager.status false
If "--pager" or "--no-pager" is specified on the command
line, it takes precedence over the config option.
There are two caveats:
- you can turn on the pager for plumbing commands.
Combined with "core.pager = always", this will probably
break a lot of things. Don't do it.
- This only works for builtin commands. The reason is
somewhat complex:
Calling git_config before we do setup_git_directory
has bad side effects, because it wants to know where
the git_dir is to find ".git/config". Unfortunately,
we cannot call setup_git_directory indiscriminately,
because some builtins (like "init") break if we do.
For builtins, this is OK, since we can just wait until
after we call setup_git_directory. But for aliases, we
don't know until we expand (recursively) which command
we're doing. This should not be a huge problem for
aliases, which can simply use "--pager" or "--no-pager"
in the alias as appropriate.
For external commands, however, we don't know we even
have an external command until we exec it, and by then
it is too late to check the config.
An alternative approach would be to have a config mode
where we don't bother looking at .git/config, but only
at the user and system config files. This would make the
behavior consistent across builtins, aliases, and
external commands, at the cost of not allowing per-repo
pager config for at all.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-07-03 19:46:57 +08:00
|
|
|
use_pager = 0;
|
2007-08-20 01:24:36 +08:00
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
2009-10-13 04:30:32 +08:00
|
|
|
} else if (!strcmp(cmd, "--no-replace-objects")) {
|
|
|
|
read_replace_refs = 0;
|
2009-11-18 14:50:58 +08:00
|
|
|
setenv(NO_REPLACE_OBJECTS_ENVIRONMENT, "1", 1);
|
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
2006-07-26 02:24:22 +08:00
|
|
|
} else if (!strcmp(cmd, "--git-dir")) {
|
2006-12-22 21:56:25 +08:00
|
|
|
if (*argc < 2) {
|
|
|
|
fprintf(stderr, "No directory given for --git-dir.\n" );
|
|
|
|
usage(git_usage_string);
|
|
|
|
}
|
2006-12-31 12:29:11 +08:00
|
|
|
setenv(GIT_DIR_ENVIRONMENT, (*argv)[1], 1);
|
2007-06-09 04:57:55 +08:00
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
2006-07-26 02:24:22 +08:00
|
|
|
(*argv)++;
|
|
|
|
(*argc)--;
|
2007-04-13 02:52:03 +08: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 17:53:29 +08:00
|
|
|
} else if (!prefixcmp(cmd, "--git-dir=")) {
|
2006-12-31 12:29:11 +08:00
|
|
|
setenv(GIT_DIR_ENVIRONMENT, cmd + 10, 1);
|
2007-06-09 04:57:55 +08:00
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
2007-06-06 15:10:42 +08: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-09 04:57:55 +08:00
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
2007-06-06 15:10:42 +08:00
|
|
|
(*argv)++;
|
|
|
|
(*argc)--;
|
|
|
|
} else if (!prefixcmp(cmd, "--work-tree=")) {
|
|
|
|
setenv(GIT_WORK_TREE_ENVIRONMENT, cmd + 12, 1);
|
2007-06-09 04:57:55 +08:00
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
2006-07-26 02:24:22 +08:00
|
|
|
} else if (!strcmp(cmd, "--bare")) {
|
2006-12-31 12:28:53 +08:00
|
|
|
static char git_dir[PATH_MAX+1];
|
2007-08-27 15:58:06 +08:00
|
|
|
is_bare_repository_cfg = 1;
|
2007-08-28 13:41:23 +08:00
|
|
|
setenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir, sizeof(git_dir)), 0);
|
2007-06-09 04:57:55 +08:00
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
2010-03-27 06:53:57 +08:00
|
|
|
} else if (!strcmp(cmd, "-c")) {
|
|
|
|
if (*argc < 2) {
|
|
|
|
fprintf(stderr, "-c expects a configuration string\n" );
|
|
|
|
usage(git_usage_string);
|
|
|
|
}
|
|
|
|
git_config_parse_parameter((*argv)[1]);
|
|
|
|
(*argv)++;
|
|
|
|
(*argc)--;
|
2006-07-26 02:24:22 +08:00
|
|
|
} else {
|
|
|
|
fprintf(stderr, "Unknown option: %s\n", cmd);
|
2006-07-31 05:42:25 +08:00
|
|
|
usage(git_usage_string);
|
2006-07-26 02:24:22 +08:00
|
|
|
}
|
2006-07-24 20:10:45 +08:00
|
|
|
|
|
|
|
(*argv)++;
|
|
|
|
(*argc)--;
|
|
|
|
handled++;
|
|
|
|
}
|
|
|
|
return handled;
|
|
|
|
}
|
|
|
|
|
2006-06-06 01:43:52 +08:00
|
|
|
static int handle_alias(int *argcp, const char ***argv)
|
|
|
|
{
|
2008-03-26 05:06:26 +08:00
|
|
|
int envchanged = 0, ret = 0, saved_errno = errno;
|
2006-06-06 01:43:52 +08:00
|
|
|
const char *subdir;
|
2006-07-30 09:30:29 +08:00
|
|
|
int count, option_count;
|
2009-05-01 17:06:36 +08:00
|
|
|
const char **new_argv;
|
2008-02-25 06:17:14 +08:00
|
|
|
const char *alias_command;
|
|
|
|
char *alias_string;
|
2008-04-01 12:33:09 +08:00
|
|
|
int unused_nongit;
|
2006-06-06 01:43:52 +08:00
|
|
|
|
2008-04-01 12:33:09 +08:00
|
|
|
subdir = setup_git_directory_gently(&unused_nongit);
|
2006-07-30 09:30:29 +08:00
|
|
|
|
|
|
|
alias_command = (*argv)[0];
|
2008-02-25 06:17:14 +08:00
|
|
|
alias_string = alias_lookup(alias_command);
|
2006-07-30 09:30:29 +08:00
|
|
|
if (alias_string) {
|
2007-02-11 08:33:58 +08:00
|
|
|
if (alias_string[0] == '!') {
|
2010-07-15 06:55:12 +08:00
|
|
|
commit_pager_choice();
|
2007-07-02 05:51:58 +08:00
|
|
|
if (*argcp > 1) {
|
2007-09-20 06:42:13 +08:00
|
|
|
struct strbuf buf;
|
2007-07-02 05:51:58 +08:00
|
|
|
|
2007-09-20 06:42:13 +08:00
|
|
|
strbuf_init(&buf, PATH_MAX);
|
|
|
|
strbuf_addstr(&buf, alias_string);
|
2007-12-03 12:51:50 +08:00
|
|
|
sq_quote_argv(&buf, (*argv) + 1, PATH_MAX);
|
2007-07-02 05:51:58 +08:00
|
|
|
free(alias_string);
|
2007-09-20 06:42:13 +08:00
|
|
|
alias_string = buf.buf;
|
2007-07-02 05:51:58 +08:00
|
|
|
}
|
2007-02-11 08:33:58 +08: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));
|
2009-01-05 02:38:41 +08:00
|
|
|
die("Failed to run '%s' when expanding alias '%s'",
|
2007-02-11 08:33:58 +08:00
|
|
|
alias_string + 1, alias_command);
|
|
|
|
}
|
2006-07-30 09:30:29 +08:00
|
|
|
count = split_cmdline(alias_string, &new_argv);
|
2008-09-22 23:06:41 +08:00
|
|
|
if (count < 0)
|
|
|
|
die("Bad alias.%s string", alias_command);
|
2007-06-09 04:57:55 +08: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 09:30:29 +08: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);
|
|
|
|
|
2007-12-03 12:51:50 +08:00
|
|
|
trace_argv_printf(new_argv,
|
2006-09-03 00:23:48 +08:00
|
|
|
"trace: alias expansion: %s =>",
|
|
|
|
alias_command);
|
2006-06-25 21:56:18 +08:00
|
|
|
|
2009-05-01 17:06:36 +08:00
|
|
|
new_argv = xrealloc(new_argv, sizeof(char *) *
|
2009-07-01 04:24:13 +08:00
|
|
|
(count + *argcp));
|
2006-07-30 09:30:29 +08:00
|
|
|
/* insert after command name */
|
2009-05-01 17:06:36 +08:00
|
|
|
memcpy(new_argv + count, *argv + 1, sizeof(char *) * *argcp);
|
2006-06-06 01:43:52 +08:00
|
|
|
|
2006-07-30 09:30:29 +08:00
|
|
|
*argv = new_argv;
|
|
|
|
*argcp += count - 1;
|
2006-06-06 01:43:52 +08:00
|
|
|
|
2006-07-30 09:30:29 +08:00
|
|
|
ret = 1;
|
2006-06-06 01:43:52 +08:00
|
|
|
}
|
|
|
|
|
2008-12-05 08:36:46 +08:00
|
|
|
if (subdir && chdir(subdir))
|
2009-06-27 23:58:46 +08:00
|
|
|
die_errno("Cannot change to '%s'", subdir);
|
2006-06-06 01:43:52 +08:00
|
|
|
|
2006-06-28 18:45:27 +08:00
|
|
|
errno = saved_errno;
|
|
|
|
|
2006-06-06 01:43:52 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2006-04-22 01:27:34 +08:00
|
|
|
const char git_version_string[] = GIT_VERSION;
|
2006-04-16 15:07:41 +08:00
|
|
|
|
2010-08-06 10:52:16 +08:00
|
|
|
#define RUN_SETUP (1<<0)
|
|
|
|
#define RUN_SETUP_GENTLY (1<<1)
|
|
|
|
#define USE_PAGER (1<<2)
|
2006-12-31 12:32:38 +08:00
|
|
|
/*
|
|
|
|
* require working tree to be present -- anything uses this needs
|
|
|
|
* RUN_SETUP for reading from the configuration file.
|
|
|
|
*/
|
2010-08-06 10:52:16 +08:00
|
|
|
#define NEED_WORK_TREE (1<<3)
|
2006-07-29 13:44:25 +08:00
|
|
|
|
2007-06-25 01:10:40 +08:00
|
|
|
struct cmd_struct {
|
|
|
|
const char *cmd;
|
|
|
|
int (*fn)(int, const char **, const char *);
|
|
|
|
int option;
|
|
|
|
};
|
|
|
|
|
2009-01-28 15:33:53 +08:00
|
|
|
static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
|
2007-06-25 01:10:40 +08:00
|
|
|
{
|
2009-11-09 23:05:01 +08:00
|
|
|
int status, help;
|
2007-06-25 01:29:33 +08:00
|
|
|
struct stat st;
|
2007-06-25 01:10:40 +08:00
|
|
|
const char *prefix;
|
|
|
|
|
|
|
|
prefix = NULL;
|
2009-11-09 23:05:01 +08:00
|
|
|
help = argc == 2 && !strcmp(argv[1], "-h");
|
|
|
|
if (!help) {
|
|
|
|
if (p->option & RUN_SETUP)
|
|
|
|
prefix = setup_git_directory();
|
2010-08-06 10:52:16 +08:00
|
|
|
if (p->option & RUN_SETUP_GENTLY) {
|
|
|
|
int nongit_ok;
|
|
|
|
prefix = setup_git_directory_gently(&nongit_ok);
|
|
|
|
}
|
2009-11-09 23:05:01 +08:00
|
|
|
|
2010-08-06 10:52:16 +08:00
|
|
|
if (use_pager == -1 && p->option & (RUN_SETUP | RUN_SETUP_GENTLY))
|
2009-11-09 23:05:01 +08:00
|
|
|
use_pager = check_pager_config(p->cmd);
|
|
|
|
if (use_pager == -1 && p->option & USE_PAGER)
|
|
|
|
use_pager = 1;
|
|
|
|
}
|
Allow per-command pager config
There is great debate over whether some commands should set
up a pager automatically. This patch allows individuals to
set their own pager preferences for each command, overriding
the default. For example, to disable the pager for git
status:
git config pager.status false
If "--pager" or "--no-pager" is specified on the command
line, it takes precedence over the config option.
There are two caveats:
- you can turn on the pager for plumbing commands.
Combined with "core.pager = always", this will probably
break a lot of things. Don't do it.
- This only works for builtin commands. The reason is
somewhat complex:
Calling git_config before we do setup_git_directory
has bad side effects, because it wants to know where
the git_dir is to find ".git/config". Unfortunately,
we cannot call setup_git_directory indiscriminately,
because some builtins (like "init") break if we do.
For builtins, this is OK, since we can just wait until
after we call setup_git_directory. But for aliases, we
don't know until we expand (recursively) which command
we're doing. This should not be a huge problem for
aliases, which can simply use "--pager" or "--no-pager"
in the alias as appropriate.
For external commands, however, we don't know we even
have an external command until we exec it, and by then
it is too late to check the config.
An alternative approach would be to have a config mode
where we don't bother looking at .git/config, but only
at the user and system config files. This would make the
behavior consistent across builtins, aliases, and
external commands, at the cost of not allowing per-repo
pager config for at all.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-07-03 19:46:57 +08:00
|
|
|
commit_pager_choice();
|
|
|
|
|
2009-11-09 23:05:01 +08:00
|
|
|
if (!help && p->option & NEED_WORK_TREE)
|
2007-11-03 19:23:11 +08:00
|
|
|
setup_work_tree();
|
|
|
|
|
2007-12-03 12:51:50 +08:00
|
|
|
trace_argv_printf(argv, "trace: built-in: git");
|
2007-06-25 01:10:40 +08:00
|
|
|
|
2007-06-25 01:29:33 +08:00
|
|
|
status = p->fn(argc, argv, prefix);
|
|
|
|
if (status)
|
2009-07-06 02:57:46 +08:00
|
|
|
return status;
|
2007-06-25 01:29:33 +08:00
|
|
|
|
|
|
|
/* 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-07-01 02:44:20 +08:00
|
|
|
if (fflush(stdout))
|
2009-06-27 23:58:46 +08:00
|
|
|
die_errno("write failure on standard output");
|
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-07-01 02:44:20 +08:00
|
|
|
if (ferror(stdout))
|
|
|
|
die("unknown write failure on standard output");
|
|
|
|
if (fclose(stdout))
|
2009-06-27 23:58:46 +08:00
|
|
|
die_errno("close failed on standard output");
|
2007-06-25 01:29:33 +08:00
|
|
|
return 0;
|
2007-06-25 01:10:40 +08: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-27 04:34:51 +08:00
|
|
|
{
|
|
|
|
const char *cmd = argv[0];
|
2007-06-25 01:10:40 +08:00
|
|
|
static struct cmd_struct commands[] = {
|
2007-06-03 22:48:16 +08:00
|
|
|
{ "add", cmd_add, RUN_SETUP | NEED_WORK_TREE },
|
2008-12-02 14:14:55 +08:00
|
|
|
{ "stage", cmd_add, RUN_SETUP | NEED_WORK_TREE },
|
2007-07-05 06:21:49 +08:00
|
|
|
{ "annotate", cmd_annotate, RUN_SETUP },
|
2010-08-16 08:36:12 +08:00
|
|
|
{ "apply", cmd_apply, RUN_SETUP_GENTLY },
|
2007-04-06 04:55:43 +08:00
|
|
|
{ "archive", cmd_archive },
|
2009-03-26 12:55:54 +08:00
|
|
|
{ "bisect--helper", cmd_bisect__helper, RUN_SETUP | NEED_WORK_TREE },
|
2007-01-28 22:25:55 +08:00
|
|
|
{ "blame", cmd_blame, RUN_SETUP },
|
2006-11-02 04:53:13 +08:00
|
|
|
{ "branch", cmd_branch, RUN_SETUP },
|
2010-08-06 11:12:46 +08:00
|
|
|
{ "bundle", cmd_bundle, RUN_SETUP_GENTLY },
|
2006-08-04 17:04:00 +08:00
|
|
|
{ "cat-file", cmd_cat_file, RUN_SETUP },
|
Build in checkout
The only differences in behavior should be:
- git checkout -m with non-trivial merging won't print out
merge-recursive messages (see the change in t7201-co.sh)
- git checkout -- paths... will give a sensible error message if
HEAD is invalid as a commit.
- some intermediate states which were written to disk in the shell
version (in particular, index states) are only kept in memory in
this version, and therefore these can no longer be revealed by
later write operations becoming impossible.
- when we change branches, we discard MERGE_MSG, SQUASH_MSG, and
rr-cache/MERGE_RR, like reset always has.
I'm not 100% sure I got the merge recursive setup exactly right; the
base for a non-trivial merge in the shell code doesn't seem
theoretically justified to me, but I tried to match it anyway, and the
tests all pass this way.
Other than these items, the results should be identical to the shell
version, so far as I can tell.
[jc: squashed lock-file fix from Dscho in]
Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-02-08 00:40:23 +08:00
|
|
|
{ "checkout", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },
|
2007-08-05 06:20:07 +08:00
|
|
|
{ "checkout-index", cmd_checkout_index,
|
|
|
|
RUN_SETUP | NEED_WORK_TREE},
|
2006-05-23 20:15:29 +08:00
|
|
|
{ "check-ref-format", cmd_check_ref_format },
|
2008-06-08 23:16:11 +08:00
|
|
|
{ "check-attr", cmd_check_attr, RUN_SETUP },
|
2006-10-24 07:01:57 +08:00
|
|
|
{ "cherry", cmd_cherry, RUN_SETUP },
|
2007-06-03 22:48:16 +08:00
|
|
|
{ "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE },
|
2008-04-28 01:39:30 +08:00
|
|
|
{ "clone", cmd_clone },
|
2007-11-12 09:48:47 +08:00
|
|
|
{ "clean", cmd_clean, RUN_SETUP | NEED_WORK_TREE },
|
2007-11-09 00:59:00 +08:00
|
|
|
{ "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE },
|
2006-08-04 17:04:00 +08:00
|
|
|
{ "commit-tree", cmd_commit_tree, RUN_SETUP },
|
2007-01-29 08:16:53 +08:00
|
|
|
{ "config", cmd_config },
|
2006-09-14 09:03:59 +08:00
|
|
|
{ "count-objects", cmd_count_objects, RUN_SETUP },
|
2007-01-10 19:36:36 +08:00
|
|
|
{ "describe", cmd_describe, RUN_SETUP },
|
2007-08-13 01:46:55 +08:00
|
|
|
{ "diff", cmd_diff },
|
2008-08-28 21:02:12 +08:00
|
|
|
{ "diff-files", cmd_diff_files, RUN_SETUP | NEED_WORK_TREE },
|
2006-08-04 17:04:00 +08:00
|
|
|
{ "diff-index", cmd_diff_index, RUN_SETUP },
|
|
|
|
{ "diff-tree", cmd_diff_tree, RUN_SETUP },
|
2007-12-02 22:14:13 +08:00
|
|
|
{ "fast-export", cmd_fast_export, RUN_SETUP },
|
2007-09-11 11:03:25 +08:00
|
|
|
{ "fetch", cmd_fetch, RUN_SETUP },
|
2007-09-11 11:03:00 +08:00
|
|
|
{ "fetch-pack", cmd_fetch_pack, RUN_SETUP },
|
2006-08-04 17:04:00 +08:00
|
|
|
{ "fmt-merge-msg", cmd_fmt_merge_msg, RUN_SETUP },
|
2006-09-16 04:30:02 +08:00
|
|
|
{ "for-each-ref", cmd_for_each_ref, RUN_SETUP },
|
2006-08-04 17:04:00 +08:00
|
|
|
{ "format-patch", cmd_format_patch, RUN_SETUP },
|
2007-01-29 23:48:06 +08:00
|
|
|
{ "fsck", cmd_fsck, RUN_SETUP },
|
|
|
|
{ "fsck-objects", cmd_fsck, RUN_SETUP },
|
2007-03-14 09:58:22 +08:00
|
|
|
{ "gc", cmd_gc, RUN_SETUP },
|
2006-08-04 16:51:04 +08:00
|
|
|
{ "get-tar-commit-id", cmd_get_tar_commit_id },
|
2010-08-06 11:06:39 +08:00
|
|
|
{ "grep", cmd_grep, RUN_SETUP_GENTLY },
|
2010-01-22 11:50:11 +08:00
|
|
|
{ "hash-object", cmd_hash_object },
|
2006-08-04 16:51:04 +08:00
|
|
|
{ "help", cmd_help },
|
2010-01-22 23:55:19 +08:00
|
|
|
{ "index-pack", cmd_index_pack },
|
2007-01-08 01:31:29 +08:00
|
|
|
{ "init", cmd_init_db },
|
2006-08-04 16:51:04 +08:00
|
|
|
{ "init-db", cmd_init_db },
|
2006-08-04 17:04:00 +08:00
|
|
|
{ "log", cmd_log, RUN_SETUP | USE_PAGER },
|
|
|
|
{ "ls-files", cmd_ls_files, RUN_SETUP },
|
|
|
|
{ "ls-tree", cmd_ls_tree, RUN_SETUP },
|
2007-11-05 04:51:17 +08:00
|
|
|
{ "ls-remote", cmd_ls_remote },
|
2006-08-04 16:51:04 +08:00
|
|
|
{ "mailinfo", cmd_mailinfo },
|
|
|
|
{ "mailsplit", cmd_mailsplit },
|
2008-07-08 01:24:20 +08:00
|
|
|
{ "merge", cmd_merge, RUN_SETUP | NEED_WORK_TREE },
|
2007-01-09 16:50:02 +08:00
|
|
|
{ "merge-base", cmd_merge_base, RUN_SETUP },
|
2006-12-06 23:26:06 +08:00
|
|
|
{ "merge-file", cmd_merge_file },
|
2010-01-22 23:29:21 +08:00
|
|
|
{ "merge-index", cmd_merge_index, RUN_SETUP },
|
2007-11-23 04:19:40 +08:00
|
|
|
{ "merge-ours", cmd_merge_ours, RUN_SETUP },
|
2008-02-08 00:40:05 +08:00
|
|
|
{ "merge-recursive", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
|
2009-11-26 10:23:55 +08:00
|
|
|
{ "merge-recursive-ours", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
|
|
|
|
{ "merge-recursive-theirs", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
|
2008-02-24 03:08:25 +08:00
|
|
|
{ "merge-subtree", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
|
2010-01-22 10:25:20 +08:00
|
|
|
{ "merge-tree", cmd_merge_tree, RUN_SETUP },
|
2010-01-22 23:34:44 +08:00
|
|
|
{ "mktag", cmd_mktag, RUN_SETUP },
|
2009-05-11 01:28:18 +08:00
|
|
|
{ "mktree", cmd_mktree, RUN_SETUP },
|
2007-06-03 22:48:16 +08:00
|
|
|
{ "mv", cmd_mv, RUN_SETUP | NEED_WORK_TREE },
|
2006-08-04 17:04:00 +08:00
|
|
|
{ "name-rev", cmd_name_rev, RUN_SETUP },
|
2010-02-14 05:28:20 +08:00
|
|
|
{ "notes", cmd_notes, RUN_SETUP },
|
2006-08-04 17:04:00 +08:00
|
|
|
{ "pack-objects", cmd_pack_objects, RUN_SETUP },
|
2010-01-22 23:42:14 +08:00
|
|
|
{ "pack-redundant", cmd_pack_redundant, RUN_SETUP },
|
2010-01-22 12:31:25 +08:00
|
|
|
{ "patch-id", cmd_patch_id },
|
2007-11-05 04:51:17 +08:00
|
|
|
{ "peek-remote", cmd_ls_remote },
|
2007-07-05 06:21:49 +08:00
|
|
|
{ "pickaxe", cmd_blame, RUN_SETUP },
|
2006-08-04 17:04:00 +08:00
|
|
|
{ "prune", cmd_prune, RUN_SETUP },
|
|
|
|
{ "prune-packed", cmd_prune_packed, RUN_SETUP },
|
2006-08-09 06:42:20 +08:00
|
|
|
{ "push", cmd_push, RUN_SETUP },
|
2006-08-04 17:04:00 +08:00
|
|
|
{ "read-tree", cmd_read_tree, RUN_SETUP },
|
2008-09-09 16:27:08 +08:00
|
|
|
{ "receive-pack", cmd_receive_pack },
|
2006-12-19 16:23:12 +08:00
|
|
|
{ "reflog", cmd_reflog, RUN_SETUP },
|
2008-02-29 09:45:45 +08:00
|
|
|
{ "remote", cmd_remote, RUN_SETUP },
|
2009-02-02 13:12:44 +08:00
|
|
|
{ "replace", cmd_replace, RUN_SETUP },
|
2007-01-29 08:16:53 +08:00
|
|
|
{ "repo-config", cmd_config },
|
2006-12-21 00:39:41 +08:00
|
|
|
{ "rerere", cmd_rerere, RUN_SETUP },
|
2007-09-11 11:19:34 +08:00
|
|
|
{ "reset", cmd_reset, RUN_SETUP },
|
2006-08-04 17:04:00 +08:00
|
|
|
{ "rev-list", cmd_rev_list, RUN_SETUP },
|
2007-11-07 04:23:14 +08:00
|
|
|
{ "rev-parse", cmd_rev_parse },
|
2007-06-03 22:48:16 +08:00
|
|
|
{ "revert", cmd_revert, RUN_SETUP | NEED_WORK_TREE },
|
2007-11-03 19:23:13 +08:00
|
|
|
{ "rm", cmd_rm, RUN_SETUP },
|
2007-10-30 10:03:39 +08:00
|
|
|
{ "send-pack", cmd_send_pack, RUN_SETUP },
|
2010-08-06 11:01:37 +08:00
|
|
|
{ "shortlog", cmd_shortlog, RUN_SETUP_GENTLY | USE_PAGER },
|
2006-08-04 17:04:00 +08:00
|
|
|
{ "show-branch", cmd_show_branch, RUN_SETUP },
|
|
|
|
{ "show", cmd_show, RUN_SETUP | USE_PAGER },
|
2008-07-22 10:41:17 +08:00
|
|
|
{ "status", cmd_status, RUN_SETUP | NEED_WORK_TREE },
|
2006-08-04 16:51:04 +08:00
|
|
|
{ "stripspace", cmd_stripspace },
|
2006-08-04 17:04:00 +08:00
|
|
|
{ "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
|
2007-07-20 07:42:28 +08:00
|
|
|
{ "tag", cmd_tag, RUN_SETUP },
|
2006-10-08 21:44:50 +08:00
|
|
|
{ "tar-tree", cmd_tar_tree },
|
2010-01-22 23:38:03 +08:00
|
|
|
{ "unpack-file", cmd_unpack_file, RUN_SETUP },
|
2006-08-04 17:04:00 +08:00
|
|
|
{ "unpack-objects", cmd_unpack_objects, RUN_SETUP },
|
|
|
|
{ "update-index", cmd_update_index, RUN_SETUP },
|
|
|
|
{ "update-ref", cmd_update_ref, RUN_SETUP },
|
2009-08-29 17:04:52 +08:00
|
|
|
{ "update-server-info", cmd_update_server_info, RUN_SETUP },
|
2006-09-07 21:12:05 +08:00
|
|
|
{ "upload-archive", cmd_upload_archive },
|
2010-01-22 12:21:55 +08:00
|
|
|
{ "var", cmd_var },
|
2007-07-27 12:07:34 +08:00
|
|
|
{ "verify-tag", cmd_verify_tag, RUN_SETUP },
|
2006-08-04 16:51:04 +08:00
|
|
|
{ "version", cmd_version },
|
2006-08-04 17:04:00 +08:00
|
|
|
{ "whatchanged", cmd_whatchanged, RUN_SETUP | USE_PAGER },
|
|
|
|
{ "write-tree", cmd_write_tree, RUN_SETUP },
|
2006-08-10 23:02:38 +08: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-16 02:19:32 +08: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 07:37:32 +08: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-27 04:34:51 +08:00
|
|
|
};
|
|
|
|
int i;
|
2007-12-09 03:57:25 +08:00
|
|
|
static const char ext[] = STRIP_EXTENSION;
|
|
|
|
|
|
|
|
if (sizeof(ext) > 1) {
|
|
|
|
i = strlen(argv[0]) - strlen(ext);
|
|
|
|
if (i > 0 && !strcmp(argv[0] + i, ext)) {
|
2008-09-10 02:57:10 +08:00
|
|
|
char *argv0 = xstrdup(argv[0]);
|
2007-12-09 03:57:25 +08:00
|
|
|
argv[0] = cmd = argv0;
|
|
|
|
argv0[i] = '\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-27 04:34:51 +08:00
|
|
|
|
2006-04-16 02:13:49 +08: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-27 04:34:51 +08:00
|
|
|
for (i = 0; i < ARRAY_SIZE(commands); i++) {
|
|
|
|
struct cmd_struct *p = commands+i;
|
|
|
|
if (strcmp(p->cmd, cmd))
|
|
|
|
continue;
|
2009-01-28 15:33:53 +08:00
|
|
|
exit(run_builtin(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-27 04:34:51 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-12-02 14:09:22 +08:00
|
|
|
static void execv_dashed_external(const char **argv)
|
|
|
|
{
|
2008-10-10 03:12:12 +08:00
|
|
|
struct strbuf cmd = STRBUF_INIT;
|
2007-12-02 14:09:22 +08:00
|
|
|
const char *tmp;
|
2009-01-28 15:38:14 +08:00
|
|
|
int status;
|
2007-12-02 14:09:22 +08:00
|
|
|
|
2010-07-15 06:55:12 +08:00
|
|
|
commit_pager_choice();
|
|
|
|
|
2007-12-02 14:09:22 +08:00
|
|
|
strbuf_addf(&cmd, "git-%s", argv[0]);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* argv[0] must be the git command, but the argv array
|
|
|
|
* belongs to the caller, and may be reused in
|
|
|
|
* subsequent loop iterations. Save argv[0] and
|
|
|
|
* restore it on error.
|
|
|
|
*/
|
|
|
|
tmp = argv[0];
|
|
|
|
argv[0] = cmd.buf;
|
|
|
|
|
|
|
|
trace_argv_printf(argv, "trace: exec:");
|
|
|
|
|
2009-01-28 15:38:14 +08:00
|
|
|
/*
|
|
|
|
* if we fail because the command is not found, it is
|
|
|
|
* OK to return. Otherwise, we just pass along the status code.
|
|
|
|
*/
|
2009-07-05 03:26:42 +08:00
|
|
|
status = run_command_v_opt(argv, RUN_SILENT_EXEC_FAILURE);
|
run_command: report system call errors instead of returning error codes
The motivation for this change is that system call failures are serious
errors that should be reported to the user, but only few callers took the
burden to decode the error codes that the functions returned into error
messages.
If at all, then only an unspecific error message was given. A prominent
example is this:
$ git upload-pack . | :
fatal: unable to run 'git-upload-pack'
In this example, git-upload-pack, the external command invoked through the
git wrapper, dies due to SIGPIPE, but the git wrapper does not bother to
report the real cause. In fact, this very error message is copied to the
syslog if git-daemon's client aborts the connection early.
With this change, system call failures are reported immediately after the
failure and only a generic failure code is returned to the caller. In the
above example the error is now to the point:
$ git upload-pack . | :
error: git-upload-pack died of signal
Note that there is no error report if the invoked program terminated with
a non-zero exit code, because it is reasonable to expect that the invoked
program has already reported an error. (But many run_command call sites
nevertheless write a generic error message.)
There was one special return code that was used to identify the case where
run_command failed because the requested program could not be exec'd. This
special case is now treated like a system call failure with errno set to
ENOENT. No error is reported in this case, because the call site in git.c
expects this as a normal result. Therefore, the callers that carefully
decoded the return value still check for this condition.
Signed-off-by: Johannes Sixt <j6t@kdbg.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-07-05 03:26:40 +08:00
|
|
|
if (status >= 0 || errno != ENOENT)
|
2009-07-05 03:26:39 +08:00
|
|
|
exit(status);
|
2007-12-02 14:09:22 +08:00
|
|
|
|
|
|
|
argv[0] = tmp;
|
|
|
|
|
|
|
|
strbuf_release(&cmd);
|
|
|
|
}
|
|
|
|
|
2009-01-05 01:16:01 +08:00
|
|
|
static int run_argv(int *argcp, const char ***argv)
|
|
|
|
{
|
|
|
|
int done_alias = 0;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
/* See if it's an internal command */
|
|
|
|
handle_internal_command(*argcp, *argv);
|
|
|
|
|
|
|
|
/* .. then try the external ones */
|
|
|
|
execv_dashed_external(*argv);
|
|
|
|
|
|
|
|
/* 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(argcp, argv))
|
|
|
|
break;
|
|
|
|
done_alias = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return done_alias;
|
|
|
|
}
|
|
|
|
|
2007-12-02 14:09:22 +08:00
|
|
|
|
2007-06-25 01:10:40 +08:00
|
|
|
int main(int argc, const char **argv)
|
2005-11-16 07:31:25 +08:00
|
|
|
{
|
2009-01-18 20:00:10 +08:00
|
|
|
const char *cmd;
|
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-27 04:34:51 +08:00
|
|
|
|
2010-08-06 10:40:35 +08:00
|
|
|
startup_info = &git_startup_info;
|
|
|
|
|
2009-01-18 20:00:11 +08:00
|
|
|
cmd = git_extract_argv0_path(argv[0]);
|
|
|
|
if (!cmd)
|
2009-01-18 20:00:10 +08:00
|
|
|
cmd = "git-help";
|
2005-11-16 07:31:25 +08: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-27 04:34:51 +08: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 17:53:29 +08: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-27 04:34:51 +08:00
|
|
|
cmd += 4;
|
|
|
|
argv[0] = cmd;
|
2007-06-25 01:10:40 +08: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-27 04:34:51 +08:00
|
|
|
die("cannot handle %s internally", cmd);
|
|
|
|
}
|
2005-11-16 07:31:25 +08: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-27 04:34:51 +08:00
|
|
|
/* Look for flags.. */
|
2006-07-26 02:24:22 +08:00
|
|
|
argv++;
|
|
|
|
argc--;
|
2007-06-09 04:57:55 +08:00
|
|
|
handle_options(&argv, &argc, NULL);
|
2006-07-26 02:24:22 +08: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 17:53:29 +08:00
|
|
|
if (!prefixcmp(argv[0], "--"))
|
2006-07-26 02:24:22 +08:00
|
|
|
argv[0] += 2;
|
|
|
|
} else {
|
2007-10-27 16:36:49 +08:00
|
|
|
/* The user didn't specify a command; give them help */
|
git --paginate: do not commit pager choice too early
When git is passed the --paginate option, starting up a pager requires
deciding what pager to start, which requires access to the core.pager
configuration.
At the relevant moment, the repository has not been searched for yet.
Attempting to access the configuration at this point results in
git_dir being set to .git [*], which is almost certainly not what was
wanted. In particular, when run from a subdirectory of the toplevel,
git --paginate does not respect the core.pager setting from the
current repository.
[*] unless GIT_DIR or GIT_CONFIG is set
So delay the pager startup when possible:
1. run_argv() already commits pager choice inside run_builtin() if a
command is found. For commands that use RUN_SETUP, waiting until
then fixes the problem described above: once git knows where to
look, it happily respects the core.pager setting.
2. list_common_cmds_help() prints out 29 lines and exits. This can
benefit from pagination, so we need to commit the pager choice
before writing this output.
Luckily ‘git’ without subcommand has no other reason to access a
repository, so it would be intuitive to ignore repository-local
configuration in this case. Simpler for now to choose a pager
using the funny code that notices a repository that happens to be
at .git. That this accesses a repository when it is very
convenient to is a bug but not an important one.
3. help_unknown_cmd() prints out a few lines to stderr. It is not
important to paginate this, so don’t.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Acked-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-06-27 03:26:37 +08:00
|
|
|
commit_pager_choice();
|
2007-10-27 16:36:49 +08:00
|
|
|
printf("usage: %s\n\n", git_usage_string);
|
|
|
|
list_common_cmds_help();
|
2008-06-06 05:15:36 +08:00
|
|
|
printf("\n%s\n", git_more_info_string);
|
2007-10-27 16:36:49 +08:00
|
|
|
exit(1);
|
2005-11-16 07:31:25 +08:00
|
|
|
}
|
2006-07-26 02:24:22 +08: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-27 04:34:51 +08:00
|
|
|
|
|
|
|
/*
|
2007-10-28 19:17:20 +08:00
|
|
|
* We use PATH to find git commands, but we prepend some higher
|
2009-04-18 02:13:30 +08:00
|
|
|
* precedence paths: the "--exec-path" option, the GIT_EXEC_PATH
|
2007-10-28 19:17:20 +08:00
|
|
|
* environment, and the $(gitexecdir) from the Makefile at build
|
|
|
|
* time.
|
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-27 04:34:51 +08:00
|
|
|
*/
|
2008-07-22 03:19:52 +08:00
|
|
|
setup_path();
|
2005-11-16 07:31:25 +08:00
|
|
|
|
2006-06-06 09:09:40 +08:00
|
|
|
while (1) {
|
2009-01-05 01:16:01 +08:00
|
|
|
static int done_help = 0;
|
|
|
|
static int was_alias = 0;
|
|
|
|
was_alias = run_argv(&argc, &argv);
|
|
|
|
if (errno != ENOENT)
|
2006-06-06 09:09:40 +08:00
|
|
|
break;
|
2009-01-05 01:16:01 +08:00
|
|
|
if (was_alias) {
|
2007-02-11 08:33:57 +08:00
|
|
|
fprintf(stderr, "Expansion of alias '%s' failed; "
|
2010-02-16 07:33:18 +08:00
|
|
|
"'%s' is not a git command\n",
|
2007-02-11 08:33:57 +08:00
|
|
|
cmd, argv[0]);
|
|
|
|
exit(1);
|
|
|
|
}
|
2009-01-05 01:16:01 +08:00
|
|
|
if (!done_help) {
|
|
|
|
cmd = argv[0] = help_unknown_cmd(cmd);
|
|
|
|
done_help = 1;
|
|
|
|
} else
|
|
|
|
break;
|
2007-02-11 08:33:57 +08:00
|
|
|
}
|
2005-12-01 20:48:35 +08:00
|
|
|
|
|
|
|
fprintf(stderr, "Failed to run command '%s': %s\n",
|
2006-06-28 17:17:21 +08:00
|
|
|
cmd, strerror(errno));
|
2005-11-16 07:31:25 +08:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|