7

Complete question rewrite

So I thought I was explaining this question very simply and direct but it seems I oversimplified to much, so here is all the extra details. Hopefully this helps everyone see this is also not a duplicate.


I have a repository (project) where I would like to automate the process of pushing commits from one directory in a branch to another branch; something I have not come across yet on SO.

Here is my project with its complete structure:

[PROJECT MASTER BRANCH]
|- gh-pages    (directory)
|- css         (directory)
|- index.html  (file)
|- readme.md   (file)

[PROJECT gh-pages BRANCH]
|- (empty at the moment)

What I am hoping to do is create a hook that will automatically handle changes in my gh-pages directory from the master branch, and copy/ clone/ replace them (whichever term is correct to use) into by gh-pages branch, the projects website branch. Here is an example with all other files left out:

[PROJECT MASTER BRANCH]
|- gh-pages         (directory)   <=== SEE UPDATE BELOW [A]
|  |- css           (directory)
|  |  |- style.css  (file)
|  |- index.html    (file)

[PROJECT gh-pages BRANCH]
|- css           (directory)   <=== SEE UPDATE BELOW [B]
|  |- style.css  (file)
|- index.html    (file)

I am completely new to this level of Git Hub. I normally just stick to the basics and never use the terminal/ shell. So in summary to clarify what I am hoping to do, I would like to:

  • Only have to work in the [Master Branch]. All changes I need to make to [gh-pages Branch] I do in the gh-pages directory of [Master Branch]
  • Preferable accomplish this by adding a simple file which seems to be a post-receive hook?

Here is some post-receive hook code that I tried using (I made it from studying a few things) but it doesn't work:

#!/bin/bash
while read oldrev newrev refname
do
    branch=$(git rev-parse --symbolic --abbrev-ref $refname)
    if [ "master" == "$branch" ]; then
        git checkout gh-pages
        git checkout master -- gh-pages
        git add gh-pages
        git commit -m "Updating project website from 'master' branch."
    fi
done

NOTE
As mentioned in my comment: This is not a duplicate. This is not asking how to push but rather how to tack on other commands that auto run when I do a normal push. These commands would do the extra work mentioned in my OP.

UPDATE
I have added these arrows to parts of my code I refer to below: <===

[A] What should happen here is that Git should recursively read the master branches gh-pages directory and only copy from that what has updated (or everything if that is easier) into the gh-pages branch.

[B] So if the gh-pages directory in master has an index.html file and a css folder with a style.css file is should only copy over that structure not the gh-pages directory itself. Below is an example of a bad hook that copies the gh-pages directory too:

[PROJECT gh-pages BRANCH]
|- gh-pages         (Directory)   <=== NOT SUPPOSED TO HAPPEN
|  |- css           (directory)
|  |  |- style.css  (file)
|  |- index.html    (file)

Also, the hook should not copy over any other files but what is inside the gh-pages. Even if several other files changed in the master branch only the gh-pages directory files should be copied over.

[C] NEW CODE - This works but causes an error:

