-
1. Ăvod
-
2. Zåklady pråce se systémem Git
-
3. VÄtve v systĂ©mu Git
- 3.1 VÄtve v kostce
- 3.2 ZĂĄklady vÄtvenĂ a sluÄovĂĄnĂ
- 3.3 SprĂĄva vÄtvĂ
- 3.4 Postupy pĆi prĂĄci s vÄtvemi
- 3.5 VzdĂĄlenĂ© vÄtve
- 3.6 PĆesklĂĄdĂĄnĂ
- 3.7 ShrnutĂ
-
4. Git na serveru
- 4.1 Protokoly
- 4.2 ZprovoznÄnĂ Gitu na serveru
- 4.3 GenerovĂĄnĂ veĆejnĂ©ho klĂÄe SSH
- 4.4 NastavenĂ serveru
- 4.5 DĂ©mon Git
- 4.6 ChytrĂœ HTTP
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 MoĆŸnosti hostovĂĄnĂ u tĆetĂ strany
- 4.10 ShrnutĂ
-
5. DistribuovanĂœ Git
-
6. GitHub
-
7. Git Tools
- 7.1 Revision Selection
- 7.2 Interactive Staging
- 7.3 Stashing and Cleaning
- 7.4 Signing Your Work
- 7.5 Searching
- 7.6 Rewriting History
- 7.7 Reset Demystified
- 7.8 Advanced Merging
- 7.9 Rerere
- 7.10 LadÄnĂ v systĂ©mu Git
- 7.11 Submodules
- 7.12 Bundling
- 7.13 Replace
- 7.14 Credential Storage
- 7.15 ShrnutĂ
-
8. Customizing Git
- 8.1 Git Configuration
- 8.2 Atributy Git
- 8.3 Git Hooks
- 8.4 An Example Git-Enforced Policy
- 8.5 ShrnutĂ
-
9. Git a ostatnà systémy
- 9.1 Git as a Client
- 9.2 Migrating to Git
- 9.3 ShrnutĂ
-
10. Git Internals
- 10.1 Plumbing and Porcelain
- 10.2 Git Objects
- 10.3 Git References
- 10.4 BalĂÄkovĂ© soubory
- 10.5 The Refspec
- 10.6 PĆenosovĂ© protokoly
- 10.7 SprĂĄva a obnova dat
- 10.8 Environment Variables
- 10.9 ShrnutĂ
-
A1. Appendix A: Git in Other Environments
- A1.1 Graphical Interfaces
- A1.2 Git in Visual Studio
- A1.3 Git in Eclipse
- A1.4 Git in Bash
- A1.5 Git in Zsh
- A1.6 Git in Powershell
- A1.7 ShrnutĂ
-
A2. Appendix B: Embedding Git in your Applications
- A2.1 Command-line Git
- A2.2 Libgit2
- A2.3 JGit
-
A3. Appendix C: Git Commands
- A3.1 Setup and Config
- A3.2 Getting and Creating Projects
- A3.3 Basic Snapshotting
- A3.4 Branching and Merging
- A3.5 Sharing and Updating Projects
- A3.6 Inspection and Comparison
- A3.7 Debugging
- A3.8 Patching
- A3.9 Email
- A3.10 External Systems
- A3.11 Administration
- A3.12 Plumbing Commands
7.14 Git Tools - Credential Storage
Credential Storage
If you use the SSH transport for connecting to remotes, itâs possible for you to have a key without a passphrase, which allows you to securely transfer data without typing in your username and password. However, this isnât possible with the HTTP protocols â every connection needs a username and password. This gets even harder for systems with two-factor authentication, where the token you use for a password is randomly generated and unpronounceable.
Fortunately, Git has a credentials system that can help with this. Git has a few options provided in the box:
-
The default is not to cache at all. Every connection will prompt you for your username and password.
-
The âcacheâ mode keeps credentials in memory for a certain period of time. None of the passwords are ever stored on disk, and they are purged from the cache after 15 minutes.
-
The âstoreâ mode saves the credentials to a plain-text file on disk, and they never expire. This means that until you change your password for the Git host, you wonât ever have to type in your credentials again. The downside of this approach is that your passwords are stored in cleartext in a plain file in your home directory.
-
If youâre using a Mac, Git comes with an âosxkeychainâ mode, which caches credentials in the secure keychain thatâs attached to your system account. This method stores the credentials on disk, and they never expire, but theyâre encrypted with the same system that stores HTTPS certificates and Safari auto-fills.
-
If youâre using Windows, you can install a helper called âwincred.â This is similar to the âosxkeychainâ helper described above, but uses the Windows Credential Store to control sensitive information.
You can choose one of these methods by setting a Git configuration value:
$ git config --global credential.helper cache
Some of these helpers have options.
The âstoreâ helper can take a --file <path>
argument, which customizes where the plain-text file is saved (the default is ~/.git-credentials
).
The âcacheâ helper accepts the --timeout <seconds>
option, which changes the amount of time its daemon is kept running (the default is â900â, or 15 minutes).
Hereâs an example of how youâd configure the âstoreâ helper with a custom file name:
$ git config --global credential.helper 'store --file ~/.my-credentials'
Git even allows you to configure several helpers.
When looking for credentials for a particular host, Git will query them in order, and stop after the first answer is provided.
When saving credentials, Git will send the username and password to all of the helpers in the list, and they can choose what to do with them.
Hereâs what a .gitconfig
would look like if you had a credentials file on a thumb drive, but wanted to use the in-memory cache to save some typing if the drive isnât plugged in:
[credential]
helper = store --file /mnt/thumbdrive/.git-credentials
helper = cache --timeout 30000
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
-
This is the command line that initiates the interaction.
-
Git-credential is then waiting for input on stdin. We provide it with the things we know: the protocol and hostname.
-
A blank line indicates that the input is complete, and the credential system should answer with what it knows.
-
Git-credential then takes over, and writes to stdout with the bits of information it found.
-
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 |
---|---|
|
Runs |
|
Runs |
|
Runs |
|
Code after |
So the helpers described above 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
purge 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
-
Here we tell
git-credential-store
to save some credentials: the username âbobâ and the password âs3cre7â are to be used whenhttps://mygithost
is accessed. -
Now weâll retrieve those credentials. We provide the parts of the connection we already know (
https://mygithost
), and an empty line. -
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 wincred
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:
-
The only action we need to pay attention to is
get
;store
anderase
are write operations, so weâll just exit cleanly when theyâre received. -
The file format of the shared-credential file is the same as that used by
git-credential-store
. -
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:
#!/usr/bin/env ruby
require 'optparse'
path = File.expand_path '~/.git-credentials' # (1)
OptionParser.new do |opts|
opts.banner = 'USAGE: git-credential-read-only [options] <action>'
opts.on('-f', '--file PATH', 'Specify path for backing store') do |argpath|
path = File.expand_path argpath
end
end.parse!
exit(0) unless ARGV[0].downcase == 'get' # (2)
exit(0) unless File.exists? path
known = {} # (3)
while line = STDIN.gets
break if line.strip == ''
k,v = line.strip.split '=', 2
known[k] = v
end
File.readlines(path).each do |fileline| # (4)
prot,user,pass,host = fileline.scan(/^(.*?):\/\/(.*?):(.*?)@(.*)$/).first
if prot == known['protocol'] and host == known['host'] and user == known['username'] then
puts "protocol=#{prot}"
puts "host=#{host}"
puts "username=#{user}"
puts "password=#{pass}"
exit(0)
end
end
-
Here we parse the command-line options, allowing the user to specify the input file. The default is
~/.git-credentials
. -
This program only responds if the action is
get
and the backing-store file exists. -
This loop reads from stdin until the first blank line is reached. The inputs are stored in the
known
hash for later reference. -
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
Since 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.