skip to content

What does Git's credential.helper do, and how do the store, cache, and keychain helpers differ?

level: middleimportance: must knowfreq 56%

answer

  1. Git asks a program before it asks you
  2. Three verbs, one of them clears bad secrets
  3. Disk, memory, or the operating system
  4. Fifteen minutes by default, in memory
  5. An empty value resets an inherited list

basics

~20 s

credential.helper names a program Git asks for a username and secret before prompting. store writes them in plaintext to ~/.git-credentials, cache keeps them in a short-lived in-memory daemon, and osxkeychain or manager delegate to an OS-backed secure store.

solid answer

~40 s

When an HTTP remote needs credentials, Git runs the configured helper with `get`, feeding it the protocol, host and optionally the path, and uses whatever the helper returns; only if nothing answers does it prompt. After a successful request Git calls the helper with `store`, and on rejection with `erase`, which is how a stale token gets evicted. The bundled helpers differ mainly in where the secret rests: `store` writes it in cleartext to `~/.git-credentials`, `cache` runs `git-credential-cache--daemon` holding it in memory with a default 900-second timeout, and platform helpers such as `osxkeychain`, `wincred`, `libsecret` or Git Credential Manager put it in an OS-protected store. You can configure several helpers — Git tries them in order — and reset an inherited list by setting `credential.helper` to an empty value.

code

ini · 5 lines
ini
[credential]
	helper = osxkeychain
[credential "https://internal.example.com"]
	helper = cache --timeout=3600
	useHttpPath = true

go deeper

for a junior

Know that Git can remember your HTTPS credential so you are not prompted every push, and that credential.helper is the setting that decides how.

for a middle

Explain the get/store/erase protocol, name where each bundled helper keeps the secret, and know that helpers are multi-valued and tried in order.

for a senior

Debug real credential failures: inspect what git credential fill returns, find helpers imposed by an outer config scope, and choose a non-persisting mechanism for ephemeral machines.

for a principal

Decide organization-wide how secrets reach the Git client on workstations and runners, and make rotation actually take effect rather than being defeated by a cached credential.

## The problem An HTTP fetch or push is a fresh request that must carry a credential. Without help, Git would prompt on every operation. The credential-helper mechanism is Git's pluggable answer: a small protocol between Git and any external program that can remember or produce secrets. ## The protocol A helper is a program named `git-credential-<name>` (or an inline shell command when the config value starts with `!`). Git invokes it with one of three actions and speaks a simple key-value format on standard input and output: - `get` — Git supplies `protocol`, `host`, and possibly `path`; the helper may reply with `username` and `password`. - `store` — after a request succeeds, Git offers the credential so the helper can remember it. - `erase` — after a rejection, Git tells the helper to forget it. This is the step that clears a revoked or expired token; when a helper misses it, users see the infuriating "it keeps sending the old token" symptom. You can drive the same machinery by hand with `git credential fill`, `git credential approve` and `git credential reject`, which is the fastest way to debug what Git is actually retrieving. ## The bundled helpers **store** — appends `https://user:secret@host` lines to `~/.git-credentials` in cleartext (a different file can be given with `--file`). Persistent across reboots, zero setup, and readable by anything that can read the file or a backup of it. **cache** — starts `git-credential-cache--daemon`, which holds credentials in memory and answers over a Unix socket. Nothing is written to disk. The default timeout is 900 seconds and is configurable, for example `credential.helper 'cache --timeout=3600'`. It is a POSIX mechanism, not a Windows one. **osxkeychain / wincred / libsecret** — delegate to the platform's secret store, so the secret is protected by the OS and by the user's login session. This is the sane default on a workstation. **manager** — Git Credential Manager, a cross-platform helper that can additionally drive interactive OAuth-style flows and store the result in the platform store. ## Configuration details worth knowing `credential.helper` is a *multi-valued* setting: several helpers can be configured and Git asks each in order until one supplies a credential, then offers `store` to all of them. Because values accumulate across config scopes, setting `credential.helper` to an empty string resets the list — the standard way to neutralize something a system-level config imposed. Helpers can be scoped per URL, as in `credential.https://example.com.helper`, so different hosts use different mechanisms. `credential.useHttpPath=true` makes the repository path part of the lookup key, which matters when one host must hold different credentials for different repositories — without it, one entry per host is the granularity. When no helper answers, Git prompts on the terminal, or calls the program named by `GIT_ASKPASS` or `core.askPass` if one is set. In automation, `GIT_TERMINAL_PROMPT=0` turns a would-be prompt into an immediate failure instead of a hung job. ## Choosing one On a workstation, prefer the OS keychain helper. In ephemeral CI containers, prefer not to persist at all: supply the token through an askpass hook or an inline helper that reads it from the environment, so nothing is left in a file on a shared image. `store` is acceptable only where the filesystem is genuinely private and short-lived, and even then it is worth knowing that the secret is sitting in cleartext.

  • A rotated token keeps failing even though you updated it. What is happening?
    A helper is still returning the old value. Git only forgets a credential when a rejection triggers the `erase` action, and if a different helper earlier in the list answers first, the stale secret is served before the updated one is reached. Inspect what Git retrieves with `git credential fill`, erase it explicitly, and check for helpers configured at system or global scope.
  • Why would you set credential.useHttpPath to true?
    By default the lookup key is protocol plus host, so one host holds one credential. With `useHttpPath` enabled the repository path joins the key, letting different repositories on the same host use different tokens. It is what you want when one machine holds narrowly scoped per-repository credentials, at the cost of more entries to manage.
  • What is the safest helper choice inside an ephemeral CI container?
    Usually none of the persisting ones. Provide the secret from the job's environment through an askpass program or an inline helper that echoes it, so it lives only in process memory for the run. Writing to `~/.git-credentials` risks the secret being captured in a layer, a cache, or an artifact of the build image.

saying these in an interview costs you the question

  • Thinks credential.helper encrypts secrets by itself
  • Believes store keeps credentials only for the session
  • Assumes the last configured helper wins
  • Never considers that erase is what clears stale tokens
  • Puts a token in the remote URL instead of a helper

context