Instantly share code, notes, and snippets.

Embed
What would you like to do?
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
@mattr-

This comment has been minimized.

mattr- commented Apr 4, 2013

For the lazy, you can create an alias in ~/.gitconfig in the [alias] section, like so:

[alias]
    stp = subtree push

which would let you type git stp --prefix dist origin gh-pages

and if you want to be really lazy 😄

[alias]
    stpp = subtree push --prefix

which would let you type git stpp dist origin gh-pages

Boom. Shortcuts. 🤘

@cobyism

This comment has been minimized.

Owner

cobyism commented May 16, 2013

@mattr- Yep, I also have a script in my dotfiles for doing this:

#!/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
@parkr

This comment has been minimized.

parkr commented Oct 2, 2013

If you keep a Jekyll site in your master branch in a subfolder, this is also incredibly helpful. Just push the Jekyll site up to gh-pages and GitHub Pages will do the rest:

git subtree push --prefix site/ origin gh-pages

@cobyism, why don't we do this for Jekyll itself?

@parkr

This comment has been minimized.

parkr commented Oct 9, 2013

No option to --force in this case.

@robwierzbowski

This comment has been minimized.

robwierzbowski commented Mar 4, 2014

If you're using Grunt I built a plugin for this exact use. https://github.com/robwierzbowski/grunt-build-control

@raine

This comment has been minimized.

raine commented Jun 10, 2014

This method isn't that nice since it forces you to keep generated files in project's source control.

Here's an alternative, https://github.com/X1011/git-directory-deploy

@jegelstaff

This comment has been minimized.

jegelstaff commented Jul 11, 2014

I am trying to use this, but keep getting an error:

Updates were rejected because a pushed branch tip is behind its remote counterpart. Checkout this branch and integrate the remote changes.

However, this doesn't make any sense, because both master and gh-pages are up to date with the origin (github). gh-pages is "ahead" of master, it was created by github through their automatic creation tools, and so it diverged from master at that point, but it's an orphan of course, it will never match master. It's just a container for the contents of the github.io site.

We have a copy of the contents of gh-pages in a single folder in the master branch, and periodically, we want an easy way to push the contents of the that folder up to github to update the github.io site. This seems like it should be the answer, but the above error is a showstopper.

Thanks for any help anyone can provide!

--Julian

@vences

This comment has been minimized.

vences commented Aug 7, 2014

hi,

They are a way to automatically deploy changement in the folder on the gh-pages.
Each times I change my directory dist I need to launch git subtree push --prefix dist origin gh-pages.
Any ideas ?

Thanks,

@iakobos

This comment has been minimized.

iakobos commented Aug 13, 2014

