chiark / gitweb /
Merge commit 'refs/top-bases/debian/locations' into debian/locations
authormartin f. krafft <madduck@debian.org>
Mon, 17 Nov 2008 21:55:07 +0000 (22:55 +0100)
committermartin f. krafft <madduck@debian.org>
Mon, 17 Nov 2008 21:55:07 +0000 (22:55 +0100)
Conflicts:
Makefile

12 files changed:
Makefile
README
contrib/tg-completion.bash [new file with mode: 0755]
debian/README.source
debian/changelog
tg-depend.sh [changed mode: 0644->0755]
tg-export.sh
tg-import.sh
tg-mail.sh
tg-summary.sh
tg-update.sh
tg.sh

index 835811ed048c967185b227b68a77fee422925f08..31cc98e6fecdc1cec803f8c5744eb9b324d5b4b0 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,16 +1,16 @@
-prefix = $(HOME)
-bindir = $(prefix)/bin
-cmddir = $(prefix)/share/topgit
-docdir = $(prefix)/share/doc/topgit
-hooksdir = $(cmddir)/hooks
+prefix ?= $(HOME)
+bindir := $(prefix)/bin
+cmddir := $(prefix)/share/topgit
+docdir := $(prefix)/share/doc/topgit
+hooksdir := $(cmddir)/hooks
 
 
-commands_in = $(wildcard tg-*.sh)
+commands_in := $(wildcard tg-*.sh)
 hooks_in = hooks/pre-commit.sh
 
-commands_out = $(patsubst %.sh,%,$(commands_in))
-hooks_out = $(patsubst %.sh,%,$(hooks_in))
-help_out = $(patsubst %.sh,%.txt,$(commands_in))
+commands_out := $(patsubst %.sh,%,$(commands_in))
+hooks_out := $(patsubst %.sh,%,$(hooks_in))
+help_out := $(patsubst %.sh,%.txt,$(commands_in))
 
 all::  tg $(commands_out) $(hooks_out) $(help_out)
 
diff --git a/README b/README
index 1893dc0973093da0da231c76b4bfde734fabcc8c..5bfe3ee14793c9591e78095e213039de3847d0ea 100644 (file)
--- a/README
+++ b/README
@@ -49,7 +49,7 @@ branch.  In order to flexibly accomodate even complex scenarios when
 you track many patches where many are independent but some depend
 on others, TopGit ignores the ancient Quilt heritage of patch series
 and instead allows the patches to freely form graphs (DAGs just like
-Git history itself, only "one lever higher"). For now, you have
+Git history itself, only "one level higher"). For now, you have
 to manually specify which patches does the current one depend
 on, but TopGit might help you with that in the future in a darcs-like
 fashion.
@@ -266,6 +266,8 @@ tg depend
        adjusting '.topmsg', prepare them in the index before
        calling 'tg depend add'.
 
+       TODO: Subcommand for removing dependencies, obviously
+
 tg info
 ~~~~~~~
        Show a summary information about the current or specified
@@ -298,6 +300,8 @@ tg mail
        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.
+       The '-r' parameter with msgid can be used to generate in-reply-to
+       and reference headers to an earlier mail.
 
        TODO: 'tg mail patchfile' to mail an already exported patch
        TODO: mailing patch series
@@ -329,8 +333,14 @@ tg summary
        '!' marks that it has missing dependencies (even recursively),
        'B' marks that it is out-of-date wrt. its base).
 
+       This can take long time to accurately determine all the relevant
+       information about each branch; you can pass '-t' to get just
+       terse list of topic branch names quickly. Alternately, you can
+       pass '--graphviz' to get a dot-suitable output to draw a dependency
+       graph between the topic branches.
+
        TODO: Speed up by an order of magnitude
-       TODO: Graph view
+       TODO: Text graph view
 
 tg export
 ~~~~~~~~~
@@ -413,12 +423,17 @@ tg import
 ~~~~~~~~~
        Import commits within the given revision range into TopGit,
        creating one topic branch per commit, the dependencies forming
-       a linear sequence starting on your current branch.
+       a linear sequence starting on your current branch (or a branch
+       specified by the '-d' parameter).
 
        The branch names are auto-guessed from the commit messages
        and prefixed by t/ by default; use '-p PREFIX' to specify
        an alternative prefix (even an empty one).
 
