Subject: Re: [PATCH] prepare deprecation of git-revert

From: Nguyen Thai Ngoc Duy <[email-masked]>
Date: Sun, 2 Nov 2008 16:32:25 +0700

On Fri, Oct 31, 2008 at 05:50:03PM +0100, Alex Riesen wrote:
> Pierre Habouzit, Fri, Oct 31, 2008 16:55:27 +0100:
> > @@ -439,16 +436,17 @@ static int revert_or_cherry_pick(int argc, const char **argv)
> >  
> >  int cmd_revert(int argc, const char **argv, const char *prefix)
> >  {
> > +#if 0
> > +	warning("git revert is deprecated, please use git cherry-pick --revert/-R instead");
> > +#endif
> 
> "git revert" is much shorter to type than "git cherry-pick -R".
> How about renaming "cherry-pick" into something short, like "pick"?

Maybe a patch like this can help? With it you can type "git cp" for
cherry-pick. If someday "git cp" is added, you can type "git c-p",
much shorter.

--<--
commit dce5cad329390905bb91115a9de0153772be57d8
Author: Nguyễn Thái Ngọc Duy <[email-masked]>
Date:   Sat Nov 1 17:12:04 2008 +0700

    Add git command expansion
    
    This allows git commands to be typed shorter (in shells that do not
    support autocompletion). There are three types of expansion:
    
     - "foo" matches "foo*" commands (bi -> bisect)
     - "foo" also matches "f*-oo*" (fim -> fast-import)
     - "foo-bar" (with dash) matches "foo*-bar*" (fo-p -> format-patch)
    
    This feature is only enabled if core.commandexpansion is true. It
    may work better if we can limit the command set (to porcelain
    only for example) but I have yet to find a way to pull
    commands-list.txt to help.c.

diff --git a/builtin.h b/builtin.h
index 1495cf6..9fb0fef 100644
--- a/builtin.h
+++ b/builtin.h
@@ -12,6 +12,7 @@ extern const char git_more_info_string[];
 
 extern void list_common_cmds_help(void);
 extern const char *help_unknown_cmd(const char *cmd);
+extern const char *expand_command(const char *cmd);
 extern void prune_packed_objects(int);
 extern int read_line_with_nul(char *buf, int size, FILE *file);
 extern int fmt_merge_msg(int merge_summary, struct strbuf *in,
diff --git a/git.c b/git.c
index 89feb0b..1bbe340 100644
--- a/git.c
+++ b/git.c
@@ -14,6 +14,7 @@ struct pager_config {
 	const char *cmd;
 	int val;
 };
+static int command_expansion;
 
 static int pager_command_config(const char *var, const char *value, void *data)
 {
@@ -415,6 +416,13 @@ static void execv_dashed_external(const char **argv)
 	strbuf_release(&cmd);
 }
 
+static int git_command_expansion_config(const char *var, const char *value, void *cb)
+{
+	if (!strcmp(var, "core.commandexpansion"))
+		command_expansion = git_config_bool(var, value);
+
+	return git_default_config(var, value, cb);
+}
 
 int main(int argc, const char **argv)
 {
@@ -501,6 +509,15 @@ int main(int argc, const char **argv)
 				cmd, argv[0]);
 			exit(1);
 		}
+		git_config(git_command_expansion_config, NULL);
+		if (command_expansion) {
+			const char *expand_cmd = expand_command(cmd);
+			if (expand_cmd) {
+				argv[0] = expand_cmd;
+				handle_internal_command(argc, argv);
+				execv_dashed_external(argv);
+			}
+		}
 		argv[0] = help_unknown_cmd(cmd);
 		handle_internal_command(argc, argv);
 		execv_dashed_external(argv);
diff --git a/help.c b/help.c
index fd87bb5..4f0e5a0 100644
--- a/help.c
+++ b/help.c
@@ -359,6 +359,67 @@ const char *help_unknown_cmd(const char *cmd)
 	exit(1);
 }
 
+const char *expand_command(const char *cmd)
+{
+	int i, n, len;
+	struct cmdnames main_cmds, other_cmds;
+	char *src, *dst;
+
+	memset(&main_cmds, 0, sizeof(main_cmds));
+	memset(&other_cmds, 0, sizeof(main_cmds));
+
+	load_command_list("git-", &main_cmds, &other_cmds);
+
+	add_cmd_list(&main_cmds, &aliases);
+	add_cmd_list(&main_cmds, &other_cmds);
+	qsort(main_cmds.names, main_cmds.cnt,
+	      sizeof(main_cmds.names), cmdname_compare);
+	uniq(&main_cmds);
+
+	len = strlen(cmd);
+	n = -1;
+	src = strchr(cmd, '-');
+	for (i = 0;i < main_cmds.cnt; i++) {
+		const char *gitcmd = main_cmds.names[i]->name;
+
+		/* match prefix */
+		if (!strncmp(cmd, gitcmd, len))
+			goto ok_expand;
+
+		if (*cmd != *gitcmd)
+			continue;
+		dst = strchr(gitcmd, '-');
+		if (!dst)
+			continue;
+
+		/* cmd is foo-bar, match foo*-bar* */
+		if (src &&
+		    !strncmp(cmd, gitcmd, src-cmd) &&
+		    !strncmp(src+1, dst+1, cmd+len-src-1))
+			goto ok_expand;
+
+		/* cmd is foobar,match f*-oobar* */
+		if (!src && !strncmp(cmd+1, dst+1, len-1))
+			goto ok_expand;
+
+		continue;
+ok_expand:
+		trace_printf("expand: %s\n", main_cmds.names[i]->name);
+		if (n != -1)
+			return NULL;
+		n = i;
+	}
+
+	if (n != -1) {
+		const char *assumed = main_cmds.names[n]->name;
+		main_cmds.names[n] = NULL;
+		clean_cmdnames(&main_cmds);
+		return assumed;
+	}
+	else
+		return NULL;
+}
+
 int cmd_version(int argc, const char **argv, const char *prefix)
 {
 	printf("git version %s\n", git_version_string);
--<--
-- 
Duy