For every commit, create an equivalent compiled commit in a separate repo or branch
Asked Answered
C

5

14

I'm building sites using Jekyll, which compiles ERB, SASS, &c. into plain HTML & CSS.

After most commits, I'd like to compile the site and commit the compiled version in a separate repository or branch so that it can be pushed to a static server.

What is the best way to go about this?

I already have a solution, but I was hoping someone might have a more elegant one.

Choreographer answered 4/2, 2017 at 21:32 Comment(0)
S
5

After most commits, I'd like to compile the site and commit the compiled version in a separate repository or branch so that it can be pushed to a static server.

The right Keyword for you is "Continuous Integration".

You can use a CI Software like Jenkins to build your system after every commit, after creating or modifying a pull request, or just nightly.

The Build Script which you configure in the CI Software is than responsible to deploy the build artefacts, in that case your compiled version, to your target system like an s3 bucket. You can also do a programmatic commit of your artefacts to a different git repo.

Have a look here: https://jenkins.io/doc/

Slice answered 4/2, 2017 at 23:15 Comment(1)
Thank you for your answer. I'm afraid that might be overkill for the situation, and am hoping to find a simple way to do it with Git, so I'm going to leave the question open for now.Choreographer
R
2

Your solution would mix in the same repo "source commits" and "delivery commits" (the _site compiled version), which is not the best practice (and will increase the size of the Git repo needlessly)

I would create a separate repo "site" that I would add as a submodule to your current repo, in a path called _site/.

cd /path/to/current/repo
git rm -R _site
git submodule add -- /url/repo/site _site

That way, each time you build your delivery with bundle exec jekyll build, it is done in a separate repo (in _site), where you can add, commit, and even push directly to where you want to test it.
Then you go back to your main repo, where you add and commit the gitlink (special entry in the index), establishing a strong link between the exact version of the source, and the exact version of the delivery (the built site).

Roxieroxine answered 9/2, 2017 at 21:16 Comment(4)
Ah, I forgot to mention in my solution that I used git init _site/, so the commits were actually going to a separate repository. It seems to me that, if anything, the source should be the submodule.Choreographer
@Choreographer Exactly: using only git init would not make it a submodule, only a nested git repo, which is bad, as I detailed in https://mcmap.net/q/831211/-caution-just-lost-nested-child-repo-by-doing-checkout-on-parent.Roxieroxine
I have _site/ in .gitignore, is there any way I can shoot myself in the foot with this setup?Choreographer
@Choreographer Yes: a submodule requires you to not ignore the root folder of the nested repo, as it is a gitlink (the special entry referencing the SHA1 of the nested repo)Roxieroxine
C
2

As you requested

I do not recommend you to use the same repo to store your compiled code. Because it can be obtained from any state of source code and it will be unnesessary dublication of information.

So, in this case you want to use git as CI tool. You should create another repo for compiled site and make there commits each time you need it.

I suggest you to choose branch for "production" state of code. And when you commiting in that branch - code should be rebuilded. Lets name it "production".

  1. Make separate git repo for builded code.
  2. Put this code to post-commit hook in your src repo. It will handle all commits in the production branch, checkout the code to temporary directory, make build and commit the changes.
srcDir='../srcWorkTree'
buildedRepo='../buildedRepo'

if [ `git rev-parse --abbrev-ref HEAD` == "production" ]; then
    echo "making builded code commit..."
    mkdir -p $srcDir
    # https://mcmap.net/q/142268/-git-checkout-to-a-specific-folder
    git checkout-index -a -f --prefix=$srcDir/

    bundle exec jekyll build --source $srcDir --destination $buildedRepo

    cd $buildedRepo
    git add -A
    commitInfo=$( git log -1 --pretty="%h %B" )
    git commit -m "autobuild for $commitInfo"
    # git push
fi

Another variant

As i can suppose, you have access to your production server. At least you mention that you have git repo there. So it will be reasonable to make there post-receive hook to build your code into target directory. It will be more clear and simple instead of doing it on the local machine as i described.

I suppose that this repo is "bare" because you shouldn't have possibility to make changes on the server.

post-receive hook:

#!/bin/sh

siteDir='/var/www/site'
tmpSrcDir='/var/www/site'

echo "**** [builder's post-receive hook]"

while read oldrev newrev refname
do
    if [ $refname = refs/heads/production ]
    then
        GIT_WORK_TREE=$tmpSrcDir git checkout --detach $newrev

        bundle exec jekyll build --source $tmpSrcDir --destination $siteDir
    fi
done

exit 0

And few comments

I see, you tryed to use submodule to store your builded site. I don't recommend that. There is no sense because your source code not depends on builded code.

Compel answered 13/2, 2017 at 23:56 Comment(0)
M
2

I'll just suggest another option : do not store the compiled versions in git, store them somewhere else.

To give you our workflow as an example :

  • when we need to test a particular commit, we run it through our CI process which produces a .tar.gz archive, and we use our deploy tool to test it on a staging server ;

  • when we select a commit for a release version, we tag this commit in git, we run it through out CI process, the .tar.gz is marked with the version number and stored in some releases/ directory on our deployment server.

We have a backup of our releases/ folder, but should we loose it, we could also rebuild any particular build from source (based on the tag).

Morrison answered 14/2, 2017 at 8:23 Comment(0)
C
1

Initialize a Git repo in _site/, then add a Git post-commit hook, .git/hooks/post-commit:

echo -n "Add commit to compiled version? (y/N) "
read answer < /dev/tty
if [ "$answer" != "y" ]; then exit; fi

message=$( git log -1 --pretty=%B )

git stash --all
bundle exec jekyll build

cd _site
    git add --all
    git commit -m "$message"
cd ..

git stash pop

Now, every time you commit, you will be asked whether you would like to add a commit to the compiled version.

Choreographer answered 4/2, 2017 at 21:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.