Fast git handover with mob

mob Logo

Test Workflow Contributors Downloads Downloads of latest Stars Slack Status

#StandWithUkraine donate here #StandWithUkraine

Fast git handover for remote pair/mob programming.

diagram how mob works

What people say about mob

Sometimes you come across a tool that you didn’t realize you needed until you do; mob is just such a tool. Living as we do in a world where remote pair programming has become the norm for many teams, having a tool that allows for seamless handover either between pairs or a wider group as part of a mob programming session is super useful. mob hides all the version control paraphernalia behind a command-line interface that makes participating in mob programming sessions simpler. It also provides specific advice around how to participate remotely, for example, to “steal the screenshare” in Zoom rather than ending a screenshare, ensuring the video layout doesn’t change for participants. A useful tool and thoughtful advice, what’s not to like? — Technology Radar Volume 25, thoughtworks

“Mob has allowed us to run fast-paced, engaging, and effective sessions by enabling sub-10-second handover times and otherwise getting out of the way. A simple but great tool!” — Jeff Langr, developer

“I love it, it is a quantum leap in our collaboration.” — Vasiliy Sivovolov, Senior Software Engineer

“What a great tool to organise remote working.” — Jennifer Gommans, IT Consultant

“I was recently introduced to for remote pairing/mobbing collaboration and I absolutely love it. The timer feature is really a selling point for me. Kudos” — Fabien Illert, IT Consultant

How to install

The recommended way to install mob is as a binary via the provided install script:

# works for macOS, linux, and even on windows in git bash
curl -sL | sh

On macOS via homebrew:

brew install remotemobprogramming/brew/mob

# upgrade to latest version
brew upgrade remotemobprogramming/brew/mob

On Windows via Scoop:

scoop install mob

or via Chocolatey

choco install mob

On Arch Linux via yay:

yay -S mobsh-bin

On Nix through declarative installation

{ pkgs, ... }:
  # Either for all users
  environment.systemPackages = with pkgs; [ mob ];

  # Or for an explicit user
  users.users."youruser".packages = with pkgs; [ mob ];

On NetBSD, macOS, SmartOS, Linux, FreeBSD, OpenBSD, and more, via pkgsrc:

# if there's a binary package for your platform
pkgin install mob

# otherwise, for any platform
cd pkgsrc/devel/mob && bmake install clean

On Ubuntu there’s an EXPERIMENTAL snap package with a known limitation (ssh-agent not working):

sudo snap install mob-sh
sudo snap connect mob-sh:ssh-keys

Using go tools

If you have go 1.20+ you can install and build directly from source:

go install

or pick a specific version:

go install

or to install latest unreleased changes:

go install

How to use

You only need three commands: mob start, mob next, and mob done.

Switch to a separate branch with mob start and handover to the next person with mob next. Repeat. When you’re done, get your changes into the staging area of the main branch with mob done and commit them.


Here’s a short example on how the two developers Carola and Maria code a feature together and push it in the end.

# Carola
main $ mob start
mob/main $ echo "hello" > work.txt
mob/main $ mob next

# Maria
main $ mob start
mob/main $ cat work.txt # shows "hello"
mob/main $ echo " world" >> work.txt
mob/main $ mob next

# Carola
mob/main $ mob start
mob/main $ cat work.txt # shows "hello world"
mob/main $ echo "!" >> work.txt
mob/main $ mob done
main $ git commit -m "create greeting file"
main $ git push

And here’s the man page of the tool:

mob enables a smooth Git handover

Basic Commands:
  start              start session from base branch in wip branch
  next               handover changes in wip branch to next person
  done               squashes all changes in wip branch to index in base branch
  reset              removes local and remote wip branch
  clean              removes all orphan wip branches

Basic Commands(Options):
  start [<minutes>]                      Start a <minutes> timer
    [--include-uncommitted-changes|-i]   Move uncommitted changes to wip branch
    [--branch|-b <branch-postfix>]       Set wip branch to 'mob/<base-branch>-<branch-postfix>'
    [--create]                           Create the remote branch
    [--room <room-name>]                 Set room name for once
    [--stay|-s]                          Stay on wip branch (default)
    [--return-to-base-branch|-r]         Return to base branch
    [--message|-m <commit-message>]      Override commit message
    [--no-squash]                        Squash no commits from wip branch, only merge wip branch
    [--squash]                           Squash all commits from wip branch
    [--squash-wip]                       Squash wip commits from wip branch, maintaining manual commits
    [--branch|-b <branch-postfix>]       Set wip branch to 'mob/<base-branch>/<branch-postfix>'

Timer Commands:
  timer <minutes>           Start a <minutes> timer
    [--room <room-name>]    Set room name for once
  timer open                Opens the timer website
    [--room <room-name>]    Set room name for once
  start <minutes>           Start mob session in wip branch and a <minutes> timer
  break <minutes>           Start a <minutes> break timer

Short Commands (Options and descriptions as above):
  s                  alias for 'start'
  n                  alias for 'next'
  d                  alias for 'done'
  b                  alias for 'branch'
  t                  alias for 'timer'

