Documentation
¶
Overview ¶
Package gitconfig implements a pure Go parser of Git SCM config files. The support is currently not matching git exactly, e.g. includes, urlmatches and multivars are currently not supported. And while we try to preserve the original file a much as possible when writing we currently don't exactly retain (insignificant) whitespaces.
The reference for this implementation is https://mirrors.edge.kernel.org/pub/software/scm/git/docs/git-config.html
Usage ¶
Use gitconfig.LoadAll with an optional workspace argument to process configuration input from these locations in order (i.e. the later ones take precedence):
- `system` - /etc/gitconfig
- `global` - `$XDG_CONFIG_HOME/git/config` or `~/.gitconfig`
- `local` - `<workdir>/config`
- `worktree` - `<workdir>/config.worktree`
- `command` - GIT_CONFIG_{COUNT,KEY,VALUE} environment variables
Note: We do not support parsing command line flags directly, but one can use the SetEnv method to set flags from the command line in the config.
Customization ¶
`gopass` and other users of this package can easily customize file and environment names by utilizing the exported variables from the Configs struct:
- SystemConfig - Path to system-wide config (e.g., /etc/gitconfig)
- GlobalConfig - Path to user config (e.g., ~/.gitconfig) or "" to disable
- LocalConfig - Per-repository config name (e.g., .git/config)
- WorktreeConfig - Per-worktree config name (e.g., .git/config.worktree)
- EnvPrefix - Environment variable prefix (defaults to GIT_CONFIG)
Note: For tests users will want to set `NoWrites = true` to avoid overwriting their real configs.
Examples ¶
## Loading and Reading Configuration
Basic reading from all scopes (respects precedence):
cfg := gitconfig.New()
cfg.LoadAll(".")
value := cfg.Get("user.name")
fmt.Println(value) // Reads from highest priority scope available
## Reading from Specific Scopes
Access configuration from a specific scope:
cfg := gitconfig.New()
cfg.LoadAll(".")
local := cfg.GetLocal("core.editor")
global := cfg.GetGlobal("user.email")
system := cfg.GetSystem("core.pager")
## Customization for Other Applications
Configure for a different application (like gopass):
cfg := gitconfig.New()
cfg.SystemConfig = "/etc/gopass/config"
cfg.GlobalConfig = ""
cfg.LocalConfig = ".gopass-config"
cfg.EnvPrefix = "GOPASS_CONFIG"
cfg.LoadAll(".")
notifications := cfg.Get("core.notifications")
## Writing Configuration
Modify and persist changes:
cfg, _ := gitconfig.LoadConfig(".git/config")
cfg.Set("user.name", "John Doe")
cfg.Set("user.email", "[email protected]")
cfg.Write() // Persist changes to disk
## Scope-Specific Writes
Write to specific scopes in multi-scope configs:
cfg := gitconfig.New()
cfg.LoadAll(".")
cfg.SetLocal("core.autocrlf", "true") // Write to .git/config
cfg.SetGlobal("user.signingkey", "...") // Write to ~/.gitconfig
cfg.SetSystem("core.pager", "less") // Write to /etc/gitconfig
## Error Handling
Use errors.Is to detect common error categories:
if err := cfg.Set("invalid", "value"); err != nil {
if errors.Is(err, gitconfig.ErrInvalidKey) {
// handle invalid key
}
}
if err := cfgs.SetLocal("core.editor", "vim"); err != nil {
if errors.Is(err, gitconfig.ErrWorkdirNotSet) {
// call LoadAll or provide a workdir
}
}
Versioning and Compatibility ¶
We aim to support the latest stable release of Git only. Currently we do not provide any backwards compatibility and semantic versioning.
Known limitations ¶
* Worktree support is only partial * Bare boolean values are not supported (e.g. a setting were only the key is present) * includeIf suppport is only partial, i.e. we only support the gitdir option
Index ¶
- Variables
- type Config
- type Configs
- func (cs *Configs) Get(key string) string
- func (cs *Configs) GetAll(key string) []string
- func (cs *Configs) GetFrom(key string, scope string) (string, bool)
- func (cs *Configs) GetGlobal(key string) string
- func (cs *Configs) GetLocal(key string) string
- func (cs *Configs) HasGlobalConfig() bool
- func (cs *Configs) IsSet(key string) bool
- func (cs *Configs) KVList(prefix, sep string) []string
- func (cs *Configs) Keys() []string
- func (cs *Configs) List(prefix string) []string
- func (cs *Configs) ListSections() []string
- func (cs *Configs) ListSubsections(wantSection string) []string
- func (cs *Configs) LoadAll(workdir string) *Configs
- func (cs *Configs) Reload()
- func (cs *Configs) SetEnv(key, value string) error
- func (cs *Configs) SetGlobal(key, value string) error
- func (cs *Configs) SetLocal(key, value string) error
- func (cs *Configs) String() string
- func (cs *Configs) UnsetGlobal(key string) error
- func (cs *Configs) UnsetLocal(key string) error
Constants ¶
This section is empty.
Variables ¶
var ( // ErrInvalidKey indicates a config key missing section or key name. ErrInvalidKey = errors.New("invalid key") // ErrWorkdirNotSet indicates a workdir is required but not configured. ErrWorkdirNotSet = errors.New("no workdir set") // ErrCreateConfigDir indicates a config directory could not be created. ErrCreateConfigDir = errors.New("failed to create config directory") // ErrWriteConfig indicates a config file could not be written. ErrWriteConfig = errors.New("failed to write config") )
var ( // CompatMode enables compatibility mode, which disables certain features like value unescaping. CompatMode bool )
Functions ¶
This section is empty.
Types ¶
type Config ¶
type Config struct {
// contains filtered or unexported fields
}
Config represents a single git configuration file from one scope.
Config handles reading and writing a single configuration file while attempting to preserve the original formatting (comments, whitespace, section order).
Fields: - path: File path of this config file - readonly: If true, prevents any modifications (even in-memory) - noWrites: If true, prevents persisting changes to disk (useful for testing) - raw: Maintains the raw text representation for round-trip fidelity - vars: Map of normalized keys to their values (may be multiple values per key) - branch: Current git branch name (for onbranch conditionals)
Note: Config is not thread-safe. Concurrent access from multiple goroutines is not supported. Callers must provide synchronization if needed.
Typical Usage:
cfg, err := LoadConfig("~/.gitconfig")
if err != nil { ... }
value, ok := cfg.Get("core.editor")
if err := cfg.Set("core.pager", "less"); err != nil { ... }
func LoadConfig ¶
LoadConfig tries to load a gitconfig from the given path.
func LoadConfigFromEnv ¶
LoadConfigFromEnv will try to parse an overlay config from the environment variables. If no environment variables are set the resulting config will be valid but empty. Either way it will not be writeable.
func LoadConfigWithWorkdir ¶
LoadConfigWithWorkdir tries to load a gitconfig from the given path and a workdir. The workdir is used to resolve relative paths in the config.
func NewFromMap ¶
NewFromMap allows creating a new preset config from a map.
func ParseConfig ¶
ParseConfig will try to parse a gitconfig from the given io.Reader. It never fails. Invalid configs will be silently rejected.
func (*Config) Get ¶
Get returns the first value of the key.
For keys with multiple values, Get returns only the first one. Use GetAll to retrieve all values for a key.
The key is case-insensitive for sections and key names but case-sensitive for subsection names (per git-config specification).
Returns (value, true) if the key is found, ("", false) otherwise.
Example:
v, ok := cfg.Get("core.editor")
if ok {
fmt.Printf("Editor: %s\n", v)
}
func (*Config) GetAll ¶
GetAll returns all values of the key.
Git config allows multiple values for the same key. This is common for: - Multiple include paths - Multiple aliases - Arrays in custom configurations
Returns (values, true) if the key is found, (nil, false) otherwise. If found, values will be non-nil but may be empty.
Example:
paths, ok := cfg.GetAll("include.path")
if ok {
for _, path := range paths {
fmt.Printf("Include: %s\n", path)
}
}
func (*Config) IsEmpty ¶
IsEmpty returns true if the config is empty (no configuration loaded).
An empty config is one that: - Is nil - Has no variables loaded - Has no raw content (not just missing path reference)
This is used to distinguish between "not yet loaded" and "loaded but empty file".
func (*Config) IsSet ¶
IsSet returns true if the key was set in this config.
Returns true even if the value is empty string (unlike checking Get with ok).
Example:
if cfg.IsSet("core.editor") {
fmt.Println("Editor is configured")
}
func (*Config) Set ¶
Set updates or adds a key in the config.
Behavior: - If the key exists, the first value is updated - If the key doesn't exist, it's added to an existing section or a new section - If possible, the underlying config file is written to disk - Original formatting (comments, whitespace) is preserved where possible
Errors: - Returns error if readonly or key is invalid (missing section or key name) - Returns error if file write fails (but in-memory value may be set)
This method normalizes the key (lowercase sections and key names) but preserves subsect names' case.
Example:
if err := cfg.Set("core.pager", "less"); err != nil {
log.Fatal(err)
}
func (*Config) Unset ¶
Unset deletes a key from the config.
Behavior: - If the key exists, it's removed from vars and the raw config string - If the key doesn't exist, this is a no-op (no error) - The underlying config file is updated if possible - Readonly configs silently ignore the unset operation
Note: Currently does not remove entire sections, only individual keys within sections.
Example:
if err := cfg.Unset("core.pager"); err != nil {
log.Fatal(err)
}
type Configs ¶
type Configs struct {
Preset *Config
Name string
SystemConfig string
GlobalConfig string
LocalConfig string
WorktreeConfig string
EnvPrefix string
NoWrites bool
// contains filtered or unexported fields
}
Configs represents all git configuration files for a repository.
Configs manages multiple Config objects from different scopes with a unified interface. It handles loading and merging configurations from multiple sourc with priority.
Scope Priority (highest to lowest): 1. Environment variables (GIT_CONFIG_*) 2. Worktree-specific config (.git/config.worktree) 3. Local/repository config (.git/config) 4. Global/user config (~/.gitconfig) 5. System config (/etc/gitconfig) 6. Preset/built-in defaults
Fields: - Preset: Built-in default configuration (optional) - system, global, local, worktree, env: Config objects for each scope - workdir: Working directory (used to locate local and worktree configs) - Name: Configuration set name (e.g., "git" or "gopass") - SystemConfig, GlobalConfig, LocalConfig, WorktreeConfig: File paths - EnvPrefix: Prefix for environment variables (e.g., "GIT_CONFIG") - NoWrites: If true, prevents all writes to disk
Usage:
cfg := New()
cfg.LoadAll(".") // Load from current directory
value := cfg.Get("core.editor") // Reads from all scopes
cfg.SetLocal("core.pager", "less") // Write to local only
func New ¶
func New() *Configs
New creates a new Configs instance with default configuration.
The returned instance is not yet loaded. Call LoadAll() to load configurations.
Default settings: - Name: "git" - SystemConfig: "/etc/gitconfig" (Unix) or auto-detected (Windows) - GlobalConfig: "~/.gitconfig" - LocalConfig: "config" (relative to workdir) - WorktreeConfig: "config.worktree" (relative to workdir) - EnvPrefix: "GIT_CONFIG" - NoWrites: false (allows persisting changes)
These settings can be customized before calling LoadAll():
cfg := New()
cfg.SystemConfig = "/etc/myapp/config"
cfg.EnvPrefix = "MYAPP_CONFIG"
cfg.LoadAll(".")
func (*Configs) Get ¶
Get returns the value for the given key from the first scope that contains it.
Lookup Order (by scope priority): 1. Environment variables (GIT_CONFIG_*) 2. Worktree config (.git/config.worktree) 3. Local config (.git/config) 4. Global config (~/.gitconfig) 5. System config (/etc/gitconfig) 6. Preset/defaults
The search stops at the first scope that has the key. Earlier scopes override later ones.
Returns the value as a string. For keys with multiple values, returns the first one. Returns empty string if key not found in any scope.
Example:
editor := cfg.Get("core.editor")
if editor != "" {
fmt.Printf("Using editor: %s\n", editor)
}
func (*Configs) GetAll ¶
GetAll returns all values for the given key from the first scope that contains it.
Like Get but returns all values for keys that can have multiple entries. See Get documentation for scope priority.
Returns nil if key not found in any scope.
func (*Configs) GetFrom ¶ added in v0.0.4
GetFrom returns the value for the given key from the given scope. Valid scopes are: env, worktree, local, global, system and preset.
func (*Configs) GetGlobal ¶
GetGlobal specifically asks the per-user (global) config for a key.
This bypasses the scope priority and only reads from the global config. Useful when you specifically want settings from ~/.gitconfig.
Returns empty string if the key is not found in the global config.
Example:
name, _ := cfg.GetGlobal("user.name")
func (*Configs) GetLocal ¶
GetLocal specifically asks the per-directory (local) config for a key.
This bypasses the scope priority and only reads from the local config (.git/config). Useful when you specifically want settings from the repository's config.
Returns empty string if the key is not found in the local config.
Example:
url, _ := cfg.GetLocal("remote.origin.url")
func (*Configs) HasGlobalConfig ¶
HasGlobalConfig indicates if a per-user config can be found.
Returns true if a global config file exists at one of the configured locations.
func (*Configs) KVList ¶ added in v0.0.2
KVList returns a list of all keys and values matching the given prefix.
func (*Configs) Keys ¶
Keys returns a list of all keys from all available scopes. Every key has section and possibly a subsection. They are separated by dots. The subsection itself may contain dots. The final key name and the section MUST NOT contain dots.
Examples
- remote.gist.gopass.pw.path -> section: remote, subsection: gist.gopass.pw, key: path
- core.timeout -> section: core, key: timeout
func (*Configs) List ¶
List returns all keys matching the given prefix. The prefix can be empty, then this is identical to Keys().
func (*Configs) ListSections ¶
ListSections returns a sorted list of all sections.
func (*Configs) ListSubsections ¶
ListSubsections returns a sorted list of all subsections in the given section.
func (*Configs) LoadAll ¶
LoadAll loads all known configuration files from their configured locations.
Behavior: - Loads configs from all scopes (system, global, local, worktree, env) - Missing or invalid files are silently ignored - Never returns an error (always returns &cs for chaining) - workdir is optional; if empty, local and worktree configs are not loaded - Processes include and includeIf directives - Merges all configs with proper scope priority
Parameters: - workdir: Working directory (usually repo root) to locate local/worktree configs
Example:
cfg := New()
cfg.LoadAll("/path/to/repo")
// Now ready to use Get, Set, etc.
func (*Configs) Reload ¶
func (cs *Configs) Reload()
Reload reloads all configuration files from disk.
This is useful when configuration files have been modified externally. Uses the same workdir that was provided to the last LoadAll call.
func (*Configs) SetEnv ¶
SetEnv sets (or adds) a key in the per-process (env) config. Useful for persisting flags during the invocation.
func (*Configs) UnsetGlobal ¶
UnsetGlobal deletes a key from the global config.
func (*Configs) UnsetLocal ¶
UnsetLocal deletes a key from the local config.