Managing multiple repositories using mr
tl;dr Using the mr tool, you can issue commands to multiple repositories in parallel. You can pull new changes, do simultaneous commits or just get the last commit log.
My typical day starts with updating a few code repositories. When dealing with a small number of repos, it’s not a problem to do a git pull
for each repo. But once you handle more than 4-5 repos, it’s worth automating the process.
Also, at times when you forget to commit some work, it can be handy to run git
status
on all your repos and see which repos need attention.
I recently came across a tool made by Joey: myrepos (or mr). The tool supports many types of repositories - git, mercurial, cvs, svn, etc.
Installation
1
2
3
4
5
6
7
8
# Debian / Ubuntu (recent versions)
sudo apt-get install mr
# Mac
brew install mr
# Others:
# - Just put the `mr` perl script in your `PATH` and it should work!
Core Usage
The tool looks for a file called .mrconfig in the current directory. This is an ini file which tracks all the repositories using relative paths, for example -
1
2
3
4
# file: ~/.mrconfig
[.homesick/repos/dotfiles]
checkout = git clone 'git@github.com:mitthu/dotfiles.git' 'dotfiles'
To start managing an existing repository (ex. handbook), run -
1
2
# handbook repo is located in ~/handbook
$ mr register handbook
The above updates the .mrconfig to -
1
2
3
4
5
6
7
# file: ~/.mrconfig
[.homesick/repos/dotfiles]
checkout = git clone 'git@github.com:mitthu/dotfiles.git' 'dotfiles'
[handbook]
checkout = git clone 'git@github.com:mitthu/handbook.git' 'handbook'
Action: git checkout
To checkout/clone the repositories in .mrconfig (skips already cloned repositories), run -
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ mr checkout
mr checkout: /Users/mitthu/.homesick/repos/dotfiles
Cloning into 'dotfiles'...
remote: Enumerating objects: 1406, done.
remote: Total 1406 (delta 0), reused 0 (delta 0), pack-reused 1406
Receiving objects: 100% (1406/1406), 455.60 KiB | 3.21 MiB/s, done.
Resolving deltas: 100% (823/823), done.
mr checkout: /Users/mitthu/handbook
Cloning into 'handbook'...
remote: Enumerating objects: 32, done.
remote: Total 32 (delta 0), reused 0 (delta 0), pack-reused 32
Receiving objects: 100% (32/32), 4.75 KiB | 4.75 MiB/s, done.
Resolving deltas: 100% (14/14), done.
mr checkout: finished (2 ok)
Action: git pull
Now to update (i.e. do a git pull
on) all managed repos, run -
1
2
3
4
5
6
7
8
9
10
11
12
# Update all managed repositories (sequential)
$ mr update
mr update: /Users/mitthu/.homesick/repos/dotfiles
Already up to date.
mr update: /Users/mitthu/handbook
Already up to date.
mr update: finished (2 ok)
# Run `git pull` simultaneously, say on 8 repos at a time
$ mr update -j8
Action: git status
To find out any uncommited/unpushed changes, run -
1
2
3
4
5
6
7
$ mr status
mr status: /home/mitthu/.homesick/repos/dotfiles
8c6f508 (HEAD, master) Add X automation script.
mr status: /home/mitthu/handbook
mr status: finished (2 ok)
My Workflow
I have mutiple .mrconfig’s, but I do make sure not to have too many configs. Using too many configs, would defeat the very purpose of automation, as you will be doing mr update in multiple directories.
I have a directory called repos in my home directory -
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Directory structure of ~/repos
~/repos
|-- following
| |-- ansible-django
| .... (all repos I follow) ....
| `-- .mrconfig
|-- ops
| |-- dotfiles_deploy
| .... (my personal automation stuff) ....
| `-- .mrconfig
`-- work
|-- gitosis-admin
.... (work related stuff) ...
`-- .mrconfig
Apart from the above, I also have an .mrconfig in my home directory. In this config, I add all the repos which I use daily and all my current projects. So everyday, I just have to do an mr update
in my home folder.
There are a few repos to which I do not have push permissions (~/repos/following/*
). mr will fail to push to such repos. It does not look very encouraging to see commands failing. To fix this, I override the mr push
command for those specific repos. So for example, if I don’t want to push to the handbook
repo, I will update my .mrconfig as follows -
1
2
3
4
5
# file: ~/.mrconfig
[handbook]
checkout = git clone 'git@github.com:mitthu/handbook.git' 'handbook'
push = echo "DO NOT PUSH"
The above would just run echo out “DO NOT PUSH” on an mr push
run. For example -
1
2
3
4
5
$ mr push
mr push: /home/mitthu/handbook
DO NOT PUSH
mr push: finished (1 ok)
Tips
- Teach new commands to mr (or overrride existing commands) via the ‘DEFAULT’ section in .mrconfig, for example -
1 2 3 4 5
[DEFAULT] # Teach mr how to "mr gc" in git repos. git_gc = git gc "$@" # Always fetch and rebase changes git_update = git pull --rebase
- Use cron and mr to keep forked repositories up to date with upstream.
- Use cron, mr and pushover to send notifications about uncommitted/unpushed changes at 5:00 pm.
- Doc: man page of mr (
man mr
) - Doc: Homepage - mr
Last updated on: June 18, 2019
← Back to homepage