Skip to content

Instantly share code, notes, and snippets.

@jpassaro
Last active January 17, 2019 21:22
Show Gist options
  • Save jpassaro/56299716bd1cc99b40756b88409fbbda to your computer and use it in GitHub Desktop.
Save jpassaro/56299716bd1cc99b40756b88409fbbda to your computer and use it in GitHub Desktop.
Maintain a separate branch for build artifacts
#!/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
@jpassaro
Copy link
Author

caveat: i have not tested this yet!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment