If you have a config containing something like this:
authorJohannes Schindelin <Johannes.Schindelin@gmx.de>
Mon, 5 Jun 2006 17:43:52 +0000 (19:43 +0200)
committerJunio C Hamano <junkio@cox.net>
Tue, 6 Jun 2006 00:49:17 +0000 (17:49 -0700)
[alias]
l = "log --stat -M ORIG_HEAD.."

you can call

git l

and it will do the same as

git log --stat -M ORIG_HEAD..

Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Junio C Hamano <junkio@cox.net>
git.c

diff --git a/git.c b/git.c
index bc463c9..8854472 100644 (file)
--- a/git.c
+++ b/git.c
@@ -10,6 +10,7 @@
 #include <stdarg.h>
 #include "git-compat-util.h"
 #include "exec_cmd.h"
+#include "cache.h"
 
 #include "builtin.h"
 
@@ -32,6 +33,113 @@ static void prepend_to_path(const char *dir, int len)
        setenv("PATH", path, 1);
 }
 
+static const char *alias_command;
+static char *alias_string = NULL;
+
+static int git_alias_config(const char *var, const char *value)
+{
+       if (!strncmp(var, "alias.", 6) && !strcmp(var + 6, alias_command)) {
+               alias_string = strdup(value);
+       }
+       return 0;
+}
+
+static int split_cmdline(char *cmdline, const char ***argv)
+{
+       int src, dst, count = 0, size = 16;
+       char quoted = 0;
+
+       *argv = malloc(sizeof(char*) * size);
+
+       /* split alias_string */
+       (*argv)[count++] = cmdline;
+       for (src = dst = 0; cmdline[src];) {
+               char c = cmdline[src];
+               if (!quoted && isspace(c)) {
+                       cmdline[dst++] = 0;
+                       while (cmdline[++src]
+                                       && isspace(cmdline[src]))
+                               ; /* skip */
+                       if (count >= size) {
+                               size += 16;
+                               *argv = realloc(*argv, sizeof(char*) * size);
+                       }
+                       (*argv)[count++] = cmdline + dst;
+               } else if(!quoted && (c == '\'' || c == '"')) {
+                       quoted = c;
+                       src++;
+               } else if (c == quoted) {
+                       quoted = 0;
+                       src++;
+               } else {
+                       if (c == '\\' && quoted != '\'') {
+                               src++;
+                               c = cmdline[src];
+                               if (!c) {
+                                       free(*argv);
+                                       *argv = NULL;
+                                       return error("cmdline ends with \\");
+                               }
+                       }
+                       cmdline[dst++] = c;
+                       src++;
+               }
+       }
+
+       cmdline[dst] = 0;
+
+       if (quoted) {
+               free(*argv);
+               *argv = NULL;
+               return error("unclosed quote");
+       }
+
+       return count;
+}
+
+static int handle_alias(int *argcp, const char ***argv)
+{
+       int nongit = 0, ret = 0;
+       const char *subdir;
+
+       subdir = setup_git_directory_gently(&nongit);
+       if (!nongit) {
+               int count;
+               const char** new_argv;
+
+               alias_command = (*argv)[0];
+               git_config(git_alias_config);
+               if (alias_string) {
+
+                       count = split_cmdline(alias_string, &new_argv);
+
+                       if (count < 1)
+                               die("empty alias for %s", alias_command);
+
+                       if (!strcmp(alias_command, new_argv[0]))
+                               die("recursive alias: %s", alias_command);
+
+                       /* insert after command name */
+                       if (*argcp > 1) {
+                               new_argv = realloc(new_argv, sizeof(char*) *
+                                               (count + *argcp - 1));
+                               memcpy(new_argv + count, *argv, sizeof(char*) *
+                                               (*argcp - 1));
+                       }
+
+                       *argv = new_argv;
+                       *argcp += count - 1;
+
+                       ret = 1;
+               }
+       }
+
+       if (subdir)
+               chdir(subdir);
+
+       return ret;
+}
+
 const char git_version_string[] = GIT_VERSION;
 
 static void handle_internal_command(int argc, const char **argv, char **envp)
@@ -121,6 +229,7 @@ int main(int argc, const char **argv, char **envp)
        if (!strncmp(cmd, "git-", 4)) {
                cmd += 4;
                argv[0] = cmd;
+               handle_alias(&argc, &argv);
                handle_internal_command(argc, argv, envp);
                die("cannot handle %s internally", cmd);
        }
@@ -178,6 +287,8 @@ int main(int argc, const char **argv, char **envp)
        exec_path = git_exec_path();
        prepend_to_path(exec_path, strlen(exec_path));
 
+       handle_alias(&argc, &argv);
+
        /* See if it's an internal command */
        handle_internal_command(argc, argv, envp);