Fix two git operation bugs

- gitCommitAll: abort commit when staging (git add -A) fails, e.g.
  due to a stale .git/index.lock.  Previously the failure was ignored
  and commit proceeded on an empty or partial index.

- gitPull: remove explicit branch argument from git pull --rebase.
  Passing both remote and branch can conflict with the branch's
  configured tracking ref, causing 'Cannot rebase onto multiple
  branches'.  Now uses just --rebase <remote>, letting git resolve
  the tracking branch from config.

- Test: index.lock scenario verifies commit is aborted on staging
  failure.
This commit is contained in:
2026-05-13 22:51:09 -04:00
parent 7d2a4b3a30
commit 25b8f24906
2 changed files with 23 additions and 7 deletions
+10 -7
View File
@@ -321,17 +321,20 @@ syncRepo opts logger repo = do
-- | Stage all changes and commit with an auto-generated message. -- | Stage all changes and commit with an auto-generated message.
gitCommitAll :: Logger -> FilePath -> IO (ExitCode, Text, Text) gitCommitAll :: Logger -> FilePath -> IO (ExitCode, Text, Text)
gitCommitAll logger repoPath = do gitCommitAll logger repoPath = do
(_, _, stageErr) <- loggedGit logger repoPath ["add", "-A"] addResult@(addCode, _, addErr) <- loggedGit logger repoPath ["add", "-A"]
unless (T.null stageErr) $ unless (T.null addErr) $
logInfo logger ("git add stderr: " <> stageErr) logInfo logger ("git add stderr: " <> addErr)
hostname <- init <$> readProcess "hostname" [] "" if addCode /= ExitSuccess
loggedGit logger repoPath ["commit", "-m", "converge: auto-commit from " <> hostname] then pure addResult
else do
hostname <- init <$> readProcess "hostname" [] ""
loggedGit logger repoPath ["commit", "-m", "converge: auto-commit from " <> hostname]
-- | Pull from the configured remote and branch. -- | Pull from the configured remote, rebasing onto the tracked upstream branch.
gitPull :: Logger -> RepoConfig -> IO (ExitCode, Text, Text) gitPull :: Logger -> RepoConfig -> IO (ExitCode, Text, Text)
gitPull logger repo = gitPull logger repo =
loggedGit logger (rcPath repo) loggedGit logger (rcPath repo)
["pull", "--rebase", T.unpack (rcRemote repo), T.unpack (rcBranch repo)] ["pull", "--rebase", T.unpack (rcRemote repo)]
-- | Push to the configured remote and branch. -- | Push to the configured remote and branch.
gitPush :: Logger -> RepoConfig -> IO (ExitCode, Text, Text) gitPush :: Logger -> RepoConfig -> IO (ExitCode, Text, Text)
+13
View File
@@ -54,6 +54,19 @@ spec = do
countAfter2 <- commitCount repo countAfter2 <- commitCount repo
countAfter2 `shouldBe` countBefore2 countAfter2 `shouldBe` countBefore2
it "aborts commit when staging fails (e.g. index.lock exists)" $ do
logger <- testLogger
withTempGitRepo $ \repo -> do
-- Create a lock file to make git add -A fail
writeFile (repo </> ".git" </> "index.lock") "locked"
writeFile (repo </> "new.txt") "new file"
countBefore <- commitCount repo
(code, _, err) <- gitCommitAll logger repo
-- Staging fails, so commit should not happen
code `shouldSatisfy` (/= ExitSuccess)
err `shouldSatisfy` ("index.lock" `T.isInfixOf`)
commitCount repo `shouldReturn` countBefore
describe "startup sync" $ do describe "startup sync" $ do
it "commits and pushes uncommitted changes on startup" $ do it "commits and pushes uncommitted changes on startup" $ do
logger <- testLogger logger <- testLogger