Skip to content

git/gogit: add FetchAndReset for push-retry recovery - #1289

Open
monotek wants to merge 1 commit into
fluxcd:mainfrom
monotek:retry-push-conflict-fetch-reset
Open

monotek wants to merge 1 commit into
fluxcd:mainfrom
monotek:retry-push-conflict-fetch-reset

Conversation

@monotek

@monotek monotek commented Aug 31, 2026

Copy link
Copy Markdown

Why

In deployments with many independent ImageUpdateAutomation (IUA) objects pushing to the same branch of one GitOps repo (e.g. one IUA per service/region, all on independent reconcile timers), push rejections become common once write concurrency is high enough. Today image-automation-controller has no in-process retry for a failed push — the next attempt only happens on the next scheduled reconcile, or via controller-runtime's per-item exponential-backoff requeue (750ms doubling, capped at 15min). Under contention, a single IUA can lose several races in a row, each costing a full backoff cycle, turning a sub-minute git operation into a delay of tens of minutes.

A companion PR (fluxcd/image-automation-controller#1090) adds a retry-with-backoff loop there, analogous to a git pull --rebase && git push retry loop reusing the same local clone across attempts (no re-clone). go-git has no rebase API, so the equivalent here is: fetch (cheap, incremental) → hard-reset onto the new remote tip → let the caller recompute and recommit → push again. That retry loop needs a way to catch a working directory up to the new remote tip without a full re-clone (today gogit.Client only exposes Clone, not Fetch).

What

  • Adds (*gogit.Client).FetchAndReset(ctx, branch): fetches branch from the remote via a scoped refspec and hard-resets the current worktree onto the fetched tip. Never touches the remote. Swallows go-git's NoErrAlreadyUpToDate. Mirrors SwitchBranch's plain (ctx, branchName) signature — no new config struct, since there's exactly one purpose and one caller today.
  • No changes to the repository.Reader/Writer/Client interfaces — image-automation-controller holds a concrete *gogit.Client, so this is purely an additive new method on the concrete type.

Testing

  • TestFetchAndReset: a stale client with its own unpushed local commit recovers onto the winner's pushed tip, working tree content included; a second call with nothing new is a no-op.
  • make test-git passes, go vet/gofmt clean.

@monotek
monotek marked this pull request as ready for review September 1, 2026 16:25
@monotek
monotek requested a review from a team as a code owner September 1, 2026 16:25
@monotek
monotek marked this pull request as draft September 9, 2026 13:03
image-automation-controller can lose a push race when many independent
ImageUpdateAutomation objects push to the same branch. Recovering
cheaply requires catching a working directory up to the new remote tip
without a full re-clone, regardless of why the previous push failed.

Add FetchAndReset(ctx, branch), which fetches branch via a scoped
refspec and hard-resets the current worktree onto the fetched tip,
swallowing NoErrAlreadyUpToDate.

No changes to the Reader/Writer/Client interfaces; it is a new method
on the concrete gogit.Client type.

Assisted-by: Claude Sonnet 5/claude-sonnet-5
Signed-off-by: André Bauer <monotek23@gmail.com>
@monotek
monotek force-pushed the retry-push-conflict-fetch-reset branch from c1457b1 to 3299da0 Compare September 9, 2026 13:10
@monotek monotek changed the title git/gogit: add FetchAndReset and ErrPushRejected for push-conflict recovery git/gogit: add FetchAndReset for push-retry recovery Sep 9, 2026
@monotek
monotek marked this pull request as ready for review September 9, 2026 14:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant