21+ years in hosting · Jaipur, India · INR billing with 18% GST · 24/7 email support
Blog · WebJi® India

How to Deploy a Website with Git

Quick answer

To deploy a website with Git, push the commit that should be live. Static HTML can publish from a GitHub Pages branch. A site that needs PHP, a database, or your server uses a bare repository and a post-receive hook, or a GitHub Actions job that copies the build into public_html.

For developers publishing sites by push instead of drag-and-drop FTP: three deploy paths, the exact commands, and the rollback when a push goes wrong.

✓ In business since 2005
✓ INR + GST billing
✓ 24/7 Email Support — avg reply < 60 min
GuideWebJi®
knowledge
Read time
5 min
Sections
6
Updated
14 Nov 2026
Written by
WebJi® team

Git deploy versus FTP for a website

Git publishes one named commit; FTP uploads whichever files you drag across, and keeps no record of what the server held before that upload. An FTP session can mix yesterday's stylesheet with today's HTML, and you cannot name that mix afterwards. Git can check the previous commit out again, so the live files return to a state you already ran.

Three ways to deploy a website with Git, by what the site needs
MethodUse it whenYou know it worked when
GitHub PagesStatic HTML, CSS and images in a repositoryThe Pages URL serves the index file from that branch
Post-receive hookPHP or other files served from your own server over SSHThe hook checks the commit out and the live URL matches it
GitHub ActionsA project that must be built before anything is uploadedThe workflow is green and public_html holds only the build output

Pick the row from what the site needs to run. Plain HTML can use the first row. PHP, a database, or a repository that must stay private belongs on a server you control. If you are still weighing the transport itself, the trade-offs between the two protocols are set out in FTP versus SFTP.

How to deploy a static website with GitHub Pages

GitHub Pages serves the files in a repository as a static website, and nothing more: it does not run PHP, Python or Ruby. On the free GitHub plan this works for a public repository; a private repository needs a paid GitHub plan before Pages will publish it.

  1. Create the repository. A user site must be named username.github.io, in lowercase. A project site can use any name.
  2. Add an entry file at the top of the folder you will publish: index.html, index.md or README.md. Without one, Pages has nothing to serve.
  3. Open Settings, then Pages, and choose the branch and folder that hold that file.
  4. Push the commit and open the site URL. Allow up to 10 minutes the first time.

A user site is served at https://username.github.io/ and a project site at https://username.github.io/repository-name/. Later changes go live the same way: commit, push, refresh. If the URL is still a 404 after ten minutes, the entry file is not at the top of the branch and folder you selected — Pages will not run a server-side app to fill that gap.

How a post-receive hook deploys a website with Git

A post-receive hook is an executable script at hooks/post-receive inside a bare repository on your server; Git runs it after accepting a push, and the script checks the new commit out into the folder the web server reads. You need SSH as a user who can write that folder.

On a WebJi® account that means VPS hosting, where you hold root and configure the shell yourself — it is not a feature to assume on every shared plan. If your plan is shared and you want this workflow, use the contact form and name the plan before you write a hook; the honest alternative on shared hosting is the file manager or FTP upload described in uploading a website over FTP.

  1. On the server, outside the web root, create the bare repository:
    git init --bare /home/USER/repo.git
  2. Create hooks/post-receive, make it executable, and give it one working line:
    chmod +x /home/USER/repo.git/hooks/post-receive
    git --work-tree=/home/USER/public_html --git-dir=/home/USER/repo.git checkout -f
  3. On your computer, add the server as a remote and push:
    git remote add deploy user@server:/home/USER/repo.git
    git push deploy main

You know it worked when the push prints the checkout and a file that exists only in that commit is what the live URL serves. If the push succeeds and the site stays old, the hook is not executable or the work-tree path is wrong.

How GitHub Actions deploys a built website

