Last active
January 17, 2019 21:22
Maintain a separate branch for build artifacts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# add to your PATH and call as | |
# $ git save-build [-d|--dirty] [<buildname>] | |
# <buildname> can be omitted if you configure a default value: git config build.save.default | |
# you must configure the following: | |
# build.save.<buildname>.cmd -- a command run when invoking this build profile | |
# build.save.<buildname>.dest -- a directory containing build artifacts | |
# build.save.<buildname>.branch -- a branch you want to track your build history on. | |
# Must start with refs/, ideally refs/heads/ | |
function fail() { | |
local ret="$1" | |
shift | |
echo >&2 "git save-build:" "$@" | |
exit "$ret" | |
} | |
function config-fail() { | |
local configsetting="$1" | |
shift | |
fail 32 "Please set git config save.build.<buildname>.$configsetting to be" "$@" | |
} | |
function no-untracked-files() { | |
git ls-files --others --exclude-standard --error-unmatch >/dev/null 2>&1 | |
[[ $? == 1 ]] && return 0 || return 1 | |
} | |
if [[ "$1" == -d|--dirty ]] | |
then | |
echo >&2 allowing a dirty build | |
allowDirty=yes | |
shift | |
fi | |
if git diff-index --quiet HEAD -- && no-untracked-files ; then | |
buildNote="built from commit $(git rev-parse --abbrev HEAD)" | |
elif [[ -n "$allowDirty" ]] ; then | |
buildNote="built from commit $(git rev-parse --abbrev HEAD) (with uncommitted changes)" | |
else | |
fail 2 aborting because of untracked changes, use --dirty to override | |
fi | |
buildPrefix="build.save.${1:-$(git config build.save.default)}" | |
[[ "$buildPrefix" == build.save.?* ]]\ | |
|| fail 128 specify a save-build profile or specify git config build.save.default | |
buildBranch="$(git config "${buildPrefix}.branch")" | |
[[ "$buildBranch" == refs/* ]] | |
|| config-fail branch of the form refs/heads/{yourbranch} | |
if git show-ref --verify --quiet "$buildBranch" 2>/dev/null ; then | |
buildParent="$(git show-ref --hash --verify "$buildBranch")" | |
elif [[ $? == 1 ]] ; then | |
buildParent="" | |
else | |
fail 128 "we seem to not be in a git repository" | |
fi | |
buildDest="$(git config "${buildPrefix}.dest")" | |
buildCmd="$(git config "${buildPrefix}.cmd")" | |
[[ -n "$buildCmd" ]] || config-fail cmd a build command | |
bash -c "$buildCmd" || fail $? "${buildPrefix}.cmd failed" | |
[[ -d "$buildDest" ]] || config-fail dest a directory containing build artifacts | |
printf -v tmp_index '/tmp/%s.%(%s)T.idx' "$buildPrefix" | |
while IFS= read -r -d $'\0' file ; do | |
blobsha="$(git hash-object -t blob -w "$file")" || fail 128 unable to hash "$file" | |
printf '100644 blob %s\t%s' "$blobsha" "${file#"$buildBranch"}" | |
done < <(find "$buildBranch" -type f -print0 ) > >(GIT_INDEX_FILE="$tmp_index" git update-index --add --index-info) | |
buildTree="$(GIT_INDEX_FILE="$tmp_index" git write-tree)" || fail $? unable to write index to a tree | |
buildCommit="$(git commit-tree "$buildTree" ${buildParent:+-p "${buildParent}"} -m "$buildNote")" \ | |
|| fail $? unable to create a commit object from tree "$buildTree" | |
git update-ref "$buildBranch" "$buildCommit" || fail $? unable to update "$buildBranch" to commit "$buildCommit" | |
echo >&2 finished updating "$buildBranch" | |
git show "$buildBranch" --stat |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
caveat: i have not tested this yet!