Get more information:
  status             show the status of the current session
  fetch              fetch remote state
  branch             show remote wip branches
  config             show all configuration options
  version            show the version
  help               show help

  moo                moo!

Add --debug to any option to enable verbose logging

  # start 10 min session in wip branch 'mob-session'
  mob start 10

  # start session in wip branch 'mob/<base-branch>/green'
  mob start --branch green

  # handover code and return to base branch
  mob next --return-to-base-branch

  # squashes all commits and puts changes in index of base branch
  mob done

  # make a sound check
  mob moo

If you need some assistance when typing the subcommands and options, you might want to have a look at fig which gives you autocompletion in your shell.

Best Practices

The Perfect Git Handover

The perfect git handover is quick, requires no talking, and allows the rest of the team to continue discussing how to best solve the current problem undisturbed by the handover. Here’s how to achieve that.

Complementary Scripts

mob-start feature1 creates a new base branch feature1 to immediately start a wip branch mob/feature1 from there.

mob-start() { git checkout -b "$@" && git push origin "$@" --set-upstream && mob start --include-uncommitted-changes; }

Useful Aliases

alias ms='mob start'
alias mn='mob next'
alias md='mob done'
alias moo='mob moo'

Use the name you like

mob version
alias ensemble='mob' # introduce alias
export MOB_CLI_NAME='ensemble' # makes it aware of the alias
ensemble next
#👉 to start working together, use
#  ensemble start

And starting with v1.12.0, mob is symlink aware as well:

mob version
ln -s /usr/local/bin/mob /usr/local/bin/ensemble
ensemble next
#👉 to start working together, use
#  ensemble start

Automatically set the timer room when using ticket numbers as branch modifiers

Say you’re a larger team and work on the same git repository using ticket numbers as branch modifiers. It’s easy to forget exporting the room that enables the integration with Just set the configuration option MOB_TIMER_ROOM_USE_WIP_BRANCH_QUALIFIER=true in ~/.mob for that.

Automatically open the last modified file of the previous typist

When you are rotating the typist, you often need to open the file, which the previous typist has modified last. Mob supports you and can automate this step. You just need the configuration option MOB_OPEN_COMMAND with the command to open a file in your preferred IDE.

For example if you want use IntelliJ the configuration option would look like this: MOB_OPEN_COMMAND="idea %s"

More on Installation

Known Issues

Linux Timer

(This is not needed when installing via snap.)

To get the timer to play “mob next” on your speakers when your time is up, you’ll need an installed speech engine. Install that on Debian/Ubuntu/Mint as follows:

sudo apt-get install espeak-ng-espeak mbrola-us1

or on Arch Linux as follows:

sudo pacman -S espeak-ng-espeak
yay -S mbrola-voices-us1

Create a little script in your $PATH called say with the following content:

espeak -v us-mbrola-1 "$@"

If you use WSL2 on windows, install eSpeak as windows tool and Create a little script in your $PATH called say with the following content:

/mnt/c/Program\ Files\ \(x86\)/eSpeak/command_line/espeak.exe "$@"

make sure that the path to the windows espeak.exefits your installation. You can avoid the long path by adding it to your windows path variable.

How to configure

Show your current configuration with mob config:

MOB_WIP_COMMIT_MESSAGE="mob next [ci-skip] [ci skip] [skip ci]"
MOB_START_COMMIT_MESSAGE="mob start [ci-skip] [ci skip] [skip ci]"
MOB_VOICE_COMMAND="say \"%s\""
MOB_NOTIFY_COMMAND="/usr/bin/osascript -e 'display notification \"%s\"'"

Override default value permanently via a .mob file in your user home or in your git project repository root. (recommended)

Override default value permanently via environment variables:

export MOB_NEXT_STAY=true

Override default value just for a single call:

MOB_NEXT_STAY=true mob next

Integration with

For your name to show up in the room at you must set a timer value either via the MOB_TIMER variable, a config file, or an argument to start.

How to uninstall

Mob can simply be uninstalled by removing the installed binary (at least if it was installed via the script).


rm /usr/local/bin/mob

Windows (Git Bash)

rm ~/bin/mob.exe


brew uninstall remotemobprogramming/brew/mob

How to contribute

Propose your change in an issue or directly create a pull request with your improvements.

# PROJECT_ROOT is the root of the project/repository


git version # >= 2.17
go version # >= 1.15

go build # builds 'mob'

go test # runs all tests
go test -run TestDetermineBranches # runs the single test named 'TestDetermineBranches'

# run tests and show test coverage in browser
go test -coverprofile=cover.out && go tool cover -html=cover.out

Design Concepts

Who is using ‘mob’?


Created by Dr. Simon Harrer in September 2018.

Currently maintained by Gregor Riegler and Joshua Töpfer, and to some limited degree still by Dr. Simon Harrer.

Contributions and testing by Jochen Christ, Martin Huber, Franziska Dessart, Nikolas Hermann and Christoph Welcz. Thank you!

Logo designed by Sonja Scheungrab.