alias.*::
- Command aliases for the linkgit:git[1] command wrapper - e.g.
- after defining `alias.last = cat-file commit HEAD`, the invocation
- `git last` is equivalent to `git cat-file commit HEAD`. To avoid
- confusion and troubles with script usage, aliases that
- hide existing Git commands are ignored except for deprecated
- commands. Arguments are split by
- spaces, the usual shell quoting and escaping are supported.
- A quote pair or a backslash can be used to quote them.
+alias.*.command::
+ Command aliases for the linkgit:git[1] command wrapper. Aliases
+ can be defined using two syntaxes:
++
+--
+1. Without a subsection, e.g., `[alias] co = checkout`. The alias
+ name ("co" in this example) is
+ limited to ASCII alphanumeric characters and `-`,
+ and is matched case-insensitively.
+2. With a subsection, e.g., `[alias "co"] command = checkout`. The
+ alias name can contain any characters (except for newlines and NUL bytes),
+ including UTF-8, and is matched case-sensitively as raw bytes.
+ You define the action of the alias in the `command`.
+--
++
+Examples:
++
+----
+# Without subsection (ASCII alphanumeric and dash only)
+[alias]
+ co = checkout
+ st = status
+
+# With subsection (allows any characters, including UTF-8)
+[alias "hämta"]
+ command = fetch
+[alias "rätta till"]
+ command = commit --amend
+----
++
+With a Git alias defined, e.g.,
+
+ $ git config --global alias.last "cat-file commit HEAD"
+ # Which is equivalent to
+ $ git config --global alias.last.command "cat-file commit HEAD"
+
+`git last` is equivalent to `git cat-file commit HEAD`. To avoid
+confusion and troubles with script usage, aliases that
+hide existing Git commands are ignored except for deprecated
+commands. Arguments are split by
+spaces, the usual shell quoting and escaping are supported.
+A quote pair or a backslash can be used to quote them.
+
Note that the first word of an alias does not necessarily have to be a
command. It can be a command-line option that will be passed into the
struct string_list *list;
};
-static int config_alias_cb(const char *key, const char *value,
+static int config_alias_cb(const char *var, const char *value,
const struct config_context *ctx UNUSED, void *d)
{
struct config_alias_data *data = d;
- const char *p;
+ const char *subsection, *key;
+ size_t subsection_len;
- if (!skip_prefix(key, "alias.", &p))
+ if (parse_config_key(var, "alias", &subsection, &subsection_len,
+ &key) < 0)
+ return 0;
+
+ /*
+ * Two config syntaxes:
+ * - alias.name = value (without subsection, case-insensitive)
+ * - [alias "name"]
+ * command = value (with subsection, case-sensitive)
+ */
+ if (subsection && strcmp(key, "command"))
return 0;
if (data->alias) {
- if (!strcasecmp(p, data->alias)) {
+ int match;
+
+ if (subsection)
+ match = (strlen(data->alias) == subsection_len &&
+ !strncmp(data->alias, subsection,
+ subsection_len));
+ else
+ match = !strcasecmp(data->alias, key);
+
+ if (match) {
FREE_AND_NULL(data->v);
return git_config_string(&data->v,
- key, value);
+ var, value);
}
} else if (data->list) {
struct string_list_item *item;
if (!value)
- return config_error_nonbool(key);
+ return config_error_nonbool(var);
- item = string_list_append(data->list, p);
+ if (subsection)
+ item = string_list_append_nodup(data->list,
+ xmemdupz(subsection, subsection_len));
+ else
+ item = string_list_append(data->list, key);
item->util = xstrdup(value);
}
#include "fsmonitor-ipc.h"
#include "repository.h"
#include "alias.h"
+#include "utf8.h"
#ifndef NO_CURL
#include "git-curl-compat.h" /* For LIBCURL_VERSION only */
for (i = 0; cmds[i].name; i++) {
if (cmds[i].category & mask) {
- size_t len = strlen(cmds[i].name);
+ size_t len = utf8_strwidth(cmds[i].name);
printf(" %s ", cmds[i].name);
if (longest > len)
mput_char(' ', longest - len);
string_list_sort(&alias_list);
for (i = 0; i < alias_list.nr; i++) {
- size_t len = strlen(alias_list.items[i].string);
+ size_t len = utf8_strwidth(alias_list.items[i].string);
if (longest < len)
longest = len;
}
/* Also use aliases for command lookup */
if (!parse_config_key(var, "alias", &subsection, &subsection_len,
&key)) {
- if (!subsection)
+ if (subsection) {
+ /* [alias "name"] command = value */
+ if (!strcmp(key, "command"))
+ add_cmdname(&cfg->aliases, subsection,
+ subsection_len);
+ } else {
+ /* alias.name = value */
add_cmdname(&cfg->aliases, key, strlen(key));
+ }
}
return 0;
test_grep "alias.noval" error
'
+test_expect_success 'subsection syntax works' '
+ test_config alias.testnew.command "!echo ran-subsection" &&
+ git testnew >output &&
+ test_grep "ran-subsection" output
+'
+
+test_expect_success 'subsection syntax only accepts command key' '
+ test_config alias.invalid.notcommand value &&
+ test_must_fail git invalid 2>error &&
+ test_grep -i "not a git command" error
+'
+
+test_expect_success 'subsection syntax requires value for command' '
+ test_when_finished "git config --remove-section alias.noval" &&
+ cat >>.git/config <<-\EOF &&
+ [alias "noval"]
+ command
+ EOF
+ test_must_fail git noval 2>error &&
+ test_grep "alias.noval.command" error
+'
+
+test_expect_success 'simple syntax is case-insensitive' '
+ test_config alias.LegacyCase "!echo ran-legacy" &&
+ git legacycase >output &&
+ test_grep "ran-legacy" output
+'
+
+test_expect_success 'subsection syntax is case-sensitive' '
+ test_config alias.SubCase.command "!echo ran-upper" &&
+ test_config alias.subcase.command "!echo ran-lower" &&
+ git SubCase >upper.out &&
+ git subcase >lower.out &&
+ test_grep "ran-upper" upper.out &&
+ test_grep "ran-lower" lower.out
+'
+
+test_expect_success 'UTF-8 alias with Swedish characters' '
+ test_config alias."förgrena".command "!echo ran-swedish" &&
+ git förgrena >output &&
+ test_grep "ran-swedish" output
+'
+
+test_expect_success 'UTF-8 alias with CJK characters' '
+ test_config alias."分支".command "!echo ran-cjk" &&
+ git 分支 >output &&
+ test_grep "ran-cjk" output
+'
+
+test_expect_success 'alias with spaces in name' '
+ test_config alias."test name".command "!echo ran-spaces" &&
+ git "test name" >output &&
+ test_grep "ran-spaces" output
+'
+
+test_expect_success 'subsection aliases listed in help -a' '
+ test_config alias."förgrena".command "!echo test" &&
+ git help -a >output &&
+ test_grep "förgrena" output
+'
+
test_done