chiark / gitweb /
Merge branch 'master' into refs/top-bases/debian/locations
authormartin f. krafft <madduck@madduck.net>
Fri, 26 Sep 2008 18:06:01 +0000 (20:06 +0200)
committermartin f. krafft <madduck@madduck.net>
Fri, 26 Sep 2008 18:06:01 +0000 (20:06 +0200)
14 files changed:
.gitignore
Makefile
README
debian/README.source
debian/changelog
tg-delete.sh
tg-depend.sh [new file with mode: 0644]
tg-export.sh
tg-import.sh
tg-info.sh
tg-mail.sh [new file with mode: 0644]
tg-patch.sh
tg-update.sh
tg.sh

index 8f1d3a7d1ea4c012f90a8a62ae27265c1fb1fd16..1e90e82b202a3d022cb998c2c61049b51e7b0108 100644 (file)
@@ -5,6 +5,8 @@ tg-delete
 tg-delete.txt
 tg-info
 tg-info.txt
+tg-mail
+tg-mail.txt
 tg-patch
 tg-patch.txt
 tg-summary
@@ -13,4 +15,9 @@ tg-update
 tg-update.txt
 tg-export
 tg-export.txt
+tg-import
+tg-import.txt
+tg-remote
+tg-remote.txt
 tg
+.*.swp
index b73a1f15b9c298e0e922df1c61f6fb15df8f7821..2c627afbaab085c72f58257399edca8da4d77fb5 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -14,7 +14,7 @@ help_out = $(patsubst %.sh,%.txt,$(commands_in))
 
 all::  tg $(commands_out) $(hooks_out) $(help_out)
 
-tg $(commands_out) $(hooks_out): % : %.sh
+tg $(commands_out) $(hooks_out): % : %.sh Makefile
        @echo "[SED] $@"
        @sed -e 's#@cmddir@#$(cmddir)#g;' \
                -e 's#@hooksdir@#$(hooksdir)#g' \
diff --git a/README b/README
index b99b03680fb7fced0e1dc2f0e699f73b141745f5..1893dc0973093da0da231c76b4bfde734fabcc8c 100644 (file)
--- a/README
+++ b/README
@@ -253,6 +253,19 @@ tg delete
 
        TODO: '-a' to delete all empty branches, depfix, revert
 
+tg depend
+~~~~~~~~~
+       Change dependencies of a TopGit-controlled topic branch.
+       This should have several subcommands, but only 'add' is
+       supported right now.
+
+       The 'add' subcommand takes an argument of a topic branch
+       to be added, adds it to '.topdeps', performs a commit and
+       then updates your topic branch accordingly. If you want to
+       do other things related to the dependency addition, like
+       adjusting '.topmsg', prepare them in the index before
+       calling 'tg depend add'.
+
 tg info
 ~~~~~~~
        Show a summary information about the current or specified
@@ -272,11 +285,31 @@ tg patch
        TODO: tg patch -i to base at index instead of branch,
                -w for working tree
 
+tg mail
+~~~~~~~
+       Send a patch from the current or specified topic branch as
+       email.
+
+       Takes the patch given on the command line and emails it out.
+       Destination addresses such as To, Cc and Bcc are taken from the
+       patch header.
+
+       Since it actually boils down to `git send-email` please refer to
+       its documentation for details on how to setup email for git.
+       You can pass arbitrary options to this command through the
+       '-s' parameter, but you must double-quote everything.
+
+       TODO: 'tg mail patchfile' to mail an already exported patch
+       TODO: mailing patch series
+       TODO: specifying additional options and addresses on command
+             line
+
 tg remote
 ~~~~~~~~~
        Register given remote as TopGit-controlled. This will create
        the namespace for the remote branch bases and teach 'git fetch'
-       and 'git push' to operate on them.
+       and 'git push' to operate on them. (Do NOT use 'git push --all'
+       for your pushes - plain 'git push' will do the right thing.)
 
        It takes a mandatory remote name argument, and optional
        '--populate' switch - use that for your origin-style remote,
@@ -362,6 +395,10 @@ tg export
        and an argument specifying the directory
        where the quilt series should be saved.
 
