2006-12-20 06:34:12 +08:00
|
|
|
#include "builtin.h"
|
2017-06-15 02:07:36 +08:00
|
|
|
#include "config.h"
|
2010-09-01 10:29:08 +08:00
|
|
|
#include "exec_cmd.h"
|
|
|
|
#include "help.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[] =
|
2013-09-09 21:47:43 +08:00
|
|
|
"git [--version] [--help] [-C <path>] [-c name=value]\n"
|
2013-03-12 03:44:15 +08:00
|
|
|
" [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n"
|
2015-01-13 15:44:47 +08: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-06 01:54:44 +08:00
|
|
|
" [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
|
2010-10-09 01:31:15 +08:00
|
|
|
" <command> [<args>]";
|
2006-07-31 05:42:25 +08:00
|
|
|
|
2008-06-06 05:15:36 +08:00
|
|
|
const char git_more_info_string[] =
|
2014-08-31 03:56:01 +08:00
|
|
|
N_("'git help -a' and 'git help -g' list available subcommands and some\n"
|
2013-04-03 06:39:48 +08:00
|
|
|
"concept guides. See 'git help <command>' or 'git help <concept>'\n"
|
|
|
|
"to read about a specific subcommand or concept.");
|
2008-06-06 05:15:36 +08: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 19:46:57 +08:00
|
|
|
static int use_pager = -1;
|
2014-06-08 17:37:10 +08:00
|
|
|
|
2017-05-30 13:18:43 +08:00
|
|
|
static void list_builtins(void);
|
|
|
|
|
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 void commit_pager_choice(void) {
|
|
|
|
switch (use_pager) {
|
|
|
|
case 0:
|
|
|
|
setenv("GIT_PAGER", "cat", 1);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
setup_pager();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-03 03:40:51 +08:00
|
|
|
void setup_auto_pager(const char *cmd, int def)
|
|
|
|
{
|
|
|
|
if (use_pager != -1 || pager_in_use())
|
|
|
|
return;
|
|
|
|
use_pager = check_pager_config(cmd);
|
|
|
|
if (use_pager == -1)
|
|
|
|
use_pager = def;
|
|
|
|
commit_pager_choice();
|
|
|
|
}
|
|
|
|
|
2009-05-01 17:06:36 +08:00
|
|
|
static int handle_options(const char ***argv, int *argc, int *envchanged)
|
2006-07-24 20:10:45 +08:00
|
|
|
{
|
2011-05-25 06:50:35 +08:00
|
|
|
const char **orig_argv = *argv;
|
2006-07-24 20:10:45 +08:00
|
|
|
|
|
|
|
while (*argc > 0) {
|
|
|
|
const char *cmd = (*argv)[0];
|
|
|
|
if (cmd[0] != '-')
|
|
|
|
break;
|
|
|
|
|
2006-07-26 02:24:22 +08:00
|
|
|
/*
|
|
|
|
* For legacy reasons, the "version" and "help"
|
|
|
|
* commands can be written with "--" prepended
|
|
|
|
* to make them look like flags.
|
|
|
|
*/
|
|
|
|
if (!strcmp(cmd, "--help") || !strcmp(cmd, "--version"))
|
|
|
|
break;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check remaining flags.
|
|
|
|
*/
|
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-19 03:47:50 +08:00
|
|
|
if (skip_prefix(cmd, "--exec-path", &cmd)) {
|
2006-07-26 02:24:22 +08:00
|
|
|
if (*cmd == '=')
|
2007-10-27 16:36:51 +08:00
|
|
|
git_set_argv_exec_path(cmd + 1);
|
2006-07-26 02:24:22 +08:00
|
|
|
else {
|
|
|
|
puts(git_exec_path());
|
|
|
|
exit(0);
|
|
|
|
}
|
2009-04-05 10:15:16 +08:00
|
|
|
} else if (!strcmp(cmd, "--html-path")) {
|
|
|
|
puts(system_path(GIT_HTML_PATH));
|
|
|
|
exit(0);
|
2011-05-01 16:16:25 +08: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-26 02:24:22 +08:00
|
|
|
} else if (!strcmp(cmd, "-p") || !strcmp(cmd, "--paginate")) {
|
Allow per-command pager config
There is great debate over whether some commands should set
up a pager automatically. This patch allows individuals to
set their own pager preferences for each command, overriding
the default. For example, to disable the pager for git
status:
git config pager.status false
If "--pager" or "--no-pager" is specified on the command
line, it takes precedence over the config option.
There are two caveats:
- you can turn on the pager for plumbing commands.
Combined with "core.pager = always", this will probably
break a lot of things. Don't do it.
- This only works for builtin commands. The reason is
somewhat complex:
Calling git_config before we do setup_git_directory
has bad side effects, because it wants to know where
the git_dir is to find ".git/config". Unfortunately,
we cannot call setup_git_directory indiscriminately,
because some builtins (like "init") break if we do.
For builtins, this is OK, since we can just wait until
after we call setup_git_directory. But for aliases, we
don't know until we expand (recursively) which command
we're doing. This should not be a huge problem for
aliases, which can simply use "--pager" or "--no-pager"
in the alias as appropriate.
For external commands, however, we don't know we even
have an external command until we exec it, and by then
it is too late to check the config.
An alternative approach would be to have a config mode
where we don't bother looking at .git/config, but only
at the user and system config files. This would make the
behavior consistent across builtins, aliases, and
external commands, at the cost of not allowing per-repo
pager config for at all.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-07-03 19:46:57 +08:00
|
|
|
use_pager = 1;
|
2007-08-20 01:24:36 +08:00
|
|
|
} else if (!strcmp(cmd, "--no-pager")) {
|
Allow per-command pager config
There is great debate over whether some commands should set
up a pager automatically. This patch allows individuals to
set their own pager preferences for each command, overriding
the default. For example, to disable the pager for git
status:
git config pager.status false
If "--pager" or "--no-pager" is specified on the command
line, it takes precedence over the config option.
There are two caveats:
- you can turn on the pager for plumbing commands.
Combined with "core.pager = always", this will probably
break a lot of things. Don't do it.
- This only works for builtin commands. The reason is
somewhat complex:
Calling git_config before we do setup_git_directory
has bad side effects, because it wants to know where
the git_dir is to find ".git/config". Unfortunately,
we cannot call setup_git_directory indiscriminately,
because some builtins (like "init") break if we do.
For builtins, this is OK, since we can just wait until
after we call setup_git_directory. But for aliases, we
don't know until we expand (recursively) which command
we're doing. This should not be a huge problem for
aliases, which can simply use "--pager" or "--no-pager"
in the alias as appropriate.
For external commands, however, we don't know we even
have an external command until we exec it, and by then
it is too late to check the config.
An alternative approach would be to have a config mode
where we don't bother looking at .git/config, but only
at the user and system config files. This would make the
behavior consistent across builtins, aliases, and
external commands, at the cost of not allowing per-repo
pager config for at all.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-07-03 19:46:57 +08:00
|
|
|
use_pager = 0;
|
2007-08-20 01:24:36 +08:00
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
2009-10-13 04:30:32 +08:00
|
|
|
} else if (!strcmp(cmd, "--no-replace-objects")) {
|
2014-02-18 19:24:55 +08:00
|
|
|
check_replace_refs = 0;
|
2009-11-18 14:50:58 +08:00
|
|
|
setenv(NO_REPLACE_OBJECTS_ENVIRONMENT, "1", 1);
|
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
2006-07-26 02:24:22 +08:00
|
|
|
} else if (!strcmp(cmd, "--git-dir")) {
|
2006-12-22 21:56:25 +08:00
|
|
|
if (*argc < 2) {
|
|
|
|
fprintf(stderr, "No directory given for --git-dir.\n" );
|
|
|
|
usage(git_usage_string);
|
|
|
|
}
|
2006-12-31 12:29:11 +08:00
|
|
|
setenv(GIT_DIR_ENVIRONMENT, (*argv)[1], 1);
|
2007-06-09 04:57:55 +08:00
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
2006-07-26 02:24:22 +08:00
|
|
|
(*argv)++;
|
|
|
|
(*argc)--;
|
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-19 03:47:50 +08:00
|
|
|
} else if (skip_prefix(cmd, "--git-dir=", &cmd)) {
|
|
|
|
setenv(GIT_DIR_ENVIRONMENT, cmd, 1);
|
2007-06-09 04:57:55 +08: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-06 01:54:44 +08: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-19 03:47:50 +08: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-06 01:54:44 +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)--;
|
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-19 03:47:50 +08:00
|
|
|
} else if (skip_prefix(cmd, "--work-tree=", &cmd)) {
|
|
|
|
setenv(GIT_WORK_TREE_ENVIRONMENT, cmd, 1);
|
2007-06-09 04:57:55 +08:00
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
2016-10-08 02:18:48 +08:00
|
|
|
} else if (!strcmp(cmd, "--super-prefix")) {
|
|
|
|
if (*argc < 2) {
|
|
|
|
fprintf(stderr, "No prefix given for --super-prefix.\n" );
|
|
|
|
usage(git_usage_string);
|
|
|
|
}
|
|
|
|
setenv(GIT_SUPER_PREFIX_ENVIRONMENT, (*argv)[1], 1);
|
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
|
|
|
(*argv)++;
|
|
|
|
(*argc)--;
|
|
|
|
} else if (skip_prefix(cmd, "--super-prefix=", &cmd)) {
|
|
|
|
setenv(GIT_SUPER_PREFIX_ENVIRONMENT, cmd, 1);
|
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
2006-07-26 02:24:22 +08:00
|
|
|
} else if (!strcmp(cmd, "--bare")) {
|
2014-07-29 02:31:57 +08:00
|
|
|
char *cwd = xgetcwd();
|
2007-08-27 15:58:06 +08:00
|
|
|
is_bare_repository_cfg = 1;
|
2014-07-29 02:31:57 +08: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 17:32:22 +08:00
|
|
|
setenv(GIT_IMPLICIT_WORK_TREE_ENVIRONMENT, "0", 1);
|
2007-06-09 04:57:55 +08:00
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
2010-03-27 06:53:57 +08:00
|
|
|
} else if (!strcmp(cmd, "-c")) {
|
|
|
|
if (*argc < 2) {
|
|
|
|
fprintf(stderr, "-c expects a configuration string\n" );
|
|
|
|
usage(git_usage_string);
|
|
|
|
}
|
2010-08-24 03:16:00 +08:00
|
|
|
git_config_push_parameter((*argv)[1]);
|
2010-03-27 06:53:57 +08: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-20 06:37:30 +08: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 16:36:08 +08: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 16:36:09 +08:00
|
|
|
} else if (!strcmp(cmd, "--icase-pathspecs")) {
|
|
|
|
setenv(GIT_ICASE_PATHSPECS_ENVIRONMENT, "1", 1);
|
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
git: add --no-optional-locks option
Some tools like IDEs or fancy editors may periodically run
commands like "git status" in the background to keep track
of the state of the repository. Some of these commands may
refresh the index and write out the result in an
opportunistic way: if they can get the index lock, then they
update the on-disk index with any updates they find. And if
not, then their in-core refresh is lost and just has to be
recomputed by the next caller.
But taking the index lock may conflict with other operations
in the repository. Especially ones that the user is doing
themselves, which _aren't_ opportunistic. In other words,
"git status" knows how to back off when somebody else is
holding the lock, but other commands don't know that status
would be happy to drop the lock if somebody else wanted it.
There are a couple possible solutions:
1. Have some kind of "pseudo-lock" that allows other
commands to tell status that they want the lock.
This is likely to be complicated and error-prone to
implement (and maybe even impossible with just
dotlocks to work from, as it requires some
inter-process communication).
2. Avoid background runs of commands like "git status"
that want to do opportunistic updates, preferring
instead plumbing like diff-files, etc.
This is awkward for a couple of reasons. One is that
"status --porcelain" reports a lot more about the
repository state than is available from individual
plumbing commands. And two is that we actually _do_
want to see the refreshed index. We just don't want to
take a lock or write out the result. Whereas commands
like diff-files expect us to refresh the index
separately and write it to disk so that they can depend
on the result. But that write is exactly what we're
trying to avoid.
3. Ask "status" not to lock or write the index.
This is easy to implement. The big downside is that any
work done in refreshing the index for such a call is
lost when the process exits. So a background process
may end up re-hashing a changed file multiple times
until the user runs a command that does an index
refresh themselves.
This patch implements the option 3. The idea (and the test)
is largely stolen from a Git for Windows patch by Johannes
Schindelin, 67e5ce7f63 (status: offer *not* to lock the
index and update it, 2016-08-12). The twist here is that
instead of making this an option to "git status", it becomes
a "git" option and matching environment variable.
The reason there is two-fold:
1. An environment variable is carried through to
sub-processes. And whether an invocation is a
background process or not should apply to the whole
process tree. So you could do "git --no-optional-locks
foo", and if "foo" is a script or alias that calls
"status", you'll still get the effect.
2. There may be other programs that want the same
treatment.
I've punted here on finding more callers to convert,
since "status" is the obvious one to call as a repeated
background job. But "git diff"'s opportunistic refresh
of the index may be a good candidate.
The test is taken from 67e5ce7f63, and it's worth repeating
Johannes's explanation:
Note that the regression test added in this commit does
not *really* verify that no index.lock file was written;
that test is not possible in a portable way. Instead, we
verify that .git/index is rewritten *only* when `git
status` is run without `--no-optional-locks`.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-09-27 14:54:30 +08:00
|
|
|
} else if (!strcmp(cmd, "--no-optional-locks")) {
|
|
|
|
setenv(GIT_OPTIONAL_LOCKS_ENVIRONMENT, "0", 1);
|
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
2013-05-26 09:16:15 +08:00
|
|
|
} else if (!strcmp(cmd, "--shallow-file")) {
|
|
|
|
(*argv)++;
|
|
|
|
(*argc)--;
|
2013-12-05 21:02:45 +08:00
|
|
|
set_alternate_shallow_file((*argv)[0], 1);
|
2013-05-26 09:16:15 +08:00
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
2013-09-09 21:47:43 +08:00
|
|
|
} else if (!strcmp(cmd, "-C")) {
|
|
|
|
if (*argc < 2) {
|
|
|
|
fprintf(stderr, "No directory given for -C.\n" );
|
|
|
|
usage(git_usage_string);
|
|
|
|
}
|
2015-03-06 19:18:08 +08:00
|
|
|
if ((*argv)[1][0]) {
|
|
|
|
if (chdir((*argv)[1]))
|
|
|
|
die_errno("Cannot change to '%s'", (*argv)[1]);
|
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
|
|
|
}
|
2013-09-09 21:47:43 +08:00
|
|
|
(*argv)++;
|
|
|
|
(*argc)--;
|
2017-05-30 13:18:43 +08:00
|
|
|
} else if (!strcmp(cmd, "--list-builtins")) {
|
|
|
|
list_builtins();
|
|
|
|
exit(0);
|
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)--;
|
|
|
|
}
|
2011-05-25 06:50:35 +08:00
|
|
|
return (*argv) - orig_argv;
|
2006-07-24 20:10:45 +08:00
|
|
|
}
|
|
|
|
|
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-07-30 09:30:29 +08:00
|
|
|
int count, option_count;
|
2009-05-01 17:06:36 +08:00
|
|
|
const char **new_argv;
|
2008-02-25 06:17:14 +08:00
|
|
|
const char *alias_command;
|
|
|
|
char *alias_string;
|
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] == '!') {
|
2016-02-23 06:44:21 +08:00
|
|
|
struct child_process child = CHILD_PROCESS_INIT;
|
2017-06-14 19:36:00 +08:00
|
|
|
int nongit_ok;
|
|
|
|
|
|
|
|
/* Aliases expect GIT_PREFIX, GIT_DIR etc to be set */
|
|
|
|
setup_git_directory_gently(&nongit_ok);
|
2011-01-07 07:00:38 +08:00
|
|
|
|
2010-07-15 06:55:12 +08:00
|
|
|
commit_pager_choice();
|
2011-01-07 07:00:38 +08:00
|
|
|
|
2016-02-23 06:44:21 +08:00
|
|
|
child.use_shell = 1;
|
|
|
|
argv_array_push(&child.args, alias_string + 1);
|
|
|
|
argv_array_pushv(&child.args, (*argv) + 1);
|
2011-01-07 07:00:38 +08:00
|
|
|
|
2016-02-23 06:44:21 +08:00
|
|
|
ret = run_command(&child);
|
2011-01-07 07:00:38 +08:00
|
|
|
if (ret >= 0) /* normal exit */
|
|
|
|
exit(ret);
|
|
|
|
|
|
|
|
die_errno("While expanding alias '%s': '%s'",
|
|
|
|
alias_command, alias_string + 1);
|
2007-02-11 08:33:58 +08:00
|
|
|
}
|
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)
|
2010-08-07 13:13:39 +08:00
|
|
|
die("Bad alias.%s string: %s", alias_command,
|
|
|
|
split_cmdline_strerror(count));
|
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
|
|
|
|
2014-09-17 02:56:57 +08:00
|
|
|
REALLOC_ARRAY(new_argv, count + *argcp);
|
2006-07-30 09:30:29 +08:00
|
|
|
/* insert after command name */
|
2009-05-01 17:06:36 +08:00
|
|
|
memcpy(new_argv + count, *argv + 1, sizeof(char *) * *argcp);
|
2006-06-06 01:43:52 +08:00
|
|
|
|
2006-07-30 09:30:29 +08:00
|
|
|
*argv = new_argv;
|
|
|
|
*argcp += count - 1;
|
2006-06-06 01:43:52 +08:00
|
|
|
|
2006-07-30 09:30:29 +08:00
|
|
|
ret = 1;
|
2006-06-06 01:43:52 +08:00
|
|
|
}
|
|
|
|
|
2006-06-28 18:45:27 +08:00
|
|
|
errno = saved_errno;
|
|
|
|
|
2006-06-06 01:43:52 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-08-06 10:52:16 +08:00
|
|
|
#define RUN_SETUP (1<<0)
|
|
|
|
#define RUN_SETUP_GENTLY (1<<1)
|
|
|
|
#define USE_PAGER (1<<2)
|
2006-12-31 12:32:38 +08:00
|
|
|
/*
|
|
|
|
* require working tree to be present -- anything uses this needs
|
|
|
|
* RUN_SETUP for reading from the configuration file.
|
|
|
|
*/
|
2010-08-06 10:52:16 +08:00
|
|
|
#define NEED_WORK_TREE (1<<3)
|
2016-10-08 02:18:48 +08:00
|
|
|
#define SUPPORT_SUPER_PREFIX (1<<4)
|
git.c: let builtins opt for handling `pager.foo` themselves
Before launching a builtin git foo and unless mechanisms with precedence
are in use, we check for and handle the `pager.foo` config. This is done
without considering exactly how git foo is being used, and indeed, git.c
cannot (and should not) know what the arguments to git foo are supposed
to achieve.
In practice this means that, e.g., `git -c pager.tag tag -a new-tag`
results in errors such as "Vim: Warning: Output is not to a terminal"
and a garbled terminal. Someone who makes use of both `git tag -a` and
`git tag -l` will probably not set `pager.tag`, so that `git tag -a`
will actually work, at the cost of not paging output of `git tag -l`.
To allow individual builtins to make more informed decisions about when
to respect `pager.foo`, introduce a flag DELAY_PAGER_CONFIG. If the flag
is set, do not check `pager.foo`.
Do not check for DELAY_PAGER_CONFIG in `execv_dashed_external()`. That
call site is arguably wrong, although in a way that is not yet visible,
and will be changed in a slightly different direction in a later patch.
Don't add any users of DELAY_PAGER_CONFIG just yet, one will follow in a
later patch.
Suggested-by: Jeff King <peff@peff.net>
Signed-off-by: Martin Ågren <martin.agren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-08-03 03:40:50 +08:00
|
|
|
#define DELAY_PAGER_CONFIG (1<<5)
|
2006-07-29 13:44:25 +08:00
|
|
|
|
2007-06-25 01:10:40 +08:00
|
|
|
struct cmd_struct {
|
|
|
|
const char *cmd;
|
|
|
|
int (*fn)(int, const char **, const char *);
|
|
|
|
int option;
|
|
|
|
};
|
|
|
|
|
2009-01-28 15:33:53 +08:00
|
|
|
static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
|
2007-06-25 01:10:40 +08:00
|
|
|
{
|
2009-11-09 23:05:01 +08:00
|
|
|
int status, help;
|
2007-06-25 01:29:33 +08:00
|
|
|
struct stat st;
|
2007-06-25 01:10:40 +08:00
|
|
|
const char *prefix;
|
|
|
|
|
|
|
|
prefix = NULL;
|
2009-11-09 23:05:01 +08:00
|
|
|
help = argc == 2 && !strcmp(argv[1], "-h");
|
|
|
|
if (!help) {
|
|
|
|
if (p->option & RUN_SETUP)
|
|
|
|
prefix = setup_git_directory();
|
2014-04-22 08:47:56 +08:00
|
|
|
else if (p->option & RUN_SETUP_GENTLY) {
|
2010-08-06 10:52:16 +08:00
|
|
|
int nongit_ok;
|
|
|
|
prefix = setup_git_directory_gently(&nongit_ok);
|
|
|
|
}
|
2009-11-09 23:05:01 +08:00
|
|
|
|
git.c: let builtins opt for handling `pager.foo` themselves
Before launching a builtin git foo and unless mechanisms with precedence
are in use, we check for and handle the `pager.foo` config. This is done
without considering exactly how git foo is being used, and indeed, git.c
cannot (and should not) know what the arguments to git foo are supposed
to achieve.
In practice this means that, e.g., `git -c pager.tag tag -a new-tag`
results in errors such as "Vim: Warning: Output is not to a terminal"
and a garbled terminal. Someone who makes use of both `git tag -a` and
`git tag -l` will probably not set `pager.tag`, so that `git tag -a`
will actually work, at the cost of not paging output of `git tag -l`.
To allow individual builtins to make more informed decisions about when
to respect `pager.foo`, introduce a flag DELAY_PAGER_CONFIG. If the flag
is set, do not check `pager.foo`.
Do not check for DELAY_PAGER_CONFIG in `execv_dashed_external()`. That
call site is arguably wrong, although in a way that is not yet visible,
and will be changed in a slightly different direction in a later patch.
Don't add any users of DELAY_PAGER_CONFIG just yet, one will follow in a
later patch.
Suggested-by: Jeff King <peff@peff.net>
Signed-off-by: Martin Ågren <martin.agren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-08-03 03:40:50 +08:00
|
|
|
if (use_pager == -1 && p->option & (RUN_SETUP | RUN_SETUP_GENTLY) &&
|
|
|
|
!(p->option & DELAY_PAGER_CONFIG))
|
2009-11-09 23:05:01 +08:00
|
|
|
use_pager = check_pager_config(p->cmd);
|
|
|
|
if (use_pager == -1 && p->option & USE_PAGER)
|
|
|
|
use_pager = 1;
|
2010-11-26 23:31:57 +08: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 23:05:01 +08: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 19:46:57 +08:00
|
|
|
commit_pager_choice();
|
|
|
|
|
2016-10-08 02:18:48 +08:00
|
|
|
if (!help && get_super_prefix()) {
|
|
|
|
if (!(p->option & SUPPORT_SUPER_PREFIX))
|
|
|
|
die("%s doesn't support --super-prefix", p->cmd);
|
|
|
|
}
|
|
|
|
|
2009-11-09 23:05:01 +08:00
|
|
|
if (!help && p->option & NEED_WORK_TREE)
|
2007-11-03 19:23:11 +08:00
|
|
|
setup_work_tree();
|
|
|
|
|
2007-12-03 12:51:50 +08:00
|
|
|
trace_argv_printf(argv, "trace: built-in: git");
|
2007-06-25 01:10:40 +08:00
|
|
|
|
2007-06-25 01:29:33 +08:00
|
|
|
status = p->fn(argc, argv, prefix);
|
|
|
|
if (status)
|
2009-07-06 02:57:46 +08:00
|
|
|
return status;
|
2007-06-25 01:29:33 +08:00
|
|
|
|
|
|
|
/* Somebody closed stdout? */
|
|
|
|
if (fstat(fileno(stdout), &st))
|
|
|
|
return 0;
|
|
|
|
/* Ignore write errors for pipes and sockets.. */
|
|
|
|
if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Check for ENOSPC and EIO errors.. */
|
git: Try a bit harder not to lose errno in stdio
This switches the checks around upon the exit codepath of the
git wrapper, so that we may recover at least non-transient errors.
It's still not perfect. As I've been harping on, stdio simply isn't very
good for error reporting. For example, if an IO error happened, you'd want
to see EIO, wouldn't you? And yes, that's what the kernel would return.
However, with buffered stdio (and flushing outside of our control), what
would likely happen is that some intermediate error return _does_ return
EIO, but then the kernel might decide to re-mount the filesystem read-only
due to the error, and the actual *report* for us might be
"write failure on standard output: read-only filesystem"
which lost the EIO.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-07-01 02:44:20 +08:00
|
|
|
if (fflush(stdout))
|
2009-06-27 23:58:46 +08:00
|
|
|
die_errno("write failure on standard output");
|
git: Try a bit harder not to lose errno in stdio
This switches the checks around upon the exit codepath of the
git wrapper, so that we may recover at least non-transient errors.
It's still not perfect. As I've been harping on, stdio simply isn't very
good for error reporting. For example, if an IO error happened, you'd want
to see EIO, wouldn't you? And yes, that's what the kernel would return.
However, with buffered stdio (and flushing outside of our control), what
would likely happen is that some intermediate error return _does_ return
EIO, but then the kernel might decide to re-mount the filesystem read-only
due to the error, and the actual *report* for us might be
"write failure on standard output: read-only filesystem"
which lost the EIO.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-07-01 02:44:20 +08:00
|
|
|
if (ferror(stdout))
|
|
|
|
die("unknown write failure on standard output");
|
|
|
|
if (fclose(stdout))
|
2009-06-27 23:58:46 +08:00
|
|
|
die_errno("close failed on standard output");
|
2007-06-25 01:29:33 +08:00
|
|
|
return 0;
|
2007-06-25 01:10:40 +08:00
|
|
|
}
|
|
|
|
|
2014-01-03 00:17:11 +08:00
|
|
|
static struct cmd_struct commands[] = {
|
|
|
|
{ "add", cmd_add, RUN_SETUP | NEED_WORK_TREE },
|
2015-08-04 21:52:06 +08:00
|
|
|
{ "am", cmd_am, RUN_SETUP | NEED_WORK_TREE },
|
2014-01-03 00:17:11 +08:00
|
|
|
{ "annotate", cmd_annotate, RUN_SETUP },
|
|
|
|
{ "apply", cmd_apply, RUN_SETUP_GENTLY },
|
2016-11-23 05:37:04 +08:00
|
|
|
{ "archive", cmd_archive, RUN_SETUP_GENTLY },
|
2014-01-03 00:17:11 +08:00
|
|
|
{ "bisect--helper", cmd_bisect__helper, RUN_SETUP },
|
|
|
|
{ "blame", cmd_blame, RUN_SETUP },
|
2017-11-19 23:03:49 +08:00
|
|
|
{ "branch", cmd_branch, RUN_SETUP | DELAY_PAGER_CONFIG },
|
2014-01-03 00:17:11 +08:00
|
|
|
{ "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-07 01:30:56 +08:00
|
|
|
{ "checkout", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },
|
2014-01-03 00:17:11 +08: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 15:50:18 +08:00
|
|
|
{ "clone", cmd_clone },
|
2014-01-03 00:17:11 +08: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 },
|
2017-01-20 04:30:40 +08:00
|
|
|
{ "difftool", cmd_difftool, RUN_SETUP | NEED_WORK_TREE },
|
2014-01-03 00:17:11 +08:00
|
|
|
{ "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 },
|
2017-08-03 03:49:23 +08:00
|
|
|
{ "grep", cmd_grep, RUN_SETUP_GENTLY },
|
2014-01-03 00:17:11 +08:00
|
|
|
{ "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 15:50:18 +08:00
|
|
|
{ "init", cmd_init_db },
|
|
|
|
{ "init-db", cmd_init_db },
|
2015-09-05 21:39:24 +08:00
|
|
|
{ "interpret-trailers", cmd_interpret_trailers, RUN_SETUP_GENTLY },
|
2014-01-03 00:17:11 +08:00
|
|
|
{ "log", cmd_log, RUN_SETUP },
|
2017-06-23 02:43:48 +08:00
|
|
|
{ "ls-files", cmd_ls_files, RUN_SETUP },
|
2014-01-03 00:17:11 +08:00
|
|
|
{ "ls-remote", cmd_ls_remote, RUN_SETUP_GENTLY },
|
|
|
|
{ "ls-tree", cmd_ls_tree, RUN_SETUP },
|
2016-11-23 05:13:16 +08:00
|
|
|
{ "mailinfo", cmd_mailinfo, RUN_SETUP_GENTLY },
|
2014-01-03 00:17:11 +08:00
|
|
|
{ "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 },
|
2016-09-13 11:23:22 +08:00
|
|
|
{ "patch-id", cmd_patch_id, RUN_SETUP_GENTLY },
|
2014-01-03 00:17:11 +08:00
|
|
|
{ "pickaxe", cmd_blame, RUN_SETUP },
|
|
|
|
{ "prune", cmd_prune, RUN_SETUP },
|
|
|
|
{ "prune-packed", cmd_prune_packed, RUN_SETUP },
|
2015-06-14 16:41:51 +08:00
|
|
|
{ "pull", cmd_pull, RUN_SETUP | NEED_WORK_TREE },
|
2014-01-03 00:17:11 +08:00
|
|
|
{ "push", cmd_push, RUN_SETUP },
|
unpack-trees: support super-prefix option
In the future we want to support working tree operations within submodules,
e.g. "git checkout --recurse-submodules", which will update the submodule
to the commit as recorded in its superproject. In the submodule the
unpack-tree operation is carried out as usual, but the reporting to the
user needs to prefix any path with the superproject. The mechanism for
this is the super-prefix. (see 74866d757, git: make super-prefix option)
Add support for the super-prefix option for commands that unpack trees
by wrapping any path output in unpacking trees in the newly introduced
super_prefixed function. This new function prefixes any path with the
super-prefix if there is one. Assuming the submodule case doesn't happen
in the majority of the cases, we'd want to have a fast behavior for no
super prefix, i.e. no reallocation/copying, but just returning path.
Another aspect of introducing the `super_prefixed` function is to consider
who owns the memory and if this is the right place where the path gets
modified. As the super prefix ought to change the output behavior only and
not the actual unpack tree part, it is fine to be that late in the line.
As we get passed in 'const char *path', we cannot change the path itself,
which means in case of a super prefix we have to copy over the path.
We need two static buffers in that function as the error messages
contain at most two paths.
For testing purposes enable it in read-tree, which has no output
of paths other than an unpack-trees.c. These are all converted in
this patch.
Signed-off-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-01-18 09:05:20 +08:00
|
|
|
{ "read-tree", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},
|
rebase--helper: add a builtin helper for interactive rebases
Git's interactive rebase is still implemented as a shell script, despite
its complexity. This implies that it suffers from the portability point
of view, from lack of expressibility, and of course also from
performance. The latter issue is particularly serious on Windows, where
we pay a hefty price for relying so much on POSIX.
Unfortunately, being such a huge shell script also means that we missed
the train when it would have been relatively easy to port it to C, and
instead piled feature upon feature onto that poor script that originally
never intended to be more than a slightly pimped cherry-pick in a loop.
To open the road toward better performance (in addition to all the other
benefits of C over shell scripts), let's just start *somewhere*.
The approach taken here is to add a builtin helper that at first intends
to take care of the parts of the interactive rebase that are most
affected by the performance penalties mentioned above.
In particular, after we spent all those efforts on preparing the sequencer
to process rebase -i's git-rebase-todo scripts, we implement the `git
rebase -i --continue` functionality as a new builtin, git-rebase--helper.
Once that is in place, we can work gradually on tackling the rest of the
technical debt.
Note that the rebase--helper needs to learn about the transient
--ff/--no-ff options of git-rebase, as the corresponding flag is not
persisted to, and re-read from, the state directory.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-10 06:23:06 +08:00
|
|
|
{ "rebase--helper", cmd_rebase__helper, RUN_SETUP | NEED_WORK_TREE },
|
2014-01-03 00:17:11 +08:00
|
|
|
{ "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 },
|
2016-12-09 05:03:25 +08:00
|
|
|
{ "submodule--helper", cmd_submodule__helper, RUN_SETUP | SUPPORT_SUPER_PREFIX},
|
2014-01-03 00:17:11 +08:00
|
|
|
{ "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
|
2017-08-03 03:40:53 +08:00
|
|
|
{ "tag", cmd_tag, RUN_SETUP | DELAY_PAGER_CONFIG },
|
2014-01-03 00:17:11 +08:00
|
|
|
{ "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 },
|
2018-03-15 02:31:41 +08:00
|
|
|
{ "upload-pack", cmd_upload_pack },
|
2014-01-03 00:17:11 +08:00
|
|
|
{ "var", cmd_var, RUN_SETUP_GENTLY },
|
2014-06-23 15:05:49 +08:00
|
|
|
{ "verify-commit", cmd_verify_commit, RUN_SETUP },
|
2014-01-03 00:17:11 +08:00
|
|
|
{ "verify-pack", cmd_verify_pack },
|
|
|
|
{ "verify-tag", cmd_verify_tag, RUN_SETUP },
|
|
|
|
{ "version", cmd_version },
|
|
|
|
{ "whatchanged", cmd_whatchanged, RUN_SETUP },
|
2015-06-29 20:51:18 +08:00
|
|
|
{ "worktree", cmd_worktree, RUN_SETUP },
|
2014-01-03 00:17:11 +08:00
|
|
|
{ "write-tree", cmd_write_tree, RUN_SETUP },
|
|
|
|
};
|
|
|
|
|
2014-11-12 21:10:22 +08:00
|
|
|
static struct cmd_struct *get_builtin(const char *s)
|
2014-01-03 00:17:11 +08:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(commands); i++) {
|
2014-11-12 21:10:22 +08:00
|
|
|
struct cmd_struct *p = commands + i;
|
2014-01-03 00:17:11 +08:00
|
|
|
if (!strcmp(s, p->cmd))
|
2014-11-12 21:10:22 +08:00
|
|
|
return p;
|
2014-01-03 00:17:11 +08:00
|
|
|
}
|
2014-11-12 21:10:22 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int is_builtin(const char *s)
|
|
|
|
{
|
|
|
|
return !!get_builtin(s);
|
2014-01-03 00:17:11 +08:00
|
|
|
}
|
|
|
|
|
2017-05-30 13:18:43 +08:00
|
|
|
static void list_builtins(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(commands); i++)
|
|
|
|
printf("%s\n", commands[i].cmd);
|
|
|
|
}
|
|
|
|
|
2016-02-22 15:18:29 +08: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-03 00:15:44 +08: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-27 04:34:51 +08:00
|
|
|
{
|
2016-08-27 01:58:36 +08:00
|
|
|
struct argv_array args = ARGV_ARRAY_INIT;
|
2016-02-22 15:18:29 +08:00
|
|
|
const char *cmd;
|
2014-11-12 21:10:22 +08:00
|
|
|
struct cmd_struct *builtin;
|
2007-12-09 03:57:25 +08:00
|
|
|
|
2016-02-22 15:18:29 +08: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-27 04:34:51 +08:00
|
|
|
|
2016-08-27 01:58:36 +08:00
|
|
|
/* Turn "git cmd --help" into "git help --exclude-guides cmd" */
|
2006-04-16 02:13:49 +08:00
|
|
|
if (argc > 1 && !strcmp(argv[1], "--help")) {
|
2016-08-27 01:58:36 +08:00
|
|
|
int i;
|
|
|
|
|
2006-04-16 02:13:49 +08:00
|
|
|
argv[1] = argv[0];
|
|
|
|
argv[0] = cmd = "help";
|
2016-08-27 01:58:36 +08:00
|
|
|
|
|
|
|
for (i = 0; i < argc; i++) {
|
|
|
|
argv_array_push(&args, argv[i]);
|
|
|
|
if (!i)
|
|
|
|
argv_array_push(&args, "--exclude-guides");
|
|
|
|
}
|
|
|
|
|
|
|
|
argc++;
|
|
|
|
argv = args.argv;
|
2006-04-16 02:13:49 +08:00
|
|
|
}
|
|
|
|
|
2014-11-12 21:10:22 +08: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 14:52:02 +08:00
|
|
|
if (builtin)
|
|
|
|
exit(run_builtin(builtin, argc, argv));
|
2016-08-27 01:58:36 +08:00
|
|
|
argv_array_clear(&args);
|
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)
|
|
|
|
{
|
2017-01-07 09:16:24 +08:00
|
|
|
struct child_process cmd = CHILD_PROCESS_INIT;
|
2009-01-28 15:38:14 +08:00
|
|
|
int status;
|
2007-12-02 14:09:22 +08:00
|
|
|
|
2016-10-08 02:18:48 +08:00
|
|
|
if (get_super_prefix())
|
|
|
|
die("%s doesn't support --super-prefix", argv[0]);
|
|
|
|
|
git.c: ignore pager.* when launching builtin as dashed external
When running, e.g., `git -c alias.bar=foo bar`, we expand the alias and
execute `git-foo` as a dashed external. This is true even if git foo is
a builtin. That is on purpose, and is motivated in a comment which was
added in commit 441981bc ("git: simplify environment save/restore
logic", 2016-01-26).
Shortly before we launch a dashed external, and unless we have already
found out whether we should use a pager, we check `pager.foo`. This was
added in commit 92058e4d ("support pager.* for external commands",
2011-08-18). If the dashed external is a builtin, this does not match
that commit's intention and is arguably wrong, since it would be cleaner
if we let the "dashed external builtin" handle `pager.foo`.
This has not mattered in practice, but a recent patch taught `git-tag`
to ignore `pager.tag` under certain circumstances. But, when started
using an alias, it doesn't get the chance to do so, as outlined above.
That recent patch added a test to document this breakage.
Do not check `pager.foo` before launching a builtin as a dashed
external, i.e., if we recognize the name of the external as a builtin.
Change the test to use `test_expect_success`.
Signed-off-by: Martin Ågren <martin.agren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-08-03 03:40:55 +08:00
|
|
|
if (use_pager == -1 && !is_builtin(argv[0]))
|
2011-08-19 06:01:32 +08:00
|
|
|
use_pager = check_pager_config(argv[0]);
|
2010-07-15 06:55:12 +08:00
|
|
|
commit_pager_choice();
|
|
|
|
|
2017-01-07 09:16:24 +08:00
|
|
|
argv_array_pushf(&cmd.args, "git-%s", argv[0]);
|
|
|
|
argv_array_pushv(&cmd.args, argv + 1);
|
|
|
|
cmd.clean_on_exit = 1;
|
execv_dashed_external: wait for child on signal death
When you hit ^C to interrupt a git command going to a pager,
this usually leaves the pager running. But when a dashed
external is in use, the pager ends up in a funny state and
quits (but only after eating one more character from the
terminal!). This fixes it.
Explaining the reason will require a little background.
When git runs a pager, it's important for the git process to
hang around and wait for the pager to finish, even though it
has no more data to feed it. This is because git spawns the
pager as a child, and thus the git process is the session
leader on the terminal. After it dies, the pager will finish
its current read from the terminal (eating the one
character), and then get EIO trying to read again.
When you hit ^C, that sends SIGINT to git and to the pager,
and it's a similar situation. The pager ignores it, but the
git process needs to hang around until the pager is done. We
addressed that long ago in a3da882120 (pager: do
wait_for_pager on signal death, 2009-01-22).
But when you have a dashed external (or an alias pointing to
a builtin, which will re-exec git for the builtin), there's
an extra process in the mix. For instance, running:
$ git -c alias.l=log l
will end up with a process tree like:
git (parent)
\
git-log (child)
\
less (pager)
If you hit ^C, SIGINT goes to all of them. The pager ignores
it, and the child git process will end up in wait_for_pager().
But the parent git process will die, and the usual EIO
trouble happens.
So we really want the parent git process to wait_for_pager(),
but of course it doesn't know anything about the pager at
all, since it was started by the child. However, we can
have it wait on the git-log child, which in turn is waiting
on the pager. And that's what this patch does.
There are a few design decisions here worth explaining:
1. The new feature is attached to run-command's
clean_on_exit feature. Partly this is convenience,
since that feature already has a signal handler that
deals with child cleanup.
But it's also a meaningful connection. The main reason
that dashed externals use clean_on_exit is to bind the
two processes together. If somebody kills the parent
with a signal, we propagate that to the child (in this
instance with SIGINT, we do propagate but it doesn't
matter because the original signal went to the whole
process group). Likewise, we do not want the parent
to go away until the child has done so.
In a traditional Unix world, we'd probably accomplish
this binding by just having the parent execve() the
child directly. But since that doesn't work on Windows,
everything goes through run_command's more spawn-like
interface.
2. We do _not_ automatically waitpid() on any
clean_on_exit children. For dashed externals this makes
sense; we know that the parent is doing nothing but
waiting for the child to exit anyway. But with other
children, it's possible that the child, after getting
the signal, could be waiting on the parent to do
something (like closing a descriptor). If we were to
wait on such a child, we'd end up in a deadlock. So
this errs on the side of caution, and lets callers
enable the feature explicitly.
3. When we send children the cleanup signal, we send all
the signals first, before waiting on any children. This
is to avoid the case where one child might be waiting
on another one to exit, causing a deadlock. We inform
all of them that it's time to die before reaping any.
In practice, there is only ever one dashed external run
from a given process, so this doesn't matter much now.
But it future-proofs us if other callers start using
the wait_after_clean mechanism.
There's no automated test here, because it would end up racy
and unportable. But it's easy to reproduce the situation by
running the log command given above and hitting ^C.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-01-07 09:22:23 +08:00
|
|
|
cmd.wait_after_clean = 1;
|
2017-01-07 09:16:24 +08:00
|
|
|
cmd.silent_exec_failure = 1;
|
2007-12-02 14:09:22 +08:00
|
|
|
|
2017-01-07 09:16:24 +08:00
|
|
|
trace_argv_printf(cmd.args.argv, "trace: exec:");
|
2007-12-02 14:09:22 +08:00
|
|
|
|
2009-01-28 15:38:14 +08:00
|
|
|
/*
|
2017-01-07 09:17:48 +08:00
|
|
|
* If we fail because the command is not found, it is
|
|
|
|
* OK to return. Otherwise, we just pass along the status code,
|
|
|
|
* or our usual generic code if we were not even able to exec
|
|
|
|
* the program.
|
2009-01-28 15:38:14 +08:00
|
|
|
*/
|
2017-01-07 09:16:24 +08:00
|
|
|
status = run_command(&cmd);
|
2017-01-07 09:17:48 +08:00
|
|
|
if (status >= 0)
|
2009-07-05 03:26:39 +08:00
|
|
|
exit(status);
|
2017-01-07 09:17:48 +08:00
|
|
|
else if (errno != ENOENT)
|
|
|
|
exit(128);
|
2007-12-02 14:09:22 +08:00
|
|
|
}
|
|
|
|
|
2009-01-05 01:16:01 +08: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 14:52:02 +08: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-05 01:16:01 +08: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 17:37:10 +08:00
|
|
|
if (done_alias)
|
|
|
|
break;
|
|
|
|
if (!handle_alias(argcp, argv))
|
2009-01-05 01:16:01 +08: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 13:58:58 +08:00
|
|
|
int cmd_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;
|
2015-03-02 20:02:37 +08: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-27 04:34:51 +08: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 14:04:04 +08:00
|
|
|
cmd = argv[0];
|
2009-01-18 20:00:11 +08:00
|
|
|
if (!cmd)
|
2009-01-18 20:00:10 +08:00
|
|
|
cmd = "git-help";
|
common-main: stop munging argv[0] path
Since 650c44925 (common-main: call git_extract_argv0_path(),
2016-07-01), the argv[0] that is seen in cmd_main() of
individual programs is always the basename of the
executable, as common-main strips off the full path. This
can produce confusing results for git-daemon, which wants to
re-exec itself.
For instance, if the program was originally run as
"/usr/lib/git/git-daemon", it will try just re-execing
"git-daemon", which will find the first instance in $PATH.
If git's exec-path has not been prepended to $PATH, we may
find the git-daemon from a different version (or no
git-daemon at all).
Normally this isn't a problem. Git commands are run as "git
daemon", the git wrapper puts the exec-path at the front of
$PATH, and argv[0] is already "daemon" anyway. But running
git-daemon via its full exec-path, while not really a
recommended method, did work prior to 650c44925. Let's make
it work again.
The real goal of 650c44925 was not to munge argv[0], but to
reliably set the argv0_path global. The only reason it
munges at all is that one caller, the git.c wrapper,
piggy-backed on that computation to find the command
basename. Instead, let's leave argv[0] untouched in
common-main, and have git.c do its own basename computation.
While we're at it, let's drop the return value from
git_extract_argv0_path(). It was only ever used in this one
callsite, and its dual purposes is what led to this
confusion in the first place.
Note that by changing the interface, the compiler can
confirm for us that there are no other callers storing the
return value. But the compiler can't tell us whether any of
the cmd_main() functions (besides git.c) were relying on the
basename munging. However, we can observe that prior to
650c44925, no other cmd_main() functions did that munging,
and no new cmd_main() functions have been introduced since
then. So we can't be regressing any of those cases.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-11-27 12:31:13 +08:00
|
|
|
else {
|
|
|
|
const char *slash = find_last_dir_sep(cmd);
|
|
|
|
if (slash)
|
|
|
|
cmd = slash + 1;
|
|
|
|
}
|
2005-11-16 07:31:25 +08:00
|
|
|
|
2014-07-12 08:07:01 +08: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-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)
|
|
|
|
*
|
2014-01-03 00:15:44 +08: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-27 04:34:51 +08: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-19 03:47:50 +08: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-27 04:34:51 +08:00
|
|
|
argv[0] = cmd;
|
2014-01-03 00:15:44 +08: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-27 04:34:51 +08:00
|
|
|
}
|
2005-11-16 07:31:25 +08:00
|
|
|
|
Teach the "git" command to handle some commands internally
This is another patch in the "prepare to do more in C" series, where the
git wrapper command is taught about the notion of handling some
functionality internally.
Right now, the only internal commands are "version" and "help", but the
point being that we can now easily extend it to handle some of the trivial
scripts internally. Things like "git log" and "git diff" wouldn't need
separate external scripts any more.
This also implies that to support the old "git-log" and "git-diff" syntax,
the "git" wrapper now automatically looks at the name it was executed as,
and if it is "git-xxxx", it will assume that it is to internally do what
"git xxxx" would do.
In other words, you can (once you implement an internal command) soft- or
hard-link that command to the "git" wrapper command, and it will do the
right thing, whether you use the "git xxxx" or the "git-xxxx" format.
There's one other change: the search order for external programs is
modified slightly, so that the first entry remains GIT_EXEC_DIR, but the
second entry is the same directory as the git wrapper itself was executed
out of - if we can figure it out from argv[0], of course.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-27 04:34:51 +08:00
|
|
|
/* Look for flags.. */
|
2006-07-26 02:24:22 +08:00
|
|
|
argv++;
|
|
|
|
argc--;
|
2007-06-09 04:57:55 +08:00
|
|
|
handle_options(&argv, &argc, NULL);
|
2006-07-26 02:24:22 +08:00
|
|
|
if (argc > 0) {
|
2014-06-19 03:56:48 +08:00
|
|
|
/* translate --help and --version into commands */
|
|
|
|
skip_prefix(argv[0], "--", &argv[0]);
|
2006-07-26 02:24:22 +08:00
|
|
|
} else {
|
2007-10-27 16:36:49 +08:00
|
|
|
/* The user didn't specify a command; give them help */
|
git --paginate: do not commit pager choice too early
When git is passed the --paginate option, starting up a pager requires
deciding what pager to start, which requires access to the core.pager
configuration.
At the relevant moment, the repository has not been searched for yet.
Attempting to access the configuration at this point results in
git_dir being set to .git [*], which is almost certainly not what was
wanted. In particular, when run from a subdirectory of the toplevel,
git --paginate does not respect the core.pager setting from the
current repository.
[*] unless GIT_DIR or GIT_CONFIG is set
So delay the pager startup when possible:
1. run_argv() already commits pager choice inside run_builtin() if a
command is found. For commands that use RUN_SETUP, waiting until
then fixes the problem described above: once git knows where to
look, it happily respects the core.pager setting.
2. list_common_cmds_help() prints out 29 lines and exits. This can
benefit from pagination, so we need to commit the pager choice
before writing this output.
Luckily ‘git’ without subcommand has no other reason to access a
repository, so it would be intuitive to ignore repository-local
configuration in this case. Simpler for now to choose a pager
using the funny code that notices a repository that happens to be
at .git. That this accesses a repository when it is very
convenient to is a bug but not an important one.
3. help_unknown_cmd() prints out a few lines to stderr. It is not
important to paginate this, so don’t.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Acked-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-06-27 03:26:37 +08:00
|
|
|
commit_pager_choice();
|
2007-10-27 16:36:49 +08:00
|
|
|
printf("usage: %s\n\n", git_usage_string);
|
|
|
|
list_common_cmds_help();
|
2013-03-10 23:10:20 +08:00
|
|
|
printf("\n%s\n", _(git_more_info_string));
|
2007-10-27 16:36:49 +08:00
|
|
|
exit(1);
|
2005-11-16 07:31:25 +08:00
|
|
|
}
|
2006-07-26 02:24:22 +08:00
|
|
|
cmd = argv[0];
|
Teach the "git" command to handle some commands internally
This is another patch in the "prepare to do more in C" series, where the
git wrapper command is taught about the notion of handling some
functionality internally.
Right now, the only internal commands are "version" and "help", but the
point being that we can now easily extend it to handle some of the trivial
scripts internally. Things like "git log" and "git diff" wouldn't need
separate external scripts any more.
This also implies that to support the old "git-log" and "git-diff" syntax,
the "git" wrapper now automatically looks at the name it was executed as,
and if it is "git-xxxx", it will assume that it is to internally do what
"git xxxx" would do.
In other words, you can (once you implement an internal command) soft- or
hard-link that command to the "git" wrapper command, and it will do the
right thing, whether you use the "git xxxx" or the "git-xxxx" format.
There's one other change: the search order for external programs is
modified slightly, so that the first entry remains GIT_EXEC_DIR, but the
second entry is the same directory as the git wrapper itself was executed
out of - if we can figure it out from argv[0], of course.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-27 04:34:51 +08:00
|
|
|
|
|
|
|
/*
|
2007-10-28 19:17:20 +08:00
|
|
|
* We use PATH to find git commands, but we prepend some higher
|
2009-04-18 02:13:30 +08:00
|
|
|
* precedence paths: the "--exec-path" option, the GIT_EXEC_PATH
|
2007-10-28 19:17:20 +08:00
|
|
|
* environment, and the $(gitexecdir) from the Makefile at build
|
|
|
|
* time.
|
Teach the "git" command to handle some commands internally
This is another patch in the "prepare to do more in C" series, where the
git wrapper command is taught about the notion of handling some
functionality internally.
Right now, the only internal commands are "version" and "help", but the
point being that we can now easily extend it to handle some of the trivial
scripts internally. Things like "git log" and "git diff" wouldn't need
separate external scripts any more.
This also implies that to support the old "git-log" and "git-diff" syntax,
the "git" wrapper now automatically looks at the name it was executed as,
and if it is "git-xxxx", it will assume that it is to internally do what
"git xxxx" would do.
In other words, you can (once you implement an internal command) soft- or
hard-link that command to the "git" wrapper command, and it will do the
right thing, whether you use the "git xxxx" or the "git-xxxx" format.
There's one other change: the search order for external programs is
modified slightly, so that the first entry remains GIT_EXEC_DIR, but the
second entry is the same directory as the git wrapper itself was executed
out of - if we can figure it out from argv[0], of course.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-27 04:34:51 +08:00
|
|
|
*/
|
2008-07-22 03:19:52 +08:00
|
|
|
setup_path();
|
2005-11-16 07:31:25 +08:00
|
|
|
|
2006-06-06 09:09:40 +08:00
|
|
|
while (1) {
|
2015-03-02 20:02:37 +08:00
|
|
|
int was_alias = run_argv(&argc, &argv);
|
2009-01-05 01:16:01 +08:00
|
|
|
if (errno != ENOENT)
|
2006-06-06 09:09:40 +08:00
|
|
|
break;
|
2009-01-05 01:16:01 +08:00
|
|
|
if (was_alias) {
|
2007-02-11 08:33:57 +08:00
|
|
|
fprintf(stderr, "Expansion of alias '%s' failed; "
|
2010-02-16 07:33:18 +08:00
|
|
|
"'%s' is not a git command\n",
|
2007-02-11 08:33:57 +08:00
|
|
|
cmd, argv[0]);
|
|
|
|
exit(1);
|
|
|
|
}
|
2009-01-05 01:16:01 +08:00
|
|
|
if (!done_help) {
|
|
|
|
cmd = argv[0] = help_unknown_cmd(cmd);
|
|
|
|
done_help = 1;
|
|
|
|
} else
|
|
|
|
break;
|
2007-02-11 08:33:57 +08:00
|
|
|
}
|
2005-12-01 20:48:35 +08:00
|
|
|
|
|
|
|
fprintf(stderr, "Failed to run command '%s': %s\n",
|
2006-06-28 17:17:21 +08:00
|
|
|
cmd, strerror(errno));
|
2005-11-16 07:31:25 +08:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|