2006-12-19 23:34:12 +01:00
|
|
|
#include "builtin.h"
|
2010-09-01 04:29:08 +02:00
|
|
|
#include "exec_cmd.h"
|
|
|
|
#include "help.h"
|
2009-01-28 08:38:14 +01:00
|
|
|
#include "run-command.h"
|
2005-11-16 00:31:25 +01:00
|
|
|
|
2006-07-30 23:42:25 +02:00
|
|
|
const char git_usage_string[] =
|
2013-09-09 15:47:43 +02:00
|
|
|
"git [--version] [--help] [-C <path>] [-c name=value]\n"
|
2013-03-11 20:44:15 +01:00
|
|
|
" [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n"
|
2015-01-13 08:44:47 +01:00
|
|
|
" [-p | --paginate | --no-pager] [--no-replace-objects] [--bare]\n"
|
ref namespaces: infrastructure
Add support for dividing the refs of a single repository into multiple
namespaces, each of which can have its own branches, tags, and HEAD.
Git can expose each namespace as an independent repository to pull from
and push to, while sharing the object store, and exposing all the refs
to operations such as git-gc.
Storing multiple repositories as namespaces of a single repository
avoids storing duplicate copies of the same objects, such as when
storing multiple branches of the same source. The alternates mechanism
provides similar support for avoiding duplicates, but alternates do not
prevent duplication between new objects added to the repositories
without ongoing maintenance, while namespaces do.
To specify a namespace, set the GIT_NAMESPACE environment variable to
the namespace. For each ref namespace, git stores the corresponding
refs in a directory under refs/namespaces/. For example,
GIT_NAMESPACE=foo will store refs under refs/namespaces/foo/. You can
also specify namespaces via the --namespace option to git.
Note that namespaces which include a / will expand to a hierarchy of
namespaces; for example, GIT_NAMESPACE=foo/bar will store refs under
refs/namespaces/foo/refs/namespaces/bar/. This makes paths in
GIT_NAMESPACE behave hierarchically, so that cloning with
GIT_NAMESPACE=foo/bar produces the same result as cloning with
GIT_NAMESPACE=foo and cloning from that repo with GIT_NAMESPACE=bar. It
also avoids ambiguity with strange namespace paths such as
foo/refs/heads/, which could otherwise generate directory/file conflicts
within the refs directory.
Add the infrastructure for ref namespaces: handle the GIT_NAMESPACE
environment variable and --namespace option, and support iterating over
refs in a namespace.
Signed-off-by: Josh Triplett <josh@joshtriplett.org>
Signed-off-by: Jamey Sharp <jamey@minilop.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-07-05 19:54:44 +02:00
|
|
|
" [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
|
2010-10-08 19:31:15 +02:00
|
|
|
" <command> [<args>]";
|
2006-07-30 23:42:25 +02:00
|
|
|
|
2008-06-05 23:15:36 +02:00
|
|
|
const char git_more_info_string[] =
|
2014-08-30 21:56:01 +02:00
|
|
|
N_("'git help -a' and 'git help -g' list available subcommands and some\n"
|
2013-04-03 00:39:48 +02:00
|
|
|
"concept guides. See 'git help <command>' or 'git help <concept>'\n"
|
|
|
|
"to read about a specific subcommand or concept.");
|
2008-06-05 23:15:36 +02:00
|
|
|
|
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 13:46:57 +02:00
|
|
|
static int use_pager = -1;
|
2014-09-02 22:27:45 +02:00
|
|
|
static char *orig_cwd;
|
2014-06-08 11:37:10 +02:00
|
|
|
static const char *env_names[] = {
|
|
|
|
GIT_DIR_ENVIRONMENT,
|
|
|
|
GIT_WORK_TREE_ENVIRONMENT,
|
|
|
|
GIT_IMPLICIT_WORK_TREE_ENVIRONMENT,
|
|
|
|
GIT_PREFIX_ENVIRONMENT
|
|
|
|
};
|
|
|
|
static char *orig_env[4];
|
2016-01-27 07:50:27 +01:00
|
|
|
static int save_restore_env_balance;
|
2014-06-08 11:37:10 +02:00
|
|
|
|
2015-12-03 19:17:55 +01:00
|
|
|
static void save_env_before_alias(void)
|
2014-06-08 11:37:10 +02:00
|
|
|
{
|
|
|
|
int i;
|
2016-01-27 07:50:27 +01:00
|
|
|
|
|
|
|
assert(save_restore_env_balance == 0);
|
|
|
|
save_restore_env_balance = 1;
|
2014-09-02 22:27:45 +02:00
|
|
|
orig_cwd = xgetcwd();
|
2014-06-08 11:37:10 +02:00
|
|
|
for (i = 0; i < ARRAY_SIZE(env_names); i++) {
|
|
|
|
orig_env[i] = getenv(env_names[i]);
|
2016-10-12 20:20:23 +02:00
|
|
|
orig_env[i] = xstrdup_or_null(orig_env[i]);
|
2014-06-08 11:37:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-20 08:50:19 +01:00
|
|
|
static void restore_env(int external_alias)
|
2014-06-08 11:37:10 +02:00
|
|
|
{
|
|
|
|
int i;
|
2016-01-27 07:50:27 +01:00
|
|
|
|
|
|
|
assert(save_restore_env_balance == 1);
|
|
|
|
save_restore_env_balance = 0;
|
2015-12-20 08:50:19 +01:00
|
|
|
if (!external_alias && orig_cwd && chdir(orig_cwd))
|
2014-06-08 11:37:10 +02:00
|
|
|
die_errno("could not move to %s", orig_cwd);
|
2014-09-02 22:27:45 +02:00
|
|
|
free(orig_cwd);
|
2014-06-08 11:37:10 +02:00
|
|
|
for (i = 0; i < ARRAY_SIZE(env_names); i++) {
|
2015-12-20 08:50:19 +01:00
|
|
|
if (external_alias &&
|
|
|
|
!strcmp(env_names[i], GIT_PREFIX_ENVIRONMENT))
|
|
|
|
continue;
|
2016-02-03 00:42:59 +01:00
|
|
|
if (orig_env[i]) {
|
2014-06-08 11:37:10 +02:00
|
|
|
setenv(env_names[i], orig_env[i], 1);
|
2016-02-03 00:42:59 +01:00
|
|
|
free(orig_env[i]);
|
|
|
|
} else {
|
2014-06-08 11:37:10 +02:00
|
|
|
unsetenv(env_names[i]);
|
2016-02-03 00:42:59 +01:00
|
|
|
}
|
2014-06-08 11:37:10 +02:00
|
|
|
}
|
|
|
|
}
|
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 13:46:57 +02:00
|
|
|
|
|
|
|
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 11:06:36 +02:00
|
|
|
static int handle_options(const char ***argv, int *argc, int *envchanged)
|
2006-07-24 14:10:45 +02:00
|
|
|
{
|
2011-05-25 00:50:35 +02:00
|
|
|
const char **orig_argv = *argv;
|
2006-07-24 14:10:45 +02:00
|
|
|
|
|
|
|
while (*argc > 0) {
|
|
|
|
const char *cmd = (*argv)[0];
|
|
|
|
if (cmd[0] != '-')
|
|
|
|
break;
|
|
|
|
|
2006-07-25 20:24:22 +02:00
|
|
|
/*
|
|
|
|
* For legacy reasons, the "version" and "help"
|
|
|
|
* commands can be written with "--" prepended
|
|
|
|
* to make them look like flags.
|
|
|
|
*/
|
|
|
|
if (!strcmp(cmd, "--help") || !strcmp(cmd, "--version"))
|
|
|
|
break;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check remaining flags.
|
|
|
|
*/
|
use skip_prefix to avoid magic numbers
It's a common idiom to match a prefix and then skip past it
with a magic number, like:
if (starts_with(foo, "bar"))
foo += 3;
This is easy to get wrong, since you have to count the
prefix string yourself, and there's no compiler check if the
string changes. We can use skip_prefix to avoid the magic
numbers here.
Note that some of these conversions could be much shorter.
For example:
if (starts_with(arg, "--foo=")) {
bar = arg + 6;
continue;
}
could become:
if (skip_prefix(arg, "--foo=", &bar))
continue;
However, I have left it as:
if (skip_prefix(arg, "--foo=", &v)) {
bar = v;
continue;
}
to visually match nearby cases which need to actually
process the string. Like:
if (skip_prefix(arg, "--foo=", &v)) {
bar = atoi(v);
continue;
}
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-06-18 21:47:50 +02:00
|
|
|
if (skip_prefix(cmd, "--exec-path", &cmd)) {
|
2006-07-25 20:24:22 +02:00
|
|
|
if (*cmd == '=')
|
2007-10-27 10:36:51 +02:00
|
|
|
git_set_argv_exec_path(cmd + 1);
|
2006-07-25 20:24:22 +02:00
|
|
|
else {
|
|
|
|
puts(git_exec_path());
|
|
|
|
exit(0);
|
|
|
|
}
|
2009-04-05 04:15:16 +02:00
|
|
|
} else if (!strcmp(cmd, "--html-path")) {
|
|
|
|
puts(system_path(GIT_HTML_PATH));
|
|
|
|
exit(0);
|
2011-05-01 10:16:25 +02:00
|
|
|
} else if (!strcmp(cmd, "--man-path")) {
|
|
|
|
puts(system_path(GIT_MAN_PATH));
|
|
|
|
exit(0);
|
|
|
|
} else if (!strcmp(cmd, "--info-path")) {
|
|
|
|
puts(system_path(GIT_INFO_PATH));
|
|
|
|
exit(0);
|
2006-07-25 20:24:22 +02: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 13:46:57 +02:00
|
|
|
use_pager = 1;
|
2007-08-19 19:24:36 +02: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 13:46:57 +02:00
|
|
|
use_pager = 0;
|
2007-08-19 19:24:36 +02:00
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
2009-10-12 22:30:32 +02:00
|
|
|
} else if (!strcmp(cmd, "--no-replace-objects")) {
|
2014-02-18 12:24:55 +01:00
|
|
|
check_replace_refs = 0;
|
2009-11-18 07:50:58 +01:00
|
|
|
setenv(NO_REPLACE_OBJECTS_ENVIRONMENT, "1", 1);
|
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
2006-07-25 20:24:22 +02:00
|
|
|
} else if (!strcmp(cmd, "--git-dir")) {
|
2006-12-22 14:56:25 +01:00
|
|
|
if (*argc < 2) {
|
|
|
|
fprintf(stderr, "No directory given for --git-dir.\n" );
|
|
|
|
usage(git_usage_string);
|
|
|
|
}
|
2006-12-31 05:29:11 +01:00
|
|
|
setenv(GIT_DIR_ENVIRONMENT, (*argv)[1], 1);
|
2007-06-08 22:57:55 +02:00
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
2006-07-25 20:24:22 +02:00
|
|
|
(*argv)++;
|
|
|
|
(*argc)--;
|
use skip_prefix to avoid magic numbers
It's a common idiom to match a prefix and then skip past it
with a magic number, like:
if (starts_with(foo, "bar"))
foo += 3;
This is easy to get wrong, since you have to count the
prefix string yourself, and there's no compiler check if the
string changes. We can use skip_prefix to avoid the magic
numbers here.
Note that some of these conversions could be much shorter.
For example:
if (starts_with(arg, "--foo=")) {
bar = arg + 6;
continue;
}
could become:
if (skip_prefix(arg, "--foo=", &bar))
continue;
However, I have left it as:
if (skip_prefix(arg, "--foo=", &v)) {
bar = v;
continue;
}
to visually match nearby cases which need to actually
process the string. Like:
if (skip_prefix(arg, "--foo=", &v)) {
bar = atoi(v);
continue;
}
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-06-18 21:47:50 +02:00
|
|
|
} else if (skip_prefix(cmd, "--git-dir=", &cmd)) {
|
|
|
|
setenv(GIT_DIR_ENVIRONMENT, cmd, 1);
|
2007-06-08 22:57:55 +02:00
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
ref namespaces: infrastructure
Add support for dividing the refs of a single repository into multiple
namespaces, each of which can have its own branches, tags, and HEAD.
Git can expose each namespace as an independent repository to pull from
and push to, while sharing the object store, and exposing all the refs
to operations such as git-gc.
Storing multiple repositories as namespaces of a single repository
avoids storing duplicate copies of the same objects, such as when
storing multiple branches of the same source. The alternates mechanism
provides similar support for avoiding duplicates, but alternates do not
prevent duplication between new objects added to the repositories
without ongoing maintenance, while namespaces do.
To specify a namespace, set the GIT_NAMESPACE environment variable to
the namespace. For each ref namespace, git stores the corresponding
refs in a directory under refs/namespaces/. For example,
GIT_NAMESPACE=foo will store refs under refs/namespaces/foo/. You can
also specify namespaces via the --namespace option to git.
Note that namespaces which include a / will expand to a hierarchy of
namespaces; for example, GIT_NAMESPACE=foo/bar will store refs under
refs/namespaces/foo/refs/namespaces/bar/. This makes paths in
GIT_NAMESPACE behave hierarchically, so that cloning with
GIT_NAMESPACE=foo/bar produces the same result as cloning with
GIT_NAMESPACE=foo and cloning from that repo with GIT_NAMESPACE=bar. It
also avoids ambiguity with strange namespace paths such as
foo/refs/heads/, which could otherwise generate directory/file conflicts
within the refs directory.
Add the infrastructure for ref namespaces: handle the GIT_NAMESPACE
environment variable and --namespace option, and support iterating over
refs in a namespace.
Signed-off-by: Josh Triplett <josh@joshtriplett.org>
Signed-off-by: Jamey Sharp <jamey@minilop.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-07-05 19:54:44 +02:00
|
|
|
} else if (!strcmp(cmd, "--namespace")) {
|
|
|
|
if (*argc < 2) {
|
|
|
|
fprintf(stderr, "No namespace given for --namespace.\n" );
|
|
|
|
usage(git_usage_string);
|
|
|
|
}
|
|
|
|
setenv(GIT_NAMESPACE_ENVIRONMENT, (*argv)[1], 1);
|
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
|
|
|
(*argv)++;
|
|
|
|
(*argc)--;
|
use skip_prefix to avoid magic numbers
It's a common idiom to match a prefix and then skip past it
with a magic number, like:
if (starts_with(foo, "bar"))
foo += 3;
This is easy to get wrong, since you have to count the
prefix string yourself, and there's no compiler check if the
string changes. We can use skip_prefix to avoid the magic
numbers here.
Note that some of these conversions could be much shorter.
For example:
if (starts_with(arg, "--foo=")) {
bar = arg + 6;
continue;
}
could become:
if (skip_prefix(arg, "--foo=", &bar))
continue;
However, I have left it as:
if (skip_prefix(arg, "--foo=", &v)) {
bar = v;
continue;
}
to visually match nearby cases which need to actually
process the string. Like:
if (skip_prefix(arg, "--foo=", &v)) {
bar = atoi(v);
continue;
}
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-06-18 21:47:50 +02:00
|
|
|
} else if (skip_prefix(cmd, "--namespace=", &cmd)) {
|
|
|
|
setenv(GIT_NAMESPACE_ENVIRONMENT, cmd, 1);
|
ref namespaces: infrastructure
Add support for dividing the refs of a single repository into multiple
namespaces, each of which can have its own branches, tags, and HEAD.
Git can expose each namespace as an independent repository to pull from
and push to, while sharing the object store, and exposing all the refs
to operations such as git-gc.
Storing multiple repositories as namespaces of a single repository
avoids storing duplicate copies of the same objects, such as when
storing multiple branches of the same source. The alternates mechanism
provides similar support for avoiding duplicates, but alternates do not
prevent duplication between new objects added to the repositories
without ongoing maintenance, while namespaces do.
To specify a namespace, set the GIT_NAMESPACE environment variable to
the namespace. For each ref namespace, git stores the corresponding
refs in a directory under refs/namespaces/. For example,
GIT_NAMESPACE=foo will store refs under refs/namespaces/foo/. You can
also specify namespaces via the --namespace option to git.
Note that namespaces which include a / will expand to a hierarchy of
namespaces; for example, GIT_NAMESPACE=foo/bar will store refs under
refs/namespaces/foo/refs/namespaces/bar/. This makes paths in
GIT_NAMESPACE behave hierarchically, so that cloning with
GIT_NAMESPACE=foo/bar produces the same result as cloning with
GIT_NAMESPACE=foo and cloning from that repo with GIT_NAMESPACE=bar. It
also avoids ambiguity with strange namespace paths such as
foo/refs/heads/, which could otherwise generate directory/file conflicts
within the refs directory.
Add the infrastructure for ref namespaces: handle the GIT_NAMESPACE
environment variable and --namespace option, and support iterating over
refs in a namespace.
Signed-off-by: Josh Triplett <josh@joshtriplett.org>
Signed-off-by: Jamey Sharp <jamey@minilop.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-07-05 19:54:44 +02:00
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
2007-06-06 09:10:42 +02:00
|
|
|
} else if (!strcmp(cmd, "--work-tree")) {
|
|
|
|
if (*argc < 2) {
|
|
|
|
fprintf(stderr, "No directory given for --work-tree.\n" );
|
|
|
|
usage(git_usage_string);
|
|
|
|
}
|
|
|
|
setenv(GIT_WORK_TREE_ENVIRONMENT, (*argv)[1], 1);
|
2007-06-08 22:57:55 +02:00
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
2007-06-06 09:10:42 +02:00
|
|
|
(*argv)++;
|
|
|
|
(*argc)--;
|
use skip_prefix to avoid magic numbers
It's a common idiom to match a prefix and then skip past it
with a magic number, like:
if (starts_with(foo, "bar"))
foo += 3;
This is easy to get wrong, since you have to count the
prefix string yourself, and there's no compiler check if the
string changes. We can use skip_prefix to avoid the magic
numbers here.
Note that some of these conversions could be much shorter.
For example:
if (starts_with(arg, "--foo=")) {
bar = arg + 6;
continue;
}
could become:
if (skip_prefix(arg, "--foo=", &bar))
continue;
However, I have left it as:
if (skip_prefix(arg, "--foo=", &v)) {
bar = v;
continue;
}
to visually match nearby cases which need to actually
process the string. Like:
if (skip_prefix(arg, "--foo=", &v)) {
bar = atoi(v);
continue;
}
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-06-18 21:47:50 +02:00
|
|
|
} else if (skip_prefix(cmd, "--work-tree=", &cmd)) {
|
|
|
|
setenv(GIT_WORK_TREE_ENVIRONMENT, cmd, 1);
|
2007-06-08 22:57:55 +02:00
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
2006-07-25 20:24:22 +02:00
|
|
|
} else if (!strcmp(cmd, "--bare")) {
|
2014-07-28 20:31:57 +02:00
|
|
|
char *cwd = xgetcwd();
|
2007-08-27 09:58:06 +02:00
|
|
|
is_bare_repository_cfg = 1;
|
2014-07-28 20:31:57 +02:00
|
|
|
setenv(GIT_DIR_ENVIRONMENT, cwd, 0);
|
|
|
|
free(cwd);
|
setup: suppress implicit "." work-tree for bare repos
If an explicit GIT_DIR is given without a working tree, we
implicitly assume that the current working directory should
be used as the working tree. E.g.,:
GIT_DIR=/some/repo.git git status
would compare against the cwd.
Unfortunately, we fool this rule for sub-invocations of git
by setting GIT_DIR internally ourselves. For example:
git init foo
cd foo/.git
git status ;# fails, as we expect
git config alias.st status
git status ;# does not fail, but should
What happens is that we run setup_git_directory when doing
alias lookup (since we need to see the config), set GIT_DIR
as a result, and then leave GIT_WORK_TREE blank (because we
do not have one). Then when we actually run the status
command, we do setup_git_directory again, which sees our
explicit GIT_DIR and uses the cwd as an implicit worktree.
It's tempting to argue that we should be suppressing that
second invocation of setup_git_directory, as it could use
the values we already found in memory. However, the problem
still exists for sub-processes (e.g., if "git status" were
an external command).
You can see another example with the "--bare" option, which
sets GIT_DIR explicitly. For example:
git init foo
cd foo/.git
git status ;# fails
git --bare status ;# does NOT fail
We need some way of telling sub-processes "even though
GIT_DIR is set, do not use cwd as an implicit working tree".
We could do it by putting a special token into
GIT_WORK_TREE, but the obvious choice (an empty string) has
some portability problems.
Instead, we add a new boolean variable, GIT_IMPLICIT_WORK_TREE,
which suppresses the use of cwd as a working tree when
GIT_DIR is set. We trigger the new variable when we know we
are in a bare setting.
The variable is left intentionally undocumented, as this is
an internal detail (for now, anyway). If somebody comes up
with a good alternate use for it, and once we are confident
we have shaken any bugs out of it, we can consider promoting
it further.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-03-08 10:32:22 +01:00
|
|
|
setenv(GIT_IMPLICIT_WORK_TREE_ENVIRONMENT, "0", 1);
|
2007-06-08 22:57:55 +02:00
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
2010-03-26 23:53:57 +01:00
|
|
|
} else if (!strcmp(cmd, "-c")) {
|
|
|
|
if (*argc < 2) {
|
|
|
|
fprintf(stderr, "-c expects a configuration string\n" );
|
|
|
|
usage(git_usage_string);
|
|
|
|
}
|
2010-08-23 21:16:00 +02:00
|
|
|
git_config_push_parameter((*argv)[1]);
|
2010-03-26 23:53:57 +01:00
|
|
|
(*argv)++;
|
|
|
|
(*argc)--;
|
add global --literal-pathspecs option
Git takes pathspec arguments in many places to limit the
scope of an operation. These pathspecs are treated not as
literal paths, but as glob patterns that can be fed to
fnmatch. When a user is giving a specific pattern, this is a
nice feature.
However, when programatically providing pathspecs, it can be
a nuisance. For example, to find the latest revision which
modified "$foo", one can use "git rev-list -- $foo". But if
"$foo" contains glob characters (e.g., "f*"), it will
erroneously match more entries than desired. The caller
needs to quote the characters in $foo, and even then, the
results may not be exactly the same as with a literal
pathspec. For instance, the depth checks in
match_pathspec_depth do not kick in if we match via fnmatch.
This patch introduces a global command-line option (i.e.,
one for "git" itself, not for specific commands) to turn
this behavior off. It also has a matching environment
variable, which can make it easier if you are a script or
porcelain interface that is going to issue many such
commands.
This option cannot turn off globbing for particular
pathspecs. That could eventually be done with a ":(noglob)"
magic pathspec prefix. However, that level of granularity is
more cumbersome to use for many cases, and doing ":(noglob)"
right would mean converting the whole codebase to use
"struct pathspec", as the usual "const char **pathspec"
cannot represent extra per-item flags.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-12-19 23:37:30 +01:00
|
|
|
} else if (!strcmp(cmd, "--literal-pathspecs")) {
|
|
|
|
setenv(GIT_LITERAL_PATHSPECS_ENVIRONMENT, "1", 1);
|
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
|
|
|
} else if (!strcmp(cmd, "--no-literal-pathspecs")) {
|
|
|
|
setenv(GIT_LITERAL_PATHSPECS_ENVIRONMENT, "0", 1);
|
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
2013-07-14 10:36:08 +02:00
|
|
|
} else if (!strcmp(cmd, "--glob-pathspecs")) {
|
|
|
|
setenv(GIT_GLOB_PATHSPECS_ENVIRONMENT, "1", 1);
|
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
|
|
|
} else if (!strcmp(cmd, "--noglob-pathspecs")) {
|
|
|
|
setenv(GIT_NOGLOB_PATHSPECS_ENVIRONMENT, "1", 1);
|
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
2013-07-14 10:36:09 +02:00
|
|
|
} else if (!strcmp(cmd, "--icase-pathspecs")) {
|
|
|
|
setenv(GIT_ICASE_PATHSPECS_ENVIRONMENT, "1", 1);
|
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
2013-05-26 03:16:15 +02:00
|
|
|
} else if (!strcmp(cmd, "--shallow-file")) {
|
|
|
|
(*argv)++;
|
|
|
|
(*argc)--;
|
2013-12-05 14:02:45 +01:00
|
|
|
set_alternate_shallow_file((*argv)[0], 1);
|
2013-05-26 03:16:15 +02:00
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
2013-09-09 15:47:43 +02:00
|
|
|
} else if (!strcmp(cmd, "-C")) {
|
|
|
|
if (*argc < 2) {
|
|
|
|
fprintf(stderr, "No directory given for -C.\n" );
|
|
|
|
usage(git_usage_string);
|
|
|
|
}
|
2015-03-06 12:18:08 +01:00
|
|
|
if ((*argv)[1][0]) {
|
|
|
|
if (chdir((*argv)[1]))
|
|
|
|
die_errno("Cannot change to '%s'", (*argv)[1]);
|
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
|
|
|
}
|
2013-09-09 15:47:43 +02:00
|
|
|
(*argv)++;
|
|
|
|
(*argc)--;
|
2006-07-25 20:24:22 +02:00
|
|
|
} else {
|
|
|
|
fprintf(stderr, "Unknown option: %s\n", cmd);
|
2006-07-30 23:42:25 +02:00
|
|
|
usage(git_usage_string);
|
2006-07-25 20:24:22 +02:00
|
|
|
}
|
2006-07-24 14:10:45 +02:00
|
|
|
|
|
|
|
(*argv)++;
|
|
|
|
(*argc)--;
|
|
|
|
}
|
2011-05-25 00:50:35 +02:00
|
|
|
return (*argv) - orig_argv;
|
2006-07-24 14:10:45 +02:00
|
|
|
}
|
|
|
|
|
2006-06-05 19:43:52 +02:00
|
|
|
static int handle_alias(int *argcp, const char ***argv)
|
|
|
|
{
|
2008-03-25 22:06:26 +01:00
|
|
|
int envchanged = 0, ret = 0, saved_errno = errno;
|
2006-07-30 03:30:29 +02:00
|
|
|
int count, option_count;
|
2009-05-01 11:06:36 +02:00
|
|
|
const char **new_argv;
|
2008-02-24 23:17:14 +01:00
|
|
|
const char *alias_command;
|
|
|
|
char *alias_string;
|
2008-04-01 06:33:09 +02:00
|
|
|
int unused_nongit;
|
2006-06-05 19:43:52 +02:00
|
|
|
|
2015-12-03 19:17:55 +01:00
|
|
|
save_env_before_alias();
|
setup.c: re-fix d95138e (setup: set env $GIT_WORK_TREE when ..
Commit d95138e [1] attempted to fix a .git file problem by
setting GIT_WORK_TREE whenever GIT_DIR is set. It sounded harmless
because we handle GIT_DIR and GIT_WORK_TREE side by side for most
commands, with two exceptions: git-init and git-clone.
"git clone" is not happy with d95138e. This command ignores GIT_DIR
but respects GIT_WORK_TREE [2] [3] which means it used to run fine
from a hook, where GIT_DIR was set but GIT_WORK_TREE was not (*).
With d95138e, GIT_WORK_TREE is set all the time and git-clone
interprets that as "I give you order to put the worktree here",
usually against the user's intention.
The solution in d95138e is reverted earlier, and instead we reuse
the solution from c056261 [4]. It fixed another setup-messed-
up-by-alias by saving and restoring env and spawning a new process,
but for git-clone and git-init only.
Now we conclude that setup-messed-up-by-alias is always evil. So the
env restoration is done for _all_ commands, including external ones,
whenever aliases are involved. It fixes what d95138e tried to fix,
without upsetting git-clone-inside-hooks.
The test from d95138e remains to verify it's not broken by this. A new
test is added to make sure git-clone-inside-hooks remains happy.
(*) GIT_WORK_TREE was not set _most of the time_. In some cases
GIT_WORK_TREE is set and git-clone will behave differently. The
use of GIT_WORK_TREE to direct git-clone to put work tree
elsewhere looks like a mistake because it causes surprises this
way. But that's a separate story.
[1] d95138e (setup: set env $GIT_WORK_TREE when work tree is set, like
$GIT_DIR - 2015-06-26)
[2] 2beebd2 (clone: create intermediate directories of destination
repo - 2008-06-25)
[3] 20ccef4 (make git-clone GIT_WORK_TREE aware - 2007-07-06)
[4] c056261 (git potty: restore environments after alias expansion -
2014-06-08)
Reported-by: Anthony Sottile <asottile@umich.edu>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-12-20 08:50:18 +01:00
|
|
|
setup_git_directory_gently(&unused_nongit);
|
2006-07-30 03:30:29 +02:00
|
|
|
|
|
|
|
alias_command = (*argv)[0];
|
2008-02-24 23:17:14 +01:00
|
|
|
alias_string = alias_lookup(alias_command);
|
2006-07-30 03:30:29 +02:00
|
|
|
if (alias_string) {
|
2007-02-11 01:33:58 +01:00
|
|
|
if (alias_string[0] == '!') {
|
2016-02-22 23:44:21 +01:00
|
|
|
struct child_process child = CHILD_PROCESS_INIT;
|
2011-01-07 00:00:38 +01:00
|
|
|
|
2010-07-15 00:55:12 +02:00
|
|
|
commit_pager_choice();
|
2015-12-20 08:50:19 +01:00
|
|
|
restore_env(1);
|
2011-01-07 00:00:38 +01:00
|
|
|
|
2016-02-22 23:44:21 +01:00
|
|
|
child.use_shell = 1;
|
|
|
|
argv_array_push(&child.args, alias_string + 1);
|
|
|
|
argv_array_pushv(&child.args, (*argv) + 1);
|
2011-01-07 00:00:38 +01:00
|
|
|
|
2016-02-22 23:44:21 +01:00
|
|
|
ret = run_command(&child);
|
2011-01-07 00:00:38 +01:00
|
|
|
if (ret >= 0) /* normal exit */
|
|
|
|
exit(ret);
|
|
|
|
|
|
|
|
die_errno("While expanding alias '%s': '%s'",
|
|
|
|
alias_command, alias_string + 1);
|
2007-02-11 01:33:58 +01:00
|
|
|
}
|
2006-07-30 03:30:29 +02:00
|
|
|
count = split_cmdline(alias_string, &new_argv);
|
2008-09-22 17:06:41 +02:00
|
|
|
if (count < 0)
|
2010-08-07 07:13:39 +02:00
|
|
|
die("Bad alias.%s string: %s", alias_command,
|
|
|
|
split_cmdline_strerror(count));
|
2007-06-08 22:57:55 +02:00
|
|
|
option_count = handle_options(&new_argv, &count, &envchanged);
|
|
|
|
if (envchanged)
|
|
|
|
die("alias '%s' changes environment variables\n"
|
|
|
|
"You can use '!git' in the alias to do this.",
|
|
|
|
alias_command);
|
2006-07-30 03:30:29 +02:00
|
|
|
memmove(new_argv - option_count, new_argv,
|
|
|
|
count * sizeof(char *));
|
|
|
|
new_argv -= option_count;
|
|
|
|
|
|
|
|
if (count < 1)
|
|
|
|
die("empty alias for %s", alias_command);
|
|
|
|
|
|
|
|
if (!strcmp(alias_command, new_argv[0]))
|
|
|
|
die("recursive alias: %s", alias_command);
|
|
|
|
|
2007-12-03 05:51:50 +01:00
|
|
|
trace_argv_printf(new_argv,
|
2006-09-02 18:23:48 +02:00
|
|
|
"trace: alias expansion: %s =>",
|
|
|
|
alias_command);
|
2006-06-25 15:56:18 +02:00
|
|
|
|
2014-09-16 20:56:57 +02:00
|
|
|
REALLOC_ARRAY(new_argv, count + *argcp);
|
2006-07-30 03:30:29 +02:00
|
|
|
/* insert after command name */
|
2009-05-01 11:06:36 +02:00
|
|
|
memcpy(new_argv + count, *argv + 1, sizeof(char *) * *argcp);
|
2006-06-05 19:43:52 +02:00
|
|
|
|
2006-07-30 03:30:29 +02:00
|
|
|
*argv = new_argv;
|
|
|
|
*argcp += count - 1;
|
2006-06-05 19:43:52 +02:00
|
|
|
|
2006-07-30 03:30:29 +02:00
|
|
|
ret = 1;
|
2006-06-05 19:43:52 +02:00
|
|
|
}
|
|
|
|
|
2015-12-20 08:50:19 +01:00
|
|
|
restore_env(0);
|
2006-06-05 19:43:52 +02:00
|
|
|
|
2006-06-28 12:45:27 +02:00
|
|
|
errno = saved_errno;
|
|
|
|
|
2006-06-05 19:43:52 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-08-06 04:52:16 +02:00
|
|
|
#define RUN_SETUP (1<<0)
|
|
|
|
#define RUN_SETUP_GENTLY (1<<1)
|
|
|
|
#define USE_PAGER (1<<2)
|
2006-12-31 05:32:38 +01:00
|
|
|
/*
|
|
|
|
* require working tree to be present -- anything uses this needs
|
|
|
|
* RUN_SETUP for reading from the configuration file.
|
|
|
|
*/
|
2010-08-06 04:52:16 +02:00
|
|
|
#define NEED_WORK_TREE (1<<3)
|
2006-07-29 07:44:25 +02:00
|
|
|
|
2007-06-24 19:10:40 +02:00
|
|
|
struct cmd_struct {
|
|
|
|
const char *cmd;
|
|
|
|
int (*fn)(int, const char **, const char *);
|
|
|
|
int option;
|
|
|
|
};
|
|
|
|
|
2009-01-28 08:33:53 +01:00
|
|
|
static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
|
2007-06-24 19:10:40 +02:00
|
|
|
{
|
2009-11-09 16:05:01 +01:00
|
|
|
int status, help;
|
2007-06-24 19:29:33 +02:00
|
|
|
struct stat st;
|
2007-06-24 19:10:40 +02:00
|
|
|
const char *prefix;
|
|
|
|
|
|
|
|
prefix = NULL;
|
2009-11-09 16:05:01 +01:00
|
|
|
help = argc == 2 && !strcmp(argv[1], "-h");
|
|
|
|
if (!help) {
|
|
|
|
if (p->option & RUN_SETUP)
|
|
|
|
prefix = setup_git_directory();
|
2014-04-22 02:47:56 +02:00
|
|
|
else if (p->option & RUN_SETUP_GENTLY) {
|
2010-08-06 04:52:16 +02:00
|
|
|
int nongit_ok;
|
|
|
|
prefix = setup_git_directory_gently(&nongit_ok);
|
|
|
|
}
|
2009-11-09 16:05:01 +01:00
|
|
|
|
2010-08-06 04:52:16 +02:00
|
|
|
if (use_pager == -1 && p->option & (RUN_SETUP | RUN_SETUP_GENTLY))
|
2009-11-09 16:05:01 +01:00
|
|
|
use_pager = check_pager_config(p->cmd);
|
|
|
|
if (use_pager == -1 && p->option & USE_PAGER)
|
|
|
|
use_pager = 1;
|
2010-11-26 16:31:57 +01:00
|
|
|
|
|
|
|
if ((p->option & (RUN_SETUP | RUN_SETUP_GENTLY)) &&
|
|
|
|
startup_info->have_repository) /* get_git_dir() may set up repo, avoid that */
|
|
|
|
trace_repo_setup(prefix);
|
2009-11-09 16:05:01 +01:00
|
|
|
}
|
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 13:46:57 +02:00
|
|
|
commit_pager_choice();
|
|
|
|
|
2009-11-09 16:05:01 +01:00
|
|
|
if (!help && p->option & NEED_WORK_TREE)
|
2007-11-03 12:23:11 +01:00
|
|
|
setup_work_tree();
|
|
|
|
|
2007-12-03 05:51:50 +01:00
|
|
|
trace_argv_printf(argv, "trace: built-in: git");
|
2007-06-24 19:10:40 +02:00
|
|
|
|
2007-06-24 19:29:33 +02:00
|
|
|
status = p->fn(argc, argv, prefix);
|
|
|
|
if (status)
|
2009-07-05 20:57:46 +02:00
|
|
|
return status;
|
2007-06-24 19:29:33 +02: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-06-30 20:44:20 +02:00
|
|
|
if (fflush(stdout))
|
2009-06-27 17:58:46 +02: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-06-30 20:44:20 +02:00
|
|
|
if (ferror(stdout))
|
|
|
|
die("unknown write failure on standard output");
|
|
|
|
if (fclose(stdout))
|
2009-06-27 17:58:46 +02:00
|
|
|
die_errno("close failed on standard output");
|
2007-06-24 19:29:33 +02:00
|
|
|
return 0;
|
2007-06-24 19:10:40 +02:00
|
|
|
}
|
|
|
|
|
2014-01-02 17:17:11 +01:00
|
|
|
static struct cmd_struct commands[] = {
|
|
|
|
{ "add", cmd_add, RUN_SETUP | NEED_WORK_TREE },
|
2015-08-04 15:52:06 +02:00
|
|
|
{ "am", cmd_am, RUN_SETUP | NEED_WORK_TREE },
|
2014-01-02 17:17:11 +01:00
|
|
|
{ "annotate", cmd_annotate, RUN_SETUP },
|
|
|
|
{ "apply", cmd_apply, RUN_SETUP_GENTLY },
|
|
|
|
{ "archive", cmd_archive },
|
|
|
|
{ "bisect--helper", cmd_bisect__helper, RUN_SETUP },
|
|
|
|
{ "blame", cmd_blame, RUN_SETUP },
|
|
|
|
{ "branch", cmd_branch, RUN_SETUP },
|
|
|
|
{ "bundle", cmd_bundle, RUN_SETUP_GENTLY },
|
|
|
|
{ "cat-file", cmd_cat_file, RUN_SETUP },
|
|
|
|
{ "check-attr", cmd_check_attr, RUN_SETUP },
|
|
|
|
{ "check-ignore", cmd_check_ignore, RUN_SETUP | NEED_WORK_TREE },
|
|
|
|
{ "check-mailmap", cmd_check_mailmap, RUN_SETUP },
|
|
|
|
{ "check-ref-format", cmd_check_ref_format },
|
2015-07-06 19:30:56 +02:00
|
|
|
{ "checkout", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },
|
2014-01-02 17:17:11 +01:00
|
|
|
{ "checkout-index", cmd_checkout_index,
|
|
|
|
RUN_SETUP | NEED_WORK_TREE},
|
|
|
|
{ "cherry", cmd_cherry, RUN_SETUP },
|
|
|
|
{ "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE },
|
|
|
|
{ "clean", cmd_clean, RUN_SETUP | NEED_WORK_TREE },
|
setup.c: re-fix d95138e (setup: set env $GIT_WORK_TREE when ..
Commit d95138e [1] attempted to fix a .git file problem by
setting GIT_WORK_TREE whenever GIT_DIR is set. It sounded harmless
because we handle GIT_DIR and GIT_WORK_TREE side by side for most
commands, with two exceptions: git-init and git-clone.
"git clone" is not happy with d95138e. This command ignores GIT_DIR
but respects GIT_WORK_TREE [2] [3] which means it used to run fine
from a hook, where GIT_DIR was set but GIT_WORK_TREE was not (*).
With d95138e, GIT_WORK_TREE is set all the time and git-clone
interprets that as "I give you order to put the worktree here",
usually against the user's intention.
The solution in d95138e is reverted earlier, and instead we reuse
the solution from c056261 [4]. It fixed another setup-messed-
up-by-alias by saving and restoring env and spawning a new process,
but for git-clone and git-init only.
Now we conclude that setup-messed-up-by-alias is always evil. So the
env restoration is done for _all_ commands, including external ones,
whenever aliases are involved. It fixes what d95138e tried to fix,
without upsetting git-clone-inside-hooks.
The test from d95138e remains to verify it's not broken by this. A new
test is added to make sure git-clone-inside-hooks remains happy.
(*) GIT_WORK_TREE was not set _most of the time_. In some cases
GIT_WORK_TREE is set and git-clone will behave differently. The
use of GIT_WORK_TREE to direct git-clone to put work tree
elsewhere looks like a mistake because it causes surprises this
way. But that's a separate story.
[1] d95138e (setup: set env $GIT_WORK_TREE when work tree is set, like
$GIT_DIR - 2015-06-26)
[2] 2beebd2 (clone: create intermediate directories of destination
repo - 2008-06-25)
[3] 20ccef4 (make git-clone GIT_WORK_TREE aware - 2007-07-06)
[4] c056261 (git potty: restore environments after alias expansion -
2014-06-08)
Reported-by: Anthony Sottile <asottile@umich.edu>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-12-20 08:50:18 +01:00
|
|
|
{ "clone", cmd_clone },
|
2014-01-02 17:17:11 +01:00
|
|
|
{ "column", cmd_column, RUN_SETUP_GENTLY },
|
|
|
|
{ "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE },
|
|
|
|
{ "commit-tree", cmd_commit_tree, RUN_SETUP },
|
|
|
|
{ "config", cmd_config, RUN_SETUP_GENTLY },
|
|
|
|
{ "count-objects", cmd_count_objects, RUN_SETUP },
|
|
|
|
{ "credential", cmd_credential, RUN_SETUP_GENTLY },
|
|
|
|
{ "describe", cmd_describe, RUN_SETUP },
|
|
|
|
{ "diff", cmd_diff },
|
|
|
|
{ "diff-files", cmd_diff_files, RUN_SETUP | NEED_WORK_TREE },
|
|
|
|
{ "diff-index", cmd_diff_index, RUN_SETUP },
|
|
|
|
{ "diff-tree", cmd_diff_tree, RUN_SETUP },
|
|
|
|
{ "fast-export", cmd_fast_export, RUN_SETUP },
|
|
|
|
{ "fetch", cmd_fetch, RUN_SETUP },
|
|
|
|
{ "fetch-pack", cmd_fetch_pack, RUN_SETUP },
|
|
|
|
{ "fmt-merge-msg", cmd_fmt_merge_msg, RUN_SETUP },
|
|
|
|
{ "for-each-ref", cmd_for_each_ref, RUN_SETUP },
|
|
|
|
{ "format-patch", cmd_format_patch, RUN_SETUP },
|
|
|
|
{ "fsck", cmd_fsck, RUN_SETUP },
|
|
|
|
{ "fsck-objects", cmd_fsck, RUN_SETUP },
|
|
|
|
{ "gc", cmd_gc, RUN_SETUP },
|
|
|
|
{ "get-tar-commit-id", cmd_get_tar_commit_id },
|
|
|
|
{ "grep", cmd_grep, RUN_SETUP_GENTLY },
|
|
|
|
{ "hash-object", cmd_hash_object },
|
|
|
|
{ "help", cmd_help },
|
|
|
|
{ "index-pack", cmd_index_pack, RUN_SETUP_GENTLY },
|
setup.c: re-fix d95138e (setup: set env $GIT_WORK_TREE when ..
Commit d95138e [1] attempted to fix a .git file problem by
setting GIT_WORK_TREE whenever GIT_DIR is set. It sounded harmless
because we handle GIT_DIR and GIT_WORK_TREE side by side for most
commands, with two exceptions: git-init and git-clone.
"git clone" is not happy with d95138e. This command ignores GIT_DIR
but respects GIT_WORK_TREE [2] [3] which means it used to run fine
from a hook, where GIT_DIR was set but GIT_WORK_TREE was not (*).
With d95138e, GIT_WORK_TREE is set all the time and git-clone
interprets that as "I give you order to put the worktree here",
usually against the user's intention.
The solution in d95138e is reverted earlier, and instead we reuse
the solution from c056261 [4]. It fixed another setup-messed-
up-by-alias by saving and restoring env and spawning a new process,
but for git-clone and git-init only.
Now we conclude that setup-messed-up-by-alias is always evil. So the
env restoration is done for _all_ commands, including external ones,
whenever aliases are involved. It fixes what d95138e tried to fix,
without upsetting git-clone-inside-hooks.
The test from d95138e remains to verify it's not broken by this. A new
test is added to make sure git-clone-inside-hooks remains happy.
(*) GIT_WORK_TREE was not set _most of the time_. In some cases
GIT_WORK_TREE is set and git-clone will behave differently. The
use of GIT_WORK_TREE to direct git-clone to put work tree
elsewhere looks like a mistake because it causes surprises this
way. But that's a separate story.
[1] d95138e (setup: set env $GIT_WORK_TREE when work tree is set, like
$GIT_DIR - 2015-06-26)
[2] 2beebd2 (clone: create intermediate directories of destination
repo - 2008-06-25)
[3] 20ccef4 (make git-clone GIT_WORK_TREE aware - 2007-07-06)
[4] c056261 (git potty: restore environments after alias expansion -
2014-06-08)
Reported-by: Anthony Sottile <asottile@umich.edu>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-12-20 08:50:18 +01:00
|
|
|
{ "init", cmd_init_db },
|
|
|
|
{ "init-db", cmd_init_db },
|
2015-09-05 15:39:24 +02:00
|
|
|
{ "interpret-trailers", cmd_interpret_trailers, RUN_SETUP_GENTLY },
|
2014-01-02 17:17:11 +01:00
|
|
|
{ "log", cmd_log, RUN_SETUP },
|
|
|
|
{ "ls-files", cmd_ls_files, RUN_SETUP },
|
|
|
|
{ "ls-remote", cmd_ls_remote, RUN_SETUP_GENTLY },
|
|
|
|
{ "ls-tree", cmd_ls_tree, RUN_SETUP },
|
|
|
|
{ "mailinfo", cmd_mailinfo },
|
|
|
|
{ "mailsplit", cmd_mailsplit },
|
|
|
|
{ "merge", cmd_merge, RUN_SETUP | NEED_WORK_TREE },
|
|
|
|
{ "merge-base", cmd_merge_base, RUN_SETUP },
|
|
|
|
{ "merge-file", cmd_merge_file, RUN_SETUP_GENTLY },
|
|
|
|
{ "merge-index", cmd_merge_index, RUN_SETUP },
|
|
|
|
{ "merge-ours", cmd_merge_ours, RUN_SETUP },
|
|
|
|
{ "merge-recursive", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
|
|
|
|
{ "merge-recursive-ours", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
|
|
|
|
{ "merge-recursive-theirs", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
|
|
|
|
{ "merge-subtree", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
|
|
|
|
{ "merge-tree", cmd_merge_tree, RUN_SETUP },
|
|
|
|
{ "mktag", cmd_mktag, RUN_SETUP },
|
|
|
|
{ "mktree", cmd_mktree, RUN_SETUP },
|
|
|
|
{ "mv", cmd_mv, RUN_SETUP | NEED_WORK_TREE },
|
|
|
|
{ "name-rev", cmd_name_rev, RUN_SETUP },
|
|
|
|
{ "notes", cmd_notes, RUN_SETUP },
|
|
|
|
{ "pack-objects", cmd_pack_objects, RUN_SETUP },
|
|
|
|
{ "pack-redundant", cmd_pack_redundant, RUN_SETUP },
|
|
|
|
{ "pack-refs", cmd_pack_refs, RUN_SETUP },
|
|
|
|
{ "patch-id", cmd_patch_id },
|
|
|
|
{ "pickaxe", cmd_blame, RUN_SETUP },
|
|
|
|
{ "prune", cmd_prune, RUN_SETUP },
|
|
|
|
{ "prune-packed", cmd_prune_packed, RUN_SETUP },
|
2015-06-14 10:41:51 +02:00
|
|
|
{ "pull", cmd_pull, RUN_SETUP | NEED_WORK_TREE },
|
2014-01-02 17:17:11 +01:00
|
|
|
{ "push", cmd_push, RUN_SETUP },
|
|
|
|
{ "read-tree", cmd_read_tree, RUN_SETUP },
|
|
|
|
{ "receive-pack", cmd_receive_pack },
|
|
|
|
{ "reflog", cmd_reflog, RUN_SETUP },
|
|
|
|
{ "remote", cmd_remote, RUN_SETUP },
|
|
|
|
{ "remote-ext", cmd_remote_ext },
|
|
|
|
{ "remote-fd", cmd_remote_fd },
|
|
|
|
{ "repack", cmd_repack, RUN_SETUP },
|
|
|
|
{ "replace", cmd_replace, RUN_SETUP },
|
|
|
|
{ "rerere", cmd_rerere, RUN_SETUP },
|
|
|
|
{ "reset", cmd_reset, RUN_SETUP },
|
|
|
|
{ "rev-list", cmd_rev_list, RUN_SETUP },
|
|
|
|
{ "rev-parse", cmd_rev_parse },
|
|
|
|
{ "revert", cmd_revert, RUN_SETUP | NEED_WORK_TREE },
|
|
|
|
{ "rm", cmd_rm, RUN_SETUP },
|
|
|
|
{ "send-pack", cmd_send_pack, RUN_SETUP },
|
|
|
|
{ "shortlog", cmd_shortlog, RUN_SETUP_GENTLY | USE_PAGER },
|
|
|
|
{ "show", cmd_show, RUN_SETUP },
|
|
|
|
{ "show-branch", cmd_show_branch, RUN_SETUP },
|
|
|
|
{ "show-ref", cmd_show_ref, RUN_SETUP },
|
|
|
|
{ "stage", cmd_add, RUN_SETUP | NEED_WORK_TREE },
|
|
|
|
{ "status", cmd_status, RUN_SETUP | NEED_WORK_TREE },
|
|
|
|
{ "stripspace", cmd_stripspace },
|
2015-09-02 23:42:24 +02:00
|
|
|
{ "submodule--helper", cmd_submodule__helper, RUN_SETUP },
|
2014-01-02 17:17:11 +01:00
|
|
|
{ "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
|
|
|
|
{ "tag", cmd_tag, RUN_SETUP },
|
|
|
|
{ "unpack-file", cmd_unpack_file, RUN_SETUP },
|
|
|
|
{ "unpack-objects", cmd_unpack_objects, RUN_SETUP },
|
|
|
|
{ "update-index", cmd_update_index, RUN_SETUP },
|
|
|
|
{ "update-ref", cmd_update_ref, RUN_SETUP },
|
|
|
|
{ "update-server-info", cmd_update_server_info, RUN_SETUP },
|
|
|
|
{ "upload-archive", cmd_upload_archive },
|
|
|
|
{ "upload-archive--writer", cmd_upload_archive_writer },
|
|
|
|
{ "var", cmd_var, RUN_SETUP_GENTLY },
|
2014-06-23 09:05:49 +02:00
|
|
|
{ "verify-commit", cmd_verify_commit, RUN_SETUP },
|
2014-01-02 17:17:11 +01:00
|
|
|
{ "verify-pack", cmd_verify_pack },
|
|
|
|
{ "verify-tag", cmd_verify_tag, RUN_SETUP },
|
|
|
|
{ "version", cmd_version },
|
|
|
|
{ "whatchanged", cmd_whatchanged, RUN_SETUP },
|
2015-06-29 14:51:18 +02:00
|
|
|
{ "worktree", cmd_worktree, RUN_SETUP },
|
2014-01-02 17:17:11 +01:00
|
|
|
{ "write-tree", cmd_write_tree, RUN_SETUP },
|
|
|
|
};
|
|
|
|
|
2014-11-12 14:10:22 +01:00
|
|
|
static struct cmd_struct *get_builtin(const char *s)
|
2014-01-02 17:17:11 +01:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(commands); i++) {
|
2014-11-12 14:10:22 +01:00
|
|
|
struct cmd_struct *p = commands + i;
|
2014-01-02 17:17:11 +01:00
|
|
|
if (!strcmp(s, p->cmd))
|
2014-11-12 14:10:22 +01:00
|
|
|
return p;
|
2014-01-02 17:17:11 +01:00
|
|
|
}
|
2014-11-12 14:10:22 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int is_builtin(const char *s)
|
|
|
|
{
|
|
|
|
return !!get_builtin(s);
|
2014-01-02 17:17:11 +01:00
|
|
|
}
|
|
|
|
|
2016-02-22 08:18:29 +01:00
|
|
|
#ifdef STRIP_EXTENSION
|
|
|
|
static void strip_extension(const char **argv)
|
|
|
|
{
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
if (strip_suffix(argv[0], STRIP_EXTENSION, &len))
|
|
|
|
argv[0] = xmemdupz(argv[0], len);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
#define strip_extension(cmd)
|
|
|
|
#endif
|
|
|
|
|
2014-01-02 17:15:44 +01:00
|
|
|
static void handle_builtin(int argc, const char **argv)
|
Teach the "git" command to handle some commands internally
This is another patch in the "prepare to do more in C" series, where the
git wrapper command is taught about the notion of handling some
functionality internally.
Right now, the only internal commands are "version" and "help", but the
point being that we can now easily extend it to handle some of the trivial
scripts internally. Things like "git log" and "git diff" wouldn't need
separate external scripts any more.
This also implies that to support the old "git-log" and "git-diff" syntax,
the "git" wrapper now automatically looks at the name it was executed as,
and if it is "git-xxxx", it will assume that it is to internally do what
"git xxxx" would do.
In other words, you can (once you implement an internal command) soft- or
hard-link that command to the "git" wrapper command, and it will do the
right thing, whether you use the "git xxxx" or the "git-xxxx" format.
There's one other change: the search order for external programs is
modified slightly, so that the first entry remains GIT_EXEC_DIR, but the
second entry is the same directory as the git wrapper itself was executed
out of - if we can figure it out from argv[0], of course.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-26 21:34:51 +01:00
|
|
|
{
|
2016-02-22 08:18:29 +01:00
|
|
|
const char *cmd;
|
2014-11-12 14:10:22 +01:00
|
|
|
struct cmd_struct *builtin;
|
2007-12-08 20:57:25 +01:00
|
|
|
|
2016-02-22 08:18:29 +01:00
|
|
|
strip_extension(argv);
|
|
|
|
cmd = argv[0];
|
Teach the "git" command to handle some commands internally
This is another patch in the "prepare to do more in C" series, where the
git wrapper command is taught about the notion of handling some
functionality internally.
Right now, the only internal commands are "version" and "help", but the
point being that we can now easily extend it to handle some of the trivial
scripts internally. Things like "git log" and "git diff" wouldn't need
separate external scripts any more.
This also implies that to support the old "git-log" and "git-diff" syntax,
the "git" wrapper now automatically looks at the name it was executed as,
and if it is "git-xxxx", it will assume that it is to internally do what
"git xxxx" would do.
In other words, you can (once you implement an internal command) soft- or
hard-link that command to the "git" wrapper command, and it will do the
right thing, whether you use the "git xxxx" or the "git-xxxx" format.
There's one other change: the search order for external programs is
modified slightly, so that the first entry remains GIT_EXEC_DIR, but the
second entry is the same directory as the git wrapper itself was executed
out of - if we can figure it out from argv[0], of course.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-26 21:34:51 +01:00
|
|
|
|
2006-04-15 20:13:49 +02:00
|
|
|
/* Turn "git cmd --help" into "git help cmd" */
|
|
|
|
if (argc > 1 && !strcmp(argv[1], "--help")) {
|
|
|
|
argv[1] = argv[0];
|
|
|
|
argv[0] = cmd = "help";
|
|
|
|
}
|
|
|
|
|
2014-11-12 14:10:22 +01:00
|
|
|
builtin = get_builtin(cmd);
|
git: simplify environment save/restore logic
The only code that cares about the value of the global variable
saved_env_before_alias after the previous fix is handle_builtin()
that turns into a glorified no-op when the variable is true, so the
logic could safely be lifted to its caller, i.e. the caller can
refrain from calling it when the variable is set.
This variable tells us if save_env_before_alias() was called (with
or without matching restore_env()), but the sole caller of the
function, handle_alias(), always calls it as the first thing, so we
can consider that the variable essentially keeps track of the fact
that handle_alias() has ever been called.
It turns out that handle_builtin() and handle_alias() are called
only from one function in a way that the value of the variable
matters, which is run_argv(), and it already keeps track of the
fact that it already called handle_alias().
So we can simplify the whole thing by:
- Change handle_builtin() to always make a direct call to the
builtin implementation it finds, and make sure the caller
refrains from calling it if handle_alias() has ever been
called;
- Remove saved_env_before_alias variable, and instead use the
local "done_alias" variable maintained inside run_argv() to
make the same decision.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-01-27 07:52:02 +01:00
|
|
|
if (builtin)
|
|
|
|
exit(run_builtin(builtin, argc, argv));
|
Teach the "git" command to handle some commands internally
This is another patch in the "prepare to do more in C" series, where the
git wrapper command is taught about the notion of handling some
functionality internally.
Right now, the only internal commands are "version" and "help", but the
point being that we can now easily extend it to handle some of the trivial
scripts internally. Things like "git log" and "git diff" wouldn't need
separate external scripts any more.
This also implies that to support the old "git-log" and "git-diff" syntax,
the "git" wrapper now automatically looks at the name it was executed as,
and if it is "git-xxxx", it will assume that it is to internally do what
"git xxxx" would do.
In other words, you can (once you implement an internal command) soft- or
hard-link that command to the "git" wrapper command, and it will do the
right thing, whether you use the "git xxxx" or the "git-xxxx" format.
There's one other change: the search order for external programs is
modified slightly, so that the first entry remains GIT_EXEC_DIR, but the
second entry is the same directory as the git wrapper itself was executed
out of - if we can figure it out from argv[0], of course.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-26 21:34:51 +01:00
|
|
|
}
|
|
|
|
|
2007-12-02 07:09:22 +01:00
|
|
|
static void execv_dashed_external(const char **argv)
|
|
|
|
{
|
2008-10-09 21:12:12 +02:00
|
|
|
struct strbuf cmd = STRBUF_INIT;
|
2007-12-02 07:09:22 +01:00
|
|
|
const char *tmp;
|
2009-01-28 08:38:14 +01:00
|
|
|
int status;
|
2007-12-02 07:09:22 +01:00
|
|
|
|
2011-08-19 00:01:32 +02:00
|
|
|
if (use_pager == -1)
|
|
|
|
use_pager = check_pager_config(argv[0]);
|
2010-07-15 00:55:12 +02:00
|
|
|
commit_pager_choice();
|
|
|
|
|
2007-12-02 07:09:22 +01: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 08:38:14 +01:00
|
|
|
/*
|
|
|
|
* if we fail because the command is not found, it is
|
|
|
|
* OK to return. Otherwise, we just pass along the status code.
|
|
|
|
*/
|
2012-01-08 21:41:09 +01:00
|
|
|
status = run_command_v_opt(argv, RUN_SILENT_EXEC_FAILURE | RUN_CLEAN_ON_EXIT);
|
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-04 21:26:40 +02:00
|
|
|
if (status >= 0 || errno != ENOENT)
|
2009-07-04 21:26:39 +02:00
|
|
|
exit(status);
|
2007-12-02 07:09:22 +01:00
|
|
|
|
|
|
|
argv[0] = tmp;
|
|
|
|
|
|
|
|
strbuf_release(&cmd);
|
|
|
|
}
|
|
|
|
|
2009-01-04 18:16:01 +01:00
|
|
|
static int run_argv(int *argcp, const char ***argv)
|
|
|
|
{
|
|
|
|
int done_alias = 0;
|
|
|
|
|
|
|
|
while (1) {
|
git: simplify environment save/restore logic
The only code that cares about the value of the global variable
saved_env_before_alias after the previous fix is handle_builtin()
that turns into a glorified no-op when the variable is true, so the
logic could safely be lifted to its caller, i.e. the caller can
refrain from calling it when the variable is set.
This variable tells us if save_env_before_alias() was called (with
or without matching restore_env()), but the sole caller of the
function, handle_alias(), always calls it as the first thing, so we
can consider that the variable essentially keeps track of the fact
that handle_alias() has ever been called.
It turns out that handle_builtin() and handle_alias() are called
only from one function in a way that the value of the variable
matters, which is run_argv(), and it already keeps track of the
fact that it already called handle_alias().
So we can simplify the whole thing by:
- Change handle_builtin() to always make a direct call to the
builtin implementation it finds, and make sure the caller
refrains from calling it if handle_alias() has ever been
called;
- Remove saved_env_before_alias variable, and instead use the
local "done_alias" variable maintained inside run_argv() to
make the same decision.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-01-27 07:52:02 +01:00
|
|
|
/*
|
|
|
|
* If we tried alias and futzed with our environment,
|
|
|
|
* it no longer is safe to invoke builtins directly in
|
|
|
|
* general. We have to spawn them as dashed externals.
|
|
|
|
*
|
|
|
|
* NEEDSWORK: if we can figure out cases
|
|
|
|
* where it is safe to do, we can avoid spawning a new
|
|
|
|
* process.
|
|
|
|
*/
|
|
|
|
if (!done_alias)
|
|
|
|
handle_builtin(*argcp, *argv);
|
2009-01-04 18:16:01 +01:00
|
|
|
|
|
|
|
/* .. 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
|
|
|
|
*/
|
2014-06-08 11:37:10 +02:00
|
|
|
if (done_alias)
|
|
|
|
break;
|
|
|
|
if (!handle_alias(argcp, argv))
|
2009-01-04 18:16:01 +01:00
|
|
|
break;
|
|
|
|
done_alias = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return done_alias;
|
|
|
|
}
|
|
|
|
|
add an extra level of indirection to main()
There are certain startup tasks that we expect every git
process to do. In some cases this is just to improve the
quality of the program (e.g., setting up gettext()). In
others it is a requirement for using certain functions in
libgit.a (e.g., system_path() expects that you have called
git_extract_argv0_path()).
Most commands are builtins and are covered by the git.c
version of main(). However, there are still a few external
commands that use their own main(). Each of these has to
remember to include the correct startup sequence, and we are
not always consistent.
Rather than just fix the inconsistencies, let's make this
harder to get wrong by providing a common main() that can
run this standard startup.
We basically have two options to do this:
- the compat/mingw.h file already does something like this by
adding a #define that replaces the definition of main with a
wrapper that calls mingw_startup().
The upside is that the code in each program doesn't need
to be changed at all; it's rewritten on the fly by the
preprocessor.
The downside is that it may make debugging of the startup
sequence a bit more confusing, as the preprocessor is
quietly inserting new code.
- the builtin functions are all of the form cmd_foo(),
and git.c's main() calls them.
This is much more explicit, which may make things more
obvious to somebody reading the code. It's also more
flexible (because of course we have to figure out _which_
cmd_foo() to call).
The downside is that each of the builtins must define
cmd_foo(), instead of just main().
This patch chooses the latter option, preferring the more
explicit approach, even though it is more invasive. We
introduce a new file common-main.c, with the "real" main. It
expects to call cmd_main() from whatever other objects it is
linked against.
We link common-main.o against anything that links against
libgit.a, since we know that such programs will need to do
this setup. Note that common-main.o can't actually go inside
libgit.a, as the linker would not pick up its main()
function automatically (it has no callers).
The rest of the patch is just adjusting all of the various
external programs (mostly in t/helper) to use cmd_main().
I've provided a global declaration for cmd_main(), which
means that all of the programs also need to match its
signature. In particular, many functions need to switch to
"const char **" instead of "char **" for argv. This effect
ripples out to a few other variables and functions, as well.
This makes the patch even more invasive, but the end result
is much better. We should be treating argv strings as const
anyway, and now all programs conform to the same signature
(which also matches the way builtins are defined).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-07-01 07:58:58 +02:00
|
|
|
int cmd_main(int argc, const char **argv)
|
2005-11-16 00:31:25 +01:00
|
|
|
{
|
2009-01-18 13:00:10 +01:00
|
|
|
const char *cmd;
|
2015-03-02 13:02:37 +01:00
|
|
|
int done_help = 0;
|
Teach the "git" command to handle some commands internally
This is another patch in the "prepare to do more in C" series, where the
git wrapper command is taught about the notion of handling some
functionality internally.
Right now, the only internal commands are "version" and "help", but the
point being that we can now easily extend it to handle some of the trivial
scripts internally. Things like "git log" and "git diff" wouldn't need
separate external scripts any more.
This also implies that to support the old "git-log" and "git-diff" syntax,
the "git" wrapper now automatically looks at the name it was executed as,
and if it is "git-xxxx", it will assume that it is to internally do what
"git xxxx" would do.
In other words, you can (once you implement an internal command) soft- or
hard-link that command to the "git" wrapper command, and it will do the
right thing, whether you use the "git xxxx" or the "git-xxxx" format.
There's one other change: the search order for external programs is
modified slightly, so that the first entry remains GIT_EXEC_DIR, but the
second entry is the same directory as the git wrapper itself was executed
out of - if we can figure it out from argv[0], of course.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-26 21:34:51 +01:00
|
|
|
|
common-main: call git_extract_argv0_path()
Every program which links against libgit.a must call this
function, or risk hitting an assert() in system_path() that
checks whether we have configured argv0_path (though only
when RUNTIME_PREFIX is defined, so essentially only on
Windows).
Looking at the diff, you can see that putting it into the
common main() saves us having to do it individually in each
of the external commands. But what you can't see are the
cases where we _should_ have been doing so, but weren't
(e.g., git-credential-store, and all of the t/helper test
programs).
This has been an accident-waiting-to-happen for a long time,
but wasn't triggered until recently because it involves one
of those programs actually calling system_path(). That
happened with git-credential-store in v2.8.0 with ae5f677
(lazily load core.sharedrepository, 2016-03-11). The
program:
- takes a lock file, which...
- opens a tempfile, which...
- calls adjust_shared_perm to fix permissions, which...
- lazy-loads the config (as of ae5f677), which...
- calls system_path() to find the location of
/etc/gitconfig
On systems with RUNTIME_PREFIX, this means credential-store
reliably hits that assert() and cannot be used.
We never noticed in the test suite, because we set
GIT_CONFIG_NOSYSTEM there, which skips the system_path()
lookup entirely. But if we were to tweak git_config() to
find /etc/gitconfig even when we aren't going to open it,
then the test suite shows multiple failures (for
credential-store, and for some other test helpers). I didn't
include that tweak here because it's way too specific to
this particular call to be worth carrying around what is
essentially dead code.
The implementation is fairly straightforward, with one
exception: there is exactly one caller (git.c) that actually
cares about the result of the function, and not the
side-effect of setting up argv0_path. We can accommodate
that by simply replacing the value of argv[0] in the array
we hand down to cmd_main().
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-07-01 08:04:04 +02:00
|
|
|
cmd = argv[0];
|
2009-01-18 13:00:11 +01:00
|
|
|
if (!cmd)
|
2009-01-18 13:00:10 +01:00
|
|
|
cmd = "git-help";
|
2005-11-16 00:31:25 +01:00
|
|
|
|
2014-07-12 02:07:01 +02:00
|
|
|
trace_command_performance(argv);
|
|
|
|
|
Teach the "git" command to handle some commands internally
This is another patch in the "prepare to do more in C" series, where the
git wrapper command is taught about the notion of handling some
functionality internally.
Right now, the only internal commands are "version" and "help", but the
point being that we can now easily extend it to handle some of the trivial
scripts internally. Things like "git log" and "git diff" wouldn't need
separate external scripts any more.
This also implies that to support the old "git-log" and "git-diff" syntax,
the "git" wrapper now automatically looks at the name it was executed as,
and if it is "git-xxxx", it will assume that it is to internally do what
"git xxxx" would do.
In other words, you can (once you implement an internal command) soft- or
hard-link that command to the "git" wrapper command, and it will do the
right thing, whether you use the "git xxxx" or the "git-xxxx" format.
There's one other change: the search order for external programs is
modified slightly, so that the first entry remains GIT_EXEC_DIR, but the
second entry is the same directory as the git wrapper itself was executed
out of - if we can figure it out from argv[0], of course.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-26 21:34:51 +01:00
|
|
|
/*
|
|
|
|
* "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)
|
|
|
|
*
|
2014-01-02 17:15:44 +01:00
|
|
|
* So we just directly call the builtin handler, and die if
|
|
|
|
* that one cannot handle it.
|
Teach the "git" command to handle some commands internally
This is another patch in the "prepare to do more in C" series, where the
git wrapper command is taught about the notion of handling some
functionality internally.
Right now, the only internal commands are "version" and "help", but the
point being that we can now easily extend it to handle some of the trivial
scripts internally. Things like "git log" and "git diff" wouldn't need
separate external scripts any more.
This also implies that to support the old "git-log" and "git-diff" syntax,
the "git" wrapper now automatically looks at the name it was executed as,
and if it is "git-xxxx", it will assume that it is to internally do what
"git xxxx" would do.
In other words, you can (once you implement an internal command) soft- or
hard-link that command to the "git" wrapper command, and it will do the
right thing, whether you use the "git xxxx" or the "git-xxxx" format.
There's one other change: the search order for external programs is
modified slightly, so that the first entry remains GIT_EXEC_DIR, but the
second entry is the same directory as the git wrapper itself was executed
out of - if we can figure it out from argv[0], of course.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-26 21:34:51 +01:00
|
|
|
*/
|
use skip_prefix to avoid magic numbers
It's a common idiom to match a prefix and then skip past it
with a magic number, like:
if (starts_with(foo, "bar"))
foo += 3;
This is easy to get wrong, since you have to count the
prefix string yourself, and there's no compiler check if the
string changes. We can use skip_prefix to avoid the magic
numbers here.
Note that some of these conversions could be much shorter.
For example:
if (starts_with(arg, "--foo=")) {
bar = arg + 6;
continue;
}
could become:
if (skip_prefix(arg, "--foo=", &bar))
continue;
However, I have left it as:
if (skip_prefix(arg, "--foo=", &v)) {
bar = v;
continue;
}
to visually match nearby cases which need to actually
process the string. Like:
if (skip_prefix(arg, "--foo=", &v)) {
bar = atoi(v);
continue;
}
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-06-18 21:47:50 +02:00
|
|
|
if (skip_prefix(cmd, "git-", &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-26 21:34:51 +01:00
|
|
|
argv[0] = cmd;
|
2014-01-02 17:15:44 +01:00
|
|
|
handle_builtin(argc, argv);
|
|
|
|
die("cannot handle %s as a builtin", 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-26 21:34:51 +01:00
|
|
|
}
|
2005-11-16 00:31:25 +01:00
|
|
|
|
Teach the "git" command to handle some commands internally
This is another patch in the "prepare to do more in C" series, where the
git wrapper command is taught about the notion of handling some
functionality internally.
Right now, the only internal commands are "version" and "help", but the
point being that we can now easily extend it to handle some of the trivial
scripts internally. Things like "git log" and "git diff" wouldn't need
separate external scripts any more.
This also implies that to support the old "git-log" and "git-diff" syntax,
the "git" wrapper now automatically looks at the name it was executed as,
and if it is "git-xxxx", it will assume that it is to internally do what
"git xxxx" would do.
In other words, you can (once you implement an internal command) soft- or
hard-link that command to the "git" wrapper command, and it will do the
right thing, whether you use the "git xxxx" or the "git-xxxx" format.
There's one other change: the search order for external programs is
modified slightly, so that the first entry remains GIT_EXEC_DIR, but the
second entry is the same directory as the git wrapper itself was executed
out of - if we can figure it out from argv[0], of course.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-26 21:34:51 +01:00
|
|
|
/* Look for flags.. */
|
2006-07-25 20:24:22 +02:00
|
|
|
argv++;
|
|
|
|
argc--;
|
2007-06-08 22:57:55 +02:00
|
|
|
handle_options(&argv, &argc, NULL);
|
2006-07-25 20:24:22 +02:00
|
|
|
if (argc > 0) {
|
2014-06-18 21:56:48 +02:00
|
|
|
/* translate --help and --version into commands */
|
|
|
|
skip_prefix(argv[0], "--", &argv[0]);
|
2006-07-25 20:24:22 +02:00
|
|
|
} else {
|
2007-10-27 10:36:49 +02: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-26 21:26:37 +02:00
|
|
|
commit_pager_choice();
|
2007-10-27 10:36:49 +02:00
|
|
|
printf("usage: %s\n\n", git_usage_string);
|
|
|
|
list_common_cmds_help();
|
2013-03-10 16:10:20 +01:00
|
|
|
printf("\n%s\n", _(git_more_info_string));
|
2007-10-27 10:36:49 +02:00
|
|
|
exit(1);
|
2005-11-16 00:31:25 +01:00
|
|
|
}
|
2006-07-25 20:24:22 +02:00
|
|
|
cmd = argv[0];
|
Teach the "git" command to handle some commands internally
This is another patch in the "prepare to do more in C" series, where the
git wrapper command is taught about the notion of handling some
functionality internally.
Right now, the only internal commands are "version" and "help", but the
point being that we can now easily extend it to handle some of the trivial
scripts internally. Things like "git log" and "git diff" wouldn't need
separate external scripts any more.
This also implies that to support the old "git-log" and "git-diff" syntax,
the "git" wrapper now automatically looks at the name it was executed as,
and if it is "git-xxxx", it will assume that it is to internally do what
"git xxxx" would do.
In other words, you can (once you implement an internal command) soft- or
hard-link that command to the "git" wrapper command, and it will do the
right thing, whether you use the "git xxxx" or the "git-xxxx" format.
There's one other change: the search order for external programs is
modified slightly, so that the first entry remains GIT_EXEC_DIR, but the
second entry is the same directory as the git wrapper itself was executed
out of - if we can figure it out from argv[0], of course.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-26 21:34:51 +01:00
|
|
|
|
|
|
|
/*
|
2007-10-28 12:17:20 +01:00
|
|
|
* We use PATH to find git commands, but we prepend some higher
|
2009-04-17 20:13:30 +02:00
|
|
|
* precedence paths: the "--exec-path" option, the GIT_EXEC_PATH
|
2007-10-28 12:17:20 +01: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-26 21:34:51 +01:00
|
|
|
*/
|
2008-07-21 21:19:52 +02:00
|
|
|
setup_path();
|
2005-11-16 00:31:25 +01:00
|
|
|
|
2006-06-06 03:09:40 +02:00
|
|
|
while (1) {
|
2015-03-02 13:02:37 +01:00
|
|
|
int was_alias = run_argv(&argc, &argv);
|
2009-01-04 18:16:01 +01:00
|
|
|
if (errno != ENOENT)
|
2006-06-06 03:09:40 +02:00
|
|
|
break;
|
2009-01-04 18:16:01 +01:00
|
|
|
if (was_alias) {
|
2007-02-11 01:33:57 +01:00
|
|
|
fprintf(stderr, "Expansion of alias '%s' failed; "
|
2010-02-16 00:33:18 +01:00
|
|
|
"'%s' is not a git command\n",
|
2007-02-11 01:33:57 +01:00
|
|
|
cmd, argv[0]);
|
|
|
|
exit(1);
|
|
|
|
}
|
2009-01-04 18:16:01 +01:00
|
|
|
if (!done_help) {
|
|
|
|
cmd = argv[0] = help_unknown_cmd(cmd);
|
|
|
|
done_help = 1;
|
|
|
|
} else
|
|
|
|
break;
|
2007-02-11 01:33:57 +01:00
|
|
|
}
|
2005-12-01 13:48:35 +01:00
|
|
|
|
|
|
|
fprintf(stderr, "Failed to run command '%s': %s\n",
|
2006-06-28 11:17:21 +02:00
|
|
|
cmd, strerror(errno));
|
2005-11-16 00:31:25 +01:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|