Customized Git Subcommands

by Sam A. Hill

I'll admit that I'm not a Git expert, but I don't think I'm alone in saying that I find git's syntax a little confusing. One neat thing about git, however, is the ability to define custom subcommands, as easily as creating a shell script in your $PATH with the name git-subcommand, and you can then git subcommand at any time to run it.

One Liners

Sometimes I will write one-liners for syntax I don't use often and forget. For example, I often forget the syntax required to rename a repository branch; not only is there no git rename command, it's tricky to remember the order to put the new name and the old name in the line (at least for me). So I created a file called git-branchrename in my $PATH with these contents:

git-branchrename
git branch -m "$1" "$2"

The "$1" refers to the first parameter given to the command, and the quotation marks are necessary if the parameter contains any spaces. Now I can type git branchrename oldname newname and it just works.

You don't need to know any shell scripting to create these; simply create a file called git-commandname in your PATH* with the code you want to run, replacing parameters you'd want to enter at runtime with the expressions "$1", "$2", etc.

*(You can type echo $PATH to see a list of folders in your PATH. I've personally created a folder in my home directory called bin where I store the commands I've defined; you can learn how to add to the $PATH here: [https://www.baeldung.com/linux/path-variable])

Here are some more examples of mine.

• Add a local branch to the remote repository

Usage: git addremotebranch <branchname>.

git-addremotebranch
git push -u origin "$1"

• Create a new branch and use it immediately

Usage: git checkout <branchname>

git-checkout
git checkout -b "$1"

• Show the history of commits

Usage: git history

git-history
git log --reflog

• Do not include this file in the repository (but don't delete it)

Usage: git ignore <file> <file> ...

git-ignore
git rm --cached $@

Other scripts

Of course, you can do more complicated things as well. Here are some of the slightly more involved scripts I've written:

• Show a list of files in the current repository

git-ls
commit=HEAD
if [[ %# -gt 0 ]] ; then commit=$1; fi
git ls-tree --full-tree -r --name-only "$commit"

The command git ls on its own provides a list of all the files in the repository, which can be useful for review or further scripting. One can also type git ls <commitname> to show the files stored in a particular commit of the repository.

• Synchronize the local files to a remote directory without git

I often write code on my local machine and then upload it to my webserver. Unfortunately, I can't set up my webserver as a git repository, so I need to use rsync to update the server, and want to make sure I update all of the files in the repository. This is the motivation behind this code:

git-sync
root=$(git rev-parse --show-toplevel)
cd $root
tgt=""
if [[ $# -ge 1 ]] ; then
    tgt="$1"
    echo $tgt > .git-sync
else
    read tgt < .git-sync;
fi

echo "Syncing to $tgt"
if [ -n "$tgt" ] ; then 
    rsync -Rrauvz $(git ls) $tgt/
else
    echo "Can't find destination"
fi

You set up a local repository by typing git sync <server>:<folder> where <server> is the url of the server you want to use, and <folder> is the name of the destination folder on the server. (This is the same syntax used by rsync and scp.) This command stores the information in the file .git-sync in the root directory of your repository for later use. Then, and every time after when you run git sync, it uses rsync and the command git ls that I defined earlier to synchronize all of the files that are part of the repository with the server.

• Show a personalized cheatsheet

Of course git help already exists, but sometimes I need a quick reminder of how certain commands work. So I define the command

git-myhelp
echo "
git branch: list all branches
git branch <branch>: create a new branch
git branchrename <old> <new>: rename a branch
git checkout <branch>: switch to branch
git checkout <branch> <file>: pull file from branch into current branch
...
"

You can of course include anything you like in the cheatsheet, and organize it however you like, maybe even pipe it through a text formatter to add color.

Of course there are many other possibilities. Happy hacking!