@vences you could use a post-commit hook (See http://githooks.com/)

@shankarmsy

This comment has been minimized.

shankarmsy commented Nov 24, 2014

This discussion thread was a life saver...thanks guys!!

On a side note, I deploy to my github user page (master not gh-pages). The one thing I realized was I needed to push to source first then subtree push the sub-directory to master. Otherwise it was throwing me a "Master is not an ancestor to commit" error.

Please correct if I am mis-stating.

@AllenSH12

This comment has been minimized.

AllenSH12 commented Jan 18, 2015

Thanks for the post, maybe someone else will also find the following command useful when trying to update gh-pages against a rebased master branch:

git push origin `git subtree split --prefix build_folder master`:gh-pages --force

(from http://stevenclontz.com/blog/2014/05/08/git-subtree-push-for-deployment/ and this question on SO)

@cDima

This comment has been minimized.

cDima commented Feb 16, 2015

This helped me out:

  1. git checkout master # you can avoid this line if you are in master...
  2. git subtree split --prefix dist -b gh-pages # create a local gh-pages branch containing the splitted output folder
  3. git push -f origin gh-pages:gh-pages # force the push of the gh-pages branch to the remote gh-pages branch at origin
  4. git branch -D gh-pages # delete the local gh-pages because you will need it: ref

from http://www.damian.oquanta.info/posts/one-line-deployment-of-your-site-to-gh-pages.html

@dandv

This comment has been minimized.

dandv commented Jun 4, 2015

Is there a way to have symlinks in the dist directory to files in directories outside of it? I've tried this with a .js included from dist/index.html via <script src="../script"> but that predictably didn't work.

My use case is a simple project with a .js in the root dir and without a build system that would copy the script from root to dist. Besides, I wouldn't want every commit to the script be mirrored in the dist copy of the script.

@edsu

This comment has been minimized.

edsu commented Jul 28, 2015

Very helpful, thanks!

@fewspider

This comment has been minimized.

fewspider commented Aug 15, 2015

thanks

@JacopKane

This comment has been minimized.

JacopKane commented Aug 19, 2015

Helped a lot thanks for sharing.

Now I'm trying to find a way without indexing dist folder, it's ugly to see minified/duplicate files in master branch.

Also found this gulp plugin for this purpose
https://github.com/shinnn/gulp-gh-pages

@BlueRaja

This comment has been minimized.

BlueRaja commented Aug 20, 2015

Another option is to use a submodule. This has the advantage of not keeping the documentation in two separate places (which might become out of sync)

@M3kH

This comment has been minimized.

M3kH commented Nov 29, 2015

I add this to my Makefile. 👍

@kaytwo

This comment has been minimized.

kaytwo commented Jan 19, 2016

If you want to immediately push to gh-pages as soon as you've committed updates to the website, you can try this: (replace site with your own specific subdirectory)

#!/bin/bash

# if anything in the site/ subdirectory changed in the prior commit,
# push that directory to gh-pages for auto generation.
git diff-tree -r --name-only --no-commit-id master | grep '^site/' &> /dev/null
if [ $? == 0 ]; then
  git push origin `git subtree split --prefix site master 2> /dev/null`:gh-pages --force
fi
@ty0x2333

This comment has been minimized.

ty0x2333 commented Feb 20, 2016

Very helpful, thanks!👍
I use Jekyll to generate website.GitHub Page does not support local plugins, because this problem has been bugging me for days. 💢

@warpling

This comment has been minimized.

warpling commented Feb 22, 2016

EXACTLY what I was looking for. Thank you!

@thinkingmedia

This comment has been minimized.

thinkingmedia commented Feb 27, 2016

This is what I did for my grunt task.

    grunt.task.registerTask('push-pages', function(){
       var shell = require('shelljs');
        shell.exec('git subtree split --prefix docs -b gh-pages');
        shell.exec('git push -f origin gh-pages:gh-pages');
        shell.exec('git branch -D gh-pages')
    });

I generate ngDocs in the subfolder docs and keep that in the master. Lets me view changes locally and when I release an update I just grunt push-pages to update the GitHub website.

@philmerrell

This comment has been minimized.

philmerrell commented Mar 5, 2016

I added this as a script to run in package.json. For example:

{
    "name": "Example App",
    "dependencies": { ... },
    "scripts": {
        "deploy": "git subtree push --prefix subfolder-name-here origin gh-pages"
    }
}

Then you just run npm run deploy

Bam! 💥 deployed.

@brod-ie

This comment has been minimized.

brod-ie commented Mar 10, 2016

@philmerrell Nice!

@brod-ie

This comment has been minimized.

brod-ie commented Mar 12, 2016

I'm using this technique but don't want to keep the dist folder in my main repo. How can I ignore it on one branch but not in the other?

Aka if I add dist to .gitignore on master when I attempt a subtree push to gh-pages it fails with Everything up to date.

@chuyik

This comment has been minimized.

chuyik commented Mar 15, 2016

@brod-ie Seems like the subtree approach could not work as you want, meaning you need to keep track of the dist folder in master branch.
But you can try https://github.com/X1011/git-directory-deploy, simply wget the script and run it via npm, it's also cool.

@drizzt

This comment has been minimized.

drizzt commented May 4, 2016

Quote!

@jimafisk

This comment has been minimized.

jimafisk commented May 5, 2016

Thanks for the guide @cobyism! I used this to create a pre-push git hook to make deploying to gh-pages using Jekyll easy: https://github.com/jimafisk/gh-pages_deploy. Thanks @AllenSH12 for providing a format that allows passing --no-verify to avoid the having the hook call itself recursively.

@JimTheMan

This comment has been minimized.

JimTheMan commented May 9, 2016

Original post doesn't work for me because my gh-pages branch contains the dist/ folder with all the files in it when I really need all the files in the root level of the gh-pages branch...

@yellownoggin

This comment has been minimized.

yellownoggin commented May 22, 2016

@JimTheMan did you use the option --prefix . Overall it worked for me. I thought the prefix option was the reason. Can't find any clear documentation on that reason why I'm unsure seems to be used in unix in general.

@guidobouman

This comment has been minimized.

guidobouman commented Jun 14, 2016

People, why such a hard approach?

You can just check-out your gh-pages branch in the dist/ subfolder and keep that folder in the gitignore to keep your history clean.

If you have an existing gh-pages branch:

git clone git@github.com:q42/blink-ct.git --branch gh-pages dist

Then add the following to the scripts section of you package.json:

{
  ...
  "scripts": {
    ...
    "clean": "rm -rf dist/*",
    "release": "npm run clean && npm run build",
    "deploy": "cd dist && git add --all && git commit -m \"Release at $(date)\" && git push"
  },
  ...
}

where npm run build is your build script. This could be Gulp, Grunt or Webpack, whatever you prefer.

@rtsao

This comment has been minimized.

rtsao commented Jun 15, 2016

@codazoda

This comment has been minimized.

codazoda commented Jun 27, 2016

Another option I like is to create the master and gh-pages branches as usual and then checkout the gh-pages branch into the ./gh-pages directory. Then you add gh-pages to the .gitignore on the master branch so that you have your master branch in the root and your gh-pages branch in the ./gh-pages directory. Both are checked out at the same time so that you don't have to flip back and forth but they are still contained in a single github repo. I got the idea from the instructions below.

https://gist.github.com/chrisjacob/833223

@daniloprates

This comment has been minimized.

daniloprates commented Jul 5, 2016

I keep getting this message. I've done pull, push, fetch and all sort of things. any clues?

screen shot 2016-07-05 at 8 01 52 am

@e-nichols

This comment has been minimized.

e-nichols commented Jul 15, 2016

AllenSH12 that did the trick for me! Thank you.

@stepquick

This comment has been minimized.

stepquick commented Aug 1, 2016

@daniloprates, it's saying your remote gh-pages branch is ahead of your local gh-pages branch. I had to destroy my remote gh-pages completely to get it submit properly.

@mikeyhogarth

This comment has been minimized.

mikeyhogarth commented Aug 17, 2016

This has been working out for me;

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

deletes the branch and re-pushes. Avoids all that remote branch being ahead fluff that others are mentioning.

@marcamillion

This comment has been minimized.

marcamillion commented Aug 27, 2016

What about in the case where you want to push to a subdirectory within your existing gh-pages repo? How do I do that?

For instance, I have a static site hosted on GH-pages, but I would like to add a blog powered by Middleman to my existing static site. I have the blog built, but when I deploy it keeps overwriting the entire gh-pages branch, when all I want it to do is to deploy to the blog/ subfolder within my gh-pages branch.

I was using middleman-deploy but it doesn't allow a subdirectory on the git deploy method.

Thoughts on how I can achieve that?

@mattspaulding

This comment has been minimized.

mattspaulding commented Aug 31, 2016

Super easy using gulp:

Terminal:
npm install --save-dev gulp-gh-pages

Then in your gulpfile.js:

var gulp = require('gulp');
var ghPages = require('gulp-gh-pages');

gulp.task('deploy', function() {
  return gulp.src('./dist/**/*')
    .pipe(ghPages());
});

Any time you want to publish to gh-pages:

gulp deploy

@finom

This comment has been minimized.

finom commented Sep 13, 2016

Check out deploy-to-git.

@laszlourszuly

This comment has been minimized.

laszlourszuly commented Nov 16, 2016

@AllenSH12 The risk with your suggestion is that the git subtree split ... command may fail and thereby return "nothing", ultimately causing your outer gitcommand to look like: git push origin :gh-pages --force, which also happens to be the command for forcefully deleting the remote gh-pages branch.

You know what I mean if you have ever done a too hasty rm -rf * :-)

@goldylucks

This comment has been minimized.

goldylucks commented Nov 22, 2016

I'm using a similar approach that does NOT check dist folder to source control:

#!/bin/bash
set -e # stop on error

echo bulid client ...
npm run build:client
echo check out branch gh-pages ...
git checkout -b gh-pages
echo add client-dist folder
git add -f client-dist
echo commit changes
git commit -m "deploy to gh-pages"
echo push to remote gh-pages
git push origin `git subtree split --prefix client-dist`:gh-pages --force
echo checkout branch master
git checkout master
echo delete branch gh-pages
git branch -D gh-pages
echo All done!

I can wrap it into an NPM package for ease of use if anyone is interested :)