+       Alternatively, you can use the '-s NAME' parameter to specify
+       the name of target branch; the command will then take one more
+       argument describing a single commit to import.
+
 tg update
 ~~~~~~~~~
        Update the current topic branch wrt. changes in the branches
@@ -478,7 +493,10 @@ can be prefilled from various optional topgit.* config options.
        .topdeps: Contains the one-per-line list of branches
 your patch depends on, pre-seeded with `tg create`. (Continuously
 updated) merge of these branches will be the "base" of your topic
-branch.
+branch. DO NOT EDIT THIS FILE MANUALLY!!! If you do so, you need
+to know exactly what are you doing, since this file must stay in
+sync with the Git history information, otherwise very bad things
+will happen.
 
 TopGit also automagically installs a bunch of custom commit-related
 hooks that will verify if you are committing the .top* files in sane
diff --git a/contrib/tg-completion.bash b/contrib/tg-completion.bash
new file mode 100755 (executable)
index 0000000..67f820e
--- /dev/null
@@ -0,0 +1,450 @@
+#
+# bash completion support for TopGit.
+#
+# Copyright (C) 2008 Jonas Fonseca <fonseca@diku.dk>
+# Copyright (C) 2006,2007 Shawn O. Pearce <spearce@spearce.org>
+# Based git's git-completion.sh: http://repo.or.cz/w/git/fastimport.git
+# Conceptually based on gitcompletion (http://gitweb.hawaga.org.uk/).
+# Distributed under the GNU General Public License, version 2.0.
+#
+# To use these routines:
+#
+#    1) Copy this file to somewhere (e.g. ~/.tg-completion.sh).
+#    2) Source it from your ~/.bashrc.
+#
+# Note: Make sure the tg script is in your PATH before you source this
+# script, so it can properly setup cached values.
+
+case "$COMP_WORDBREAKS" in
+*:*) : great ;;
+*)   COMP_WORDBREAKS="$COMP_WORDBREAKS:"
+esac
+
+### {{{ Utilities
+
+__tgdir ()
+{
+       if [ -z "$1" ]; then
+               if [ -n "$__tg_dir" ]; then
+                       echo "$__tg_dir"
+               elif [ -d .git ]; then
+                       echo .git
+               else
+                       git rev-parse --git-dir 2>/dev/null
+               fi
+       elif [ -d "$1/.git" ]; then
+               echo "$1/.git"
+       else
+               echo "$1"
+       fi
+}
+
+__tgcomp_1 ()
+{
+       local c IFS=' '$'\t'$'\n'
+       for c in $1; do
+               case "$c$2" in
+               --*=*) printf %s$'\n' "$c$2" ;;
+               *.)    printf %s$'\n' "$c$2" ;;
+               *)     printf %s$'\n' "$c$2 " ;;
+               esac
+       done
+}
+
+__tgcomp ()
+{
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+       if [ $# -gt 2 ]; then
+               cur="$3"
+       fi
+       case "$cur" in
+       --*=)
+               COMPREPLY=()
+               ;;
+       *)
+               local IFS=$'\n'
+               COMPREPLY=($(compgen -P "$2" \
+                       -W "$(__tgcomp_1 "$1" "$4")" \
+                       -- "$cur"))
+               ;;
+       esac
+}
+
+__tg_heads ()
+{
+       local cmd i is_hash=y dir="$(__tgdir "$1")"
+       if [ -d "$dir" ]; then
+               git --git-dir="$dir" for-each-ref --format='%(refname:short)' \
+                       refs/heads
+               return
+       fi
+       for i in $(git ls-remote "$1" 2>/dev/null); do
+               case "$is_hash,$i" in
+               y,*) is_hash=n ;;
+               n,*^{}) is_hash=y ;;
+               n,refs/heads/*) is_hash=y; echo "${i#refs/heads/}" ;;
+               n,*) is_hash=y; echo "$i" ;;
+               esac
+       done
+}
+
+__tg_refs ()
+{
+       local cmd i is_hash=y dir="$(__tgdir "$1")"
+       if [ -d "$dir" ]; then
+               if [ -e "$dir/HEAD" ]; then echo HEAD; fi
+               git --git-dir="$dir" for-each-ref --format='%(refname:short)' \
+                       refs/tags refs/heads refs/remotes
+               return
+       fi
+       for i in $(git ls-remote "$dir" 2>/dev/null); do
+               case "$is_hash,$i" in
+               y,*) is_hash=n ;;
+               n,*^{}) is_hash=y ;;
+               n,refs/tags/*) is_hash=y; echo "${i#refs/tags/}" ;;
+               n,refs/heads/*) is_hash=y; echo "${i#refs/heads/}" ;;
+               n,refs/remotes/*) is_hash=y; echo "${i#refs/remotes/}" ;;
+               n,*) is_hash=y; echo "$i" ;;
+               esac
+       done
+}
+
+__tg_refs2 ()
+{
+       local i
+       for i in $(__tg_refs "$1"); do
+               echo "$i:$i"
+       done
+}
+
+__tg_refs_remotes ()
+{
+       local cmd i is_hash=y
+       for i in $(git ls-remote "$1" 2>/dev/null); do
+               case "$is_hash,$i" in
+               n,refs/heads/*)
+                       is_hash=y
+                       echo "$i:refs/remotes/$1/${i#refs/heads/}"
+                       ;;
+               y,*) is_hash=n ;;
+               n,*^{}) is_hash=y ;;
+               n,refs/tags/*) is_hash=y;;
+               n,*) is_hash=y; ;;
+               esac
+       done
+}
+
+__tg_remotes ()
+{
+       local i ngoff IFS=$'\n' d="$(__tgdir)"
+       shopt -q nullglob || ngoff=1
+       shopt -s nullglob
+       for i in "$d/remotes"/*; do
+               echo ${i#$d/remotes/}
+       done
+       [ "$ngoff" ] && shopt -u nullglob
+       for i in $(git --git-dir="$d" config --list); do
+               case "$i" in
+               remote.*.url=*)
+                       i="${i#remote.}"
+                       echo "${i/.url=*/}"
+                       ;;
+               esac
+       done
+}
+
+__tg_find_subcommand ()
+{
+       local word subcommand c=1
+
+       while [ $c -lt $COMP_CWORD ]; do
+               word="${COMP_WORDS[c]}"
+               for subcommand in $1; do
+                       if [ "$subcommand" = "$word" ]; then
+                               echo "$subcommand"
+                               return
+                       fi
+               done
+               c=$((++c))
+       done
+}
+
+__tg_complete_revlist ()
+{
+       local pfx cur="${COMP_WORDS[COMP_CWORD]}"
+       case "$cur" in
+       *...*)
+               pfx="${cur%...*}..."
+               cur="${cur#*...}"
+               __tgcomp "$(__tg_refs)" "$pfx" "$cur"
+               ;;
+       *..*)
+               pfx="${cur%..*}.."
+               cur="${cur#*..}"
+               __tgcomp "$(__tg_refs)" "$pfx" "$cur"
+               ;;
+       *)
+               __tgcomp "$(__tg_refs)"
+               ;;
+       esac
+}
+
+__tg_topics ()
+{
+       tg summary -t
+}
+
+__tg_commands ()
+{
+       if [ -n "$__tg_all_commandlist" ]; then
+               echo "$__tg_all_commandlist"
+               return
+       fi
+       local i IFS=" "$'\n'
+       for i in $(tg help | sed -n 's/^Usage:.*(\(.*\)).*/\1/p' | tr '|' ' ')
+       do
+               case $i in
+               *--*)             : helper pattern;;
+               *) echo $i;;
+               esac
+       done
+}
+__tg_all_commandlist=
+__tg_all_commandlist="$(__tg_commands 2>/dev/null)"
+
+__tg_complete_arg ()
+{
+       if [ $COMP_CWORD -gt 2 ] && [ "${COMP_WORDS[$COMP_CWORD - 1]}" = "$1" ]; then
+               return 0
+       fi
+       return 1
+}
+
+### }}}
+### {{{ Commands
+
+_tg_create ()
+{
+       local cmd="$1"
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+
+       # Name must be the first arg after the create command
+       if [ $((cmd + 1)) = $COMP_CWORD ]; then
+               __tgcomp "$(__tg_topics)"
+               return
+       fi
+
+       __tg_complete_arg "-r" && {
+               __tgcomp "$(__tg_remotes)"
+               return
+       }
+
+       case "$cur" in
+       -*)
+               __tgcomp "
+                       -r
+               "
+               ;;
+       *)
+               __tgcomp "$(__tg_refs)"
+       esac
+}
+
+_tg_delete ()
+{
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+
+       case "$cur" in
+       -*)
+               __tgcomp "
+                       -f
+               "
+               ;;
+       *)
+               __tgcomp "$(__tg_topics)"
+       esac
+}
+
+_tg_depend ()
+{
+       local subcommands="add"
+       local subcommand="$(__git_find_subcommand "$subcommands")"
+       if [ -z "$subcommand" ]; then
+               __tgcomp "$subcommands"
+               return
+       fi
+
+       case "$subcommand" in
+       add)
+               __tgcomp "$(__tg_refs)"
+       esac
+}
+
+_tg_export ()
+{
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+
+       __tg_complete_arg "--collapse" && {
+               __tgcomp "$(__tg_heads)"
+               return
+       }
+
+       __tg_complete_arg "--quilt" && {
+               return
+       }
+
+       case "$cur" in
+       *)
+               __tgcomp "
+                       --collapse
+                       --quilt
+               "
+       esac
+}
+
+_tg_help ()
+{
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+       case "$cur" in
+       -*)
+               COMPREPLY=()
+               return
+               ;;
+       esac
+       __tgcomp "$(__tg_commands)"
+}
+
+_tg_import ()
+{
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+
+       __tg_complete_arg "-p" && {
+               COMPREPLY=()
+               return
+       }
+
+       case "$cur" in
+       -*)
+               __tgcomp "
+                       -p
+               "
+               ;;
+       *)
+               __tg_complete_revlist
+       esac
+}
+
+_tg_info ()
+{
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+
+       case "$cur" in
+       *)
+               __tgcomp "$(__tg_topics)"
+       esac
+}
+
+_tg_mail ()
+{
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+
+       case "$cur" in
+       *)
+               __tgcomp "$(__tg_topics)"
+       esac
+}
+
+_tg_patch ()
+{
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+
+       case "$cur" in
+       *)
+               __tgcomp "$(__tg_topics)"
+       esac
+}
+
+_tg_remote ()
+{
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+
+       case "$cur" in
+       *)
+               __tgcomp "$(__tg_remotes)"
+       esac
+}
+
+_tg_summary ()
+{
+       COMPREPLY=()
+}
+
+_tg_update ()
+{
+       COMPREPLY=()
+}
+
+### }}}
+### {{{ tg completion
+
+_tg ()
+{
+       local i c=1 command __tg_dir
+
+       while [ $c -lt $COMP_CWORD ]; do
+               i="${COMP_WORDS[c]}"
+               case "$i" in
+               -r) 
+                       c=$((++c))
+                       if [ $c -lt $COMP_CWORD ]; then
+                               __tgcomp "$(__tg_remotes)"
+                               return
+                       fi
+                       ;;
+               -h|--help) command="help"; break ;;
+               *) command="$i"; break ;;
+               esac
+               c=$((++c))
+       done
+
+       if [ -z "$command" ]; then
+               case "${COMP_WORDS[COMP_CWORD]}" in
+               -*)     __tgcomp "
+                               -r
+                               -h
+                               --help
+                       "
+                       ;;
+               *)     __tgcomp "$(__tg_commands)" ;;
+               esac
+               return
+       fi
+
+       case "$command" in
+       create)      _tg_create "$c" ;;
+       delete)      _tg_delete ;;
+       depend)      _tg_depend ;;
+       export)      _tg_export ;;
+       help)        _tg_help ;;
+       import)      _tg_import ;;
+       info)        _tg_info ;;
+       mail)        _tg_mail ;;
+       patch)       _tg_patch ;;
+       remote)      _tg_remote ;;
+       summary)     _tg_summary ;;
+       update)      _tg_update ;;
+       *)           COMPREPLY=() ;;
+       esac
+}
+
+### }}}
+
+complete -o default -o nospace -F _tg tg
+
+# The following are necessary only for Cygwin, and only are needed
+# when the user has tab-completed the executable name and consequently
+# included the '.exe' suffix.
+#
+if [ Cygwin = "$(uname -o 2>/dev/null)" ]; then
+complete -o default -o nospace -F _tg tg.exe
+fi
index 6fafbb44ea23b33f53b9d4c5ee17fbb420408ef6..e6c6f6ce587503aa974dee781bbc0b04acac411d 100644 (file)
@@ -1,7 +1,7 @@
 Building topgit for Debian
 --------------------------
 
