App::GitGot - 2013-12-15

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.

Get GitGot

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 git , 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: git@github.com: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 git@github.com:genehack/STAMPS.git 3) app-gitgitr git git@github.com:genehack/app-gitgitr.git 4) app-gitgot git git@github.com:genehack/app-gitgot.git 5) app-miseenplace git git@github.com:genehack/app-miseenplace.git 6) build-color git git@github.com:genehack/build-color.git 7) dosetool git genehack.net:/var/git/private/dosetool 8) emacs git git@github.com:genehack/emacs.git 9) etc git git@github.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 git@github.com:genehack/STAMPSOB.git 4) app-gitgot git git@github.com:genehack/app-gitgot.git 5) app-miseenplace git git@github.com:genehack/app-miseenplace.git 6) build-color git git@github.com:genehack/build-color.git 7) dosetool git genehack.net:/var/git/private/dosetool 9) etc git git@github.com:genehack/etc.git

You can also specify tags with the -t flag:

% got ls -t config 5) app-miseenplace git git@github.com:genehack/app-miseenplace.git 8) emacs git git@github.com:genehack/emacs.git 9) etc git git@github.com:genehack/etc.git

Multiple -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 git@github.com: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 gc , got status , or got update .

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.

Note: The update_status , update , and 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!

Acknowledgments

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.

See Also