# Git and source control (/docs/concepts/git-and-source-control)



Bowline syncs the files in your workspace and leaves source control to you. Commits, branches, remotes, staging, and publishing stay with Git, jj, and your forge, exactly as they are today. This separation is the Source-Control Boundary, and it's what keeps Bowline a sync engine rather than a Git wrapper.

## The Source-Control Boundary [#the-source-control-boundary]

The Source-Control Boundary is the rule that Bowline syncs workspace files and leaves Git, jj, forges, commits, branches, remotes, staging, and publishing to your tools. Bowline carries the bytes in your tree across machines and agents; you decide when and how that work becomes commits and pull requests.

Supporting Git means not breaking Git projects by syncing the files inside them. It does not mean Git integration. Your `git`, `jj`, and forge workflows run unchanged, because Bowline never reaches into them.

<Callout type="warn" title="Important">
  Bowline is not a Git wrapper. It must not run Git commands, edit
  `.gitignore`, stage files, create commits or branches, manage remotes, open
  pull requests, repair Git state, or publish to a forge. Source control is
  always driven by your tools, never by Bowline.
</Callout>

This table summarizes the split.

| Bowline does this                              | You and your tools do this                |
| ---------------------------------------------- | ----------------------------------------- |
| Sync workspace files across authorized devices | Commit, branch, and rebase                |
| Sync `.git/` bytes as Opaque Git State         | Manage remotes and fetch or push          |
| Carry uncommitted and unpublished work         | Stage changes and resolve Git merges      |
| Report advisory Git status (read-only)         | Open pull requests and publish to a forge |

## `.git/` syncs as Opaque Git State [#git-syncs-as-opaque-git-state]

The `.git/` directory still travels with your project, because losing it would break the repository on your next machine. Bowline syncs it as Opaque Git State: encrypted `.git/` bytes carried as workspace state without ever being interpreted as Git.

Bowline must not parse, repair, merge, publish, or mutate `.git/` as Git. To the sync engine, those are ordinary opaque bytes. A few rules keep this safe:

* High-confidence `.git/` lock and temp files are generated tool state and stay local by default, so transient files like `*.lock`, `gc.log`, and `objects/pack/tmp_*` don't spread across machines.
* Divergent `.git/` state between machines creates a normal [Sync Conflict](/docs/concepts/conflicts). There's no Git-aware merge and no last-writer-wins.
* Everything else in `.git/` syncs by bytes only, so your local history and refs follow you without Bowline understanding them.

## Continuity doesn't depend on Git ceremony [#continuity-doesnt-depend-on-git-ceremony]

Git cleanliness isn't the contract for your work following you. A directory with local edits, brand-new files, or no remote at all still holds real work, and that work travels through [Workspace Snapshots](/docs/concepts/workspace-model) regardless of Git state.

This is the promise across machines and agents:

```text
No remote: keep working.
Uncommitted edits: keep working.
New files: keep working.
Agent finished without committing: keep working.
Open the project later and keep working.
```

When an agent finishes a task without committing, its output still becomes a Workspace Snapshot and follows you. You publish later with Git or any other tool, on your schedule. Until then, the work is already in `~/Code` on your next machine. See [sync and continuity](/docs/concepts/sync-and-continuity) for how snapshots capture work as you go, and [working with agents](/docs/guides/working-with-agents) for how agent output lands.

## The read-only Git observer [#the-read-only-git-observer]

Bowline can run a read-only Git observer purely to make status, freshness, and explanations more useful. It inspects local repository metadata and local remote-tracking state to report advisory signals only.

| Signal        | Meaning                                                       |
| ------------- | ------------------------------------------------------------- |
| Dirty state   | The working tree has uncommitted changes.                     |
| Known remotes | The remotes configured in the local repository.               |
| Ahead/behind  | Local commits relative to the last-known remote-tracking ref. |
| Stale base    | The branch is based on an old upstream point.                 |

The observer is advisory and read-only. It must not fetch, write, repair, merge, publish, or decide sync semantics, and `.git/` remains Opaque Git State to the sync engine. These signals help you understand a project's state in `bowline status` and `bowline explain`; they never drive what Bowline syncs.

<Callout type="info">
  The Git observer never changes your repository. If it can't read Git metadata,
  Bowline still syncs your files normally. The observer only adds context to
  status output.
</Callout>

## Next steps [#next-steps]

* [Workspace model](/docs/concepts/workspace-model): snapshots, heads, and overlays that carry work without Git.
* [Sync and continuity](/docs/concepts/sync-and-continuity): how Bowline captures work as you go.
* [Path policy](/docs/concepts/path-policy): what under your root syncs, and how `.bowlineignore` overrides it.
* [Conflicts](/docs/concepts/conflicts): how divergent state, including `.git/`, is preserved and repaired.
* [Status and health](/docs/concepts/status-and-health): where advisory Git signals appear.
