Create a gist now

Instantly share code, notes, and snippets.

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- 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. 🤘

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 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 commented Oct 9, 2013

No option to --force in this case.

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

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

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 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 commented Aug 13, 2014

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

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.

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 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 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 commented Jul 28, 2015

Very helpful, thanks!

thanks

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

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 commented Nov 29, 2015

I add this to my Makefile. 👍

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

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. 💢

EXACTLY what I was looking for. Thank you!

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.

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 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 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 commented May 4, 2016

Quote!

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.

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 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.

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.

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

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

AllenSH12 that did the trick for me! Thank you.

@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.

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.

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?

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 commented Sep 13, 2016

Check out deploy-to-git.

@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 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

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

Thank you all. That's really helpful.

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.

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 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 👍

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.

@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?

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

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

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 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 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.

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