typing on keyboard [cropped]

How to change a git repository from https to ssh

I seemed to spend a crazy amount of time trying to work out how to change access to a Git repository (repo) from HTTPS to SSH to avoid password prompts when pushing changes to BitBucket and GitHub. Here, I outline how to do it on Mac OS X, partly to remind myself how to do it in the future, partly to collate all the infomation on the internet about it and partly in the hope that someone else might find it useful.

This rigmarole needs to be done on each computer you intend to access your Git repo with for each repo you have that you want to access by SSH rather than by HTTPS.

Change the remote path of the repo

This is how you tell your Git server how you want to access it.

Open Terminal or your command-line app of choice and navigate to your repo’s directory:

cd ~/projects/reponame

then check to see what you have on your server already:

git remote -v

You should see a pair of entries for every each remote repo (I once had origin and origin2, but that’s another story): one for fetch, which includes pull, and one for push:

origin https://username@bitbucket.org/username/reponame.git (fetch)
origin https://username@bitbucket.org/username/reponame.git (push)

This example shows a repo on BitBucket; GitHub is similar. You can see that the URLs include the https:// protocol. This is what we want to change. Type the following for BitBucket:

git remote set-url origin git@bitbucket.org:username/reponame.git

For GitHub, replace bitbucket.org with github.com. Then check what’s there again:

git remote -v

This time, you’ll see something like this:

origin git@bitbucket.org:username/reponame.git (fetch)
origin git@bitbucket.org:username/reponame.git (push)

Troubleshooting

Error: could not resolve hostname

You might get this error:

ssh: Could not resolve hostname github.com:username: nodename nor servname provided, or not known
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

If you do, check the output from git remote -v carefully. See if the SSH URL is prefixed with ssh://, like this:

origin ssh://git@github.com:pandammonium/buffer-guess-who.git (fetch)
origin ssh://git@github.com:pandammonium/buffer-guess-who.git (push)

If it is, run set-url again, making sure to exclude the ssh:// part of the URL. Run git remote -v again and check the output. You may find that only fetch has changed — if so, read on.

Only fetch changes; push stays the same

If the fetch URL has changed but the push URL has not, like this:

origin git@github.com:pandammonium/buffer-guess-who.git (fetch)
origin ssh://git@github.com:pandammonium/buffer-guess-who.git (push)

you’ll need to do the push separately by using the --push option:

git remote set-url --push origin git@bitbucket.org:username/reponame.git

You don’t need to do anything further for pull because it does what fetch does (because pull is equivalent to fetch then merge).

I don’t know why it works for some cases but not other ones. It happened for me when I got the could not resolve hostname error above and ran set-url again. It seems that the set-url command is applied to both fetch and push when changing the protocol, but when keeping the (SSH) protocol the same, it only updates fetch.

Create a SSH key

If you don’t already have a SSH key for BitBucket and/or GitHub on the particular computer you’re using, you’ll need to create one for each service that you use and on each computer that you will use to access your repos:

You’ll end up with two SSH keys, one private and one public, which you can see by running:

ssh-add -l

or you can list all the SHH keys you have by running:

ls ~/.ssh

which will output something like

bitbucket_id_rsa
bitbucket_id_rsa.pub

The key without the extension is the private key and the key with the .pub extension is the public key. The private key stays on your computer and the public key is uploaded onto the server.

BitBucket …recommend you keep the default key name [id_rsa] unless you have a reason to change it. However, I’d recommend using something descriptive, like bitbucket_id_rsa so you know what it’s for later and to avoid accidentally overwriting the key if you create one for bitbucket and one for github and one for your web server and so on.

Add the public SSH key to your remote Git server

The public SSH key (the one with the .pub extension) is for the server, so you need to upload it to your account on the relevant one:

Add the private SSH key to your keychain

If you don’t add the SSH key to your keychain, you’ll have to keep entering the passphrase you set up when creating the SSH key.

  1. Start the SSH agent in the background:

    eval $(ssh-agent)

    which gives you an agent pid:

    Agent pid: 12345

  2. Add the private SSH key (the one with no extension) to your keychain; the -K option is Mac-specific and is what tells your Mac to add it to the keychain as well as wherever else it adds it to:

    ssh-add -K ~/.ssh/github_id_rsa

  3. For MacOS Sierra onwards, you must add the SSH key file to the ~/.config file so you don’t have to call the previous command every time you restart your Mac. This also seems to be what makes the whole thing work with Sourcetree.

    1. Create a config file in your SSH keys directory, if there isn’t one already (you can check by using ls ~/.ssh):

      nano ~/.ssh/config

      I prefer the Nano editor if I’m going to use a command-line editor, but you can use Vim or Emacs or whatever you like, of course.

    2. Add an entry for Host * (any host, I presume) stating that the keychain is to be used and the keys are to be added to said keychain. An identity file entry in your ~/.ssh/config file is needed for each SSH key:

      Host *
        AddKeysToAgent yes
        UseKeychain yes
        IdentityFile ~/.ssh/bitbucket_id_rsa
        IdentityFile ~/.ssh/github_id_rsa

    If you don’t add this config file, you’ll have to run ssh-add -K ~/.sshkeyname every time you restart your Mac.

You should now be able to use Git without having to use your password all the time.

Test it works

You can type in the terminal for a GitHub repo:

ssh -T git@github.com

to get the following message:

Hi username! You've successfully authenticated, but GitHub does not provide shell access.

For a BitBucket repo, type:

ssh -T git@bitbucket.org

to get the following message:

logged in as pandammonium.

You can use Git or hg to connect to Bitbucket. Shell access is disabled.

In your terminal, assuming your repo is up-to-date, you can test everything works by typing the following:

git fetch

which should give no output if it works. Typing:

git push

should result in an up-to-date message:

Everything up-to-date

If that works, try fetching in Sourcetree then pushing. If you get no errors, you’re good to go.

Troubleshooting

Error: permission denied

If you get this error, especially in Sourcetree:

git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

then check that you have spelt everything correctly and followed every step.

Sources and further reading

In no particular order, the following links helped me get all this working and/or contain more information that might help you understand what’s going on:

I am very grateful to all the people who contributed to getting this information out there for me to find. Thank you.

Do you want to reply?

This site uses Akismet to reduce spam. Learn how your comment data is processed.