Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can a pre-commit Git hook zip a directory and add it to the repository?

I'm doing development on a Wordpress plugin. My development directory contains a lot of development-specific stuff (e.g. Grunt files, Sass files, the git repository itself, etc.).

Obviously, I don't want to distribute this folder containing all of those development files; people don't want a few MB of Grunt files when they download my Wordpress plugin.

Up until now, though, my "release" process has been cumbersome:

  1. Commit the Git changes
  2. Zip the entire folder
  3. Open the zip file and delete the .git folder, grunt files, and all the other development-specific files
  4. Release the new zip

I don't know the best way to accomplish this, but I'm very vaguely familiar with Git hooks, and I had this thought: could I set up a Git hook that would zip ONLY the needed production files into a ZIP file and store it with the repo? That way, every time I commit it would automatically create a new release ZIP.

Is that possible? If so, could someone point me in the right direction?

Oh also, I'm on Windows (・_・;). So I'm hoping that there's a way to do it on Windows.

like image 920
Pete Avatar asked Jan 08 '23 23:01

Pete


1 Answers

I can't speak for Windows, but:

  1. It's technically possible to do that sort of thing in a pre-commit hook.
  2. Don't.

A pre-commit hook that modifies "what you will commit" is annoying (if nothing else, it violates the "rule of least astonishment", where your version control system simply stores the versions you tell it to store). Apart from that, storing large pre-compressed binaries interferes with git's attempt to save space in pack files, and will cause rapid repository bloat, poor performance, running out of memory, and so on. A ZIP-archive is a pre-compressed binary and hence will behave badly.

In general, a more reasonable "hook-y" way to handle releases is to set up a "release server" to which you push new releases, and have the push trigger the archive-generation. (There are ways to do this without a separate server / repository, and you can do it in a more pull-style fashion, but the push-style is easy to illustrate.)

[Edit: I had originally considered git archive but did not realize you could get it to exclude files conveniently, so wrote up the below instead. So, jthill's answer is better and should be one's first resort. I'll leave this in place as an alternative for some case where for some reason, git archive might not do.]

For instance, here's a server-side post-receive hook code fragment that checks whether a branch whose name matches release* has been pushed-to, and if so, invokes a shell function with the name of the branch (once for each such branch):

#! /bin/sh

NULL_SHA1=0000000000000000000000000000000000000000

scan()
{
    local oldsha newsha fullref shortref
    local optype

    while read oldsha newsha fullref; do
        case $oldsha,$newsha in
        $NULL_SHA1,*) optype=create;;
        *,$NULL_SHA1) optype=delete;;
        *)            optype=update;;
        esac
        case $fullref in
        refs/heads/*)
            reftype=branch
            shortref=${fullref#refs/heads/}
            ;;
        *)
            reftype=other
            shortref=fullref
            ;;
        esac

        case $optype,$reftype,$shortref in
        create,branch,release*|update,branch,release*)
            do_release $shortref;;
        esac
    done
}

scan

(much of the above is boilerplate, which I have stripped down to essentials). You would have to write the do_release function, which might resemble (totally untested):

do_release()
{
    local tmpdir=/tmp/build.$$ # or use mktemp -d

    # $tmpdir/index is git's index; $tmpdir/t is the work tree
    trap "rm -rf $tmpdir; exit 1" 1 2 3 15
    rm -rf $tmpdir
    mkdir $tmpdir/t

    GIT_INDEX_FILE=$tmpdir/index GIT_WORK_TREE=$tmpdir/t git checkout $1

    # now clean out grunt files and make zip archive
    (cd $workdir/t; rm -rf grunt; zip ../t.zip .)

    # put completed zip archive in export location, name it
    # based on the branch name
    mv $workdir/t.zip /place/where/zip/files/live/$1.zip

    # clean up temp dir now, and no longer need to clean up
    # on signal related abort
    rm -rf $tmpdir
    trap - 1 2 3 15
}
like image 53
torek Avatar answered Jan 23 '23 02:01

torek