+       With '--quilt', you can also pass '-b' parameter followed by
+       a comma-separated explicit list of branches to export. This
+       mode of operation is currently not supported with collapse.
+
        Usage: tg export ([--collapse] BRANCH | --quilt DIR)
 
        TODO: Make stripping of non-essential headers configurable
@@ -369,8 +406,6 @@ tg export
        TODO: --mbox option for other mode of operation
        TODO: -n option to prevent exporting of empty patches
        TODO: -a option to export all branches
-       TODO: Allow branches to be exported to be passed as arguments, default
-             to the current branch if none are specified
        TODO: For quilt exporting, use a temporary branch and remove it when
              done - this would allow producing conflict-less series
 
index 732e5d4da1db2f7b804d8af6433cf1b45af5d374..6fafbb44ea23b33f53b9d4c5ee17fbb420408ef6 100644 (file)
@@ -63,30 +63,29 @@ The upstream tarball for $VERSION can be obtained using pristine-tar:
 To build the package, you check out the build branch, recreate debian/patches,
 commit, build, test, upload, tag:
 
- 1. tg create stage-0.3-1 debian/locations
- 2. git commit -m'staging 0.3-1'
+ 1. tg create stage-0.4-1 debian/locations
+ 2. git commit -m'staging 0.4-1'
  3. tg export --quilt debian/patches.new
  4. rm debian/patches.new/stage-*
  5. sed -i '/^stage-/d' debian/patches.new/series
  6. git checkout build && git rm -r debian/patches
  7. mv debian/patches.new debian/patches && git add debian/patches
- 8. git commit -m'preparing 0.3-1'
- 9. build, test, upload, tag ('debian/topgit-0.3-1')
-10. tg delete stage-0.3-1
+ 8. git commit -m'preparing 0.4-1'
+ 9. build, test, upload, tag ('debian/topgit-0.4-1')
+10. tg delete stage-0.4-1
 
 This process is still very cumbersome and needs to be improved, ideally within
 TopGit.
 
 5. Importing a new upstream version
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-To import a new upstream, pull it into the upstream branch, merge upstream
+To import a new upstream, update the remote, merge the tag you want to merge
 into the master branch, ideally together with an update to debian/changelog,
 then update all TopGit branches:
 
-1. git checkout upstream
-2. git pull
-3. git checkout master
-4. git merge upstream
+1. git remote update
+2. git checkout master
+3. git merge topgit-0.4
 
 Now proceed as in the next step.
 
@@ -105,10 +104,12 @@ this procedure:
 Until upstream provides official tarballs, the following can be used to create
 them for Debian:
 
-1. git archive --prefix=$(git describe upstream)/ --verbose upstream \
-    | gzip -9 > ../$(git describe upstream | sed s,-,_,).orig.tar.gz
-2. pristine-tar commit ../$(git describe upstream | sed s,-,_,).orig.tar.gz \
-    upstream
+1. git checkout topgit-0.4
+2. git archive --prefix=$(git describe HEAD)/ --verbose HEAD \
+    | gzip -9 > ../$(git describe HEAD | sed s,-,_,).orig.tar.gz
+3. pristine-tar commit ../$(git describe HEAD | sed s,-,_,).orig.tar.gz \
+    HEAD
+4. git checkout master
 
 All comments and suggestions are welcome, especially those pertaining to
 auto-generating debian/changelog from commit logs.
