2006-12-20 06:34:12 +08:00
|
|
|
#include "builtin.h"
|
2006-06-06 01:43:52 +08:00
|
|
|
#include "cache.h"
|
2010-09-01 10:29:08 +08:00
|
|
|
#include "exec_cmd.h"
|
|
|
|
#include "help.h"
|
2006-06-25 21:56:18 +08:00
|
|
|
#include "quote.h"
|
2009-01-28 15:38:14 +08:00
|
|
|
#include "run-command.h"
|
2013-05-26 09:16:15 +08:00
|
|
|
#include "commit.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"
|
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
|
|
|
" [-p|--paginate|--no-pager] [--no-replace-objects] [--bare]\n"
|
|
|
|
" [--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[] =
|
2013-04-03 06:39:48 +08:00
|
|
|
N_("'git help -a' and 'git help -g' lists available subcommands and some\n"
|
|
|
|
"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
|
|
|
|
2010-08-06 10:40:35 +08:00
|
|
|
static struct startup_info git_startup_info;
|
Allow per-command pager config
There is great debate over whether some commands should set
up a pager automatically. This patch allows individuals to
set their own pager preferences for each command, overriding
the default. For example, to disable the pager for git
status:
git config pager.status false
If "--pager" or "--no-pager" is specified on the command
line, it takes precedence over the config option.
There are two caveats:
- you can turn on the pager for plumbing commands.
Combined with "core.pager = always", this will probably
break a lot of things. Don't do it.
- This only works for builtin commands. The reason is
somewhat complex:
Calling git_config before we do setup_git_directory
has bad side effects, because it wants to know where
the git_dir is to find ".git/config". Unfortunately,
we cannot call setup_git_directory indiscriminately,
because some builtins (like "init") break if we do.
For builtins, this is OK, since we can just wait until
after we call setup_git_directory. But for aliases, we
don't know until we expand (recursively) which command
we're doing. This should not be a huge problem for
aliases, which can simply use "--pager" or "--no-pager"
in the alias as appropriate.
For external commands, however, we don't know we even
have an external command until we exec it, and by then
it is too late to check the config.
An alternative approach would be to have a config mode
where we don't bother looking at .git/config, but only
at the user and system config files. This would make the
behavior consistent across builtins, aliases, and
external commands, at the cost of not allowing per-repo
pager config for at all.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-07-03 19:46:57 +08:00
|
|
|
static int use_pager = -1;
|
|
|
|
|
|
|
|
static void commit_pager_choice(void) {
|
|
|
|
switch (use_pager) {
|
|
|
|
case 0:
|
|
|
|
setenv("GIT_PAGER", "cat", 1);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
setup_pager();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-01 17:06:36 +08:00
|
|
|
static int handle_options(const char ***argv, int *argc, int *envchanged)
|
2006-07-24 20:10:45 +08:00
|
|
|
{
|
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.
|
|
|
|
*/
|
2013-12-01 04:55:40 +08:00
|
|
|
if (starts_with(cmd, "--exec-path")) {
|
2006-07-26 02:24:22 +08:00
|
|
|
cmd += 11;
|
|
|
|
if (*cmd == '=')
|
2007-10-27 16:36:51 +08:00
|
|
|
git_set_argv_exec_path(cmd + 1);
|
2006-07-26 02:24:22 +08:00
|
|
|
else {
|
|
|
|
puts(git_exec_path());
|
|
|
|
exit(0);
|
|
|
|
}
|
2009-04-05 10:15:16 +08:00
|
|
|
} else if (!strcmp(cmd, "--html-path")) {
|
|
|
|
puts(system_path(GIT_HTML_PATH));
|
|
|
|
exit(0);
|
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")) {
|
|
|
|
read_replace_refs = 0;
|
2009-11-18 14:50:58 +08:00
|
|
|
setenv(NO_REPLACE_OBJECTS_ENVIRONMENT, "1", 1);
|
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
2006-07-26 02:24:22 +08:00
|
|
|
} else if (!strcmp(cmd, "--git-dir")) {
|
2006-12-22 21:56:25 +08:00
|
|
|
if (*argc < 2) {
|
|
|
|
fprintf(stderr, "No directory given for --git-dir.\n" );
|
|
|
|
usage(git_usage_string);
|
|
|
|
}
|
2006-12-31 12:29:11 +08:00
|
|
|
setenv(GIT_DIR_ENVIRONMENT, (*argv)[1], 1);
|
2007-06-09 04:57:55 +08:00
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
2006-07-26 02:24:22 +08:00
|
|
|
(*argv)++;
|
|
|
|
(*argc)--;
|
2013-12-01 04:55:40 +08:00
|
|
|
} else if (starts_with(cmd, "--git-dir=")) {
|
2006-12-31 12:29:11 +08:00
|
|
|
setenv(GIT_DIR_ENVIRONMENT, cmd + 10, 1);
|
2007-06-09 04:57:55 +08:00
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
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)--;
|
2013-12-01 04:55:40 +08:00
|
|
|
} else if (starts_with(cmd, "--namespace=")) {
|
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
|
|
|
setenv(GIT_NAMESPACE_ENVIRONMENT, cmd + 12, 1);
|
|
|
|
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)--;
|
2013-12-01 04:55:40 +08:00
|
|
|
} else if (starts_with(cmd, "--work-tree=")) {
|
2007-06-06 15:10:42 +08:00
|
|
|
setenv(GIT_WORK_TREE_ENVIRONMENT, cmd + 12, 1);
|
2007-06-09 04:57:55 +08:00
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
2006-07-26 02:24:22 +08:00
|
|
|
} else if (!strcmp(cmd, "--bare")) {
|
2006-12-31 12:28:53 +08:00
|
|
|
static char git_dir[PATH_MAX+1];
|
2007-08-27 15:58:06 +08:00
|
|
|
is_bare_repository_cfg = 1;
|
2007-08-28 13:41:23 +08:00
|
|
|
setenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir, sizeof(git_dir)), 0);
|
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;
|
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);
|
|
|
|
}
|
|
|
|
if (chdir((*argv)[1]))
|
|
|
|
die_errno("Cannot change to '%s'", (*argv)[1]);
|
|
|
|
if (envchanged)
|
|
|
|
*envchanged = 1;
|
|
|
|
(*argv)++;
|
|
|
|
(*argc)--;
|
2006-07-26 02:24:22 +08:00
|
|
|
} else {
|
|
|
|
fprintf(stderr, "Unknown option: %s\n", cmd);
|
2006-07-31 05:42:25 +08:00
|
|
|
usage(git_usage_string);
|
2006-07-26 02:24:22 +08:00
|
|
|
}
|
2006-07-24 20:10:45 +08:00
|
|
|
|
|
|
|
(*argv)++;
|
|
|
|
(*argc)--;
|
|
|
|
}
|
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-06-06 01:43:52 +08:00
|
|
|
const char *subdir;
|
2006-07-30 09:30:29 +08:00
|
|
|
int count, option_count;
|
2009-05-01 17:06:36 +08:00
|
|
|
const char **new_argv;
|
2008-02-25 06:17:14 +08:00
|
|
|
const char *alias_command;
|
|
|
|
char *alias_string;
|
2008-04-01 12:33:09 +08:00
|
|
|
int unused_nongit;
|
2006-06-06 01:43:52 +08:00
|
|
|
|
2008-04-01 12:33:09 +08:00
|
|
|
subdir = setup_git_directory_gently(&unused_nongit);
|
2006-07-30 09:30:29 +08:00
|
|
|
|
|
|
|
alias_command = (*argv)[0];
|
2008-02-25 06:17:14 +08:00
|
|
|
alias_string = alias_lookup(alias_command);
|
2006-07-30 09:30:29 +08:00
|
|
|
if (alias_string) {
|
2007-02-11 08:33:58 +08:00
|
|
|
if (alias_string[0] == '!') {
|
2011-01-07 07:00:38 +08:00
|
|
|
const char **alias_argv;
|
|
|
|
int argc = *argcp, i;
|
|
|
|
|
2010-07-15 06:55:12 +08:00
|
|
|
commit_pager_choice();
|
2011-01-07 07:00:38 +08:00
|
|
|
|
|
|
|
/* build alias_argv */
|
|
|
|
alias_argv = xmalloc(sizeof(*alias_argv) * (argc + 1));
|
|
|
|
alias_argv[0] = alias_string + 1;
|
|
|
|
for (i = 1; i < argc; ++i)
|
|
|
|
alias_argv[i] = (*argv)[i];
|
|
|
|
alias_argv[argc] = NULL;
|
|
|
|
|
2011-05-26 11:37:13 +08:00
|
|
|
ret = run_command_v_opt(alias_argv, RUN_USING_SHELL);
|
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
|
|
|
|
2009-05-01 17:06:36 +08:00
|
|
|
new_argv = xrealloc(new_argv, sizeof(char *) *
|
2009-07-01 04:24:13 +08:00
|
|
|
(count + *argcp));
|
2006-07-30 09:30:29 +08:00
|
|
|
/* insert after command name */
|
2009-05-01 17:06:36 +08:00
|
|
|
memcpy(new_argv + count, *argv + 1, sizeof(char *) * *argcp);
|
2006-06-06 01:43:52 +08:00
|
|
|
|
2006-07-30 09:30:29 +08:00
|
|
|
*argv = new_argv;
|
|
|
|
*argcp += count - 1;
|
2006-06-06 01:43:52 +08:00
|
|
|
|
2006-07-30 09:30:29 +08:00
|
|
|
ret = 1;
|
2006-06-06 01:43:52 +08:00
|
|
|
}
|
|
|
|
|
2008-12-05 08:36:46 +08:00
|
|
|
if (subdir && chdir(subdir))
|
2009-06-27 23:58:46 +08:00
|
|
|
die_errno("Cannot change to '%s'", subdir);
|
2006-06-06 01:43:52 +08:00
|
|
|
|
2006-06-28 18:45:27 +08:00
|
|
|
errno = saved_errno;
|
|
|
|
|
2006-06-06 01:43:52 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-08-06 10:52:16 +08:00
|
|
|
#define RUN_SETUP (1<<0)
|
|
|
|
#define RUN_SETUP_GENTLY (1<<1)
|
|
|
|
#define USE_PAGER (1<<2)
|
2006-12-31 12:32:38 +08:00
|
|
|
/*
|
|
|
|
* require working tree to be present -- anything uses this needs
|
|
|
|
* RUN_SETUP for reading from the configuration file.
|
|
|
|
*/
|
2010-08-06 10:52:16 +08:00
|
|
|
#define NEED_WORK_TREE (1<<3)
|
2006-07-29 13:44:25 +08:00
|
|
|
|
2007-06-25 01:10:40 +08:00
|
|
|
struct cmd_struct {
|
|
|
|
const char *cmd;
|
|
|
|
int (*fn)(int, const char **, const char *);
|
|
|
|
int option;
|
|
|
|
};
|
|
|
|
|
2009-01-28 15:33:53 +08:00
|
|
|
static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
|
2007-06-25 01:10:40 +08:00
|
|
|
{
|
2009-11-09 23:05:01 +08:00
|
|
|
int status, help;
|
2007-06-25 01:29:33 +08:00
|
|
|
struct stat st;
|
2007-06-25 01:10:40 +08:00
|
|
|
const char *prefix;
|
|
|
|
|
|
|
|
prefix = NULL;
|
2009-11-09 23:05:01 +08:00
|
|
|
help = argc == 2 && !strcmp(argv[1], "-h");
|
|
|
|
if (!help) {
|
|
|
|
if (p->option & RUN_SETUP)
|
|
|
|
prefix = setup_git_directory();
|
2010-08-06 10:52:16 +08:00
|
|
|
if (p->option & RUN_SETUP_GENTLY) {
|
|
|
|
int nongit_ok;
|
|
|
|
prefix = setup_git_directory_gently(&nongit_ok);
|
|
|
|
}
|
2009-11-09 23:05:01 +08:00
|
|
|
|
2010-08-06 10:52:16 +08:00
|
|
|
if (use_pager == -1 && p->option & (RUN_SETUP | RUN_SETUP_GENTLY))
|
2009-11-09 23:05:01 +08:00
|
|
|
use_pager = check_pager_config(p->cmd);
|
|
|
|
if (use_pager == -1 && p->option & USE_PAGER)
|
|
|
|
use_pager = 1;
|
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();
|
|
|
|
|
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 },
|
|
|
|
{ "annotate", cmd_annotate, RUN_SETUP },
|
|
|
|
{ "apply", cmd_apply, RUN_SETUP_GENTLY },
|
|
|
|
{ "archive", cmd_archive },
|
|
|
|
{ "bisect--helper", cmd_bisect__helper, RUN_SETUP },
|
|
|
|
{ "blame", cmd_blame, RUN_SETUP },
|
|
|
|
{ "branch", cmd_branch, RUN_SETUP },
|
|
|
|
{ "bundle", cmd_bundle, RUN_SETUP_GENTLY },
|
|
|
|
{ "cat-file", cmd_cat_file, RUN_SETUP },
|
|
|
|
{ "check-attr", cmd_check_attr, RUN_SETUP },
|
|
|
|
{ "check-ignore", cmd_check_ignore, RUN_SETUP | NEED_WORK_TREE },
|
|
|
|
{ "check-mailmap", cmd_check_mailmap, RUN_SETUP },
|
|
|
|
{ "check-ref-format", cmd_check_ref_format },
|
|
|
|
{ "checkout", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },
|
|
|
|
{ "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 },
|
|
|
|
{ "clone", cmd_clone },
|
|
|
|
{ "column", cmd_column, RUN_SETUP_GENTLY },
|
|
|
|
{ "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE },
|
|
|
|
{ "commit-tree", cmd_commit_tree, RUN_SETUP },
|
|
|
|
{ "config", cmd_config, RUN_SETUP_GENTLY },
|
|
|
|
{ "count-objects", cmd_count_objects, RUN_SETUP },
|
|
|
|
{ "credential", cmd_credential, RUN_SETUP_GENTLY },
|
|
|
|
{ "describe", cmd_describe, RUN_SETUP },
|
|
|
|
{ "diff", cmd_diff },
|
|
|
|
{ "diff-files", cmd_diff_files, RUN_SETUP | NEED_WORK_TREE },
|
|
|
|
{ "diff-index", cmd_diff_index, RUN_SETUP },
|
|
|
|
{ "diff-tree", cmd_diff_tree, RUN_SETUP },
|
|
|
|
{ "fast-export", cmd_fast_export, RUN_SETUP },
|
|
|
|
{ "fetch", cmd_fetch, RUN_SETUP },
|
|
|
|
{ "fetch-pack", cmd_fetch_pack, RUN_SETUP },
|
|
|
|
{ "fmt-merge-msg", cmd_fmt_merge_msg, RUN_SETUP },
|
|
|
|
{ "for-each-ref", cmd_for_each_ref, RUN_SETUP },
|
|
|
|
{ "format-patch", cmd_format_patch, RUN_SETUP },
|
|
|
|
{ "fsck", cmd_fsck, RUN_SETUP },
|
|
|
|
{ "fsck-objects", cmd_fsck, RUN_SETUP },
|
|
|
|
{ "gc", cmd_gc, RUN_SETUP },
|
|
|
|
{ "get-tar-commit-id", cmd_get_tar_commit_id },
|
|
|
|
{ "grep", cmd_grep, RUN_SETUP_GENTLY },
|
|
|
|
{ "hash-object", cmd_hash_object },
|
|
|
|
{ "help", cmd_help },
|
|
|
|
{ "index-pack", cmd_index_pack, RUN_SETUP_GENTLY },
|
|
|
|
{ "init", cmd_init_db },
|
|
|
|
{ "init-db", cmd_init_db },
|
|
|
|
{ "log", cmd_log, RUN_SETUP },
|
|
|
|
{ "ls-files", cmd_ls_files, RUN_SETUP },
|
|
|
|
{ "ls-remote", cmd_ls_remote, RUN_SETUP_GENTLY },
|
|
|
|
{ "ls-tree", cmd_ls_tree, RUN_SETUP },
|
|
|
|
{ "mailinfo", cmd_mailinfo },
|
|
|
|
{ "mailsplit", cmd_mailsplit },
|
|
|
|
{ "merge", cmd_merge, RUN_SETUP | NEED_WORK_TREE },
|
|
|
|
{ "merge-base", cmd_merge_base, RUN_SETUP },
|
|
|
|
{ "merge-file", cmd_merge_file, RUN_SETUP_GENTLY },
|
|
|
|
{ "merge-index", cmd_merge_index, RUN_SETUP },
|
|
|
|
{ "merge-ours", cmd_merge_ours, RUN_SETUP },
|
|
|
|
{ "merge-recursive", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
|
|
|
|
{ "merge-recursive-ours", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
|
|
|
|
{ "merge-recursive-theirs", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
|
|
|
|
{ "merge-subtree", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE },
|
|
|
|
{ "merge-tree", cmd_merge_tree, RUN_SETUP },
|
|
|
|
{ "mktag", cmd_mktag, RUN_SETUP },
|
|
|
|
{ "mktree", cmd_mktree, RUN_SETUP },
|
|
|
|
{ "mv", cmd_mv, RUN_SETUP | NEED_WORK_TREE },
|
|
|
|
{ "name-rev", cmd_name_rev, RUN_SETUP },
|
|
|
|
{ "notes", cmd_notes, RUN_SETUP },
|
|
|
|
{ "pack-objects", cmd_pack_objects, RUN_SETUP },
|
|
|
|
{ "pack-redundant", cmd_pack_redundant, RUN_SETUP },
|
|
|
|
{ "pack-refs", cmd_pack_refs, RUN_SETUP },
|
|
|
|
{ "patch-id", cmd_patch_id },
|
|
|
|
{ "pickaxe", cmd_blame, RUN_SETUP },
|
|
|
|
{ "prune", cmd_prune, RUN_SETUP },
|
|
|
|
{ "prune-packed", cmd_prune_packed, RUN_SETUP },
|
|
|
|
{ "push", cmd_push, RUN_SETUP },
|
|
|
|
{ "read-tree", cmd_read_tree, RUN_SETUP },
|
|
|
|
{ "receive-pack", cmd_receive_pack },
|
|
|
|
{ "reflog", cmd_reflog, RUN_SETUP },
|
|
|
|
{ "remote", cmd_remote, RUN_SETUP },
|
|
|
|
{ "remote-ext", cmd_remote_ext },
|
|
|
|
{ "remote-fd", cmd_remote_fd },
|
|
|
|
{ "repack", cmd_repack, RUN_SETUP },
|
|
|
|
{ "replace", cmd_replace, RUN_SETUP },
|
|
|
|
{ "rerere", cmd_rerere, RUN_SETUP },
|
|
|
|
{ "reset", cmd_reset, RUN_SETUP },
|
|
|
|
{ "rev-list", cmd_rev_list, RUN_SETUP },
|
|
|
|
{ "rev-parse", cmd_rev_parse },
|
|
|
|
{ "revert", cmd_revert, RUN_SETUP | NEED_WORK_TREE },
|
|
|
|
{ "rm", cmd_rm, RUN_SETUP },
|
|
|
|
{ "send-pack", cmd_send_pack, RUN_SETUP },
|
|
|
|
{ "shortlog", cmd_shortlog, RUN_SETUP_GENTLY | USE_PAGER },
|
|
|
|
{ "show", cmd_show, RUN_SETUP },
|
|
|
|
{ "show-branch", cmd_show_branch, RUN_SETUP },
|
|
|
|
{ "show-ref", cmd_show_ref, RUN_SETUP },
|
|
|
|
{ "stage", cmd_add, RUN_SETUP | NEED_WORK_TREE },
|
|
|
|
{ "status", cmd_status, RUN_SETUP | NEED_WORK_TREE },
|
|
|
|
{ "stripspace", cmd_stripspace },
|
|
|
|
{ "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
|
|
|
|
{ "tag", cmd_tag, RUN_SETUP },
|
|
|
|
{ "unpack-file", cmd_unpack_file, RUN_SETUP },
|
|
|
|
{ "unpack-objects", cmd_unpack_objects, RUN_SETUP },
|
|
|
|
{ "update-index", cmd_update_index, RUN_SETUP },
|
|
|
|
{ "update-ref", cmd_update_ref, RUN_SETUP },
|
|
|
|
{ "update-server-info", cmd_update_server_info, RUN_SETUP },
|
|
|
|
{ "upload-archive", cmd_upload_archive },
|
|
|
|
{ "upload-archive--writer", cmd_upload_archive_writer },
|
|
|
|
{ "var", cmd_var, RUN_SETUP_GENTLY },
|
|
|
|
{ "verify-pack", cmd_verify_pack },
|
|
|
|
{ "verify-tag", cmd_verify_tag, RUN_SETUP },
|
|
|
|
{ "version", cmd_version },
|
|
|
|
{ "whatchanged", cmd_whatchanged, RUN_SETUP },
|
|
|
|
{ "write-tree", cmd_write_tree, RUN_SETUP },
|
|
|
|
};
|
|
|
|
|
|
|
|
int is_builtin(const char *s)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(commands); i++) {
|
|
|
|
struct cmd_struct *p = commands+i;
|
|
|
|
if (!strcmp(s, p->cmd))
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
|
|
|
const char *cmd = argv[0];
|
|
|
|
int i;
|
2007-12-09 03:57:25 +08:00
|
|
|
static const char ext[] = STRIP_EXTENSION;
|
|
|
|
|
|
|
|
if (sizeof(ext) > 1) {
|
|
|
|
i = strlen(argv[0]) - strlen(ext);
|
|
|
|
if (i > 0 && !strcmp(argv[0] + i, ext)) {
|
2008-09-10 02:57:10 +08:00
|
|
|
char *argv0 = xstrdup(argv[0]);
|
2007-12-09 03:57:25 +08:00
|
|
|
argv[0] = cmd = argv0;
|
|
|
|
argv0[i] = '\0';
|
|
|
|
}
|
|
|
|
}
|
Teach the "git" command to handle some commands internally
This is another patch in the "prepare to do more in C" series, where the
git wrapper command is taught about the notion of handling some
functionality internally.
Right now, the only internal commands are "version" and "help", but the
point being that we can now easily extend it to handle some of the trivial
scripts internally. Things like "git log" and "git diff" wouldn't need
separate external scripts any more.
This also implies that to support the old "git-log" and "git-diff" syntax,
the "git" wrapper now automatically looks at the name it was executed as,
and if it is "git-xxxx", it will assume that it is to internally do what
"git xxxx" would do.
In other words, you can (once you implement an internal command) soft- or
hard-link that command to the "git" wrapper command, and it will do the
right thing, whether you use the "git xxxx" or the "git-xxxx" format.
There's one other change: the search order for external programs is
modified slightly, so that the first entry remains GIT_EXEC_DIR, but the
second entry is the same directory as the git wrapper itself was executed
out of - if we can figure it out from argv[0], of course.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-27 04:34:51 +08:00
|
|
|
|
2006-04-16 02:13:49 +08:00
|
|
|
/* Turn "git cmd --help" into "git help cmd" */
|
|
|
|
if (argc > 1 && !strcmp(argv[1], "--help")) {
|
|
|
|
argv[1] = argv[0];
|
|
|
|
argv[0] = cmd = "help";
|
|
|
|
}
|
|
|
|
|
Teach the "git" command to handle some commands internally
This is another patch in the "prepare to do more in C" series, where the
git wrapper command is taught about the notion of handling some
functionality internally.
Right now, the only internal commands are "version" and "help", but the
point being that we can now easily extend it to handle some of the trivial
scripts internally. Things like "git log" and "git diff" wouldn't need
separate external scripts any more.
This also implies that to support the old "git-log" and "git-diff" syntax,
the "git" wrapper now automatically looks at the name it was executed as,
and if it is "git-xxxx", it will assume that it is to internally do what
"git xxxx" would do.
In other words, you can (once you implement an internal command) soft- or
hard-link that command to the "git" wrapper command, and it will do the
right thing, whether you use the "git xxxx" or the "git-xxxx" format.
There's one other change: the search order for external programs is
modified slightly, so that the first entry remains GIT_EXEC_DIR, but the
second entry is the same directory as the git wrapper itself was executed
out of - if we can figure it out from argv[0], of course.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-27 04:34:51 +08:00
|
|
|
for (i = 0; i < ARRAY_SIZE(commands); i++) {
|
|
|
|
struct cmd_struct *p = commands+i;
|
|
|
|
if (strcmp(p->cmd, cmd))
|
|
|
|
continue;
|
2009-01-28 15:33:53 +08:00
|
|
|
exit(run_builtin(p, argc, argv));
|
Teach the "git" command to handle some commands internally
This is another patch in the "prepare to do more in C" series, where the
git wrapper command is taught about the notion of handling some
functionality internally.
Right now, the only internal commands are "version" and "help", but the
point being that we can now easily extend it to handle some of the trivial
scripts internally. Things like "git log" and "git diff" wouldn't need
separate external scripts any more.
This also implies that to support the old "git-log" and "git-diff" syntax,
the "git" wrapper now automatically looks at the name it was executed as,
and if it is "git-xxxx", it will assume that it is to internally do what
"git xxxx" would do.
In other words, you can (once you implement an internal command) soft- or
hard-link that command to the "git" wrapper command, and it will do the
right thing, whether you use the "git xxxx" or the "git-xxxx" format.
There's one other change: the search order for external programs is
modified slightly, so that the first entry remains GIT_EXEC_DIR, but the
second entry is the same directory as the git wrapper itself was executed
out of - if we can figure it out from argv[0], of course.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-27 04:34:51 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-12-02 14:09:22 +08:00
|
|
|
static void execv_dashed_external(const char **argv)
|
|
|
|
{
|
2008-10-10 03:12:12 +08:00
|
|
|
struct strbuf cmd = STRBUF_INIT;
|
2007-12-02 14:09:22 +08:00
|
|
|
const char *tmp;
|
2009-01-28 15:38:14 +08:00
|
|
|
int status;
|
2007-12-02 14:09:22 +08:00
|
|
|
|
2011-08-19 06:01:32 +08:00
|
|
|
if (use_pager == -1)
|
|
|
|
use_pager = check_pager_config(argv[0]);
|
2010-07-15 06:55:12 +08:00
|
|
|
commit_pager_choice();
|
|
|
|
|
2007-12-02 14:09:22 +08:00
|
|
|
strbuf_addf(&cmd, "git-%s", argv[0]);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* argv[0] must be the git command, but the argv array
|
|
|
|
* belongs to the caller, and may be reused in
|
|
|
|
* subsequent loop iterations. Save argv[0] and
|
|
|
|
* restore it on error.
|
|
|
|
*/
|
|
|
|
tmp = argv[0];
|
|
|
|
argv[0] = cmd.buf;
|
|
|
|
|
|
|
|
trace_argv_printf(argv, "trace: exec:");
|
|
|
|
|
2009-01-28 15:38:14 +08:00
|
|
|
/*
|
|
|
|
* if we fail because the command is not found, it is
|
|
|
|
* OK to return. Otherwise, we just pass along the status code.
|
|
|
|
*/
|
2012-01-09 04:41:09 +08:00
|
|
|
status = run_command_v_opt(argv, RUN_SILENT_EXEC_FAILURE | RUN_CLEAN_ON_EXIT);
|
run_command: report system call errors instead of returning error codes
The motivation for this change is that system call failures are serious
errors that should be reported to the user, but only few callers took the
burden to decode the error codes that the functions returned into error
messages.
If at all, then only an unspecific error message was given. A prominent
example is this:
$ git upload-pack . | :
fatal: unable to run 'git-upload-pack'
In this example, git-upload-pack, the external command invoked through the
git wrapper, dies due to SIGPIPE, but the git wrapper does not bother to
report the real cause. In fact, this very error message is copied to the
syslog if git-daemon's client aborts the connection early.
With this change, system call failures are reported immediately after the
failure and only a generic failure code is returned to the caller. In the
above example the error is now to the point:
$ git upload-pack . | :
error: git-upload-pack died of signal
Note that there is no error report if the invoked program terminated with
a non-zero exit code, because it is reasonable to expect that the invoked
program has already reported an error. (But many run_command call sites
nevertheless write a generic error message.)
There was one special return code that was used to identify the case where
run_command failed because the requested program could not be exec'd. This
special case is now treated like a system call failure with errno set to
ENOENT. No error is reported in this case, because the call site in git.c
expects this as a normal result. Therefore, the callers that carefully
decoded the return value still check for this condition.
Signed-off-by: Johannes Sixt <j6t@kdbg.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-07-05 03:26:40 +08:00
|
|
|
if (status >= 0 || errno != ENOENT)
|
2009-07-05 03:26:39 +08:00
|
|
|
exit(status);
|
2007-12-02 14:09:22 +08:00
|
|
|
|
|
|
|
argv[0] = tmp;
|
|
|
|
|
|
|
|
strbuf_release(&cmd);
|
|
|
|
}
|
|
|
|
|
2009-01-05 01:16:01 +08:00
|
|
|
static int run_argv(int *argcp, const char ***argv)
|
|
|
|
{
|
|
|
|
int done_alias = 0;
|
|
|
|
|
|
|
|
while (1) {
|
2014-01-03 00:15:44 +08:00
|
|
|
/* See if it's a builtin */
|
|
|
|
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
|
|
|
|
*/
|
|
|
|
if (done_alias || !handle_alias(argcp, argv))
|
|
|
|
break;
|
|
|
|
done_alias = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return done_alias;
|
|
|
|
}
|
|
|
|
|
2007-12-02 14:09:22 +08:00
|
|
|
|
2013-04-28 03:19:47 +08:00
|
|
|
int main(int argc, char **av)
|
2005-11-16 07:31:25 +08:00
|
|
|
{
|
2013-04-28 03:19:47 +08:00
|
|
|
const char **argv = (const char **) av;
|
2009-01-18 20:00:10 +08:00
|
|
|
const char *cmd;
|
Teach the "git" command to handle some commands internally
This is another patch in the "prepare to do more in C" series, where the
git wrapper command is taught about the notion of handling some
functionality internally.
Right now, the only internal commands are "version" and "help", but the
point being that we can now easily extend it to handle some of the trivial
scripts internally. Things like "git log" and "git diff" wouldn't need
separate external scripts any more.
This also implies that to support the old "git-log" and "git-diff" syntax,
the "git" wrapper now automatically looks at the name it was executed as,
and if it is "git-xxxx", it will assume that it is to internally do what
"git xxxx" would do.
In other words, you can (once you implement an internal command) soft- or
hard-link that command to the "git" wrapper command, and it will do the
right thing, whether you use the "git xxxx" or the "git-xxxx" format.
There's one other change: the search order for external programs is
modified slightly, so that the first entry remains GIT_EXEC_DIR, but the
second entry is the same directory as the git wrapper itself was executed
out of - if we can figure it out from argv[0], of course.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-27 04:34:51 +08:00
|
|
|
|
2010-08-06 10:40:35 +08:00
|
|
|
startup_info = &git_startup_info;
|
|
|
|
|
2009-01-18 20:00:11 +08:00
|
|
|
cmd = git_extract_argv0_path(argv[0]);
|
|
|
|
if (!cmd)
|
2009-01-18 20:00:10 +08:00
|
|
|
cmd = "git-help";
|
2005-11-16 07:31:25 +08:00
|
|
|
|
2013-07-16 17:27:37 +08:00
|
|
|
/*
|
|
|
|
* Always open file descriptors 0/1/2 to avoid clobbering files
|
|
|
|
* in die(). It also avoids messing up when the pipes are dup'ed
|
|
|
|
* onto stdin/stdout/stderr in the child processes we spawn.
|
|
|
|
*/
|
|
|
|
sanitize_stdfds();
|
|
|
|
|
i18n: add infrastructure for translating Git with gettext
Change the skeleton implementation of i18n in Git to one that can show
localized strings to users for our C, Shell and Perl programs using
either GNU libintl or the Solaris gettext implementation.
This new internationalization support is enabled by default. If
gettext isn't available, or if Git is compiled with
NO_GETTEXT=YesPlease, Git falls back on its current behavior of
showing interface messages in English. When using the autoconf script
we'll auto-detect if the gettext libraries are installed and act
appropriately.
This change is somewhat large because as well as adding a C, Shell and
Perl i18n interface we're adding a lot of tests for them, and for
those tests to work we need a skeleton PO file to actually test
translations. A minimal Icelandic translation is included for this
purpose. Icelandic includes multi-byte characters which makes it easy
to test various edge cases, and it's a language I happen to
understand.
The rest of the commit message goes into detail about various
sub-parts of this commit.
= Installation
Gettext .mo files will be installed and looked for in the standard
$(prefix)/share/locale path. GIT_TEXTDOMAINDIR can also be set to
override that, but that's only intended to be used to test Git itself.
= Perl
Perl code that's to be localized should use the new Git::I18n
module. It imports a __ function into the caller's package by default.
Instead of using the high level Locale::TextDomain interface I've
opted to use the low-level (equivalent to the C interface)
Locale::Messages module, which Locale::TextDomain itself uses.
Locale::TextDomain does a lot of redundant work we don't need, and
some of it would potentially introduce bugs. It tries to set the
$TEXTDOMAIN based on package of the caller, and has its own
hardcoded paths where it'll search for messages.
I found it easier just to completely avoid it rather than try to
circumvent its behavior. In any case, this is an issue wholly
internal Git::I18N. Its guts can be changed later if that's deemed
necessary.
See <AANLkTilYD_NyIZMyj9dHtVk-ylVBfvyxpCC7982LWnVd@mail.gmail.com> for
a further elaboration on this topic.
= Shell
Shell code that's to be localized should use the git-sh-i18n
library. It's basically just a wrapper for the system's gettext.sh.
If gettext.sh isn't available we'll fall back on gettext(1) if it's
available. The latter is available without the former on Solaris,
which has its own non-GNU gettext implementation. We also need to
emulate eval_gettext() there.
If neither are present we'll use a dumb printf(1) fall-through
wrapper.
= About libcharset.h and langinfo.h
We use libcharset to query the character set of the current locale if
it's available. I.e. we'll use it instead of nl_langinfo if
HAVE_LIBCHARSET_H is set.
The GNU gettext manual recommends using langinfo.h's
nl_langinfo(CODESET) to acquire the current character set, but on
systems that have libcharset.h's locale_charset() using the latter is
either saner, or the only option on those systems.
GNU and Solaris have a nl_langinfo(CODESET), FreeBSD can use either,
but MinGW and some others need to use libcharset.h's locale_charset()
instead.
=Credits
This patch is based on work by Jeff Epler <jepler@unpythonic.net> who
did the initial Makefile / C work, and a lot of comments from the Git
mailing list, including Jonathan Nieder, Jakub Narebski, Johannes
Sixt, Erik Faye-Lund, Peter Krefting, Junio C Hamano, Thomas Rast and
others.
[jc: squashed a small Makefile fix from Ramsay]
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-11-18 07:14:42 +08:00
|
|
|
git_setup_gettext();
|
|
|
|
|
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
|
|
|
*/
|
2013-12-01 04:55:40 +08:00
|
|
|
if (starts_with(cmd, "git-")) {
|
Teach the "git" command to handle some commands internally
This is another patch in the "prepare to do more in C" series, where the
git wrapper command is taught about the notion of handling some
functionality internally.
Right now, the only internal commands are "version" and "help", but the
point being that we can now easily extend it to handle some of the trivial
scripts internally. Things like "git log" and "git diff" wouldn't need
separate external scripts any more.
This also implies that to support the old "git-log" and "git-diff" syntax,
the "git" wrapper now automatically looks at the name it was executed as,
and if it is "git-xxxx", it will assume that it is to internally do what
"git xxxx" would do.
In other words, you can (once you implement an internal command) soft- or
hard-link that command to the "git" wrapper command, and it will do the
right thing, whether you use the "git xxxx" or the "git-xxxx" format.
There's one other change: the search order for external programs is
modified slightly, so that the first entry remains GIT_EXEC_DIR, but the
second entry is the same directory as the git wrapper itself was executed
out of - if we can figure it out from argv[0], of course.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-02-27 04:34:51 +08:00
|
|
|
cmd += 4;
|
|
|
|
argv[0] = cmd;
|
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) {
|
2013-12-01 04:55:40 +08:00
|
|
|
if (starts_with(argv[0], "--"))
|
2006-07-26 02:24:22 +08:00
|
|
|
argv[0] += 2;
|
|
|
|
} else {
|
2007-10-27 16:36:49 +08:00
|
|
|
/* The user didn't specify a command; give them help */
|
git --paginate: do not commit pager choice too early
When git is passed the --paginate option, starting up a pager requires
deciding what pager to start, which requires access to the core.pager
configuration.
At the relevant moment, the repository has not been searched for yet.
Attempting to access the configuration at this point results in
git_dir being set to .git [*], which is almost certainly not what was
wanted. In particular, when run from a subdirectory of the toplevel,
git --paginate does not respect the core.pager setting from the
current repository.
[*] unless GIT_DIR or GIT_CONFIG is set
So delay the pager startup when possible:
1. run_argv() already commits pager choice inside run_builtin() if a
command is found. For commands that use RUN_SETUP, waiting until
then fixes the problem described above: once git knows where to
look, it happily respects the core.pager setting.
2. list_common_cmds_help() prints out 29 lines and exits. This can
benefit from pagination, so we need to commit the pager choice
before writing this output.
Luckily ‘git’ without subcommand has no other reason to access a
repository, so it would be intuitive to ignore repository-local
configuration in this case. Simpler for now to choose a pager
using the funny code that notices a repository that happens to be
at .git. That this accesses a repository when it is very
convenient to is a bug but not an important one.
3. help_unknown_cmd() prints out a few lines to stderr. It is not
important to paginate this, so don’t.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Acked-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-06-27 03:26:37 +08:00
|
|
|
commit_pager_choice();
|
2007-10-27 16:36:49 +08:00
|
|
|
printf("usage: %s\n\n", git_usage_string);
|
|
|
|
list_common_cmds_help();
|
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) {
|
2009-01-05 01:16:01 +08:00
|
|
|
static int done_help = 0;
|
|
|
|
static int was_alias = 0;
|
|
|
|
was_alias = run_argv(&argc, &argv);
|
|
|
|
if (errno != ENOENT)
|
2006-06-06 09:09:40 +08:00
|
|
|
break;
|
2009-01-05 01:16:01 +08:00
|
|
|
if (was_alias) {
|
2007-02-11 08:33:57 +08:00
|
|
|
fprintf(stderr, "Expansion of alias '%s' failed; "
|
2010-02-16 07:33:18 +08:00
|
|
|
"'%s' is not a git command\n",
|
2007-02-11 08:33:57 +08:00
|
|
|
cmd, argv[0]);
|
|
|
|
exit(1);
|
|
|
|
}
|
2009-01-05 01:16:01 +08:00
|
|
|
if (!done_help) {
|
|
|
|
cmd = argv[0] = help_unknown_cmd(cmd);
|
|
|
|
done_help = 1;
|
|
|
|
} else
|
|
|
|
break;
|
2007-02-11 08:33:57 +08:00
|
|
|
}
|
2005-12-01 20:48:35 +08:00
|
|
|
|
|
|
|
fprintf(stderr, "Failed to run command '%s': %s\n",
|
2006-06-28 17:17:21 +08:00
|
|
|
cmd, strerror(errno));
|
2005-11-16 07:31:25 +08:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|