Push to GitHub
Connect GitHub, let MaShop create a private mashop-{slug} repo in your account, and push the full backoffice template as one commit. The repo is yours.
How-to
This page shows you how to connect GitHub, get a private repository created in your own GitHub account, and push your generated code into it. The repository is yours: MaShop creates it under your login, pushes with your token, and never holds a copy of your code.
What MaShop puts on GitHub
When you publish a project, MaShop does three things on your GitHub account:
- Creates a private repository named
mashop-{slug}, where{slug}is your project slug. - Pushes the full merchant backoffice template into that repository as a single commit.
- Records the repository on your project so later pushes and the Netlify deploy target it.
The repository lives in your account, not MaShop's. MaShop acts through the OAuth token you grant, so every commit shows as pushed by you. Netlify then builds from this repository, which is why the deploy fails with no linked repo. See Netlify deploys and Deploy overview.
Step 1: connect GitHub
Open the GitHub panel in the workspace. When you have never connected GitHub, the panel shows Connectez votre compte GitHub pour pousser ce projet vers un depot. and a Se connecter a GitHub button.
Clicking it starts the OAuth flow at /api/oauth/initiate?provider=github. MaShop requests the repo user:email scope, which is what lets it create a repository and push commits. A popup opens on GitHub; you authorize, and the popup closes itself.
On success, MaShop exchanges the code for an access token, encrypts it, and stores it in oauth_tokens keyed by your user and the github provider. It also reads your GitHub profile and sets github_connected, github_username, and your avatar on your profile. After that, the GitHub panel shows a green dot and GitHub connecte.
MaShop stores an encrypted OAuth token, not your GitHub password. The token is decrypted only on the server when MaShop needs to talk to GitHub on your behalf. Your prompts and generated code are not sent to OpenAI or Anthropic.
Step 2: how the repository name is built
MaShop derives the repository name from your project slug. The slug is lowercased, every character that is not a letter, digit, dot, dash, or underscore becomes a dash, leading and trailing dashes are trimmed, and the result is capped at 90 characters. MaShop then prefixes it with mashop-.
So a project with slug my-coffee-shop becomes the repository mashop-my-coffee-shop. If the slug is empty, the name falls back to mashop-project.
Step 3: publish to create and push the repo
Repository creation and the code push run as two stages of the publish flow. In the workspace, the Publish modal (titled Publier votre site ou app) drives a resumable provisioning state machine. It calls POST /api/projects/[projectId]/provision and polls every 3 seconds, showing each stage as it completes.
Two of those stages are the GitHub stages:
| Stage | What it does |
|---|---|
github_creating_repo | Creates mashop-{slug} if your project has no linked repo yet. |
github_pushing_template | Pushes the backoffice template into the repo as one commit. |
In the modal these read Creation de votre depot GitHub and Envoi du code dans votre depot. The second task shows a live file count as the push runs.
Publishing creates real infrastructure on your own accounts, so it is owner-only and gated to a paid plan. On the Free plan the provision route returns 402 with La publication necessite un plan payant. (code UPGRADE_REQUIRED). See Plans.
Step 4: what the repository creation does
When MaShop creates the repository, it calls GitHub's create-for-authenticated-user endpoint with private: true and auto_init: true. The auto_init flag means GitHub seeds the repo with one initial commit so a main branch exists to push onto.
Creation is idempotent. If a repository with that name already exists on your account (for example a previous attempt created it but crashed before recording it), MaShop reuses the existing repository instead of failing. It catches the GitHub 422 "name already exists" response, looks the repo up, and continues. After creating or reusing, MaShop saves github_repo (as owner/name) and github_branch on your project row.
Step 5: what gets pushed, and how
The push is a single commit, not a file-by-file upload. MaShop uses GitHub's Git data API: it fetches the branch HEAD, builds one tree with every template file inlined as blob content, creates one commit on top of HEAD, then moves the branch ref to it. That is roughly three API calls regardless of file count.
The payload is the entire templates/backend/ tree: the universal Next.js 15 backoffice, its components, libraries, and its own Supabase migrations. As generated, that bundle is 592 files. The commit message is:
feat: scaffold merchant backoffice from MaShop template
This commit was generated by MaShop onboarding (Slice 2 - provision-github).
Because the tree is built on top of the auto-init HEAD, GitHub's seeded files survive unless the template ships its own version of the same path, in which case the template's file wins. The push is also idempotent: once a commit SHA is recorded for the project, a retry skips the push and moves on to the Netlify build rather than committing the code a second time.
The provisioning push always sends the backoffice template. Pushing your later AI edits is a separate action, covered in Step 7.
Step 6: link an existing repository instead
If you would rather use a repository you already own, MaShop can link it instead of creating a new one. The connect-repo endpoint accepts two modes:
| Mode | Behaviour |
|---|---|
create | Creates a new repo from the name you pass. The name must match a single segment. |
link | Links an existing repo passed as owner/name. MaShop verifies it exists, then records it on your project. |
Either way, MaShop persists github_repo and github_branch on your project, and the provisioning push then targets that repository. Listing your repos for the linker is rate limited to 20 requests per minute, and connecting is limited to 10 per minute.
Step 7: push later changes from the workspace
After the first push, the provisioning template push does not run again. To send your subsequent project files to the repository, MaShop exposes a manual push at POST /api/github/push. It reads the project files, commits them on top of the recorded branch, and updates the last-pushed SHA and timestamp on your project.
This push has guardrails:
- Any file whose name starts with
.envis dropped before committing, so secrets never reach the repo. - The push rejects more than 500 files or a total payload over 5 MB.
- It is rate limited to 10 pushes per 5 minutes per user.
When no message is given, the commit message defaults to chore: sync from MaShop builder (N files). On success the response includes the commit SHA and a link to it on GitHub.
Failure modes you may hit
| Message | Cause |
|---|---|
GitHub non connecte | No stored GitHub token. Connect GitHub first (Step 1). |
GitHub OAuth not connected. The merchant must reconnect GitHub before the template can be pushed. | The token row is missing or unreadable at the push stage. Reconnect GitHub, then retry the publish. |
name invalide / existingRepo invalide | The repo name or owner/name you passed failed validation. |
Aucun repo GitHub connecte | You triggered a manual push before any repository was linked to the project. |
In the Publish modal, any GitHub-stage failure is shown as Erreur cote GitHub. Verifiez votre connexion GitHub puis reessayez. The raw error stays in the console; retrying resumes the state machine from where it stopped, so a recovered run does not recreate the repository or duplicate the commit.
Next steps
- Build from the repo: Netlify deploys.
- Understand the full ownership model: Your code.
- Understand what the builder generates: How the AI builder works.