index c61ba3e99d6d8d535ce943c0f360c91623b86a2c..40e7e14c642a9ec9a65d9d893583ec8c8bb6ff2e 100644 (file)
@@ -1,3 +1,9 @@
+topgit (0.4-1) unstable; urgency=low
+
+  * New upstream release.
+
+ -- martin f. krafft <madduck@debian.org>  Fri, 26 Sep 2008 19:55:58 +0200
+
 topgit (0.3-1) unstable; urgency=low
 
   * New upstream release (closes: #498559).
index 075d15c3ab76ea402cddce32fb72ff1b030ae8ff..7f7ede7068d71bd5f50e10686ea87398f26f1b41 100644 (file)
@@ -31,7 +31,7 @@ branchrev="$(git rev-parse --verify "$name" 2>/dev/null)" ||
        die "invalid branch name: $name"
 baserev="$(git rev-parse --verify "refs/top-bases/$name" 2>/dev/null)" ||
        die "not a TopGit topic branch: $name"
-[ "$(git symbolic-ref HEAD)" != "refs/heads/$name" ] ||
+! git symbolic-ref HEAD >/dev/null || [ "$(git symbolic-ref HEAD)" != "refs/heads/$name" ] ||
        die "cannot delete your current branch"
 
 nonempty=
diff --git a/tg-depend.sh b/tg-depend.sh
new file mode 100644 (file)
index 0000000..af78808
--- /dev/null
@@ -0,0 +1,41 @@
+#!/bin/sh
+# TopGit - A different patch queue manager
+# (c) Petr Baudis <pasky@suse.cz>  2008
+# GPLv2
+
+name=
+
+
+## Parse options
+
+subcmd="$1"; shift
+[ "$subcmd" = "add" ] || die "unknown subcommand ($subcmd)"
+
+while [ -n "$1" ]; do
+       arg="$1"; shift
+       case "$arg" in
+       -*)
+               echo "Usage: tg [...] depend add NAME" >&2
+               exit 1;;
+       *)
+               [ -z "$name" ] || die "name already specified ($name)"
+               name="$arg";;
+       esac
+done
+
+
+## Sanity checks
+
+[ -n "$name" ] || die "no branch name specified"
+branchrev="$(git rev-parse --verify "$name" 2>/dev/null)" ||
+       die "invalid branch name: $name"
+baserev="$(git rev-parse --verify "refs/top-bases/$name" 2>/dev/null)" ||
+       die "not a TopGit topic branch: $name"
+
+
+## Record new dependency
+
+echo "$name" >>.topdeps
+git add .topdeps
+git commit -m"New TopGit dependency: $name"
+$tg update
index 654b38bf50805c182f67f189ce4cf5cfecda3fc0..a7c459a17f37c14696edfba30e121ce3ca10996e 100644 (file)
@@ -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 [-b BRANCH1,BRANCH2...] ([--collapse] NEWBRANCH | --quilt DIRECTORY)" >&2
                exit 1;;
        *)
                [ -z "$output" ] || die "output already specified ($output)"
@@ -31,6 +34,9 @@ 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 -t tg-export.XXXXXX)"
 trap 'rm -rf "$playground"' EXIT
@@ -38,17 +44,6 @@ 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 +64,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 +87,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"
 }
@@ -176,6 +163,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"
@@ -185,8 +173,16 @@ 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
index 6a4f79ea27e0116814c271b03046a3f2eb874da4..799efc9a8395228604e1ccf94cc66a0c36144ec9 100644 (file)
@@ -24,6 +24,15 @@ while [ -n "$1" ]; do
 done
 
 
