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
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.
Table of Contents
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!
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 'email@example.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 'firstname.lastname@example.org:mitthu/dotfiles.git' 'dotfiles' [handbook] checkout = git clone 'email@example.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)
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 'firstname.lastname@example.org: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)
- 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 (
- Doc: Homepage - mr
Last updated on: June 18, 2019
← Back to homepage