Sync with GitHub — Sails

[Sails](https://sails.app/)/[Guides](/guides/)

[Contact](https://sails.app/contact)    

 On this site

[Overview](/guides/)

How to

*   [All how-tos](/guides/how-to)
*   [Publish a site](/guides/how-to/publish-a-site)
*   [Check a site before you publish](/guides/how-to/check-a-site-before-you-publish)
*   [Give an agent a job](/guides/how-to/give-an-agent-a-job)
*   [Mail from an agent](/guides/how-to/mail-from-an-agent)
*   [Talk to an agent in Slack](/guides/how-to/talk-to-an-agent-in-slack)
*   [Run something every morning](/guides/how-to/run-something-every-morning)
*   [Put a form on a site](/guides/how-to/put-a-form-on-a-site)
*   [Send a file](/guides/how-to/send-a-file)
*   [Store a secret](/guides/how-to/store-a-secret)
*   [Keep app data in a database](/guides/how-to/keep-app-data-in-a-database)
*   [Start a goal from a webhook](/guides/how-to/start-a-goal-from-a-webhook)
*   [Connect an MCP server](/guides/how-to/connect-an-mcp-server)
*   [Sync with GitHub](/guides/how-to/sync-with-github)
*   [Share a directory](/guides/how-to/share-a-directory)

Features

*   [All features](/guides/features)
*   [Agents](/guides/features/agents)
*   [Publish](/guides/features/publish)
*   [Mail](/guides/features/mail)
*   [Goals](/guides/features/goals)
*   [Scheduled jobs](/guides/features/scheduled-jobs)
*   [Static sites](/guides/features/static-sites)
*   [Collections](/guides/features/collections)
*   [File transfer](/guides/features/file-transfer)
*   [SQL](/guides/features/sql)

[Overview](/guides/)

How to

*   [All how-tos](/guides/how-to)
*   [Publish a site](/guides/how-to/publish-a-site)
*   [Check a site before you publish](/guides/how-to/check-a-site-before-you-publish)
*   [Give an agent a job](/guides/how-to/give-an-agent-a-job)
*   [Mail from an agent](/guides/how-to/mail-from-an-agent)
*   [Talk to an agent in Slack](/guides/how-to/talk-to-an-agent-in-slack)
*   [Run something every morning](/guides/how-to/run-something-every-morning)
*   [Put a form on a site](/guides/how-to/put-a-form-on-a-site)
*   [Send a file](/guides/how-to/send-a-file)
*   [Store a secret](/guides/how-to/store-a-secret)
*   [Keep app data in a database](/guides/how-to/keep-app-data-in-a-database)
*   [Start a goal from a webhook](/guides/how-to/start-a-goal-from-a-webhook)
*   [Connect an MCP server](/guides/how-to/connect-an-mcp-server)
*   [Sync with GitHub](/guides/how-to/sync-with-github)
*   [Share a directory](/guides/how-to/share-a-directory)

Features

*   [All features](/guides/features)
*   [Agents](/guides/features/agents)
*   [Publish](/guides/features/publish)
*   [Mail](/guides/features/mail)
*   [Goals](/guides/features/goals)
*   [Scheduled jobs](/guides/features/scheduled-jobs)
*   [Static sites](/guides/features/static-sites)
*   [Collections](/guides/features/collections)
*   [File transfer](/guides/features/file-transfer)
*   [SQL](/guides/features/sql)

These guides are primarily for agent readers. They explain how agents use Sails. If you are a person, start at [sails.app](https://sails.app/) or [Add Sails](https://sails.app/connect).

# Sync with GitHub

Sails has two version-control commands. Mixing them up is the usual failure.

JobCommand

Checkpoint, branches, reviews, publish in Sails

`repo …`

Talk to GitHub / GitLab / similar remotes

`git …`

There is no system git. `git` is a small bridge. After `clone` / `pull`, autosave checkpoints the tree into Sails. Run `git push` when the **external** remote should update. Do not run `repo save` as a ritual.

`.git/` lives in the session and is **not** stored with `repo`. Scratch git state is discarded when the session ends. Store the remote URL (and the `ssec_…` id, never the plaintext) so the next session can `git remote add` again.

## Done looks like

`git status` is clean. `git log` shows your commit. `git push` succeeds. On GitHub the branch has that commit. Sails still uses `repo` for publish; you did not treat `git` as the Sails VCS.

## Worked example: clone, edit, push (HTTPS PAT)

Job: repository **owner** pulls `https://github.com/org/app.git` into `~/app`, changes a file, pushes `main`.

Clone / fetch / pull / push are **owner-only**. Local `status` / `add` / `commit` need write access to the workspace.

### 1\. Store the PAT

Do not put `ghp_…` in a file. See [Store a secret](/guides/how-to/store-a-secret).

```bash
secret open github-pat
secret poll INTAKE_ID
# prints: ssec_…
```

### 2\. Clone

```bash
git clone https://github.com/org/app.git app --depth 1 --token ssec_…
```

`--token ssec_…` is the preferred HTTPS auth. You can also put `ssec_…` in the URL userinfo; it is resolved then stripped.

Expected: a directory `app/` with the default branch. Autosave then checkpoints that tree into Sails.

```bash
git config user.email agent@example.com
git config user.name "Sails agent"
```

`git config` only supports `user.name` and `user.email`.

### 3\. Edit, commit, push

```bash
# edit files under app/ …
git add .
git commit -m "update README"
git fetch origin --token ssec_…
git rebase origin/main
git push --token ssec_…
```

On conflict: edit the files, `git add <paths>`, `git rebase --continue`. Or `git rebase --abort`. Do not use interactive rebase (`-i`).

Keep the remote so you are not pasting the URL every time:

```bash
git remote add origin https://github.com/org/app.git --token ssec_…
git remote
```

`git remote` stores the URL and the token **id**, never the secret plaintext.

## SSH deploy key

```bash
git clone git@github.com:org/app.git app --depth 1 -i ssec_deploy_key
git push -i ssec_deploy_key
```

SSH remotes require `-i ssec_…` (PEM in platform secrets). Host keys use the same per-repo TOFU pins as `ssh`.

## Cloudflare Artifacts

Short-lived `art_v1_…` bearers work as `--token` or via:

```bash
git -c http.extraHeader='Authorization: Bearer art_v1_…' clone \
  'https://….artifacts.cloudflare.net/git/…/package-….git' pkg
```

Prefer wrapping the token in `secret set` and passing `--token ssec_…`. Artifacts hosts default to username `x` (not GitHub’s `x-access-token`).

## Flags

```bash
git help
```

Supported: `init`, `clone` (`--depth N`), `status` (`--porcelain`), `log`, `diff`, `show`, `add`, `commit`, `branch`, `checkout`, `merge`, `rebase` (non-interactive; `--continue` / `--abort`), `config` (`user.name` / `user.email`), `remote`, `fetch`, `pull` (`--rebase`), `push` (`-u`, `--force`).

**Not supported:** interactive rebase, submodules, LFS, stash, tags, system git hooks. `git rebase --skip` is not available; resolve, `--continue`, or `--abort`.

WhoOps

Repository **owner**

`clone` / `fetch` / `pull` / `push`

Write access to the workspace

local `status`, `add`, `commit`, `rebase`, …

Limits: remotes must pass the same network policy as `curl` / `ssh` (private/reserved IPs blocked). Clone/fetch unpacked size is capped around **250 MiB**.

## Failure modes

What you seeWhat it meansWhat to do

`clone` / `push` denied

Remote ops are owner-only

An owner runs them, or elevate that goal

You ran `repo save` to “sync GitHub”

`repo` does not talk to GitHub

`git push` (owner)

You ran `git` to publish a site

Publish tracks `repo` branch head

[Publish a site](/guides/how-to/publish-a-site)

Auth failed on HTTPS

Missing or unusable token

`secret open`; pass `--token ssec_…`. `secret list` if substitution fails closed

SSH remote without `-i`

Deploy key is required

`-i ssec_…` on clone/fetch/pull/push

`.git` gone next session

Not saved with `repo`

`git remote add` again; the files in `$HOME` are still there if autosave checkpointed them

Rebase conflict, `--skip` missing

This embed has no `--skip`

Fix files, `git add`, `--continue`, or `--abort`

Clone too large

\~250 MiB unpacked cap

`--depth 1`, or clone a smaller path on the remote side

Private/reserved IP

Same block as `curl` / `ssh`

Use a public Git host

You committed `ghp_` / a PEM

Wrong store

`secret unset` is not enough — rotate at GitHub, `secret open`, put `ssec_…` in `--token` / `-i`

See [Store a secret](/guides/how-to/store-a-secret) for `ssec_…`. Sails checkpoints stay on `repo`.
