Files
josh-sync/docs/adr/005-git-trailer-loop-prevention.md
sync-bot b35703d271 Import josh-sync from subrepo/main
Sync-Origin: import/josh-sync/20260528-041502
2026-05-28 04:15:02 +01:00

2.4 KiB

ADR-005: Git Trailer for Loop Prevention

Status: Accepted Date: 2026-01

Context

Bidirectional sync creates an infinite loop risk: forward sync pushes commit A to the subrepo, reverse sync sees commit A as "new" and creates a PR back to the monorepo, forward sync sees the merged PR as "new" and pushes again, etc.

Alternatives considered

  1. SHA tracking only: Compare SHAs to skip already-synced content. Breaks when josh-proxy rewrites SHAs (which it always does for filtered views). The monorepo commit SHA and the filtered/subrepo commit SHA are never the same.

  2. Commit message prefix: Add [sync] to bot commit messages. Fragile — humans might use the same prefix. Requires string matching on message content.

  3. Git trailer: A structured key-value pair in the commit message body (after a blank line), following the git interpret-trailers convention. Format: Key: value. Machine-parseable, unlikely to be used by humans, and supported by git log --grep.

Decision

All bot commits include a git trailer with a configurable key (default: Josh-Sync-Origin). Both sync directions filter out commits containing this trailer.

Format

Sync from monorepo 2026-02-12T10:30:00Z

Josh-Sync-Origin: forward/main/2026-02-12T10:30:00Z

The trailer value encodes: direction, branch, and timestamp. This aids debugging but is not parsed by the loop filter — only the trailer key presence matters.

Filtering

  • Reverse sync: git log --invert-grep --grep="^${BOT_TRAILER}:" excludes all commits with the trailer
  • CI loop guard: The composite action checks if HEAD commit has the trailer before running sync at all

Configuration

The trailer key is set in .josh-sync.yml under bot.trailer. This allows multiple josh-sync instances (with different bots) to operate on the same repos without interfering.

Consequences

Positive:

  • Reliable loop prevention — trailer is part of the immutable commit object
  • Configurable key avoids conflicts between multiple sync bots
  • Human-readable — git log shows the trailer in commit messages
  • CI loop guard prevents unnecessary sync runs entirely

Negative:

  • Commits with manually-added trailers matching the key would be incorrectly filtered
  • Trailer must be in the commit body (after blank line), not the subject line
  • Squash-and-merge on PRs may lose the trailer if the platform doesn't preserve commit message body