Now departing · laptop to TestFlight

From the gate to the
App Store, in one command.

Ship an iOS app to TestFlight from your laptop. No CI, no Ruby, no Fastlane setup tax. One bash script that does the whole release in a single pass.

$ curl -fsSL https://raw.githubusercontent.com/tshiv/pushback/main/install.sh | bash
✈ DEPARTURES--:--
FLIGHT
DESTINATION
GATE
STATUS
PB·001
TESTFLIGHT
main
ON TIME
PB·002
APP STORE
next
BOARDING
The whole release

One command. Eight steps. You watch it go.

This is a real pushback run in PR mode: it verifies the build, runs the gate, merges the PR, bumps the version, archives, uploads, and pushes. You type one thing and walk away.

~/flip-or-pass · pushback
The flight plan

Every leg of the trip, in order.

The name is the joke and the spec. In aviation, pushback is the tug easing the plane off the gate, the first move of departure. Here is each leg, start to wheels-down.

Slow is smooth, smooth is fast

The two things it refuses to get wrong.

A release tool earns trust by what it will not do. pushback is careful in exactly the two places where a mistake actually costs you.

Pre-merge

A broken build can't land in main.

pushback detects the open PR for your branch, checks your local HEAD matches it, and verifies the build compiles before the squash-merge. Most setups catch a broken build after the merge. pushback catches it before, so main stays shippable.

Burned build numbers

It never reverts a number the upload already burned.

Once the upload to App Store Connect succeeds, that build number is gone. Reuse it and your next run fails validation. If the upload lands but the commit doesn't, pushback leaves the bump in place and tells you exactly what to run. It knows the one thing you must never undo.

Honest positioning

Reach for the right tool.

pushback is not trying to be Fastlane, and it's not a fastlane killer. It's the glue for one specific case, made first-class. Here's when to use what.

pushbackthis thing

One app. One person. Shipping from a laptop, no CI. You just want the build on TestFlight without the ceremony. It drives xcodebuild, git, gh, and xcodegen directly. iOS only, on purpose.

Fastlaneincumbent

A team sharing certificates (match), automating App Store metadata and screenshots, or running inside CI. If that's you, use Fastlane. It's great at it.

ascpower tool

You want fine-grained control over the App Store Connect API from a scriptable Go binary, with 1,200+ endpoints to compose yourself. asc is the toolkit; pushback is the opinionated workflow.

Xcode + altoolbuilt in

You ship rarely and don't mind the clicks: Archive, Export, Upload, by hand, every time. Free, manual, and fine for a couple releases a year.

What it isn't: it's a 30KB bash script, not a platform. iOS only. It assumes you use xcodegen with a project.yml and ship with gh. No screenshots, no metadata, no multi-platform, no dashboard. If you need those, that's Fastlane's job, not this one.

Get started

Install, point it at your app, ship.

Install the script

One file onto your PATH. No package manager, no runtime.

# installs to the first writable dir on your PATH
curl -fsSL https://raw.githubusercontent.com/tshiv/pushback/main/install.sh | bash
needs gitneeds ghneeds xcodegenneeds Xcodeneeds App Store Connect API key optional xcbeautifyoptional maestro

Add a tiny config

Drop a .pushbackrc in your project. It's plain shell, so no YAML parser. In most projects you only set the scheme; everything else derives from it.

# ios/.pushbackrc
PUSHBACK_PRODUCT_NAME="my app"
PUSHBACK_APP_DIR="ios"
PUSHBACK_SCHEME="MyApp"

Rehearse, then ship

Run a dry run first. It does everything reversible and stubs the merge, archive, upload, and push, then reverts the bump. When it looks right, drop the flag.

# rehearse the whole thing, change nothing
pushback --config ios/.pushbackrc --dry-run

# then for real: auto-detects an open PR, else ships the current branch
pushback --config ios/.pushbackrc