Script Git Logins with git credential
Your deploy script needs a Git password, and hard-coding it in the script is how tokens end up on the internet. In about fifteen minutes you will build a scriptable workflow with git credential: describe a remote, ask a configured helper for credentials, and approve or reject the result. The examples use Git 2.43.0, the version installed on this machine. You need Git and a shell, and no elevated privileges.
The route
Jump straight to the step you need, or tick off Done means at the end.
Security boundary
Credentials are secrets. The examples use example.com and a throwaway token. Do not paste a real password into shell history, a ticket or an article. A helper may store whatever you approve, so inspect its configuration before you send it anything.
1. Understand the three actions
git credential is an interface for programs that want Git's normal credential lookup. It reads a credential description from standard input. The action is one of fill, approve or reject:
fillasks. It consults configuration, helpers and possibly the user for a username and password, then prints the completed description.approvevouches. It tells configured helpers the credential worked, so they may store or reuse it.rejectretracts. It tells configured helpers the credential failed, so they may erase a matching entry.
approve and reject normally print nothing. The command never contacts the remote server itself. Your application must use the returned credential, decide whether authentication succeeded, and then report that result.
2. Feed a complete description
Each attribute is one key=value line. End the input with a blank line or end-of-file. For an HTTPS repository, the useful identifying fields are usually the protocol, host and path:
$ printf '%s\n' \\
'protocol=https' \\
'host=example.com' \\
'path=team/project.git' \\
''
- The blank line is not decoration. It terminates the description.
- No newlines or NULs in values. There is no quoting or escaping layer.
- Ports live in the host. Write
example.com:8443when one is present.
You can hand over a URL instead of splitting it yourself. The URL must include a protocol:
$ printf '%s\n' 'url=https://example.com/team/project.git' ''
Git parses that special attribute into the matching credential fields. An unrecognised attribute is silently discarded, so check your spelling. Never put a password in a URL used for diagnostics or logs.
3. Retrieve a credential with fill
Ask the configured helpers for a credential, and capture the output only where your program can protect it:
$ printf '%s\n' \\
'protocol=https' \\
'host=example.com' \\
'path=team/project.git' \\
'' | git credential fill
protocol=https
host=example.com
username=guide-user
password=guide-token
The username and password depend on your helper, so the values above are illustrative. A helper might already hold a credential, or Git might prompt on the terminal. In a non-interactive program, decide deliberately whether prompting is acceptable, and treat a non-zero exit status as a failed lookup.
Tip
Watch the path default. For HTTP and HTTPS, Git may drop path when credential.useHttpPath is false, so one credential covers a whole host. If separate repositories on the same host need separate credentials, check this setting before you rely on the path as a boundary:
$ git config --show-origin --get credential.useHttpPath
No output means the setting is not explicitly configured in the places Git searched. The effective default for HTTP(S) is false. Change it only after checking how your existing helper stores credentials.
4. Approve only a credential that worked
Once your application has authenticated to the remote, send the completed description to approve. Include the username and password that fill returned, not just the original lookup fields:
$ printf '%s\n' \\
'protocol=https' \\
'host=example.com' \\
'path=team/project.git' \\
'username=guide-user' \\
'password=guide-token' \\
'' | git credential approve
There should be no normal output. This command can change state in a configured helper, including writing a credential to a file or keychain. It does not grant access to the repository and does not verify the token.
Warning
Approving before the remote has accepted the credential can preserve a bad secret and cause repeated failures.
5. Reject a credential that failed
If the remote refused the credential, pass the same completed description to reject:
$ printf '%s\n' \\
'protocol=https' \\
'host=example.com' \\
'path=team/project.git' \\
'username=guide-user' \\
'password=guide-token' \\
'' | git credential reject
Expect no output again. Helpers decide how to erase a matching credential, and rejection does not guarantee every copy has vanished, particularly when several helpers are configured. Check the helper documentation if you need deletion guarantees.
Recovery
If you approved a test or compromised credential, reject it immediately and rotate it with the service that issued it. Removing a local helper file alone does not invalidate a token already sent to a remote service or copied into a keychain backup.
6. Test a helper without touching your real store
For a repeatable smoke test, point Git's temporary configuration at a throwaway store under /tmp. The store helper is used here only to demonstrate the protocol:
$ helper_file=$(mktemp /tmp/git-credential-demo.XXXXXX)
$ chmod 600 "$helper_file"
$ printf '%s\n' \\
'protocol=https' 'host=example.com' \\
'username=guide-user' 'password=guide-token' '' |
git -c credential.helper="store --file=$helper_file" credential approve
$ printf '%s\n' 'protocol=https' 'host=example.com' '' |
git -c credential.helper="store --file=$helper_file" credential fill
protocol=https
host=example.com
username=guide-user
password=guide-token
$ printf '%s\n' \\
'protocol=https' 'host=example.com' \\
'username=guide-user' 'password=guide-token' '' |
git -c credential.helper="store --file=$helper_file" credential reject
The temporary file sits deliberately outside your normal Git configuration. The chmod keeps other users out while it exists, but it is still a plain-text test store. Inspect it if you need to verify the test, then remove it when finished:
$ test ! -s "$helper_file" && echo 'test credential removed'
$ rm -- "$helper_file"
Warning
The final rm deletes that temporary file for good, though it does not touch a repository. Do not substitute a path from your real credential configuration.
7. Keep scripts from leaking secrets
- No tracing. Do not enable shell tracing around
fill. - No routine dumps. Do not print the complete response for ordinary logging.
- Protect the password. Keep it in a protected variable or pipe, clear temporary files promptly, and pass only the fields the helper needs.
- Refresh tokens are secret too.
oauth_refresh_tokenis confidential. Git treats it as helper data and applies no special logic to it, while it does recognisepassword_expiry_utcfor expired generated passwords.
Use a non-zero result to stop a deployment when fill cannot return a usable credential. Keep the three outcomes separate: lookup failed, authentication failed, authentication succeeded. Only the last one merits approve.
Done means
- Input is well formed. The script sends a terminated attribute list with the correct protocol and host.
- Output is treated as secret.
filloutput is never copied into logs. - Approval is earned.
approveis sent only after the remote accepts the credential. - Failure is reported.
rejectis sent after an authentication failure, with rotation for exposed credentials. - Scope matches intent. Helper scope, especially the HTTP(S) path default, fits the access boundary you meant.