Use GitHub Actions when the browser should receive your build output, not your source: a Vite or similar project must be built first, and the job can build it and copy only the result. A red job has published nothing, so read the log before you push again.

  1. Store the server host, the SSH user and a private key that user accepts as repository secrets — never in the workflow file.
  2. On a push to main, install dependencies and run the build, so a folder such as dist or build exists.
  3. Copy only that folder to the server:
    rsync -az --delete dist/ user@server:/home/USER/public_html/
  4. Stop when the job is green and the live URL shows a string that exists only in that build.

Do not copy the whole repository: node_modules and the source tree are not the website. A static site with no build step can be checked out straight into the web root; a built site must land there only after the build, with the index.html inside dist, not the project root. A worked example of a Node application behind Nginx on a VPS is in deploying Next.js with PM2 and Nginx.

Permissions, ownership and what stays out of the repository

"Permission denied" during a push or checkout names one layer — SSH, the hook's execute bit, or file ownership — and it is never a sign that Git itself is broken. Read the words in brackets before you change anything. The deploy user has to own the directory, or the web server will not serve the new files; directories at 755, files at 644, all owned by the same user. On cPanel the account user already owns public_html; on a Linux VPS you create that user yourself, and a hook that runs as root leaves files the next deploy cannot replace.

Keep four things out of the commit in the first place:

  • Secrets: .env files, database passwords and API keys do not belong in a repository the server checks out.
  • Dependencies: node_modules and vendor are installed on the machine that builds; they are not committed.
  • Machine junk: .DS_Store and editor folders are not part of the site.
  • Build output, conditionally: if Actions builds the site, ignore dist and let the job upload it. If the hook checks the repository out as the live site, the HTML must be in the commit — ignoring index.html means the site will not have it.

How to roll a Git website deploy back

Rollback is why Git beats FTP for a site you will change again: the old files are still a commit, so tag the one you trust while it is live. Both deploy paths undo in one command.

On the hook path, SSH in and check the previous hash out:

git --work-tree=/home/USER/public_html --git-dir=/home/USER/repo.git checkout -f OLDER-COMMIT-HASH

From your computer you can instead git revert the bad commit and push, so the hook runs the same way it does for a normal release. On the Actions path, re-run the workflow from the older commit; if you deploy into timestamped folders and flip a symlink, point the symlink back. In every case you know it worked when the live page matches the file from the older commit, not the one you just removed.

FAQ

Frequently asked questions

How do I deploy a website using Git?

Push the commit that should be live. For static HTML, publish a GitHub Pages branch that contains index.html. For a site on your own server, push to a bare repository whose post-receive hook checks that commit out into public_html, or let GitHub Actions copy the built folder there.

Can I host a website on GitHub, and how do I publish plain HTML there?

Yes, when the site is static. Put index.html at the top of the branch you will publish, push the repository, then in Settings open Pages and select that branch. A user site serves at https://username.github.io/ and a project site at https://username.github.io/repository-name/. GitHub Pages does not run PHP or a database.

What is a Git post-receive hook?

It is an executable script at hooks/post-receive inside a bare repository on your server. Git runs it after a push is accepted, and a website hook uses that moment to check the new commit out into public_html — the folder the web server reads. The hook needs SSH access as a user who can write that folder.

How do I auto-deploy from GitHub to my own server?

Add a GitHub Actions workflow on push to main. It builds the site if a build is required, then copies only that output over SSH into public_html, commonly with rsync. Keep the host, the SSH user and the private key in repository secrets. The live site changes when the job is green, not before.

My git push says permission denied — what is wrong?

Read the bracketed words first: they name the failing layer, whether SSH access, the hook's execute bit, or ownership of the web folder. Make sure the deploy user owns public_html with directories at 755 and files at 644. Git itself is almost never the problem; the layers around it are.

Commands verified against Git's documented behaviour · Reviewed by the WebJi® team, Jaipur.

WebJi® since 2005

Ready to get started with WebJi®?

Join 12,000+ businesses across India and overseas. INR pricing, 18% GST shown before payment and 24/7 email support in Hindi and English — average first reply under 60 minutes.