How to easily add co-authors to you commits
Tags: git, github, pairing, collaboration
Published: 2020-07-20 06:53:34

[Git mob](https://github.com/findmypast-oss/git-mob) allows to add co-authors to git commits in an easy way. You can follow these steps to configure it for any repo you want.

### 1. Install the tool ⚙️

```bash
npm i -g git-mob
```

### 2. Create the co-authors file 📃

Create a file named `.git-coauthors` in your home directory with the following content:

```json
{
  "coauthors": {
    "foo": {
      "name": "Foo"
      "email": "foo@company.com"
    },
    "bar": {
      "name": "Bar",
      "email": "bar@company.com"
    }
  }
}
```

The keys of each co-author object will be the ones you need to type when selecting your commit co-authors, so you can change them to whatever you prefer.

### 3. Create the git hook ⚓

`git mob` uses the git `prepare-commit-msg` hook to append the co-authors to the commit message. Choose one of the following options to configure it:

[Option 1: Create the git `prepare-commit-msg` hook globally (for all repos)](#option1)
[Option 2: Create the git hook only for a specific repo](#option2)
[Option 3: Advanced case: make the git hook work alongside other `prepare-commit-msg` hooks](#option3)

<a name="option1"></a>
**Option 1: Create the git `prepare-commit-msg` hook globally (for all repos)**

Enable git templates:

```bash
git config --global init.templatedir '~/.git-templates'
```

This tells git to copy everything in `~/.git-templates` to your repo `.git/` directory when you run `git init`.

Create the file `.git-templates/hooks/prepare-commit-msg` in your home folder

```bash
mkdir -p .git-templates/hooks && touch .git-templates/hooks/prepare-commit-msg
```
with the following content:


```bash
#!/usr/bin/env node
let exec = require('child_process').exec,
    fs = require('fs');

const commitMessage = process.argv[2];
// expect .git/COMMIT_EDITMSG
if(/COMMIT_EDITMSG/g.test(commitMessage)){
    let contents = "";
    exec("git mob-print",
        function (err, stdout) {
        if(err) {
            process.exit(0);
        }

        // opens .git/COMMIT_EDITMSG
        contents = fs.readFileSync(commitMessage);

        if(contents.indexOf(stdout.trim()) !== -1) {
            process.exit(0);
        }

        const commentPos = contents.indexOf('# ');
        const gitMessage = contents.slice(0, commentPos);
        const gitComments = contents.slice(commentPos)

        fs.writeFileSync(commitMessage, gitMessage + stdout + gitComments);
        process.exit(0);
    });
}
```

make it executable running:

```bash
chmod +x .git-templates/hooks/prepare-commit-msg
```

and make it available in the repo you want by entering the repo folder and running:

```bash
git init
```

<a name="option2"></a>
**Option 2: Create the git hook only for a specific repo**

Create the file `.git/hooks/prepare-commit-msg` in your repo folder with the following content:

```bash
#!/usr/bin/env node
let exec = require('child_process').exec,
    fs = require('fs');

const commitMessage = process.argv[2];
// expect .git/COMMIT_EDITMSG
if(/COMMIT_EDITMSG/g.test(commitMessage)){
    let contents = "";
    exec("git mob-print",
        function (err, stdout) {
        if(err) {
            process.exit(0);
        }

        // opens .git/COMMIT_EDITMSG
        contents = fs.readFileSync(commitMessage);

        if(contents.indexOf(stdout.trim()) !== -1) {
            process.exit(0);
        }

        const commentPos = contents.indexOf('# ');
        const gitMessage = contents.slice(0, commentPos);
        const gitComments = contents.slice(commentPos)

        fs.writeFileSync(commitMessage, gitMessage + stdout + gitComments);
        process.exit(0);
    });
}
```

and make it executable with:

```bash
chmod +x .git-templates/hooks/prepare-commit-msg
```

<a name="option3"></a>
**Option 3: Advanced case: make the git hook work alongside other `prepare-commit-msg` hooks**

Only one script can be executed in each specific git hook, so in order to run multiple scripts for one hook, we'll need to create a parent script that will invoke all others.

Change the content of you `prepare-commit-msg` for this:

{% gist https://gist.github.com/mjackson/7e602a7aa357cfe37dadcc016710931b %} 

Create a folder named `prepare-commit-msg.d` in the same folder and move all your other `prepare-commit-msg` hook scripts into it. Your hooks folder structure should look similar to:

```bash
.git-templates/hooks
├── prepare-commit-msg
└── prepare-commit-msg.d
    ├── add-co-authors
    ├── some-script
    ├── ...
    └── some-other-script
```

Don't forget to make every script executable with:

```bash
chmod +x {path-to-my-script}
```

If you this globally remember to make it available in the repo you want by entering the repo folder and running:

```bash
git init
```

### 4. Create the template ✍️

In your repo folder run:

```bash
git mob --installTemplate && touch .git/.gitmessage
```

This will create the file `.git/.git-mob-template` where it will write the selected co-authors into.

### 5. Start a mob/pairing session 👯‍♀️

When you start working with your teammates type:

```bash
git mob foo bar
```

The names you use here are the same you used on the `.git-coauthors` file before.

When you do `git commit` you'll see this already in the message:

```bash
Co-authored-by: Foo <foo@company.com>
Co-authored-by: Bar <bar@company.com>
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# On branch master
```

### 6. Work alone 🤷

To start working by yourself just type:

```bash
git solo
```

### Other useful commands

- Show current co-authors:

```bash
git mob --print
```

- Show all available co-authors and their aliases:

```bash
git mob --list
```

Check [https://github.com/findmypast-oss/git-mob](https://github.com/findmypast-oss/git-mob) for more info.