Skip to content

Handling conflicts

Rebasing rewrites history, and history sometimes disagrees with itself. When sync replays your commits onto an updated parent and Git cannot apply one cleanly, the rebase stops with a conflict. git-city does not paper over this or leave you guessing — it pauses cleanly, tells you exactly where it stopped, and hands you a short menu of next steps.

A pause is not a failure. It is a deliberate checkpoint: the rebase is left in progress in your working tree (exactly as a plain git rebase would), and the remaining work git-city had planned is saved to disk so it can pick up where it left off once you have resolved the conflict.


What a pause looks like

When a sync hits a conflict, git-city stops and prints the state of the paused operation:

git-city: sync add-login is paused.
  stopped on:  git rebase --onto main <base> add-login
  resolve the conflict and `git add`, then:
    git city continue   resume the operation
    git city abort      undo everything and return to the start
    git city info       show this and the repo status

The message names the operation that paused, the exact git command it stopped on, and the three commands that get you out. There is no traceback — git-city errors are always a clean git-city: <message> on stderr.

Note

The pause is persisted to <git-dir>/git-city/runstate.json. It survives closing your terminal: come back tomorrow, finish resolving, and git city continue still works. Because the run-state holds a single operation, only the most recent paused (or completed) command is remembered.


The resolve loop

While paused you are in an ordinary in-progress rebase, so you resolve conflicts with ordinary Git. The cycle is:

Step What you do Tool
1 Open the conflicted files and fix the <<<<<<< / >>>>>>> markers your editor
2 Stage the resolved files git add <file>
3 Tell git-city to carry on git city continue

git city continue resumes the rebase from where it stopped and then runs the rest of the plan git-city had queued — finishing the rebase, force-pushing with --force-with-lease, and moving on to any remaining branches in an --all sync. If resuming uncovers a further conflict, git-city simply pauses again and you repeat the loop.

# fix the conflicted files in your editor, then:
git add src/auth.py
git city continue

Tip

Forgot where you were? git city info leads with the same pause banner shown above, then prints the repo dashboard. It is read-only — run it as many times as you like.


Backing out instead

If you would rather not push through the conflict right now, abort:

git city abort

git city abort undoes the operation entirely and returns you to exactly where you started — the in-progress rebase is unwound and any refs that had already moved are restored. Nothing is left half-applied. You can then sync again later, or change your approach (for example, reparent the branch before retrying).

Command Effect
git city continue Resume after you resolved the conflict and git added
git city abort Roll the whole operation back to its starting point
git city info Re-print the paused state, then the dashboard (read-only)

While an operation is paused

A pause holds a lock on your repository's git-city state, so a few things are intentionally blocked until you resolve it:

Warning

git city undo refuses while an operation is paused. Undo and the pause loop are two different recovery mechanisms — finish the current operation with continue, or unwind it with abort, before reaching for undo.

The right tool depends on the situation:

  • Mid-conflict (sync is paused): use continue to finish or abort to back out.
  • After a completed command: use undo to reverse the last git-city command, replaying its captured inverses in reverse.

Both paths are built on the same reversible engine, which captures how to undo every step before it mutates anything.

Reversible operations


Avoiding conflicts in the first place

Conflicts are most common when a branch and its parent have both moved a long way apart. Syncing often keeps the gap small, so each rebase replays only a handful of commits. Because git-city syncs parents before children, a single git city sync --all keeps an entire stack consistent and minimises the surface area for any one conflict.

sync · Recovery and undo