so far it works on one of my proejcts

@thislooksfun

This comment has been minimized.

thislooksfun commented Dec 1, 2016

This is now built in, as of Aug. 17, 2016. https://github.com/blog/2228-simpler-github-pages-publishing

@wangpin34

This comment has been minimized.

wangpin34 commented Dec 5, 2016

Thank you all. That's really helpful.

@gunnarmorling

This comment has been minimized.

gunnarmorling commented Jan 3, 2017

I'm using this approach (based on @guidobouman's advice above, but's using a local clone instead of remote):

# remove previous publication
rm -rf dist
mkdir dist

# clone gh-pages branch from the local repo into a repo located within "dist"
git clone .git --branch gh-pages dist

# generate contents...    

# commit the changes in the clone and push them back to the local gh-pages branch    
cd dist && git add --all && git commit -m "Publishing to gh-pages" && git push origin gh-pages

# publish
git push upstream gh-pages

If you are on git 2.5 or later, the same may be achieved using the new worktree feature.

@astericky

This comment has been minimized.

astericky commented Jan 16, 2017

I need to thank you for this. I have been looking for this solution for quite sometime. Apparently, I starred this some years ago and didn't realize it actually works. Saturday was the first time I tried this out for some unknown reason. In any case, thanks again.

@lbineau

