Skip to content

Instantly share code, notes, and snippets.

@cobyism
Last active November 11, 2024 00:02
Show Gist options
  • Save cobyism/4730490 to your computer and use it in GitHub Desktop.
Save cobyism/4730490 to your computer and use it in GitHub Desktop.
Deploy to `gh-pages` from a `dist` folder on the master branch. Useful for use with [yeoman](http://yeoman.io).

Deploying a subfolder to GitHub Pages

Sometimes you want to have a subdirectory on the master branch be the root directory of a repository’s gh-pages branch. This is useful for things like sites developed with Yeoman, or if you have a Jekyll site contained in the master branch alongside the rest of your code.

For the sake of this example, let’s pretend the subfolder containing your site is named dist.

Step 1

Remove the dist directory from the project’s .gitignore file (it’s ignored by default by Yeoman).

Step 2

Make sure git knows about your subtree (the subfolder with your site).

git add dist && git commit -m "Initial dist subtree commit"

Step 3

Use subtree push to send it to the gh-pages branch on GitHub.

git subtree push --prefix dist origin gh-pages

Boom. If your folder isn’t called dist, then you’ll need to change that in each of the commands above.


If you do this on a regular basis, you could also create a script containing the following somewhere in your path:

#!/bin/sh
if [ -z "$1" ]
then
  echo "Which folder do you want to deploy to GitHub Pages?"
  exit 1
fi
git subtree push --prefix $1 origin gh-pages

Which lets you type commands like:

git gh-deploy path/to/your/site
@fabriziomartini
Copy link

"git push origin :gh-pages && git subtree push --prefix dist origin gh-pages" - this command worked perfectly

@VenexCon
Copy link

Does anyone know if this tutorial works if you are not dual-booting a linux OS? Say if i have created this project in a windows directory would this still work as intended? Having some issues figuring this out, as I cannot seem to find a good solution on how to publish this to gh-pages, nor if I was to publish it to another host i.e. Netlify or similar.

@hosja83
Copy link

hosja83 commented Jul 16, 2022

If you already have a "gh-pages" branch, use the 1st command below. If you don't have a "gh-pages" branch, initialize it by using the 2nd command below. Make it easier to run by creating scripts like these in your package.json file:

"scripts": {
      "gh-deploy": "git push origin :gh-pages && git subtree push --prefix dist origin gh-pages"
      "gh-deploy-init": "git push origin && git subtree push --prefix dist origin gh-pages",
}

In terminal:

npm run gh-deploy
npm run gh-deploy-init

We aren't done just yet. Now go to your repository in GitHub. Go to Settings. Go to Pages. Under the Source section you will see a dropdown list of branches. Select the "gh-pages" branch and select the root as your folder. Then click Save.

Give GitHub some time to rebuild and deploy your repository's site. Boom you have your site up and running.

Hopefully this works for you all. Shoutout to @TheOdinProject.

@riivanov
Copy link

riivanov commented Aug 13, 2022

I tried this approach, but I think git-worktree, and deployment from a seperate branch, is a cleaner alternative, since I won't have commits in my main branch, intermingled with commits from re-deployment, which I find more succinct, and I won't have to delete the remote branch every time, which is unnecessary.

git-worktree mounts your sub-directory, dist, in this example, to a separate branch, gh-pages.

Here's how:

git branch --track gh-pages origin/gh-pages         # Create new gh-pages branch; Add tracking for initial push
git checkout --orphan gh-pages                      # Initialize gh-pages without main's history
git reset --hard                                    # Remove all history
git commit --allow-empty -m "Init"                  # First commit without any files
git checkout main                                   # Go back to main (or master) branch
git worktree add dist gh-pages                      # Mount dist and bind it to the gh-pages branch

dist is an npm build script which looks like:

"scripts": {
  ...
  "dist": "ng build --configuration production && echo 'gitdir: /home/<user>/<repo>/.git/worktrees/dist' > ./dist/.git"
  ...
}

All it does is re-creates the git-worktree reference, because the .git file in dist was removed by ng build by default.
This reference is needed by git to link dist to the index.

And the workflow goes something like this:

npm run dist                                        # Build website with new changes; Removes dist and re-creates it
cd dist                                             # Move to gh-pages branch by switching into a directory (cool huh)
git add .                                           # Add all generated files to staging area
git commit -m "v0.0.3"                              # Update the version history of the gh-pages branch
git push                                            # Push changes to gh-branch

If you run git status it will reply On branch gh-pages.
And git log will show one commit "Init".

But when you cd .. and run git status again, the response will be On branch main.
And git log will show all of your original commits to main.

So what's happened here is quite interesting. The folder dist now has a separate branch, with it's own, unrelated history to main,
and all you have to do to switch is cd dist to access that branch (gh-pages).

This is unlike git checkout dist, which would append the dist directory, with the auto generated build files to your working tree, intermingling your main and deployment histories, which is inconvenient.

Here your src files will be untouched, along with their own history in main, or cd .., and only the files needed for deployment, will be on this branch, which is really convenient, because it keeps the src history seperate from the deployment history.

Now you'd deploy not from a folder, but from a branch, which holds the latest compiled version of your site in GitHub pages.

Of course there's probably an improvement that could be done here as well.
For example make npm run dist do all of this, but my personal preference is to do these steps manually.

Read more about this method here.

This is the how, for the suggestion by @kutsan.

@alex-drocks This is how it was suppose to do. Some build systems produce file names with hashes in them for caching. In order to prevent duplication, files are on specified branch needs to be deleted before new ones take over.

My suggestion is, use a separate branch for dist files that is generated by your build system and configure GitHub Pages to use root (/) of that branch. Have a good day!

After posting I realized @ChrisBAshton had already documented this approach. The only difference being the echo command in the
npm build dist script.

But I'd agree, that if you're working on a team, it's probably better to use a tool like gh-pages, to enforce standards in your project.

I hope my explanation is somewhat of a contribution as well, and not just a re-statement of the mentioned methods above.

@avgspacelover
Copy link

head is genuinely spinning trying to understand this

@avgspacelover
Copy link

avgspacelover commented Aug 22, 2022

i have a github repo - project
the subfolder , which is a create react app is named application

now how should i host my github pages from project/application?

@riivanov
Copy link

@antariksh17 if that's where the statically produced webpack(or other) bundles are output, then, you'll have a separate branch, in the above example called gh-pages, in your GitHub repo, which will only contain the static bundle files built from the source files of your project/application.

But I'm guessing, knowing no react, that project/application is not the same as dist, which is where the bundles will be output. So probably something like project/application/dist, is the folder, when mounted to your local git index, where your ng build react equivalent command would put your webpack bundles intended for distribution.

So if you did this correctly, then, cd ~/project/application/dist will display a separate version history, as if you'd done a git init in project/application/dist, and had a .git folder there, in addition to the parent folder. You can think about that gh-pages branch as a separate repo, and this is what makes this approach so convenient, because each git push from project/application/dist will only update gh-pages, with the latest compiled bundles, and none of the source files from project.

So you'd want to deploy from a branch in GitHub, gh-pages in the example above, using /root.

@bomszx
Copy link

bomszx commented Sep 14, 2022

"scripts": {
      "gh-deploy": "git push origin :gh-pages && git subtree push --prefix dist origin gh-pages"
      "gh-deploy-init": "git push origin && git subtree push --prefix dist origin gh-pages",
}

In terminal:

npm run gh-deploy
npm run gh-deploy-init

this one worked for me, thanks mate!

@SonyDennisAdams
Copy link

I want to deploy my website using Jekyll-scholar on Github pages. Since Github pages don't deploy it on their own, I will have to use another way of deploying a pre-built website. Can you please suggest some ways how to do that? I used rakefile, and when I force the built _site subdirectory to be the root of the project, it deletes everything, and therefore, nothing can be pushed. I am using this command git filter-branch --subdirectory-filter _site/ -f" I am using macOS 11.6 and using Jekyll-scholar. I am extremely new to this, so please pardon my naivety.

It's the leading underscore -- see: https://github.com/orgs/community/discussions/23640

@SookiezBoly
Copy link

SookiezBoly commented Sep 26, 2022

If you already have a "gh-pages" branch, use the 1st command below. If you don't have a "gh-pages" branch, initialize it by using the 2nd command below. Make it easier to run by creating scripts like these in your package.json file:

"scripts": {
      "gh-deploy": "git push origin :gh-pages && git subtree push --prefix dist origin gh-pages"
      "gh-deploy-init": "git push origin && git subtree push --prefix dist origin gh-pages",
}

In terminal:

npm run gh-deploy
npm run gh-deploy-init

We aren't done just yet. Now go to your repository in GitHub. Go to Settings. Go to Pages. Under the Source section you will see a dropdown list of branches. Select the "gh-pages" branch and select the root as your folder. Then click Save.

Give GitHub some time to rebuild and deploy your repository's site. Boom you have your site up and running.

Hopefully this works for you all. Shoutout to @TheOdinProject.

Thanks.

It kinda works, but all the images i have on the website just gone now :(

@zooks
Copy link

zooks commented Oct 28, 2022

If you got this error:

 ! [rejected]        * -> gh-pages (non-fast-forward)
error: failed to push some refs to 'https://github.com/*'
hint: Updates were rejected because a pushed branch tip is behind its remote
hint: counterpart. Check out this branch and integrate the remote changes
hint: (e.g. 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

Just delete the branch gh-pages by this command:

git push origin --delete gh-pages

@marc714
Copy link

marc714 commented Dec 25, 2022

This won't work on github pages:

const myPicture = new Image();
myPicture.src = "./src/assets/image.png" 

You must use:

import myPicture from "./src/assets/image.png"
const banner = new Image();
banner.src = myPicture;

Make changes to your main branch (your gh-pages branch wont see changes):
git push

Make changes to your gh-pages branch:
git subtree push --prefix dist origin gh-pages

To refresh your chrome browser to see changes asap, press F12 to go into developer tools. Then right click on the reload icon next to your URL bar. Click 'Empty Cache and Hard Reload'

@MrGassner
Copy link

If you already have a "gh-pages" branch, use the 1st command below. If you don't have a "gh-pages" branch, initialize it by using the 2nd command below. Make it easier to run by creating scripts like these in your package.json file:

"scripts": {
      "gh-deploy": "git push origin :gh-pages && git subtree push --prefix dist origin gh-pages"
      "gh-deploy-init": "git push origin && git subtree push --prefix dist origin gh-pages",
}

In terminal:

npm run gh-deploy
npm run gh-deploy-init

We aren't done just yet. Now go to your repository in GitHub. Go to Settings. Go to Pages. Under the Source section you will see a dropdown list of branches. Select the "gh-pages" branch and select the root as your folder. Then click Save.

Give GitHub some time to rebuild and deploy your repository's site. Boom you have your site up and running.

Hopefully this works for you all. Shoutout to @TheOdinProject.

This is what worked for me on the restaurant project of @TheOdinProject

@Stan-Stani
Copy link

If you got this error:

 ! [rejected]        * -> gh-pages (non-fast-forward)
error: failed to push some refs to 'https://github.com/*'
hint: Updates were rejected because a pushed branch tip is behind its remote
hint: counterpart. Check out this branch and integrate the remote changes
hint: (e.g. 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

Just delete the branch gh-pages by this command:

git push origin --delete gh-pages

Thank you!

Does anyone know if this tutorial works if you are not dual-booting a linux OS? Say if i have created this project in a windows directory would this still work as intended? Having some issues figuring this out, as I cannot seem to find a good solution on how to publish this to gh-pages, nor if I was to publish it to another host i.e. Netlify or similar.

I have gotten it to work on Windows but I'm not using Yeoman.

@Heechem
Copy link

Heechem commented Mar 22, 2023

Nothing worked for me , im still receiving subtree isnt a git command , im unsing linux

@arrahhal
Copy link

Nothing worked for me , im still receiving subtree isnt a git command , im unsing linux

Me too, I use Fedora.

@tonybalde
Copy link

I don't understand yet! I've tried but didn't work! I will search in google!

@typenoob
Copy link

can add it into npm run command

  "scripts": {
    "deploy":"git subtree push --prefix dist origin gh-pages"
  },

@scottwright-dev
Copy link

scottwright-dev commented Jun 24, 2023

git push origin :gh-pages && git subtree push --prefix dist origin gh-pages

Thank you for this @fabriziomartini, this is what helped me deploy my project.

@max-torch
Copy link

max-torch commented Sep 23, 2023

I found a really neat solution, which I tested for a static site:

  1. In your repo, go to Settings > Pages.

  2. In the Source dropdown list, select GitHub Actions Beta.

  3. Choose Static Site

  4. A page showing an editor for a .github/workflows/static.yml will load. In that file, we have the following section:

         uses: actions/upload-pages-artifact@v2
         with:
           # Upload
           path: '.'

    It's essentially uploading the root directory of the repository as the GitHub Pages source artifact. Simply change the path to ./dist so that only the dist directory will be uploaded.

  5. Commit changes.

  6. Check if the deployment was successful.

The GitHub Actions option is in Beta status and is subject to change.

Please let me know if someone else tries this and confirm it also works for you.

@spirus-dev
Copy link

spirus-dev commented Oct 23, 2023

The command, "git subtree push --prefix dist origin gh-pages," is a Git command used to push a subtree of your Git repository to a specific branch, typically used for deploying a website or any other code that needs to be hosted on a separate branch, such as a GitHub Pages branch.

Here's a breakdown of the command:

  1. git subtree push: This is the main command that tells Git to push a subtree. A subtree, in this context, is a directory within your Git repository that you want to push to a different branch.

  2. --prefix dist: This option specifies the directory (in this case, "dist") that you want to push as a subtree. The "dist" directory is typically used for compiled or built code that is ready for deployment. You can replace "dist" with the path to the specific directory you want to push.

  3. origin: This is the remote repository where you want to push the subtree. "Origin" is a common default name for the remote repository that you cloned your project from. If you have multiple remotes, you can replace "origin" with the name of the specific remote you want to push to.

  4. gh-pages: This is the name of the branch to which you want to push the subtree. In this case, it's "gh-pages," which is a common branch name for hosting GitHub Pages websites. You should replace "gh-pages" with the name of the branch you want to push to in your specific repository.

In summary, this command is used when you have a Git repository with a "dist" directory that contains the compiled or built code you want to deploy, and you want to push this directory as a subtree to a specific branch, in this case, "gh-pages" on the "origin" remote repository. This is a common workflow for deploying websites or other built code to a hosting service like GitHub Pages.

@Stan-Stani
Copy link

Stan-Stani commented Nov 5, 2023

JamesIves/github-pages-deploy-action has helped me deploy automatically when I push to main, and I don't have to actually push a prebuilt dist to the repo.

name: Deploy to GitHub Pages

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2 # This action checks out your repository
      - name: Setup Node.js
        uses: actions/setup-node@v2
        with:
          node-version: '20.9.0'  # Use whatever node version your project requires

      - name: Install Dependencies
        run: yarn install

      - name: Build Project
        run: yarn build  # Use the correct build command for your project. It may include 'dist' as part of the script in your package.json.
      - name: Build and Deploy
        uses: JamesIves/[email protected]
        with:
          branch: gh-pages # The branch the action should deploy to.
          folder: dist # The folder the action should deploy.
          # You can specify additional configuration here as needed.

Also don't forget to allow your actions to write to the repo in the repo settings:
image

And as I'm using Vite I had to also do:

// vite.config.js
export default {
    base: '/minigames/',
  }

where you would replace minigames with you repository name so everything is loaded correctly when it's hosted on gh-pages.

@nimit2801
Copy link

JamesIves/github-pages-deploy-action has helped me deploy automatically when I push to main, and I don't have to actually push a prebuilt dist to the repo.

name: Deploy to GitHub Pages

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2 # This action checks out your repository
      - name: Setup Node.js
        uses: actions/setup-node@v2
        with:
          node-version: '20.9.0'  # Use whatever node version your project requires

      - name: Install Dependencies
        run: yarn install

      - name: Build Project
        run: yarn build  # Use the correct build command for your project. It may include 'dist' as part of the script in your package.json.
      - name: Build and Deploy
        uses: JamesIves/[email protected]
        with:
          branch: gh-pages # The branch the action should deploy to.
          folder: dist # The folder the action should deploy.
          # You can specify additional configuration here as needed.

Also don't forget to allow your actions to write to the repo in the repo settings: image

And as I'm using Vite I had to also do:

// vite.config.js
export default {
    base: '/minigames/',
  }

where you would replace minigames with you repository name so everything is loaded correctly when it's hosted on gh-pages.

Amazing solution this works like a charm!

@nico9506
Copy link

I found a really neat solution, which I tested for a static site:

  1. In your repo, go to Settings > Pages.

  2. In the Source dropdown list, select GitHub Actions Beta.

  3. Choose Static Site

  4. A page showing an editor for a .github/workflows/static.yml will load. In that file, we have the following section:

         uses: actions/upload-pages-artifact@v2
         with:
           # Upload
           path: '.'

    It's essentially uploading the root directory of the repository as the GitHub Pages source artifact. Simply change the path to ./dist so that only the dist directory will be uploaded.

  5. Commit changes.

  6. Check if the deployment was successful.

The GitHub Actions option is in Beta status and is subject to change.

Please let me know if someone else tries this and confirm it also works for you.

It worked perfectly.
Thanks mate!

@ErreurDeSyntaxe
Copy link

This guide is great. Thank you for sharing it.

@daniel-keen
Copy link

I found a really neat solution, which I tested for a static site:

  1. In your repo, go to Settings > Pages.

  2. In the Source dropdown list, select GitHub Actions Beta.

  3. Choose Static Site

  4. A page showing an editor for a .github/workflows/static.yml will load. In that file, we have the following section:

         uses: actions/upload-pages-artifact@v2
         with:
           # Upload
           path: '.'

    It's essentially uploading the root directory of the repository as the GitHub Pages source artifact. Simply change the path to ./dist so that only the dist directory will be uploaded.

  5. Commit changes.

  6. Check if the deployment was successful.

The GitHub Actions option is in Beta status and is subject to change.

Please let me know if someone else tries this and confirm it also works for you.

It worked, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment