PABLO
Docs
Documentation home

Getting started

  • What is PABLO?
  • Quickstart
  • Installation
  • Your first project
  • Your first task

Guides

  • Managing tasks
  • Dashboard
  • Analytics
  • Backups & restore
  • Troubleshooting

Concepts

  • How it works
  • Task states
  • Agents
  • Sync & rebase

Reference

  • Commands
  • Configuration
  • Providers
  • Storage

Contributing

  • Development

Concepts

Sync & rebase

PABLO keeps two things up to date for every project: your task branches, rebased onto the primary branch, and the project's main checkout, fast-forwarded to the remote. Both are cautious: they report by default, skip anything with local changes, and never resolve a conflict in code.

Task branches#

On each project's sync.interval_minutes (or when you run pablo sync:run), PABLO lists the repository's worktrees and syncs only those that belong to an active task. Other worktrees are left alone. For each one:

  1. fetch, and bring in the branch's own remote first, so a collaborator's push is never overwritten;
  2. rebase or merge (per sync.strategy) onto <primary_remote>/<primary_branch>. For a stacked pull request, an open pull request targeting another branch, it uses that base branch instead, whatever the tracker. A merged or closed pull request's base is ignored, and a base that no longer exists falls back to the primary branch;
  3. if the history changed and the branch exists on the remote, push with --force-with-lease, never plain --force. If the lease fails (someone pushed in the meantime), the worktree is rolled back and sync tries again next time.

Report first, apply when you're ready#

By default sync is a dry run: it reports what it would do. It applies changes only with sync.auto_apply: true in the project (or the global config), or when you run pablo sync:run --apply. Turn auto_apply on for the projects where you know the shape of the work.

bash
pablo sync:run               # every project, dry run
pablo sync:run acme-pim --apply
pablo sync:log               # what the last sync did, per project

Skipped on purpose#

  • ✋ Dirty worktrees, with uncommitted changes, are never rebased.
  • 🔒 Busy tasks: sync and the poller never work on the same task at the same time. A locked task is skipped and retried next time.

Conflicts#

PABLO's code never resolves a conflict. When an applied sync hits one, it aborts the rebase cleanly, records the worktree, the branch, the conflicting files and a summary of the hunks, then launches the rebase-conflict-resolver agent headless. The agent replays the rebase onto the exact target sync used, resolves the conflicts and pushes with --force-with-lease; if it can't resolve something safely, it stops without pushing.

The last sync of each project is shown by pablo sync:log and on the dashboard, including the command to open the resolver's session. Each sync replaces the previous log: there's no history, only what the last one did.

Primary checkout update#

On each project's main_update.interval_minutes (default 60, or when you run pablo sync:main), PABLO brings the project's main checkout (repo.path, not the task worktrees) up to date with <primary_remote>/<primary_branch>. Turn it off for a project with main_update.enabled: false.

The checks run in this order; the first one that matches decides:

SituationOutcome
repo.path is missing or isn't a git checkout⚠️ missing, skipped
a rebase, merge, cherry-pick, revert or bisect is in progress✋ busy, skipped
any change in git status, tracked or untracked, on any branch✋ dirty, skipped
git fetch fails, or the remote branch doesn't exist❌ the job fails and is retried next time
the local primary branch has commits that aren't on the remote✋ ahead, skipped: local commits are never thrown away
clean, on another branch, while the primary branch is checked out in another worktree⚠️ checked-out-elsewhere, skipped
clean, on another branch or a detached HEADgit checkout <primary_branch> (created from the remote if needed), then the next row
clean, on the primary branchgit reset --hard <primary_remote>/<primary_branch>: ✅ updated or up-to-date

Because a branch with local commits is never touched, the reset --hard is in practice a fast-forward. Task worktrees aren't affected: they always start from the remote primary branch, never from your local one.

bash
pablo sync:main             # every project with main_update enabled
pablo sync:main acme-pim    # this one, even if main_update is disabled
PreviousAgents NextCommands

Edit this page on GitHub

On this page

  • Task branches
  • Report first, apply when you're ready
  • Skipped on purpose
  • Conflicts
  • Primary checkout update
PABLO

MIT licensed · made by Baptiste Leduc · GitHub · Docs