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[] =
|
2007-08-20 01:24:36 +08: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-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.";
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-09 04:57:55 +08:00
|
|
|
static int handle_options(const char*** argv, int* argc, int* envchanged)
|
2006-07-24 20:10:45 +08:00
|
|
|
{
|
|
|
|
int handled = 0;
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
} 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;
|
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;
|
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;
|
|
|
|
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] == '!') {
|
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
|
|
|
|
2006-08-26 22:16:18 +08:00
|
|
|
new_argv = xrealloc(new_argv, sizeof(char*) *
|
|
|
|
(count + *argcp + 1));
|
2006-07-30 09:30:29 +08:00
|
|
|
/* insert after command name */
|
|
|
|
memcpy(new_argv + count, *argv + 1, sizeof(char*) * *argcp);
|
|
|
|
new_argv[count+*argcp] = NULL;
|
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))
|
|
|
|
die("Cannot change to %s: %s", subdir, strerror(errno));
|
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
|
|
|
|
2006-08-04 17:04:00 +08:00
|
|
|
#define RUN_SETUP (1<<0)
|
|
|
|
#define USE_PAGER (1<<1)
|
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.
|
|
|
|
*/
|
2007-06-03 22:48:16 +08:00
|
|
|
#define NEED_WORK_TREE (1<<2)
|
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
|
|
|
{
|
2007-06-25 01:29:33 +08:00
|
|
|
int status;
|
|
|
|
struct stat st;
|
2007-06-25 01:10:40 +08:00
|
|
|
const char *prefix;
|
|
|
|
|
|
|
|
prefix = NULL;
|
|
|
|
if (p->option & RUN_SETUP)
|
|
|
|
prefix = setup_git_directory();
|
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
|
|
|
|
|
|
|
if (use_pager == -1 && p->option & RUN_SETUP)
|
|
|
|
use_pager = check_pager_config(p->cmd);
|
|
|
|
if (use_pager == -1 && p->option & USE_PAGER)
|
|
|
|
use_pager = 1;
|
|
|
|
commit_pager_choice();
|
|
|
|
|
2007-11-03 19:23:11 +08:00
|
|
|
if (p->option & NEED_WORK_TREE)
|
|
|
|
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)
|
2007-11-14 04:05:02 +08:00
|
|
|
return status & 0xff;
|
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))
|
2007-06-25 01:29:33 +08: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-07-01 02:44:20 +08: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-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 },
|
2006-08-04 16:51:04 +08:00
|
|
|
{ "apply", cmd_apply },
|
2007-04-06 04:55:43 +08:00
|
|
|
{ "archive", cmd_archive },
|
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 },
|
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 08:59:14 +08:00
|
|
|
{ "bundle", cmd_bundle },
|
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 },
|
2007-01-16 16:23:24 +08:00
|
|
|
{ "fetch--tool", cmd_fetch__tool, 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 },
|
2007-02-19 22:56:04 +08:00
|
|
|
{ "grep", cmd_grep, RUN_SETUP | USE_PAGER },
|
2006-08-04 16:51:04 +08:00
|
|
|
{ "help", cmd_help },
|
2007-09-11 11:02:45 +08:00
|
|
|
#ifndef NO_CURL
|
|
|
|
{ "http-fetch", cmd_http_fetch, RUN_SETUP },
|
|
|
|
#endif
|
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 },
|
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 },
|
2008-02-24 03:08:25 +08:00
|
|
|
{ "merge-subtree", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
|
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 },
|
|
|
|
{ "pack-objects", cmd_pack_objects, RUN_SETUP },
|
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 },
|
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 },
|
2008-03-15 05:35:24 +08:00
|
|
|
{ "shortlog", cmd_shortlog, 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 },
|
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 },
|
2006-09-07 21:12:05 +08:00
|
|
|
{ "upload-archive", cmd_upload_archive },
|
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
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
status = run_command_v_opt(argv, 0);
|
|
|
|
if (status != -ERR_RUN_COMMAND_EXEC) {
|
|
|
|
if (IS_RUN_COMMAND_ERR(status))
|
|
|
|
die("unable to run '%s'", argv[0]);
|
|
|
|
exit(-status);
|
|
|
|
}
|
|
|
|
errno = ENOENT; /* as if we called execvp */
|
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
|
|
|
|
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);
|
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();
|
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 */
|
|
|
|
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
|
|
|
|
* precidence paths: the "--exec-path" option, the GIT_EXEC_PATH
|
|
|
|
* 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; "
|
|
|
|
"'%s' is not a git-command\n",
|
|
|
|
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;
|
|
|
|
}
|