Under the Hood

How does this all work? Git’s root command for the credential-helper system is git credential, which takes a command as an argument, and then more input through stdin.

This might be easier to understand with an example. Let’s say that a credential helper has been configured, and the helper has stored credentials for mygithost. Here’s a session that uses the fill command, which is invoked when Git is trying to find credentials for a host:

$ git credential fill (1)
protocol=https (2)
host=mygithost
(3)
protocol=https (4)
host=mygithost
username=bob
password=s3cre7
$ git credential fill (5)
protocol=https
host=unknownhost

Username for 'https://unknownhost': bob
Password for 'https://bob@unknownhost':
protocol=https
host=unknownhost
username=bob
password=s3cre7
  1. This is the command line that initiates the interaction.
  2. Git-credential is then waiting for input on stdin. We provide it with the things we know: the protocol and hostname.
  3. A blank line indicates that the input is complete, and the credential system should answer with what it knows.
  4. Git-credential then takes over, and writes to stdout with the bits of information it found.
  5. If credentials are not found, Git asks the user for the username and password, and provides them back to the invoking stdout (here they’re attached to the same console).

The credential system is actually invoking a program that’s separate from Git itself; which one and how depends on the credential.helper configuration value. There are several forms it can take:

Configuration Value

Behavior

foo

Runs git-credential-foo

foo -a --opt=bcd

Runs git-credential-foo -a --opt=bcd

/absolute/path/foo -xyz

Runs /absolute/path/foo -xyz

!f() { echo "password=s3cre7"; }; f

Code after ! evaluated in shell

So the helpers described here are actually named git-credential-cache, git-credential-store, and so on, and we can configure them to take command-line arguments. The general form for this is git-credential-foo [args] <action>. The stdin/stdout protocol is the same as git-credential, but they use a slightly different set of actions:

  • get is a request for a username/password pair.
  • store is a request to save a set of credentials in this helper’s memory.
  • erase purges the credentials for the given properties from this helper’s memory.

For the store and erase actions, no response is required (Git ignores it anyway). For the get action, however, Git is very interested in what the helper has to say. If the helper doesn’t know anything useful, it can simply exit with no output, but if it does know, it should augment the provided information with the information it has stored. The output is treated like a series of assignment statements; anything provided will replace what Git already knows.

Here’s the same example from above, but skipping git-credential and going straight for git-credential-store:

$ git credential-store --file ~/git.store store (1)
protocol=https
host=mygithost
username=bob
password=s3cre7
$ git credential-store --file ~/git.store get (2)
protocol=https
host=mygithost

username=bob (3)
password=s3cre7
  1. Here we tell git-credential-store to save some credentials: the username bob and the password s3cre7 are to be used when https://mygithost is accessed.
  2. Now we’ll retrieve those credentials. We provide the parts of the connection we already know (https://mygithost), and an empty line.
  3. git-credential-store replies with the username and password we stored above.

Here’s what the ~/git.store file looks like:

https://bob:s3cre7@mygithost

It’s just a series of lines, each of which contains a credential-decorated URL. The osxkeychain and winstore helpers use the native format of their backing stores, while cache uses its own in-memory format (which no other process can read).

A Custom Credential Cache

Given that git-credential-store and friends are separate programs from Git, it’s not much of a leap to realize that any program can be a Git credential helper. The helpers provided by Git cover many common use cases, but not all. For example, let’s say your team has some credentials that are shared with the entire team, perhaps for deployment. These are stored in a shared directory, but you don’t want to copy them to your own credential store, because they change often. None of the existing helpers cover this case; let’s see what it would take to write our own. There are several key features this program needs to have:

  1. The only action we need to pay attention to is get; store and erase are write operations, so we’ll just exit cleanly when they’re received.
  2. The file format of the shared-credential file is the same as that used by git-credential-store.
  3. The location of that file is fairly standard, but we should allow the user to pass a custom path just in case.

Once again, we’ll write this extension in Ruby, but any language will work so long as Git can execute the finished product. Here’s the full source code of our new credential helper:

link:../git-credential-read-only[]
  1. Here we parse the command-line options, allowing the user to specify the input file. The default is ~/.git-credentials.
  2. This program only responds if the action is get and the backing-store file exists.
  3. This loop reads from stdin until the first blank line is reached. The inputs are stored in the known hash for later reference.
  4. This loop reads the contents of the storage file, looking for matches. If the protocol and host from known match this line, the program prints the results to stdout and exits.

We’ll save our helper as git-credential-read-only, put it somewhere in our PATH and mark it executable. Here’s what an interactive session looks like:

$ git credential-read-only --file=/mnt/shared/creds get
protocol=https
host=mygithost

protocol=https
host=mygithost
username=bob
password=s3cre7

Because its name starts with git-, we can use the simple syntax for the configuration value:

$ git config --global credential.helper read-only --file /mnt/shared/creds

As you can see, extending this system is pretty straightforward, and can solve some common problems for you and your team.

Summary

You’ve seen a number of advanced tools that allow you to manipulate your commits and staging area more precisely. When you notice issues, you should be able to easily figure out what commit introduced them, when, and by whom. If you want to use subprojects in your project, you’ve learned how to accommodate those needs. At this point, you should be able to do most of the things in Git that you’ll need on the command line day to day and feel comfortable doing so.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset