Programmer Diaries: S01E01 – Multiple GitHub Keys

As a programmer, every couple weeks I have to get into some sysadmin tasks, like creating a SSL certificate, pushing a new build to PyPi, setting password-protected directories in apache, using the same server for two GitHub repositories, etc. Nothing fancy, you might say, but it always take me some time to remember “how it was done.” Since at Tivix we love to share our knowledge, I’ve decided to create this Programmer Diaries blogpost series.

Multiple GitHub deploy keys on same server

So you have your Linux testing server where you want to put many GitHub projects on the same system user account? You will probably get Error: Key already in use. This error occurs when you try to add a key to an account, and that key has already been added to another account or repository. Do we have to create a new Linux user and assign a new key? Not really. We can create multiple keys for same Linux user with one small SSH configuration file and still use git pull or git push without a problem.

  1. Create SSH keys for your projects and change the keyname to something more specific:
    ssh-keygen -t rsa -C "Project 1"
    Generating public/private rsa key pair.
    Enter file in which to save the key (/Users/xxx/.ssh/id_rsa): project_1
    Enter passphrase (empty for no passphrase):
    Enter same passphrase again:
    Your identification has been saved in test.
    Your public key has been saved in project_1.pub.
    
    ssh-keygen -t rsa -C "Project 2"
        Generating public/private rsa key pair.
    Enter file in which to save the key (/Users/xxx/.ssh/id_rsa): project_2
    Enter passphrase (empty for no passphrase):
    Enter same passphrase again:
    Your identification has been saved in test.
    Your public key has been saved in project_2.pub.
    
    ...
  2. Copy the corresponding public keys to the Deploy Key section of your GitHub repository.
  3. Set up the SSH config file, by editing ~/.ssh/config:
    nano ~/.ssh/config

    and add these values:

    Host project_1 GitHub.com
    Hostname GitHub.com
    IdentityFile /home/xxx/.ssh/project_1
    
    Host project_2 GitHub.com
    Hostname GitHub.com
    IdentityFile /home/xxx/.ssh/project_2

That’s all! To clone your repository using proper SSH keys just replace github.com with the new host name, for example,

git clone git@github.com:your_account/project_1.git
git clone git@github.com:your_account/project_2.git

should look like this:

git clone git@project_1:your_account/project_1.git
git clone git@project_2:your_account/project_2.git

From now on, you can use all git commands like git pull or git push without providing any extra parameters!

Bonus: Incomprehensible Git conflicts – diff3

We all know Git is awesome. But every version control system has conflicts. Sometimes it’s really hard to determine what was really changed and how to resolve it.

Example of git diff output:

<<<<<<< HEAD
report = user.generate_report(full=False)
=======
report = user.prepare_report(full=True)
>>>>>>> change-branch

Looking at this conflict we are unable to say what exactly each branch changed. Moreover we have no idea what it’s intent was.

To resolve this issue let’s use diff3. It’s easy like running one command:

git config --global merge.conflictstyle diff3

Now let’s run git diff once again:

<<<<<<< HEAD
report = user.generate_report(full=False)
||||||| merged common ancestor
report = user.prepare_report(full=False)
=======
report = user.prepare_report(full=True)
>>>>>>> change-branch

New lines comes up called common ancestor. Now conflict resolution workflow looks like:

  1. Use common ancestor branch as starting point
  2. Compare ancestor branch with other branches, HEAD and change-branch in our case
  3. HEAD intent is to change function name from prepare_report to generate_report
  4. change-branch intent is to change default parameter full from False to True
  5. Combine intent of both and merge changes

In our case, after merging changes we receive:

report = user.generate_report(full=True)

That’s it! We resolved our conflict!

See you on the next episode of Programmer Diaries!