A Git Workflow for Shopify Themes That Survives Client Edits
Standard git assumes developers are the only ones changing the code. On a Shopify store, merchants and apps are committing too — they just aren’t using git.
Why normal git advice doesn’t fit
Git works on the assumption that everyone changing the code is using git. Application code satisfies that. Shopify themes don't.
On a live store, at least three other parties write to the same files you do, and none of them commit. Every one of those changes is legitimate — a merchant reordering sections is doing their job, an app injecting a snippet is what the merchant paid for.
So the usual model, where your branch is authoritative and deploys push it outward, has a hidden cost: every deploy silently reverts everyone else's work. Automate that and you've built a machine that destroys merchant edits on a schedule.
Sync direction is the whole design decision
Get this right and most of the problems disappear. Development themes and live themes need opposite defaults.
Stated as rules:
- Development themes: your branch wins. Commits flow out to the theme. Nobody else is editing, so there's nothing to lose.
- Live and draft themes: the store wins. Pull on a schedule and commit what changed. Git becomes a record of reality rather than an instruction to overwrite it.
- Deploying to live is always a human action. Preceded by a pull, so you can see what you're about to replace.
A branching model that fits theme work
Theme projects don't need much ceremony. What they do need is a branch that honestly represents the live store.
| Branch | Represents | Written by |
|---|---|---|
production | Exactly what's on the live theme, including merchant and app changes | The sync process, automatically |
main | Your integrated, reviewed work | Merged pull requests |
feature/* | One piece of work, one dev theme | You |
release/* | A candidate prepared for deploy | Cut from main before a release |
production is the branch most teams don't have and most need. It isn't where you work — it's a mirror. Its value is that git diff production main answers the question you need before every deploy: what will this release change on the live store, including things I didn't write?
Showing a client two directions
A branch per direction, each on its own development theme, is far better than two draft themes on the store. It costs no theme slots, keeps both options current as you iterate, and the client can switch between them without you rebuilding anything.
git switch -c feature/homepage-editorial
git switch -c feature/homepage-conversion
# Each branch drives its own dev theme; client compares both live.
Living with settings_data.json
Once you're pulling from a live theme, config/settings_data.json becomes the noisiest file in the repo. Every colour tweak and section reorder is a diff, frequently a large and unreadable one.
The failure mode is predictable: the noise gets annoying, someone gitignores the file, and now theme configuration isn't in version control at all — which was the main thing worth capturing.
What works instead
- Separate commits for config. Prefix them
config:so code review stays readable and a bad settings change can be reverted alone. - Never hand-merge it. Take one side entirely. A half-merged settings file produces sections that don't render, and diagnosing that is miserable.
- Set a merge strategy. Tell git not to attempt a textual merge on these files:
config/settings_data.json merge=ours
templates/*.json merge=ours
That makes conflicts a deliberate choice rather than a mess to untangle. Pick a side, then verify by loading the page.
The deploy sequence
Every live deploy runs the same three phases, in this order. The first one is the one that gets skipped.
# 1. Capture anything the store changed since the last sync
shopify theme pull --theme $LIVE_THEME --store $STORE
git add -A && git commit -m "config: pre-deploy sync from store" || true
# 2. Bring in the release
git merge --no-ff release/2026-09-30
# 3. Push, having seen exactly what changes
git diff --stat HEAD~1
shopify theme push --theme $LIVE_THEME --allow-live --store $STORE
Phase one is what makes this safe. Without it you're pushing a branch that doesn't know about last Tuesday's banner change, and the deploy removes it.
Rollback
Because production mirrors the live theme, rollback is a commit reference rather than an archaeology exercise. Check out the commit from before the deploy and push that. Combined with duplicating the live theme beforehand, you have two independent ways back.
How ThemeSync implements this
- Direction is set per theme type. Development themes sync git out to the theme. Production themes pull from the store and commit what changed — the store stays the source of truth where it should be.
- Pull intervals are configurable, including off. Every 30 seconds for an active build, five minutes for a store being watched, manual-only when you want nothing happening on its own.
- Deploys pull before pushing. The pre-deploy sync is part of the flow rather than a step you remember, so last-minute merchant edits survive your release.
- Editor changes come back into the branch. Review themes run with editor sync on, so client work in the customiser lands as commits instead of being overwritten.
- Uncommitted store changes are visible before you push. You see what's changed on the theme versus what you're about to upload, so overwriting is a decision rather than an accident.
- Sync health is visible per store. Healthy, syncing, stale or erroring — across a portfolio, rather than discovered during a deploy.
- Versions are branches. Showing a client two directions means two branches on development themes, costing no theme slots on their store.
Takeaways
- Git assumes developers are the only authors. On a Shopify store, merchants, apps and other contractors all write to the same files.
- Development themes: your branch is the source of truth, push freely.
- Live themes: the store is the source of truth. Pull automatically, push manually.
- Keep a
productionbranch that mirrors the live theme.git diff production mainis your pre-deploy safety check. - Commit config separately, never hand-merge
settings_data.json, and don't gitignore it. - Always pull before deploying. A large pre-deploy diff is information, not an inconvenience.
- Use branches, not extra draft themes, to show clients alternative directions.
Git that respects what the merchant changed
ThemeSync syncs development themes from git and live themes into git, pulls before every deploy, and shows you uncommitted store changes before anything is overwritten.
Try ThemeSync Free →