Saturday, October 20, 2012

Git command extention

You probably know about "git config alias.*" command. See quote from documentation:
If the alias expansion is prefixed with an exclamation point, it will be treated as a shell command. For example, defining " = !gitk --all --not ORIG_HEAD", the invocation "git new" is equivalent to running the shell command "gitk --all --not ORIG_HEAD". Note that shell commands will be executed from the top-level directory of a repository, which may not necessarily be the current directory.
Base on this we can define some "new" command via aliases. But, there is another way for extending git. Let's have a quick view into git.c source:
int main(int argc, const char **argv)
const char *cmd;

startup_info = &git_startup_info;

cmd = git_extract_argv0_path(argv[0]);
if (!cmd)
cmd = "git-help";


* "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)
* So we just directly call the internal command handler, and
* die if that one cannot handle it.
if (!prefixcmp(cmd, "git-")) {
cmd += 4;
argv[0] = cmd;
handle_internal_command(argc, argv);
die("cannot handle %s internally", cmd);

It means we can define some executable peace of code (shell script, ruby script, etc.) which has prefix "git-". Put this script on system path (add to $PATH variable) and it will be treated as git command.

Let's clarify all this via sample code:
$ cd ~
$ mkdir bin

$ #create git-foobar file 
$ cat > git-foobar
echo "[foobar] commad"
$ chmod +x git-foobar

$ git-foobar
[foobar] commad
$ cd ~

$ #check if ~./bin folder is in $PATH variable
$ cat .bash_profile
export PATH="$HOME/bin:$PATH"

$ #now check git 
$ git foobar
[foobar] commad