When working with a remote git repository, typing the password every single pull/push is quite tiresome.
A good way would be to store the credentials locally, however the most common way of doing so is just wrong from a security point of view.

The problem

Most people will search online for “how to store git credentials” and resort to this “solution”:

$ git config credential.helper store

This “trick” will actually create a plain text file ~/.git-credentials with the password, when it’s typed the next time with git pull or git push commands.
Here’s what this file usually looks like:

https://<username>:<password>@<url>

This file gets 0600 permission by default, so only the current user can see it.
But that’s not good enough.

The solution

It starts with a simple command:

$ shred -u ~/.git-credentials

This command makes sure to remove the file and overwrite where it was stored on the drive, making it impossible to recover even if someone physically got hold of the machine.

Once we made sure nobody will ever be able to recover our password again, we’re left with two main options for encrypting the credentials.

The GNOME way: libsecret

This solution simply uses GNOME’s libsecret for encrypting and storing the credentials. However, even though it’s GNOME, it should work on basically any UNIX system.

  1. Get and install libsecret which presents in any modern Linux distribution’s software repository.
    Debian-based distributions: libsecret-1-0 and libsecret-1-dev packages.
  2. Configure git to use libsecret (mind the --global flag):
     $ git config --global credential.helper libsecret
    

    This will effectively create a file ~/.gitconfig with the following content (or append to the existing one):

    [credential]
    helper = libsecret
    
  3. On the next pull or push commands, a popup should come up asking for a password:
    Insert password to create a new keyring

    This password will be used for encrypting what’s called a “keyring” which is used for encrypting the git password.
    All keyrings are stored in ~/.local/share/keyrings.

With the default settings it’s required to type in the password only once per login session, which is much more convenient compared to each git command.

Encrypting using GnuPG

For people who use pass, this should be the preferred option.

  1. Create a new password file (the name doesn’t matter):
     $ pass add -m <name>
    

    Note: The -m switch allows typing multi-line credentials.

  2. Here’s the content that should be inside:
    machine <domain>
    protocol <http|https|ssh>
    login <username>
    password <password>
    

    machine → The repository’s domain name. (Ex: GitHub: github.com, Bitbucket: bitbucket.org)
    protocol → Whatever fits the repository: http, https or ssh
    login/password → The username and password for the service
    Note: It’s possible to store multiple service’s credentials. Simply add another paragraph for each service.

  3. Optional: By default, the credentials file is stored at pass main directory (usually ~/.password-store) but I recommend linking it to $HOME for convenience:
    $ ln -s $HOME/.password-store/<file-name> $HOME/.git.gpg
    

    Note: When linking files it’s usually safer to use $HOME instead of ~/ to indicate the home directory.

  4. Next, configure git accordingly, to use the netrc script:
    $ git config --global credential.helper "netrc -v -f <path-to-file>"
    
Encrypting manually using GnuPG (without pass)

Those who don’t use pass can still use this option, however it requires (a little bit of) extra work:

  1. Create a file with the content mentioned in step 2 above.
  2. Generate a new GPG key (if there’s none already):
    $ gpg --gen-key
    
  3. Encrypt the file:
    $ gpg -e -r <recipient> <path-to-file>
    

    Note: <recipient> is usually the email address (of yourself). Use gpg --list-keys to confirm.

  4. Continue to step 4 above.

Troubleshooting

“Not a git command” error

When running git pull or git push for the first time, the following error might show up:

git: 'credential-<libsecret|netrc>' is not a git command. See 'git --help'.

It happens because on some distribution the required binary is not in $PATH or even compiled.
To fix this, we need to find a file named git-credentials-libsecret for libsecret or git-credentials-netrc for GnuPG.

Distribution Path
Debian /usr/share/doc/git/contrib/credential/
Arch /usr/lib/git-core/

Then, choose one of the following:

  • Copy git-credentials-<libsecret|netrc> to any directory in $PATH.
  • Direct git to use git-credentials-<libsecret|netrc> from this location. Simply re-run the config command:
      $ git config --global credential.helper $PWD/git-credentials-<libsecret|netrc>
    

    Note: We’re using $PWD that indicates the current path. This should be where the git-credentials-<libsecret|netrc> file is.

Notes:

  • If the target file is in $PATH, git-credentials- prefix will be automatically prepended to libsecret or netrc.
  • git-credentials-netrc supports --help for more information (when running the script directly) and -d for debugging.
For libsecret only

If only a file named git-credentials-libsecret.c is present, it means we have to compile it.
Make sure basic build packages are present on the system (build-essential on Debian-based systems, for example):

$ sudo make

Note: The sudo part is essential since we’re inside /usr which is probably not owned by the current user.
This process should end in a fraction of a second on any machine.

“lookup failed” error

On Arch, the following error may show up:

** (process:6182): CRITICAL **: 22:10:58.547: lookup failed: GDBus.Error:org.freedesktop.DBus.Error.ServiceUnknown: The name org.freedesktop.secrets was not provided by any .service files

It can be fixed by installing the gnome-keyring package which provides the necessary service for libsecret to run.

Plain text ~/.git-credentials keeps coming back

Some repositories might have been configured to use the store plugin locally and those settings override the global ones.
To reset this setting, simply run inside the suspected repository:

$ git config --unset credential.helper

By the way, it’s possible to confirm (or change) those settings manually by editing .git/config in every repository.

Can’t type in GnuPG password on a headless machine

GnuPG assumes that it runs inside an Xserver environment and tries to launch a window asking for a password. However, on a headless machine it’s not the case.

There’s a global variable $GPG_TTY that can be set to fix this:

$ export GPG_TTY=$(tty)

Note: This line can be added to .bashrc/.zshrc for convenience.

Extra: GUI for credentials management

The Seahorse GUI utility can be used for managing all passwords stored by libsecret or the keys for GnuPG.
It can even manage SSH keys and do a lot more.

Seahorse GUI Utility