Some workflows require coordinated development between repositories on machines that can never be connected. This utility creates a bundle containing a pack of objects and associated references (heads or tags) that can be independently transferred to another machine, effectively supporting git-push like operations between disconnected systems. Signed-off-by: Mark Levedahl <mdl123@xxxxxxxxxxx> --- git-bundle.sh | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 103 insertions(+), 0 deletions(-) create mode 100755 git-bundle.sh diff --git a/git-bundle.sh b/git-bundle.sh new file mode 100755 index 0000000..c431b52 --- /dev/null +++ b/git-bundle.sh @@ -0,0 +1,103 @@ +#!/bin/sh +# Create a bundle to carry from one git repo to another +# (e.g., "sneaker-net" based push) +# git-bundle <git-rev-list args> +# git-bundle --bare <git-rev-list args> +# creates bundle.tar in current directory (can rename of course) +# +# The bundle includes all refs given (--all selects every ref in the repo). +# and all of the commit objects needed subject to the list given. +# +# Objects to be packed are limited by specifying one or more of +# ^commit-ish - indicated commits already at the target +# (can have more than one ^commit-ish) +# --since=xxx - Assume target repo has all relevant commits +# earlier than xxx + +USAGE='git-bundle [--output=file] <git-rev-list arguments>' +SUBDIRECTORY_OK=1 +. git-sh-setup + +# pull out rev-list args vs program args, parse the latter +gitrevargs=$(git-rev-parse --symbolic --revs-only $*) || exit 1 +myargs=$(git-rev-parse --no-revs $*) || exit 1 + +bfile=bundle.tar +nextisoutput= +for arg in $myargs ; do + case "$arg" in + -h|--h|--he|--hel|--help) + echo "$USAGE" + exit;; + --output=*) + bfile=${arg##--output=};; + *) + die "unknown option: $arg";; + esac +done + +# find the refs to carry along and get sha1s for each. +refs= +fullrevargs= +for arg in $gitrevargs ; do + #ignore options and basis refs, get unambiguous ref name for things + # we will transport (e.g., user gives master, have heads/master and + # remotes/origin/master, we keep the former). + case "$arg" in + -*) fullrevargs="$fullrevargs $arg";; + ^*) fullrevargs="$fullrevargs $arg";; + *) ref=$(git-show-ref "$arg" | head -n1) + [ -z "$ref" ] && die "unknown reference: $arg" + fullrevargs="$fullrevargs ${ref#* }" + refs="$refs $ref" + ;; + esac +done +[ -z "$refs" ] && die "No references specified, I don't know what to bundle." + +# git-rev-list cannot determine edge objects if a date restriction is given... +# we do things a slow way if max-age or min-age are given +fast= +[ "${fullrevargs##*--max-age}" == "$fullrevargs" ] && \ +[ "${fullrevargs##*--min-age}" == "$fullrevargs" ] && fast=1 + +if [ -z "$fast" ] ; then + # get a list of all commits that will be packed along with parents of each. + # A fixed git-rev-list --boundary should replace all of this. + echo "Finding prerequisites and commits to bundle..." + commits=$(git-rev-list $fullrevargs) + + # get immediate parents of each commit to include + parents= + for c in $commits ; do + parents="$parents $(git-rev-list --parents $c | head -1 | cut -b42-)" + done + parents=$(printf "%s\n" $parents | sort | uniq) + + # factor out what will be in this bundle, the remainder are the bundle's pre-requisites. + # double up commits in this as we only want things that are only in parents to appear once + prereqs=$(printf "%s\n" $parents $commits $commits | \ + sort | \ + uniq -c | \ + grep ' 1 ' \ + | sed 's/ *1 //') +else + prereqs=$(git-rev-list --objects-edge $fullrevargs | \ + grep '^-' | sed 's/-//') +fi + +# create refs and pack +[ -e "$bfile" ] && rm -f "$bfile" 2>/dev/null +printf "%s\n" $prereqs > .gitBundleReferences +echo "-" >> .gitBundleReferences +git-show-ref $refs >> .gitBundleReferences +(git-rev-list --objects $fullrevargs | \ + cut -b-40 | \ + git pack-objects --all-progress --stdout >.gitBundlePack) \ + || (rm -f "$bfile" ; exit) +tar cf "$bfile" .gitBundleReferences .gitBundlePack +tar cf "$bfile" .gitBundleReferences .gitBundlePack +rm .gitBundleReferences .gitBundlePack + +# done +echo "Created $bfile" -- 1.5.0.34.g6afaa - To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html