Sync with GitHub
Sails has two version-control commands. Mixing them up is the usual failure.
| Job | Command |
|---|---|
| Checkpoint, branches, reviews, publish in Sails | repo … |
| Talk to GitHub / GitLab / similar remotes | git … |
There is no system git. git is a small bridge to external remotes. 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.
Run git from inside the repository workspace ($HOME or a folder under it). That is where autosave and the bridge agree on which files exist.
Done looks like
git status is clean. git log --oneline 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 / rebase need write access to the workspace.
1. Store the PAT for the git host
Do not put ghp_… in a file. secret open requires --origin, and the origin has to match the host git talks to. Git over HTTPS talks to https://github.com, not https://api.github.com. A token stored for the API origin will not authenticate a clone. See Store a secret.
secret open --origin https://github.com github-pat
Expected output (shape):
Open this URL to submit the secret:
https://…/secrets/intake/…
Intake: 8c1e…
Open the URL, sign in as a repository owner, paste the PAT, submit. Then:
secret poll 8c1e…
# prints: ssec_a1b2c3d4...
Do not pass --wait from bash_exec. You would not see the URL until the wait ends. Print, then secret poll.
2. Clone
git clone https://github.com/org/app.git app --depth 1 --token ssec_a1b2c3d4...
--token ssec_… is the preferred HTTPS auth. You can also put ssec_… in the URL userinfo (https://x-access-token:ssec_…@github.com/org/app.git); it is resolved, then stripped. The HTTPS username defaults to x-access-token. Pass --username NAME when a host wants something else.
Expected: a directory app/ with the default branch. Autosave then checkpoints that tree into Sails.
cd app
git config user.email agent@example.com
git config user.name "Sails agent"
git config only supports user.name and user.email. Anything else fails with git config: only user.name and user.email are supported.
3. Save the remote once
A fresh clone is enough to push in the same session. To keep the auth with the remote (and for a later git init workspace), add it with the token id:
git remote add origin https://github.com/org/app.git --token ssec_a1b2c3d4...
git remote
# origin
git remote stores the URL and the token id, never the secret plaintext. Change the URL with git remote set-url origin URL. Drop it with git remote remove origin.
4. Edit, commit, rebase, push
# edit files under app/ …
git status --porcelain
git diff
git add -A
git diff --cached
git commit -m "update README"
git fetch origin --token ssec_a1b2c3d4...
git rebase origin/main # or: git pull --rebase origin main --token ssec_…
git push origin main --token ssec_a1b2c3d4...
Expected after the commit (ids differ):
$ git status
On branch main
nothing to commit, working tree clean
$ git log --oneline -n 1
eedec5f update README
On conflict: edit the files, git add <paths>, git rebase --continue. To drop the commit that conflicts, git rebase --skip. To give up, git rebase --abort. Interactive rebase (-i) is not available.
First push of a new branch:
git checkout -b fix-typo
# edit, add, commit …
git push -u origin fix-typo --token ssec_a1b2c3d4...
git push --force exists. Use it only on a branch you own; it rewrites history on GitHub.
SSH deploy key
Store the private key PEM as a platform secret, then pass its ssec_… id with -i on every remote op:
git clone git@github.com:org/app.git app --depth 1 -i ssec_deploy_key
git remote add origin git@github.com:org/app.git -i ssec_deploy_key
git fetch origin -i ssec_deploy_key
git push origin main -i ssec_deploy_key
SSH remotes (git@host:org/repo.git or ssh://…) require -i ssec_…. Host keys use the same per-repo TOFU pins as ssh, so a GitHub host you already pinned for SSH to a host is trusted here too.
Cloudflare Artifacts
Artifacts remotes use short-lived art_v1_… bearers. One-shot clone with the header form:
git -c http.extraHeader='Authorization: Bearer art_v1_…' clone \
'https://….artifacts.cloudflare.net/git/…/package-….git' pkg
-c http.extraHeader='Authorization: Bearer …' is the only -c setting the bridge accepts. It maps to --token. art_v1_… also works directly as --token, or embedded in the URL userinfo.
When you will reuse the remote or push later, wrap the bearer in a secret (paste only the art_v1_… value, no ?expires=). Set --origin to the Artifacts host from the clone URL, scheme + host only:
printf '%s' "$ART_TOKEN" | secret set --origin https://….artifacts.cloudflare.net --stdin
# prints: ssec_…
git clone 'https://….artifacts.cloudflare.net/git/…/package-….git' pkg --token ssec_…
Artifacts hosts default to username x (not GitHub's x-access-token).
Live usage
git help prints the full usage. Subcommands do not take --help (git clone --help fails with unsupported flag '--help').
git [-c http.extraHeader='Authorization: Bearer <token>'] <command> …
git init [--bare] [directory]
git clone <url> [directory] [--depth N] [-i ssec_…] [--token ssec_|art_v1_…] [--username NAME]
git status [--porcelain]
git log [--oneline] [-n N]
git diff [--cached] [refs…] [--] [paths…]
git show <object>
git add [-A|--all] <path>…
git commit -m <message> [--allow-empty]
git branch [<name>] | git branch -d <name>
git checkout [-b] <branch|ref>
git merge <branch> | git merge --abort | git merge --continue
git rebase <upstream> | git rebase --continue|--abort|--skip
git config user.name|user.email <value>
git remote | git remote add <name> <url> [-i ssec_…] [--token ssec_|art_v1_…] [--username NAME]
git remote remove <name> | git remote set-url <name> <url>
git fetch [remote] [-i ssec_…] [--token ssec_|art_v1_…] [--username NAME]
git pull [--rebase] [remote] [branch] [-i ssec_…] [--token ssec_|art_v1_…] [--username NAME]
git push [-u] [--force] [remote] [branch] [-i ssec_…] [--token ssec_|art_v1_…] [--username NAME]
| Flag | Where | What it does |
|---|---|---|
--token ssec_… / art_v1_… | clone, remote add, fetch, pull, push | HTTPS auth |
-i ssec_… | same | SSH deploy key (required for SSH remotes) |
--username NAME | same | HTTPS username. Default x-access-token, or x on Artifacts hosts |
--depth N | clone | Shallow clone. Use it on big repos |
-u | push | Set upstream for a new branch |
--force | push | Overwrite the remote branch |
--rebase | pull | Rebase instead of merge |
--porcelain | status | Machine-readable status for scripts |
--oneline, -n N | log | Short history |
--cached | diff | Staged changes |
--allow-empty | commit | Commit with no changes |
Not supported: interactive rebase, submodules, LFS, stash, tags, system git hooks, any git config key besides user.name / user.email.
| Who | Ops |
|---|---|
| Repository owner | clone / fetch / pull / push |
| Write access to the workspace | local init, status, add, commit, branch, checkout, merge, 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 see | What it means | What to do |
|---|---|---|
clone / push denied | Remote ops are owner-only | An owner runs them, or elevate that goal |
secret: secret open requires --origin URL | You ran secret open github-pat with no origin | secret open --origin https://github.com github-pat |
Clone with a valid ssec_… still fails auth | Secret origin is https://api.github.com (or another host) | Git talks to https://github.com. Store the PAT for that origin |
git: git clone: unsupported flag '--help' | Subcommands have no --help | git help |
git: unknown or unsupported subcommand 'stash' (or 'tag') | Not in the bridge | Commit to a scratch branch instead of stashing. Tag on GitHub |
git: git rebase: interactive rebase (-i) is not supported | No -i | Plain git rebase <upstream>, then --continue, --skip, or --abort |
git: git config: only user.name and user.email are supported | Only those two keys exist | Set only user.name and user.email |
git: there is no rebase in progress | You ran --continue / --skip / --abort with nothing to resume | Check git status; start the rebase first |
git: could not find '…/sails-git/…' to stat | You ran git outside the repository workspace (for example /tmp) | Work under $HOME |
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 the repo branch head | Publish a site |
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 |
| Clone too large | ~250 MiB unpacked cap | --depth 1, or split the repo on the remote side |
| Private/reserved IP | Same block as curl / ssh | Use a public Git host |
You committed ghp_ or a PEM | Wrong store | secret unset is not enough. Rotate at GitHub, secret open --origin https://github.com, use the new ssec_… with --token / -i |
See Store a secret for ssec_…. Sails checkpoints stay on repo.