+## Make sure our tree is clean
+
+git update-index --ignore-submodules --refresh || exit
+[ -z "$(git diff-index --cached --name-status -r --ignore-submodules HEAD --)" ] ||
+       die "the index is not clean"
+
+
+## Perform import
+
 get_commit_msg()
 {
        commit="$1"
@@ -52,7 +61,7 @@ process_commit()
        branch_name=$(get_branch_name "$commit")
        info "---- Importing $commit to $branch_prefix$branch_name"
        tg create "$branch_prefix""$branch_name"
-       git read-tree "$commit"
+       git cherry-pick --no-commit "$commit"
        get_commit_msg "$commit" > .topmsg
        git add -f .topmsg .topdeps
        git commit -C "$commit"
index b5b92f654116c852ddae266cbacb08765a914dfb..90762479eb44f3b0ef2f366fc4a7865e05087c76 100644 (file)
@@ -20,7 +20,7 @@ while [ -n "$1" ]; do
        esac
 done
 
-[ -n "$name" ] || name="$(git symbolic-ref HEAD | sed 's#^refs/heads/##')"
+[ -n "$name" ] || name="$(git symbolic-ref HEAD | sed 's#^refs/\(heads\|top-bases\)/##')"
 base_rev="$(git rev-parse --short --verify "refs/top-bases/$name" 2>/dev/null)" ||
        die "not a TopGit-controlled branch"
 
@@ -32,7 +32,7 @@ if [ "$(git rev-parse --short "$name")" = "$base_rev" ]; then
        exit 0
 fi
 
-git cat-file blob "$name:.topmsg" | grep ^Subject:
+git cat-file blob "$name:.topmsg" | grep ^Subject: || :
 
 echo "Base: $base_rev"
 branch_contains "$name" "$base_rev" ||
diff --git a/tg-mail.sh b/tg-mail.sh
new file mode 100644 (file)
index 0000000..24e5f67
--- /dev/null
@@ -0,0 +1,53 @@
+#!/bin/sh
+# TopGit - A different patch queue manager
+# GPLv2
+
+name=
+send_email_args=
+
+
+## Parse options
+
+while [ -n "$1" ]; do
+       arg="$1"; shift
+       case "$arg" in
+       -s)
+               send_email_args="$1"; shift;;
+       -*)
+               echo "Usage: tg [...] mail [-s SEND_EMAIL_ARGS] [NAME]" >&2
+               exit 1;;
+       *)
+               [ -z "$name" ] || die "name already specified ($name)"
+               name="$arg";;
+       esac
+done
+
+[ -n "$name" ] || 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 a TopGit-controlled branch"
+
+
+patchfile="$(mktemp -t tg-mail.XXXXXX)"
+
+$tg patch $name >"$patchfile"
+
+hlines=$(grep -n -m 1 '^---' "$patchfile" | sed 's/:---//')
+header=$(head -n $(($hlines - 1)) "$patchfile")
+
+
+
+from="$(echo "$header" | grep '^From:' | sed 's/From:\s*//')"
+to="$(echo "$header" | grep '^To:' | sed 's/To:\s*//')"
+
+
+# XXX: I can't get quoting right without arrays
+people=()
+[ -n "$from" ] && people=("${people[@]}" --from "$from")
+# FIXME: there could be multimple To
+[ -n "$to" ]   && people=("${people[@]}" --to "$to")
+
+
+# NOTE: git-send-email handles cc itself
+git send-email $send_email_args "${people[@]}" "$patchfile"
+
+rm "$patchfile"
index 7a2471827d1e27db9a520f51541cecc4dd69c12a..97338ab63ef77f52eb876c77ca50b669c458f333 100644 (file)
@@ -20,7 +20,7 @@ while [ -n "$1" ]; do
        esac
 done
 
-[ -n "$name" ] || name="$(git symbolic-ref HEAD | sed 's#^refs/heads/##')"
+[ -n "$name" ] || name="$(git symbolic-ref HEAD | sed 's#^refs/\(heads\|top-bases\)/##')"
 base_rev="$(git rev-parse --short --verify "refs/top-bases/$name" 2>/dev/null)" ||
        die "not a TopGit-controlled branch"
 
index 39769bead098c674ff8a8a12f7dfb48254191a7b..f36624fe71b73263471e5df8fbb0014d47ca2ee0 100644 (file)
@@ -75,7 +75,7 @@ if [ -s "$depcheck" ]; then
                        info "Updating base with $dep changes..."
                        if ! git merge "$dep"; then
                                if [ -z "$TG_RECURSIVE" ]; then
-                                       resume='`$tg update` again'
+                                       resume="\`$tg update\` again"
                                else # subshell
                                        resume='exit'
                                fi
diff --git a/tg.sh b/tg.sh
index b4933997e9a6fb484554257b4e2cf31c2dca924c..7005f98c882bde7c97094862aeb88b07b28de390 100644 (file)
--- a/tg.sh
+++ b/tg.sh
@@ -26,7 +26,7 @@ setup_hook()
                # Another job well done!
                return
        fi
-       # Prepare incanation
+       # Prepare incantation
        if [ -x "$git_dir/hooks/$1" ]; then
                hook_call="$hook_call"' || exit $?'
        else
@@ -222,10 +222,14 @@ do_help()
                        sep="|"
                done
 
-               echo "TopGit v0.3 - A different patch queue manager"
+               echo "TopGit v0.4 - A different patch queue manager"
                echo "Usage: tg [-r REMOTE] ($cmds|help) ..."
-       elif [ -r "@sharedir@/tg-$1.txt" ] ; then
-               cat "@sharedir@/tg-$1.txt"
+       elif [ -r "@cmddir@"/tg-$1 ] ; then
+               @cmddir@/tg-$1 -h || :
+               echo
+               if [ -r "@sharedir@/tg-$1.txt" ] ; then
+                       cat "@sharedir@/tg-$1.txt"
+               fi
        else
                echo "`basename $0`: no help for $1" 1>&2
        fi