Got Git? Ask Santa to get Got!
Many Git Repos Can Get Messy
Like most developers, I've got a lot of source code in Git repositories, scattered and duplicated across the four-odd machines I use on a regular basis (the laptop, the server, the other laptop, the VPS...) It's actually worse than that, because it's not just source code — I've got various configuration files in different repositories, a couple repositories that just contain documents, and so on. I keep everything in sync and configured the same across all my machines by depending on these repositories to be reasonably up-to-date with the master copy (which is some times at Github, some times on $WORK's repo server, some times on one of my servers...)
In order to effectively manage the all these git repositories, from all those different locations, across all those machines, I use got.
got is a utility that makes it trivial to run various
git commands across some or all of the repositories that
got knows about.
Before you can use
got, you need to install it. Luckily, it's on CPAN, in the App::GitGot dist. Fire up your favorite CPAN client and install that, and once all the dependencies install, you should have a shiny new
got command available to you. Much like
got works via a series of sub-commands — if you just run
got, you'll get a list of all the available sub-commands.
Gotta tell got where your git repos are
In order for
got to manage your repositories, you'll have to add them to the configuration file. (By default, this lives at
~/.gitgot.) One way to add a repo is the
got add command —
cd into the repo you want to add, and run
got add. You'll be prompted for a few pieces of info — the defaults are generally correct — and then the repository will be added to the config file.
% got add Name: etc URL: firstname.lastname@example.org:genehack/etc.git Path: /Users/genehack/etc Tags: config
Note the "Tags" entry — as we'll see shortly, tags are one way you can select repositories to operate on.
If you want to just accept the defaults without having a chance to edit them, you can run
got add -D, which will just accept the default options. Currently, there isn't any command to edit a repository after it has been added (to add or change tags, for example), but the configuration file is a very simple YAML file which is trivial to hand-edit.
There are a couple of other sub-commands that add repositories to your config file.
got clone $CLONE_URL will run
git clone on the given URL, and then add the resulting repository checkout to your
got config. Similarly,
got fork $GITHUB_URL will fork the given Github repo, then clone the resulting fork, and finally add it to your
got config. The
got fork sub-command depends on having a properly configured
~/.github-identity file with your Github authentication information.
Got Gets Your Git Repos In Line
Once you've added some git repositories to your
got config file, you can use
got to carry out various batch operations. For example, you can show all the repositories
got is aware of with the
got list (aka
got ls) sub-command. You can also specify a subset of repositories to operate on by providing additional arguments. For example, given this output:
% got ls 1) Perl-Build git git://github.com/tokuhirom/Perl-Build 2) STAMPS git email@example.com:genehack/STAMPS.git 3) app-gitgitr git firstname.lastname@example.org:genehack/app-gitgitr.git 4) app-gitgot git email@example.com:genehack/app-gitgot.git 5) app-miseenplace git firstname.lastname@example.org:genehack/app-miseenplace.git 6) build-color git email@example.com:genehack/build-color.git 7) dosetool git genehack.net:/var/git/private/dosetool 8) emacs git firstname.lastname@example.org:genehack/emacs.git 9) etc git email@example.com:genehack/etc.git
You can specify one or more repository index numbers, or number ranges, to only select certain repos. For example:
% got ls 2 4-6 7 9 2) STAMPS git firstname.lastname@example.org:genehack/STAMPSOB.git 4) app-gitgot git email@example.com:genehack/app-gitgot.git 5) app-miseenplace git firstname.lastname@example.org:genehack/app-miseenplace.git 6) build-color git email@example.com:genehack/build-color.git 7) dosetool git genehack.net:/var/git/private/dosetool 9) etc git firstname.lastname@example.org:genehack/etc.git
You can also specify tags with the
% got ls -t config 5) app-miseenplace git email@example.com:genehack/app-miseenplace.git 8) emacs git firstname.lastname@example.org:genehack/emacs.git 9) etc git email@example.com:genehack/etc.git
-t options may be given, in which case they are combined in a "logical OR" fashion.
Finally, you can specify repos by name:
% got ls emacs 8) emacs git firstname.lastname@example.org:genehack/emacs.git
This ability to select a subset of repositories to operate on applies not just to the
got ls subcommand, but to any
got subcommand that operates on multiple repositories, such as
got status, or
Gotta Get It Together Now
As I mentioned above, I depend on a number of git repositories being kept up to date with the master copy in order to propagate configuration changes across machines and to maintain consistency in how things are configured. I do this by frequently (at least once a week, if not more often), using a combination of
got update_status and
got status to first update all the repositories on a given machine, then display repositories that have either uncommitted changes or changes that have been locally committed but not pushed up to the master. By using these two commands and iterating across all my active machines, it becomes trivial to make sure everything is up to date.
status commands all take an optional
-q (for quiet) flag. This hides the output from repositories that don't have anything "interesting" to show — all the unchanged repos, all the clean repos that are in sync with the remote, etc. Also worth noting is that the
update command does a
git pull. There's an outstanding request for a
git fetch command, which is waiting on me to have a spare tuit, or some brave volunteer to send in a pull request.
But Wait, We Got More
got also has a number of commands that are designed to make it easier to work with individual repositories without needing to know exactly where they live on disk. The
got chdir REPO command spawns a new subshell inside the given repository, and the
got tmux REPO subcommand (contributed by Yanick Champoux) spawns a new
tmux window with the working directory inside the given repository. The repository's name will be used as the name of the
tmux window. If the window has already been created by a previous invocation of
got tmux, instead of creating a new window, the existing window will be selected.
If you're curious whether a given repository is being managed by
got, you can use the
got this command (contributed by Yanick Champoux) while inside the repository. If it is managed by
got, you'll get back the listing output for the repo. If it is not managed by
got, you'll see a message to that effect.
What You Got?
At this point,
got is a very good fit for my personal workflow around git repositories across multiple machines. I realize, however, that my workflow is not everybody's workflow, and I'm very open to additional commands or command flags being added to make
got more generically useful to more people.
got was also originally intended to be a VCS-agnostic tool; it just so happened that around the time I got the first usable version of it completed, my need to use anything other than
git for revision control evaporated. The extension hooks for other VCSen are still in place, however, and I would love to merge code that adds SVN, Hg, or even CVS support.
Please fork the repository on Github, add your own contribution, and send in a pull request!
got was originally very heavily inspired by a similar tool, developed by Ingy döt Net, called App::AYCABTU. In particular, the repository selection interface and large chunks of the config file were shamelessly pilfered.
got has also been greatly improved by the efforts of Yanick Champoux, Mike Greb, and Chris Prather, as well as everybody who has reported a bug or wishlist feature.