Summary
Per the agreed framing, libra config is intentionally backed by SQLite + a settings file rather than Git's INI files; this issue only evaluates behavioral consistency at the CLI surface (0.22.5 vs git 2.55) and test coverage. The subcommand layer (config set/get/list/unset) is solid; the Git-compat flag layer has real drift.
Behavior differences
-
--get-regexp <pattern> requires the pattern to contain a literal dot (P1)
libra validates the pattern with the "key must contain a section" rule before treating it as a regex:
$ libra config --get-regexp '^user' # valid regex, matches user.name/user.email
error: key does not contain a section: ^user (LBR-INTERNAL-001, exit 1)
$ libra config --get-regexp '^user\.' # works
user.email = a@b ...
Git: git config --get-regexp '^user' lists all user.* keys (exit 0); a non-matching pattern exits 1. Also note the error is tagged category=internal (LBR-INTERNAL-001) for what is a user-input issue.
The same bug hits --get-all nosuchkey (Git: silent, exit 1; libra: "does not contain a section" — misleading) and value-position patterns.
-
git config <key> <value-pattern> (the third positional) semantics diverge
Git treats the middle positional as a value regex for get/unset and refuses single-value overwrite when multiple values exist ("Use a regexp, --add or --replace-all"):
git config --get multi.k two → prints two.
git config --unset multi.k one → removes only the one entry.
git config multi.k three with 2 existing values → fatal, suggests --add/--replace-all.
libra:
--get multi.k two → ignores the pattern, prints last value (two by accident).
--unset multi.k one → error cannot unset 'multi.k': 2 values exist (pattern ignored).
multi.k three (bare set) → error cannot set: 2 values exist — matches Git's refusal but libra has no --replace-all to resolve it, so a multi-valued key can only be cleared with --unset-all. --replace-all is simply missing from the compat surface.
-
--show-origin output format
--list --show-origin: libra prints local core.bare = false (scope label); Git prints file:/path/to/config<TAB>core.bare=false. For the file-backed upgrade.* keys libra does print file:{path} (tested), so the two formats coexist. Scripts parsing origin will break either way; undocumented in COMPATIBILITY.md.
--show-origin is silently ignored by --get/--get-all/--get-regexp — libra prints the bare value with no origin and exit 0, while Git prefixes every match with file:.... Confirmed for --get (plain value only) and --get-regexp.
-
--show-scope and --file <path> are not implemented — unexpected argument. --file is how Git does one-off script config; nothing in help/COMPATIBILITY.md says "use subcommands instead".
-
--type support is a strict subset: bool|int|path work (verified: --type=bool x.y true canonicalizes; --get --type=path expands ~/x — matches Git). Missing: bool-or-str, color, expiry-date, int size suffixes like 1k on read canonicalization. Error message is clear, so this is a gap note, not a bug.
-
config edit — libra: error: config edit is not supported (SQLite storage does not support text-based editing), exit 128. Git opens $EDITOR. Intentional (storage), but exit 128 + no hint pointing to config set makes it a dead end; also GIT_EDITOR=true git config --edit is used in countless CI scripts that will hard-fail.
-
Exit-code drift: libra config --get nonexistent.key exits 1 (matches Git). --get-regexp no-match exits 1 (matches). But --get-regexp 'user' (the "no dot" bug) also exits 1 — with a wrong error. config edit exits 128 vs Git's success. --system on a non-root box: libra fails reads with fatal: failed to read system config ... where Git just skips a missing/unreadable file.
-
Verified-consistent areas (no issue): -z/--null record format for --get-regexp/--list matches key\nvalue\0; --get-all ordering; --add allowing duplicates; --unset-all count reporting; --remove-section/--rename-section; --bool/--int/--path shortcuts; -d/--default (Git actually rejects --get --default without --get in older versions — libra's broader support is a superset); spell-correction hints (did you mean) are a libra-only UX improvement.
Test gaps vs Git
t/t1300-config.sh is Git's largest config suite (~200 cases). libra's tests/command/config_test.rs has 79 tests, and the following behaviors are untested (all verified to be wrong or undocumented above):
--get-regexp with a dotless pattern (current behavior: misleading error).
--get <key> <value-pattern> / --unset <key> <value-pattern> positional semantics.
--show-origin with --get/--get-all/--get-regexp (currently silently ignored).
--type unsupported-values error path (bool-or-str/color/expiry-date).
- exit-code table for
config edit / --file / --show-scope rejections.
--get-all for a missing key without a dot (current: "does not contain a section" instead of clean exit 1).
Summary
Per the agreed framing,
libra configis intentionally backed by SQLite + a settings file rather than Git's INI files; this issue only evaluates behavioral consistency at the CLI surface (0.22.5 vs git 2.55) and test coverage. The subcommand layer (config set/get/list/unset) is solid; the Git-compat flag layer has real drift.Behavior differences
--get-regexp <pattern>requires the pattern to contain a literal dot (P1)libra validates the pattern with the "key must contain a section" rule before treating it as a regex:
Git:
git config --get-regexp '^user'lists all user.* keys (exit 0); a non-matching pattern exits 1. Also note the error is taggedcategory=internal(LBR-INTERNAL-001) for what is a user-input issue.The same bug hits
--get-all nosuchkey(Git: silent, exit 1; libra: "does not contain a section" — misleading) and value-position patterns.git config <key> <value-pattern>(the third positional) semantics divergeGit treats the middle positional as a value regex for
get/unsetand refuses single-value overwrite when multiple values exist ("Use a regexp, --add or --replace-all"):git config --get multi.k two→ printstwo.git config --unset multi.k one→ removes only theoneentry.git config multi.k threewith 2 existing values → fatal, suggests--add/--replace-all.libra:
--get multi.k two→ ignores the pattern, prints last value (twoby accident).--unset multi.k one→ errorcannot unset 'multi.k': 2 values exist(pattern ignored).multi.k three(bare set) → errorcannot set: 2 values exist— matches Git's refusal but libra has no--replace-allto resolve it, so a multi-valued key can only be cleared with--unset-all.--replace-allis simply missing from the compat surface.--show-originoutput format--list --show-origin: libra printslocal core.bare = false(scope label); Git printsfile:/path/to/config<TAB>core.bare=false. For the file-backedupgrade.*keys libra does printfile:{path}(tested), so the two formats coexist. Scripts parsing origin will break either way; undocumented in COMPATIBILITY.md.--show-originis silently ignored by--get/--get-all/--get-regexp— libra prints the bare value with no origin and exit 0, while Git prefixes every match withfile:.... Confirmed for--get(plain value only) and--get-regexp.--show-scopeand--file <path>are not implemented —unexpected argument.--fileis how Git does one-off script config; nothing in help/COMPATIBILITY.md says "use subcommands instead".--typesupport is a strict subset:bool|int|pathwork (verified:--type=bool x.y truecanonicalizes;--get --type=pathexpands~/x— matches Git). Missing:bool-or-str,color,expiry-date,intsize suffixes like1kon read canonicalization. Error message is clear, so this is a gap note, not a bug.config edit— libra:error: config edit is not supported (SQLite storage does not support text-based editing), exit 128. Git opens$EDITOR. Intentional (storage), but exit 128 + no hint pointing toconfig setmakes it a dead end; alsoGIT_EDITOR=true git config --editis used in countless CI scripts that will hard-fail.Exit-code drift:
libra config --get nonexistent.keyexits 1 (matches Git).--get-regexpno-match exits 1 (matches). But--get-regexp 'user'(the "no dot" bug) also exits 1 — with a wrong error.config editexits 128 vs Git's success.--systemon a non-root box: libra fails reads withfatal: failed to read system config ...where Git just skips a missing/unreadable file.Verified-consistent areas (no issue):
-z/--nullrecord format for--get-regexp/--listmatcheskey\nvalue\0;--get-allordering;--addallowing duplicates;--unset-allcount reporting;--remove-section/--rename-section;--bool/--int/--pathshortcuts;-d/--default(Git actually rejects--get --defaultwithout--getin older versions — libra's broader support is a superset); spell-correction hints (did you mean) are a libra-only UX improvement.Test gaps vs Git
t/t1300-config.shis Git's largest config suite (~200 cases). libra'stests/command/config_test.rshas 79 tests, and the following behaviors are untested (all verified to be wrong or undocumented above):--get-regexpwith a dotless pattern (current behavior: misleading error).--get <key> <value-pattern>/--unset <key> <value-pattern>positional semantics.--show-originwith--get/--get-all/--get-regexp(currently silently ignored).--typeunsupported-values error path (bool-or-str/color/expiry-date).config edit/--file/--show-scoperejections.--get-allfor a missing key without a dot (current: "does not contain a section" instead of clean exit 1).