X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=topgit.git;a=blobdiff_plain;f=tg-export.sh;h=52af88dfd14e891627b145f63702b1212155a82c;hp=4ce54cd1e96a903a72781eb90af0e63c9ff831cf;hb=9f5917da92ab8c32ab765a331ebcaf227b3e2f85;hpb=6d1f60429c7c8a769e4e78a0a5bbc460dea7248a diff --git a/tg-export.sh b/tg-export.sh index 4ce54cd..52af88d 100644 --- a/tg-export.sh +++ b/tg-export.sh @@ -4,6 +4,7 @@ # GPLv2 name= +branches= output= driver=collapse @@ -13,12 +14,14 @@ driver=collapse while [ -n "$1" ]; do arg="$1"; shift case "$arg" in + -b) + branches="$1"; shift;; --quilt) driver=quilt;; --collapse) driver=collapse;; -*) - echo "Usage: tg export ([--collapse] NEWBRANCH | --quilt DIRECTORY)" >&2 + echo "Usage: tg [...] export ([--collapse] NEWBRANCH | [-b BRANCH1,BRANCH2...] --quilt DIRECTORY)" >&2 exit 1;; *) [ -z "$output" ] || die "output already specified ($output)" @@ -27,28 +30,24 @@ while [ -n "$1" ]; do done -name="$(git symbolic-ref HEAD | sed 's#^refs/heads/##')" -base_rev="$(git rev-parse --short --verify "refs/top-bases/$name" 2>/dev/null)" || - die "not on a TopGit-controlled branch" +[ -z "$branches" -o "$driver" = "quilt" ] || + die "-b works only with the quilt driver" -playground="$(mktemp -d)" +if [ -z "$branches" ]; then + # this check is only needed when no branches have been passed + name="$(git symbolic-ref HEAD | sed 's#^refs/heads/##')" + base_rev="$(git rev-parse --short --verify "refs/top-bases/$name" 2>/dev/null)" || + die "not on a TopGit-controlled branch" +fi + + +playground="$(mktemp -d -t tg-export.XXXXXX)" trap 'rm -rf "$playground"' EXIT ## Collapse driver -# Trusty Cogito code: -load_author() -{ - if [ -z "$GIT_AUTHOR_NAME" ] && echo "$1" | grep -q '^[^< ]'; then - export GIT_AUTHOR_NAME="$(echo "$1" | sed 's/ *<.*//')" - fi - if [ -z "$GIT_AUTHOR_EMAIL" ] && echo "$1" | grep -q '<.*>'; then - export GIT_AUTHOR_EMAIL="$(echo "$1" | sed 's/.*<\(.*\)>.*/\1/')" - fi -} - # pretty_tree NAME # Output tree ID of a cleaned-up tree without tg's artifacts. pretty_tree() @@ -69,19 +68,16 @@ collapsed_commit() >"$playground/^body" # Get commit message and authorship information - git cat-file blob "$name:.topmsg" >"$playground/^msg" - while read line; do - if [ -z "$line" ]; then - # end of header - cat >"$playground/^body" - break - fi - case "$line" in - From:*) load_author "${line#From: }";; - Subject:*) echo "${line#Subject: }" >>"$playground/^pre";; - *) echo "$line" >>"$playground/^post";; - esac - done <"$playground/^msg" + git cat-file blob "$name:.topmsg" | git mailinfo "$playground/^msg" /dev/null > "$playground/^info" + + GIT_AUTHOR_NAME="$(sed -n '/^Author/ s/Author: //p' "$playground/^info")" + GIT_AUTHOR_EMAIL="$(sed -n '/^Email/ s/Email: //p' "$playground/^info")" + GIT_AUTHOR_DATE="$(sed -n '/^Date/ s/Date: //p' "$playground/^info")" + SUBJECT="$(sed -n '/^Subject/ s/Subject: //p' "$playground/^info")" + + test -n "$GIT_AUTHOR_NAME" && export GIT_AUTHOR_NAME + test -n "$GIT_AUTHOR_EMAIL" && export GIT_AUTHOR_EMAIL + test -n "$GIT_AUTHOR_DATE" && export GIT_AUTHOR_DATE # Determine parent parent="$(cut -f 1 "$playground/$name^parents")" @@ -95,14 +91,9 @@ collapsed_commit() $(for p in $parent; do echo -p $p; done))" fi - { - if [ -s "$playground/^pre" ]; then - cat "$playground/^pre" - echo - fi - cat "$playground/^body" - [ ! -s "$playground/^post" ] || cat "$playground/^post" - } | git commit-tree "$(pretty_tree "$name")" -p "$parent" + (printf '%s\n\n' "$SUBJECT"; cat "$playground/^msg") | + git stripspace | + git commit-tree "$(pretty_tree "$name")" -p "$parent" echo "$name" >>"$playground/^ticker" } @@ -122,11 +113,10 @@ collapse() else # First time hitting this dep; the common case + echo "Collapsing $_dep" commit="$(collapsed_commit "$_dep")" - mkdir -p "$playground/$(dirname "$_dep")" echo "$commit" >"$playground/$_dep" - echo "Collapsed $_dep" fi # Propagate our work through the dependency chain @@ -150,10 +140,10 @@ quilt() return fi + echo "Exporting $_dep" mkdir -p "$(dirname "$filename")" - tg patch "$_dep" >"$filename" + $tg patch "$_dep" >"$filename" echo "$_dep.diff -p1" >>"$output/series" - echo "Exported $_dep" } @@ -162,7 +152,7 @@ quilt() if [ "$driver" = "collapse" ]; then [ -n "$output" ] || die "no target branch specified" - ! git rev-parse --verify "$output" >/dev/null 2>&1 || + ! ref_exists "$output" || die "target branch '$output' already exists; first run: git branch -D $output" elif [ "$driver" = "quilt" ]; then @@ -177,6 +167,7 @@ fi driver() { + case $_dep in refs/remotes/*) return;; esac branch_needs_update >/dev/null [ "$_ret" -eq 0 ] || die "cancelling export of $_dep (-> $_name): branch not up-to-date" @@ -186,12 +177,20 @@ driver() # Call driver on all the branches - this will happen # in topological order. -recurse_deps driver "$name" -(_ret=0; _dep="$name"; _name=""; _dep_is_tgish=1; driver) +if [ -z "$branches" ]; then + recurse_deps driver "$name" + (_ret=0; _dep="$name"; _name=""; _dep_is_tgish=1; driver) +else + echo "$branches" | tr ',' '\n' | while read _dep; do + _dep_is_tgish=1 + $driver + done + name="$(echo "$branches" | sed 's/.*,//')" +fi if [ "$driver" = "collapse" ]; then - git update-ref "refs/heads/$output" "$(cat "$playground/$name")" + git update-ref "refs/heads/$output" "$(cat "$playground/$name")" "" depcount="$(cat "$playground/^ticker" | wc -l)" echo "Exported topic branch $name (total $depcount topics) to branch $output"