Easily Create Clean Compressed Tarballs of Your Git Repository

Ideally, you could refer the whole world — or at least, the significant portion thereof that want your code — to your (public mirror) Git repository. But unfortunately, the whole world does not (yet) use Git (“I know it was you Fredo, I know it was you, and it breaks my heart.“). Sad. Sooooo sad. But true. So the only recourse is for you to send these tortured souls an archived snapshot of your code via e-mail. I’ll pause now to let you finish retching/sobbing/lamenting/venting. …

Back?

Anyway, Git has a neat “archive” command that helps you create the required archive, but perhaps it does not have the most friendliest interface in the world. I’ve written some scripts to wrap the Git command to facilitate its use, which I share here.

Update 2011-07-07: I have re-written the original three scripts previously described here as a single script, incorporating some of the excellent suggestions that kind folks provided in the comments. Immediately below this is the new, unified, all-bells-and-whistles-included script. Simply name it something like “git-makedist”, switch on its executable bit, and place it somewhere on your system path. Reasonable names, filepaths, prefixes, etc. are all provided if you do not explicitly specify them. All of which means that, in most cases, once installed, simply invoking the command “git makedist” without any options or arguments from within a Git repository “just works ™”, resulting in a sensibly-named compressed archive of the current HEAD ready for distribution. At the same time, various flags and options allow you to fine-tune the operations, e.g. determine the compression/archive method, the path prefixes, the archive name, etc.

Update 2011-07-22, Excluding Files: Sometimes, not all files need to make it out to an archive. You can use the “.gitattributes” file to control which files get archived. Simply add the paths/names/globs of the files or directories you would like to exclude, and add a “export-ignore” after it. For example:

.gitattributes export-ignore
.gitignore export-ignore
*.tmp export-ignore

Note that the “.gitattributes” file has to be committed for it to have an effect.

#! /bin/bash

compose_name()

function usage

NOPREFIX=0
while [ -n $1 ]; do
    case $1 in
    -f|--format)
        FORMAT=$2
        shift 2
        ;;
    -r|--revision)
        REVISION=$2
        shift 2
        ;;
    --no-prefix)
        NOPREFIX=1
        shift
        ;;
    -p|--prefix)
        PREFIX=$2
        shift 2
        ;;
    -n|--name)
        REPONAME=$2
        shift 2
        ;;
    -o|--output)
        OUTPUTDIR=$2
        shift 2
        ;;
    -h|--help)
        usage
        ;;
    *)
        break
        ;;
    esac
done

if [[ -z $FORMAT ]]
then
    FORMAT="targz"
fi

if [[ -z "$REVISION" ]]
then
    REVISION="HEAD"
fi

if [[ -z $REPONAME ]]
then
    REPONAME=$(compose_name)
    if [[ -z $REPONAME ]]
    then
        echo "FATAL: not a Git repository, or could not parse repository name (supply using '-p'/'--prefix' flag)"
        exit 1
    fi
fi

if [[ -z "$OUTPUTDIR" ]]
then
    OUTPUTDIR="."
fi

if [[ $FORMAT == "zip" ]]
then
    GITARCHIVEFORMAT="zip"
    EXT=".zip"
else
    GITARCHIVEFORMAT="tar"
    if [[ $FORMAT == "tarbz" ]]
    then
        EXT=".tar.bz2"
        COMPRESS="bzip2"
    elif [[ $FORMAT == "targz" ]]
    then
        EXT=".tar.gz"
        COMPRESS="gzip"
    else
        echo "FATAL: Unrecognized format '$FORMAT'"
        exit 1
    fi
fi

if [[ $NOPREFIX == 1 ]]
then
    PREFIXCOMMAND=""
elif [[ -z "$PREFIX" ]]
then
    PREFIXCOMMAND="--prefix=$REPONAME/"
else
    PREFIXCOMMAND="--prefix=$PREFIX/"
fi

ARCHIVEBASENAME="$REPONAME-$(git describe --always)"
OUTPUTPATH="$OUTPUTDIR/$ARCHIVEBASENAME$EXT"
if [[ $FORMAT == "zip" ]]
then
    git archive --format="$GITARCHIVEFORMAT" $PREFIXCOMMAND $REVISION > $OUTPUTPATH
else
    git archive --format="$GITARCHIVEFORMAT" $PREFIXCOMMAND $REVISION | $COMPRESS >$OUTPUTPATH
fi
Share