-The topgit source package  uses quilt to apply and remove its patches. Please
+The topgit source package uses quilt to apply and remove its patches. Please
 refer to /usr/share/doc/quilt/README.source for information about how to use
 quilt for source packages.
 
@@ -18,6 +18,8 @@ Cloning a TopGit repository requires an additional step to normal Git cloning:
 2. cd topgit
 3. tg remote --populate origin
 
+TODO: debcheckout support
+
 Branches in use
 '''''''''''''''
 The following branches are in use in the package:
@@ -77,6 +79,9 @@ commit, build, test, upload, tag:
 This process is still very cumbersome and needs to be improved, ideally within
 TopGit.
 
+TODO: provide Makefile snippet for the above to prevent useless duplication (#501991)
+TODO: rewrite to use tg-export -b, which will be fixed in TopGit 0.5 (#500273)
+
 5. Importing a new upstream version
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 To import a new upstream, update the remote, merge the tag you want to merge
index 40e7e14c642a9ec9a65d9d893583ec8c8bb6ff2e..a62613ec33581f6122053210d035b79e8ca13fd1 100644 (file)
@@ -1,4 +1,4 @@
-topgit (0.4-1) unstable; urgency=low
+topgit (0.5-1) unstable; urgency=low
 
   * New upstream release.
 
old mode 100644 (file)
new mode 100755 (executable)
index af78808..ff4541c
@@ -8,8 +8,16 @@ name=
 
 ## Parse options
 
-subcmd="$1"; shift
-[ "$subcmd" = "add" ] || die "unknown subcommand ($subcmd)"
+subcmd="$1"; shift || :
+case "$subcmd" in
+       -h|"")
+               echo "Usage: tg [...] depend add NAME" >&2
+               exit 1;;
+       add)
+               ;;
+       *)
+               die "unknown subcommand ($subcmd)";;
+esac
 
 while [ -n "$1" ]; do
        arg="$1"; shift
@@ -35,7 +43,7 @@ baserev="$(git rev-parse --verify "refs/top-bases/$name" 2>/dev/null)" ||
 
 ## Record new dependency
 
-echo "$name" >>.topdeps
-git add .topdeps
+echo "$name" >>"$root_dir/.topdeps"
+git add -f "$root_dir/.topdeps"
 git commit -m"New TopGit dependency: $name"
 $tg update
index a7c459a17f37c14696edfba30e121ce3ca10996e..52af88dfd14e891627b145f63702b1212155a82c 100644 (file)
@@ -21,7 +21,7 @@ while [ -n "$1" ]; do
        --collapse)
                driver=collapse;;
        -*)
-               echo "Usage: tg [...] export [-b BRANCH1,BRANCH2...] ([--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)"
@@ -30,13 +30,17 @@ 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"
 
+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
index 799efc9a8395228604e1ccf94cc66a0c36144ec9..b036b8645f184f54ca14878cdc02312f4f925eaf 100644 (file)
@@ -5,7 +5,9 @@
 # GPLv2
 
 branch_prefix=t/
+single=
 ranges=
+basedep=
 
 
 ## Parse options
@@ -13,10 +15,14 @@ ranges=
 while [ -n "$1" ]; do
        arg="$1"; shift
        case "$arg" in
+       -d)
+               basedep="$1"; shift;;
        -p)
                branch_prefix="$1"; shift;;
+       -s)
+               single="$1"; shift;;
        -*)
-               echo "Usage: tg [...] import [-p PREFIX] RANGE..." >&2
+               echo "Usage: tg [...] import [-d BASE_BRANCH] {[-p PREFIX] RANGE...|-s NAME COMMIT}" >&2
                exit 1;;
        *)
                ranges="$ranges $arg";;
@@ -36,7 +42,11 @@ git update-index --ignore-submodules --refresh || exit
 get_commit_msg()
 {
        commit="$1"
-       git log -1 --pretty=format:"From: %an <%ae>%n%n%s%n%n%b" "$commit"
+       headers=""
+       ! header="$(git config topgit.to)" || headers="$headers%nTo: $header"
+       ! header="$(git config topgit.cc)" || headers="$headers%nCc: $header"
+       ! header="$(git config topgit.bcc)" || headers="$headers%nBcc: $header"
+       git log -1 --pretty=format:"From: %an <%ae>$headers%nSubject: %s%n%n%b" "$commit"
 }
 
 get_branch_name()
@@ -58,16 +68,25 @@ get_branch_name()
 process_commit()
 {
        commit="$1"
-       branch_name=$(get_branch_name "$commit")
-       info "---- Importing $commit to $branch_prefix$branch_name"
-       tg create "$branch_prefix""$branch_name"
-       git cherry-pick --no-commit "$commit"
+       branch_name="$2"
+       info "---- Importing $commit to $branch_name"
+       tg create "$branch_name" $basedep
+       basedep=
        get_commit_msg "$commit" > .topmsg
        git add -f .topmsg .topdeps
+       if ! git cherry-pick --no-commit "$commit"; then
+               info "The commit will also finish the import of this patch."
+               exit 2
+       fi
        git commit -C "$commit"
        info "++++ Importing $commit finished"
 }
 
+if [ -n "$single" ]; then
+       process_commit $ranges "$single"
+       exit
+fi
+
 # nice arg verification stolen from git-format-patch.sh
 for revpair in $ranges
 do
@@ -92,7 +111,7 @@ do
                        info "Merged already: $comment"
                        ;;
                *)
-                       process_commit "$rev"
+                       process_commit "$rev" "$branch_prefix$(get_branch_name "$rev")"
                        ;;
                esac
        done
index 24e5f67b2742b8edf6fd6213f58d6546a27e013c..7b8f7ffdd61b9b9b802df04790be5d51ffa67c2a 100644 (file)
@@ -4,6 +4,7 @@
 
 name=
 send_email_args=
+in_reply_to=
 
 
 ## Parse options
@@ -13,8 +14,10 @@ while [ -n "$1" ]; do
        case "$arg" in
        -s)
                send_email_args="$1"; shift;;
+       -r)
+               in_reply_to="$1"; shift;;
        -*)
-               echo "Usage: tg [...] mail [-s SEND_EMAIL_ARGS] [NAME]" >&2
+               echo "Usage: tg [...] mail [-s SEND_EMAIL_ARGS] [-r REFERENCE_MSGID] [NAME]" >&2
                exit 1;;
        *)
                [ -z "$name" ] || die "name already specified ($name)"
@@ -26,13 +29,16 @@ done
 base_rev="$(git rev-parse --short --verify "refs/top-bases/$name" 2>/dev/null)" ||
        die "not a TopGit-controlled branch"
 
+if [ -n "$in_reply_to" ]; then
+       send_email_args="$send_email_args --in-reply-to=$in_reply_to"
+fi
+
 
 patchfile="$(mktemp -t tg-mail.XXXXXX)"
 
-$tg patch $name >"$patchfile"
+$tg patch "$name" >"$patchfile"
 
-hlines=$(grep -n -m 1 '^---' "$patchfile" | sed 's/:---//')
-header=$(head -n $(($hlines - 1)) "$patchfile")
+header="$(sed -e '/^$/,$d' "$patchfile")"
 
 
 
@@ -40,14 +46,12 @@ 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")
+people=
+[ -n "$from" ] && people="$people --from '$from'"
 # FIXME: there could be multimple To
-[ -n "$to" ]   && people=("${people[@]}" --to "$to")
-
+[ -n "$to" ] && people="$people --to '$to'"
 
 # NOTE: git-send-email handles cc itself
-git send-email $send_email_args "${people[@]}" "$patchfile"
+eval git send-email $send_email_args "$people" "$patchfile"
 
 rm "$patchfile"
index 409f45622910caf29b5f6d68a2930b3f76b6a274..3c90a6b5952e526bac9da80e84386d6abf6246a8 100644 (file)
@@ -3,22 +3,64 @@
 # (c) Petr Baudis <pasky@suse.cz>  2008
 # GPLv2
 
+terse=
+graphviz=
+
 
 ## Parse options
 
-if [ -n "$1" ]; then
-       echo "Usage: tg [...] summary" >&2
-       exit 1
-fi
+while [ -n "$1" ]; do
+       arg="$1"; shift
+       case "$arg" in
+       -t)
+               terse=1;;
+       --graphviz)
+               graphviz=1;;
+       *)
+               echo "Usage: tg [...] summary [-t | --graphviz]" >&2
+               exit 1;;
+       esac
+done
 
 curname="$(git symbolic-ref HEAD | sed 's#^refs/\(heads\|top-bases\)/##')"
 
+if [ -n "$graphviz" ]; then
+       cat <<EOT
+# GraphViz output; pipe to:
+#   | dot -Tpng -o <ouput>
+# or
+#   | dot -Txlib
+
+digraph G {
+
+graph [
+  rankdir = "TB"
+  label="TopGit Layout\n\n\n"
+  fontsize = 14
+  labelloc=top
+  pad = "0.5,0.5"
+];
+
+EOT
+fi
+
 
 ## List branches
 
 git for-each-ref refs/top-bases |
        while read rev type ref; do
                name="${ref#refs/top-bases/}"
+               if [ -n "$terse" ]; then
+                       echo "$name"
+                       continue
+               fi
+               if [ -n "$graphviz" ]; then
+                       git cat-file blob "$name:.topdeps" | while read dep; do
+                               echo "\"$name\" -> \"$dep\";"
+                       done
+                       continue
+               fi
+
                missing_deps=
 
                current=' '
@@ -52,3 +94,7 @@ git for-each-ref refs/top-bases |
                printf '%s\t%-31s\t%s\n' "$current$nonempty$remote$rem_update$deps_update$deps_missing$base_update" \
                        "$name" "$subject"
        done
+
+if [ -n "$graphviz" ]; then
+       echo '}'
+fi
index f36624fe71b73263471e5df8fbb0014d47ca2ee0..040800d6fb3805ef92519e436fe9cbb353cdbb77 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="\`git checkout $name && $tg update\` again"
                                else # subshell
                                        resume='exit'
                                fi
@@ -87,14 +87,16 @@ if [ -s "$depcheck" ]; then
                                exit 2
                        fi
                done
-
-       # Home, sweet home...
-       git checkout -q "$name"
 else
        info "The base is up-to-date."
 fi
 rm "$depcheck"
 
+# Home, sweet home...
+# (We want to always switch back, in case we were on the base from failed
+# previous merge.)
+git checkout -q "$name"
+
 merge_with="refs/top-bases/$name"
 
 
diff --git a/tg.sh b/tg.sh
index ecc65748141dd53a224f382f7d53ddcacb2ba65d..a8eb71870f1cab15b8705e8c6a7fd7c4cdf8fee7 100644 (file)
--- a/tg.sh
+++ b/tg.sh
@@ -222,7 +222,7 @@ do_help()
                        sep="|"
                done
 
-               echo "TopGit v0.4 - A different patch queue manager"
+               echo "TopGit v0.5 - A different patch queue manager"
                echo "Usage: tg [-r REMOTE] ($cmds|help) ..."
        elif [ -r "@cmddir@"/tg-$1 ] ; then
                @cmddir@/tg-$1 -h || :
@@ -241,6 +241,8 @@ do_help()
 set -e
 git_dir="$(git rev-parse --git-dir)"
 root_dir="$(git rev-parse --show-cdup)"; root_dir="${root_dir:-.}"
+# Make sure root_dir doesn't end with a trailing slash.
+root_dir="${root_dir%/}"
 base_remote="$(git config topgit.remote 2>/dev/null)" || :
 tg="tg"
 # make sure merging the .top* files will always behave sanely