From ed44eee01d963fc385d314f646425d50d2710976 Mon Sep 17 00:00:00 2001 From: Jerry Xie Date: Sat, 28 Mar 2026 22:31:51 -0700 Subject: [PATCH 1/4] fix: check all git config scopes, not just --global The previous implementation only checked --global git config, but users may have their git identity configured in: - Local repository config (.git/config) - System config (/etc/gitconfig) - Other scopes This change first tries --global, then falls back to checking all scopes if --global returns empty. This ensures we detect git configuration regardless of where it's set. Closes git config detection issue --- internal/system/system.go | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/internal/system/system.go b/internal/system/system.go index f22be6e..1ac19db 100644 --- a/internal/system/system.go +++ b/internal/system/system.go @@ -70,11 +70,19 @@ func InstallHomebrew() error { } func GetGitConfig(key string) string { + // Try global first (most common) output, err := RunCommandSilent("git", "config", "--global", key) - if err != nil { - return "" + if err == nil && output != "" { + return output + } + + // Fall back to any available config (local, system, etc.) + output, err = RunCommandSilent("git", "config", key) + if err == nil { + return output } - return output + + return "" } func GetExistingGitConfig() (name, email string) { From 7db09da9d83828ef7a3d3175eb7dfd4ec594397f Mon Sep 17 00:00:00 2001 From: Jerry Xie <> Date: Sat, 28 Mar 2026 22:50:59 -0700 Subject: [PATCH 2/4] test: add test for git config scope fallback Adds TestGetGitConfig_FallsBackToAnyScope to verify that GetGitConfig checks all git config scopes (global, local, system) when looking for user.name and user.email, not just --global. Related to git config detection issue --- internal/system/system_test.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/internal/system/system_test.go b/internal/system/system_test.go index 84ca188..48234a7 100644 --- a/internal/system/system_test.go +++ b/internal/system/system_test.go @@ -302,3 +302,21 @@ func TestRunCommandSilent_MultilineOutput(t *testing.T) { assert.Contains(t, output, "line2") assert.Contains(t, output, "line3") } + +// TestGetGitConfig_FallsBackToAnyScope verifies that GetGitConfig checks all git config scopes, +// not just --global. This handles cases where user.name/user.email are set in local or system config. +// Regression test for: git config detection issue +func TestGetGitConfig_FallsBackToAnyScope(t *testing.T) { + tmpDir := t.TempDir() + t.Setenv("HOME", tmpDir) + + // Create a temporary git config file + gitConfigDir := tmpDir + "/.config/git" + os.MkdirAll(gitConfigDir, 0755) + + // Test that GetGitConfig returns empty when nothing is set + value := GetGitConfig("user.testkey") + // If git is not installed or no config exists, should return empty + // The function tries --global first, then falls back to any scope + assert.IsType(t, "", value) +} From 7d6fec4ee1b46147b7f2417feeb01a2a07382e52 Mon Sep 17 00:00:00 2001 From: Jerry Xie <> Date: Sat, 28 Mar 2026 22:57:06 -0700 Subject: [PATCH 3/4] fix: don't check dotfiles repo state when URLs are empty The diffDotfiles function was always checking the local ~/.dotfiles git state, even when comparing snapshots with empty dotfiles URLs. This caused test failures when the user's actual dotfiles repo had uncommitted changes. Fix: Only check dotfiles repo state if at least one URL is configured. If both system and reference have empty dotfiles URLs, skip the git state check entirely. This makes the tests deterministic and not dependent on the user's local dotfiles repo state. --- internal/diff/compare.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/internal/diff/compare.go b/internal/diff/compare.go index 57c292f..c7f414c 100644 --- a/internal/diff/compare.go +++ b/internal/diff/compare.go @@ -171,6 +171,12 @@ func diffDotfiles(systemURL, referenceURL string) *DotfilesDiff { dd.RepoChanged = &ValueChange{System: systemURL, Reference: referenceURL} } + // Only check local dotfiles repo state if dotfiles are actually configured + // If both URLs are empty, there's no dotfiles setup to check + if sysNorm == "" && refNorm == "" { + return dd + } + // Check local dotfiles repo for dirty state home, err := os.UserHomeDir() if err != nil { From 7072234b0ee73052c626cd9a76b9492956a51bdc Mon Sep 17 00:00:00 2001 From: Jerry Xie Date: Sat, 28 Mar 2026 23:48:27 -0700 Subject: [PATCH 4/4] refactor: remove trailing whitespace and improve test coverage for git config fallback --- internal/system/system.go | 3 +-- internal/system/system_test.go | 35 +++++++++++++++++++++++++--------- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/internal/system/system.go b/internal/system/system.go index 1ac19db..a920f12 100644 --- a/internal/system/system.go +++ b/internal/system/system.go @@ -75,13 +75,12 @@ func GetGitConfig(key string) string { if err == nil && output != "" { return output } - // Fall back to any available config (local, system, etc.) output, err = RunCommandSilent("git", "config", key) if err == nil { return output } - + return "" } diff --git a/internal/system/system_test.go b/internal/system/system_test.go index 48234a7..8c82f20 100644 --- a/internal/system/system_test.go +++ b/internal/system/system_test.go @@ -310,13 +310,30 @@ func TestGetGitConfig_FallsBackToAnyScope(t *testing.T) { tmpDir := t.TempDir() t.Setenv("HOME", tmpDir) - // Create a temporary git config file - gitConfigDir := tmpDir + "/.config/git" - os.MkdirAll(gitConfigDir, 0755) - - // Test that GetGitConfig returns empty when nothing is set - value := GetGitConfig("user.testkey") - // If git is not installed or no config exists, should return empty - // The function tries --global first, then falls back to any scope - assert.IsType(t, "", value) + // Create a git repo in tmpDir + cmd := exec.Command("git", "init") + cmd.Dir = tmpDir + if err := cmd.Run(); err != nil { + t.Skip("git not installed, skipping") + } + + // Set a local config value (not global) + cmd = exec.Command("git", "config", "user.localtest", "local-value") + cmd.Dir = tmpDir + require.NoError(t, cmd.Run()) + + // Change to the tmpDir so git can find the local config + oldWd, _ := os.Getwd() + os.Chdir(tmpDir) + defer os.Chdir(oldWd) + + // Set XDG_CONFIG_HOME to avoid reading global git config + oldXdg := os.Getenv("XDG_CONFIG_HOME") + os.Setenv("XDG_CONFIG_HOME", tmpDir+"/nonexistent") + defer os.Setenv("XDG_CONFIG_HOME", oldXdg) + + // The global config should be empty since we changed HOME + // but the local config should be found via fallback + value := GetGitConfig("user.localtest") + assert.Equal(t, "local-value", value, "GetGitConfig should fall back to local config when global is not set") }