This comment has been minimized.

lbineau commented Feb 13, 2017

Really easy to use gh-pages npm package
https://www.npmjs.com/package/gh-pages
It creates a clone of your repo in order not to commit builded files in yours so your history remains clean 👍

@lukehler

This comment has been minimized.

lukehler commented Feb 14, 2017

For user and organizational pages (in which the visible branch is master instead of gh-pages), I ran into the same issue as @daniloprates and managed to get around it by...

  1. In the repo's Settings / Branches, making my src branch the Default Branch
  2. With the src branch checked out, deleting the master branch with git push origin :master
  3. Creating a new master branch with git subtree push --prefix dest origin master
  4. Resetting the master branch as the Default Branch in the repo's Settings.
@vhbsouza

This comment has been minimized.

vhbsouza commented Mar 27, 2017

@lukehler, but after doing what you suggets.. how can I update my forked repository?
Because now my forked source code isn't on master branch anymore, it's now on src.

Any suggestion on how to manage that?

@kostia-lev

This comment has been minimized.

kostia-lev commented Apr 23, 2017

I did it, and my github.io still points to master branch :-(

@bdjunayed

This comment has been minimized.

bdjunayed commented May 3, 2017

I did it! with a git supported dumb host, just pointing the domain to the dest folder.

@lukehler

This comment has been minimized.

lukehler commented May 6, 2017

@vhbsouza and @kostia-lev: About a month or two late, but I just checked in and noticed the last couple of comments. Apologies.

In my case...

  • I've got all my build scripts in the src branch.
  • When I change the source files, I update, commit, and push the src branch.
  • I then, with the src branch still checked out, manually push the subtree into the master branch with git subtree push --prefix dest origin master (I added a line to my package.json to make an NPM build script to run that command, so I just use npm run deploy as an alias).

That lets you update, maintain, and track the source files in the src branch and the master branch is just a clone of the dest folder. I basically only ever use src as my "master" and populate the actual master branch exclusively with the subtree.

I hope that helps.

@kreedz

This comment has been minimized.

kreedz commented Jun 25, 2017

On which branch should be performed step 1 and step 2? It doesn't mentioned in any way.
I did it at master branch, because at gh-pages it caused errors.

But I have a problem with that.
Now at gh-pages in the root directory I have index.html file.
And I get 404 when trying to follow kreedz.github.io/Test.
But this kreedz.github.io/Test/index.html works.

Earlier it worked well without git subtree push when I did it with git merge master at gh-pages branch.

@mac-s-g

This comment has been minimized.

mac-s-g commented Nov 11, 2017

@kreedz same thing happened to me at first.

regarding your first question, you should be running those commands from master.

regarding the 404:
--this is only applicable if serving from a custom domain--
I was missing my CNAME record. make sure you're copying that into your /dist/ directory so that gh-pages has the dns config necessary to serve your site with only the files in that dir.

@musteresel

This comment has been minimized.

musteresel commented Jan 31, 2018

I think I found a better solution:

# 1. Set up a worktree in directory dist checked out on branch gh-pages
git worktree add dist gh-pages
# 2. Build whatever needs to be in dist however you like
# 3. Add everything in dist
(cd dist; git add .)
# 4. Commit, with some nice message to link to sources commit
(cd dist; git commit -m "Build output as of $(git log '--format=format:%H' master -1)"
# 5. Push
git push origin gh-pages
  • No duplicate repositories (no space waste, duplicate configurations, ...)
  • No build files in source tree (source branch)
  • Versioned builds (rollback made easy)
@maciejmyslinski

This comment has been minimized.

maciejmyslinski commented Feb 21, 2018

@musteresel this is great!

@js2me

This comment has been minimized.

js2me commented Feb 22, 2018

@musteresel please add closed ) to this line:

(cd dist; git commit -m "Build output as of $(git log '--format=format:%H' master -1)"
@sukima

This comment has been minimized.

sukima commented Mar 9, 2018

@gunnarmorling solution was about 10000 times easier! To elaborate for git >2.5 (worktree)

Setup

$ rm -rf dist
$ echo "dist/" >> .gitignore
$ git worktree add dist gh-pages

Making changes

$ make # or what ever you run to populate dist
$ cd dist
$ git add --all
$ git commit -m "Deploy to gh-pages"
$ git push origin gh-pages
$ cd ..

Notes

git worktree feature has its own garbage collection so if dist is deleted it will not affect much and can be recreated as needed. If you want it to go away you can use git worktree prune See man pages on it.

Makefile

To make this stream line the following Makefile can be used to automate this process:

.PHONY: all deploy clean

all: dist dist/index.html

dist:
	git worktree add dist gh-pages

# Replace this rule with whatever builds your project
dist/index.html: src/index.html
	cp $< $@

deploy: all
	cd dist && \
	git add --all && \
	git commit -m "Deploy to gh-pages" && \
	git push origin gh-pages

# Removing the actual dist directory confuses git and will require a git worktree prune to fix
clean:
	rm -rf dist/*
@manugarg

This comment has been minimized.

manugarg commented Mar 29, 2018

@sukima Much thanks for this. This worked very well for me.

@rhyolight

This comment has been minimized.

rhyolight commented Apr 5, 2018

This is so much easier than what I've been doing, thanks.

@burrich

This comment has been minimized.

burrich commented Apr 10, 2018

The git worktree solution is perfect, thanks guys.

@shilangyu

This comment has been minimized.

shilangyu commented Oct 20, 2018

@sukima solution worked for me

@aaronkorver

This comment has been minimized.

aaronkorver commented Nov 19, 2018

git worktree add -b gh-pages dist gh-pages
I will append to this Gist (which was super helpful) that depending on how you cloned your main project the worktree might be in a Detached HEAD state. The above snippet will attach it to a branch so you can push back upstream. This took me a bit to wrap my head around, so maybe it will help those poor souls like me who find this Gist.

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