Playbook / Guide 9 min read

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.

TS
ThemeSync Team
WHO ACTUALLY WRITES TO A SHOPIFY THEMEYouLiquid, CSS and JS through commits, branches and pull requests.uses gitThe merchantSection order, copy, images and settings via the theme editor.no gitTheir appsSnippets and blocks injected into templates and theme.liquid.no gitWhoever else has accessA freelancer, a marketer, the previous agency, an admin code editor at 11pm.no gitOnly the first one uses git. The rest write straight to the store.

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.

This is why "we set up CI/CD for the theme" sometimes makes things worse. Automation applied in the wrong direction converts an occasional accident into a reliable one.

Sync direction is the whole design decision

Get this right and most of the problems disappear. Development themes and live themes need opposite defaults.

TWO THEME TYPES, OPPOSITE RULESDEV THEMELIVE / DRAFT THEMESource of truthYour branchThe storeAutomatic directiongit → themetheme → gitDeploysContinuousManual onlyWho else writes hereNobodyMerchant + appsRisk of a bad pushLowHighConfig churn in commitsMinimalConstantAutomatic pulling only records. Automatic pushing destroys.

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.
One-line version: pull automatically, push deliberately. Pulling only ever adds information; pushing is the only direction that can destroy.

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.

BranchRepresentsWritten by
productionExactly what's on the live theme, including merchant and app changesThe sync process, automatically
mainYour integrated, reviewed workMerged pull requests
feature/*One piece of work, one dev themeYou
release/*A candidate prepared for deployCut 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.

Two concepts, side by side
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:
.gitattributes
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.

Don't gitignore it. When a client asks "why did the homepage change last Tuesday", that file is the only thing that can answer. The churn is the price of having a record.

The deploy sequence

Every live deploy runs the same three phases, in this order. The first one is the one that gets skipped.

Pull, merge, then push
# 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.

If the pre-deploy pull produces a large diff, stop. That's a signal the store has drifted more than you expected. Read it before you merge — that's exactly the moment the information is useful.

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 production branch that mirrors the live theme. git diff production main is 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 →