#!/bin/bash
branch=$(git rev-parse --abbrev-ref HEAD)
if [ "master" == "$branch" ]; then
    git fetch && git checkout gh-pages
    git checkout master -- gh-pages/*
    git add -A
    git commit -m "Updating project website from 'master' branch."
    git push -u origin gh-pages
fi

This wont work for two reasons. 1) If the repo is behind on commits it cant handle that, it will error out; if a pull is used instead of a fetch the local repo gets wiped like so:

Local repo has been wiped when changing code to pull.

If I leave fetch the local repo stays the way it should:

Local repo the way it should stay after a push. Fetch was used here.

2) The whole gh-pages directory gets copied over to the gh-pages branch still and not just the files inside it.

Blizzardengle
  • 992
  • 1
  • 17
  • 30
  • Possible duplicate of [How to automatically push after committing in git?](http://stackoverflow.com/questions/7925850/how-to-automatically-push-after-committing-in-git) – gzh Feb 05 '16 at 04:57
  • @gzh this is not a duplicate. This is not asking how to push but rather how to tack on other commands that auto run when I do a normal push. These commands would do the extra work mentioned in my OP. [That question](http://stackoverflow.com/questions/7925850/how-to-automatically-push-after-committing-in-git) is about automating the whole Git cycle every time the user hits commit, not committing to master and simultaneously cloning a directory into a whole different branch. – Blizzardengle Feb 05 '16 at 07:34
  • 1
    It seems that you need to write a post-receive hook to do this task. – gzh Feb 05 '16 at 07:51
  • @gzh bump. Reworded the question. Post-receive hook makes sense but I am lost at how to implement that. – Blizzardengle Feb 06 '16 at 03:30
  • The hook script is expected to be under $your_repo/hooks/post-receive directory, then what is the running directory for your hook script, and where your checkout code will be put? I think you should create a new folder, clone the source and do what you want. – gzh Feb 07 '16 at 06:50
  • It is there and I have 0 experience coding these. You could answer the OP with a working example. At least I learn by working off code than creating it from pieces. I use git for windows to push all my commits by the way. – Blizzardengle Feb 07 '16 at 06:56
  • It is not convenience for me to write working example for now, but [Here](http://stackoverflow.com/questions/7401303/how-do-i-run-cmd-from-the-git-post-commit-hook) is some hook sample running on windows. Good luck. – gzh Feb 07 '16 at 07:07

2 Answers2

5

You really don't need this complex approach.

Simply add your own repo as a submodule (of itself!), submodule following the gh-pages branch (since a submodule can follow the latest commit of a branch)!

git checkout master
git rm -r gh-pages # save your data first
git submodule add -b gh-pages -- /remote/url/of/your/own/repo
git commit -m "ADd gh-pages branch as submodule"
git push

That way, you can change files either in your main branch, or in the gh-pages folder (which is actually a submodule)

Whenever you are making changes in gh-pages folder, don't forget to commit there, and in the main folder of your repo in order to record the new gitlink (special entry in the index) reprsenting the new SHA1 of the gh-pages submodule.

cd myrepo/gh-pages
# modify files
git add .
git commit -m "modify gh-pages files"
cd .. # back to myrepo folder
git add gh-pages
git commit -m "record gh-pages new SHA1"
git push

With git 2.7+, you can set:

cd /path/to/main/repo
git config push.recurseSubmodules on-demand

Then a single git push from your main repo will also push the gh-pages submodule to the gh-pages branch.

Later, a single git clone would clone both your main repo and its gh-pages branch (in the gh-pages submodule folder).

That way, you always have both content visible.

And you don't need a complex "synchronization/copy" mechanism.


Update August 2016: Simpler GitHub Pages publishing now allows to keep your page files in a subfolder of the same branch (no more gh-pages needed):

Now you can select a source in your repository settings and GitHub Pages will look for your content there.

You don't need the submodule approach anymore, since your pagers can be in a subfolder within the same branch.

Community
  • 1
  • 1
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • Note: that is an old approach I mentioned back in 2011 (http://stackoverflow.com/a/8148319/6309), based on [Mark Longair](http://stackoverflow.com/users/223092/mark-longair)'s answer (http://stackoverflow.com/a/5296433/6309). But at the time, submodules did not follow branches, and you could not push everything in one go. – VonC Feb 10 '16 at 05:34
  • You lost me here: "Whenever you are making changes in gh-pages folder, don't forget to commit there". If I run your code in shell it works but if I try to do a normal commit of any kind with Git for windows (desktop) I get an error saying to add the submodel with shell or remove the .git file – Blizzardengle Feb 11 '16 at 03:23
  • I tried this answer but no dice: http://stackoverflow.com/questions/5542910/how-do-i-commit-changes-in-a-git-submodule – Blizzardengle Feb 11 '16 at 03:23
  • @Blizzardengle I have detailled the "dn't forget to commit there" step. And I have added the commit you must do after the initial `submodule add`. Clone your repo again, and try again those steps. (in command line only. GitHub Desktop is a GUI which wraps and obfuscates what is really going on: you don't need it) – VonC Feb 11 '16 at 05:16
  • I have been up all night trying to modify this and only have two things to say. 1) Its works, thank you. 2) It does not answer my OP where I asked for a non-shell solution. My goal and burning desire is to use Gits window GUI and not the shell every time. I made a pre-commit hook and even a pre-push hook to auto commit the submodule changes before my GUI commits and no dice. But again if I did that manually in the shell it works...not happy with it but it works. – Blizzardengle Feb 11 '16 at 08:01
  • It will work with any Windows GUI using a recent 2.7.1 git. It will work with GitHub Desktop when that GUI will end up using a recent enough git embedded in it (as I well know, you cannot change its git version: http://stackoverflow.com/a/33703716/6309). Embrace the command line: you can script it and make the all process "push-button". – VonC Feb 11 '16 at 08:13
  • I'm embracing the command line begrudgingly. I know its always the best thing to use, thanks for your answer. I think it is the best auto-project-website setups I have seen. – Blizzardengle Feb 11 '16 at 15:44
  • @Blizzardengle Again, if you have a GUI which calls a recent enough git (Like Tortoise Git, SmartTree, ...), all the command line you need is the initial `git submodule add`, and the `git config push.recurseSubmodules on-demand`. Everything else can be done from the GUI. Not from GitHub Desktop though. – VonC Feb 11 '16 at 15:47
3

What's the problem with the hook script you wrote ? What were the contents of the branch gh-pages when you created it?

I had created an empty branch gh-pages with below command:

git checkout --orphan gh-pages
git rm -rf .
touch README.txt
git add README.txt
git commit -m "Initial commit"
git push -u origin gh-pages

Then I ran below script as a part of post-receive hook and it worked for me.

#!/bin/bash
branch=`git rev-parse --abbrev-ref HEAD` 
if [ "master" == "$branch" ]; then
    git fetch && git checkout gh-pages
    git checkout master -- gh-pages
    git add -A
    git commit -m "Updating project website from 'master' branch."
    git push -u origin gh-pages
fi
done
SnehalK
  • 699
  • 4
  • 12
  • I don't understand your code so I think you may have misunderstood. For some reason my hook wont run but if I run all that myself in shell it kinda works. All it did was copy every changed file from my whole master branch into gh-pages which is not what I need. https://github.com/blizzardengle/barebones-framework – Blizzardengle Feb 09 '16 at 18:41
  • I edited my question to point out the part that is not working. – Blizzardengle Feb 09 '16 at 18:42
  • This never worked as is because branch=`git rev-parse --abbrev-ref HEAD` needs to be $(git rev-parse --abbrev-ref HEAD). It also copied over more than what it was supposed to, namely the gh-pages directory. It is a quick solution and can be consider an answer but @VonC answer hits the nail more on the head. – Blizzardengle Feb 11 '16 at 15:39
  • we would make a shell to handle the expected task as I suggested yesterday. However I agree VonC's answer is the deserving one .. – SnehalK Feb 11 '16 at 17:00