/tg-info.txt
/tg-mail
/tg-mail.txt
+/tg-next
+/tg-next.txt
/tg-log
/tg-log.txt
/tg-patch
/tg-patch.txt
+/tg-prev
+/tg-prev.txt
/tg-push
/tg-push.txt
/tg-remote
to let `git send-email` ask for confirmation before sending any mail.
+ Options:
+ -i base patch generation on index instead of branch
+ -w base patch generation on working tree instead of branch
+
TODO: 'tg mail patchfile' to mail an already exported patch
TODO: mailing patch series
TODO: specifying additional options and addresses on command
branches in a machine-readable format. Feed this to "tsort"
to get the output from --sort.
+ Options:
+ -i Use TopGit meta data from the index instead of branch
+ -w Use TopGit meta data from the working tree instead of branch
+
TODO: Speed up by an order of magnitude
TODO: Text graph view
Note: if you have merged changes from a different repository, this
command might not list all interesting commits.
-TODO: tg rename
+tg prev
+~~~~~~~
+ Outputs the direct dependencies for the current or named patch.
+ Options:
+ -i show dependencies based on index instead of branch
+ -w show dependencies based on working tree instead of branch
+
+tg next
+~~~~~~~
+ Outputs all patches which directly depend on the current or
+ named patch.
+
+ Options:
+ -i show dependencies based on index instead of branch
+ -w show dependencies based on working tree instead of branch
+
+TODO: tg rename
IMPLEMENTATION
--------------
local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
+ -*)
+ __tgcomp "
+ -i
+ -w
+ -s
+ -r
+ "
+ ;;
*)
__tgcomp "$(__tg_topics)"
esac
*)
__tgcomp "
--graphviz
+ --sort
+ --deps
-t
+ -i
+ -w
"
esac
}
esac
}
+_tg_next ()
+{
+ local cur="${COMP_WORDS[COMP_CWORD]}"
+
+ case "$cur" in
+ -*)
+ __tgcomp "
+ -i
+ -w
+ "
+ ;;
+ *)
+ __tgcomp "$(__tg_heads)"
+ esac
+}
+
+_tg_prev ()
+{
+ local cur="${COMP_WORDS[COMP_CWORD]}"
+
+ case "$cur" in
+ -*)
+ __tgcomp "
+ -i
+ -w
+ "
+ ;;
+ *)
+ __tgcomp "$(__tg_topics)"
+ esac
+}
+
### }}}
### {{{ tg completion
info) _tg_info ;;
log) _tg_log ;;
mail) _tg_mail ;;
+ next) _tg_next ;;
patch) _tg_patch ;;
+ prev) _tg_prev ;;
push) _tg_push ;;
remote) _tg_remote ;;
summary) _tg_summary ;;
echo "TopGit-driven merge of branches:"
echo
cut -f 2 "$playground/$name^parents"
- } | git commit-tree "$(pretty_tree "refs/top-bases/$name")" \
+ } | git commit-tree "$(pretty_tree "$name" -b)" \
$(for p in $parent; do echo -p $p; done))"
fi
else
retmerge=0;
- git merge-recursive "$(pretty_tree "refs/top-bases/$_dep")" -- HEAD "$(pretty_tree "refs/heads/$_dep")" || retmerge="$?";
+ git merge-recursive "$(pretty_tree "$_dep" -b)" -- HEAD "$(pretty_tree "refs/heads/$_dep")" || retmerge="$?";
if test "x$retmerge" != "x0"; then
git rerere;
# GPLv2
name=
-topic=
+head_from=
## Parse options
while [ -n "$1" ]; do
arg="$1"; shift
case "$arg" in
- -i)
- [ -z "$topic" ] || die "-i and -w are mutually exclusive"
- topic=-i;;
- -w)
- [ -z "$topic" ] || die "-i and -w are mutually exclusive"
- topic=-w;;
+ -i|-w)
+ [ -z "$head_from" ] || die "-i and -w are mutually exclusive"
+ head_from="$arg";;
-*)
echo "Usage: tg [...] files [-i | -w] [NAME]" >&2
exit 1;;
done
-[ -n "$name" -a -n "$topic" ] &&
- die "-i/-w are mutually exclusive with NAME"
+head="$(git symbolic-ref HEAD)"
+head="${head#refs/heads/}"
-[ -n "$name" ] || name="$(git symbolic-ref HEAD | sed 's#^refs/\(heads\|top-bases\)/##')"
+[ -n "$name" ] ||
+ name="$head"
base_rev="$(git rev-parse --short --verify "refs/top-bases/$name" 2>/dev/null)" ||
die "not a TopGit-controlled branch"
+if [ -n "$head_from" ] && [ "$name" != "$head" ]; then
+ die "$head_from makes only sense for the current branch"
+fi
+
b_tree=$(pretty_tree "$name" -b)
-t_tree=$(pretty_tree "$name" $topic)
+t_tree=$(pretty_tree "$name" $head_from)
git diff-tree --name-only -r $b_tree $t_tree
# vim:noet
+
# GPLv2
name=
+head_from=
send_email_args=
in_reply_to=
while [ -n "$1" ]; do
arg="$1"; shift
case "$arg" in
+ -i|-w)
+ [ -z "$head_from" ] || die "-i and -w are mutually exclusive"
+ head_from="$arg";;
-s)
send_email_args="$1"; shift;;
-r)
in_reply_to="$1"; shift;;
-*)
- echo "Usage: tg [...] mail [-s SEND_EMAIL_ARGS] [-r REFERENCE_MSGID] [NAME]" >&2
+ echo "Usage: tg [...] mail [-s SEND_EMAIL_ARGS] [-r REFERENCE_MSGID] [-i | -w] [NAME]" >&2
exit 1;;
*)
[ -z "$name" ] || die "name already specified ($name)"
esac
done
-[ -n "$name" ] || name="$(git symbolic-ref HEAD | sed 's#^refs/heads/##')"
+head="$(git symbolic-ref HEAD | sed 's#^refs/heads/##')"
+[ -n "$name" ] || name="$head"
base_rev="$(git rev-parse --short --verify "refs/top-bases/$name" 2>/dev/null)" ||
die "not a TopGit-controlled branch"
patchfile="$(get_temp tg-mail)"
-$tg patch "$name" >"$patchfile"
+# let tg patch sort out whether $head_from makes sense for $name
+$tg patch "$name" $head_from >"$patchfile"
header="$(sed -e '/^$/,$d' -e "s,','\\\\'',g" "$patchfile")"
--- /dev/null
+#!/bin/sh
+# TopGit - A different patch queue manager
+# (c) Petr Baudis <pasky@suse.cz> 2008
+# (c) Bert Wesarg <Bert.Wesarg@googlemail.com> 2009
+# GPLv2
+
+name=
+head_from=
+
+
+## Parse options
+
+while [ -n "$1" ]; do
+ arg="$1"; shift
+ case "$arg" in
+ -i|-w)
+ [ -z "$head_from" ] || die "-i and -w are mutually exclusive"
+ head_from="$arg";;
+ -*)
+ echo "Usage: tg next [-i | -w] [NAME]" >&2
+ exit 1;;
+ *)
+ [ -z "$name" ] || die "name already specified ($name)"
+ name="$arg";;
+ esac
+done
+
+head="$(git rev-parse --abbrev-ref=loose HEAD)"
+[ -n "$name" ] ||
+ name="$head"
+
+git for-each-ref --format='%(refname)' refs/top-bases |
+ while read ref; do
+ parent="${ref#refs/top-bases/}"
+
+ from=$head_from
+ # select .topdeps source for HEAD branch
+ [ "x$parent" = "x$head" ] ||
+ from=
+
+ cat_file "$parent:.topdeps" $from | fgrep -qx "$name" ||
+ continue
+
+ echo "$parent"
+ done
name=
head_from=
-diff_opts=
-diff_committed_only=yes # will be unset for index/worktree
## Parse options
while [ -n "$1" ]; do
arg="$1"; shift
case "$arg" in
- -i)
+ -i|-w)
[ -z "$head_from" ] || die "-i and -w are mutually exclusive"
- head_from=-i
- diff_opts="$diff_opts --cached";
- diff_committed_only=;;
- -w)
- [ -z "$head_from" ] || die "-i and -w are mutually exclusive"
- head_from=-w
- diff_committed_only=;;
+ head_from="$arg";;
-*)
echo "Usage: tg [...] patch [-i | -w] [NAME]" >&2
exit 1;;
setup_pager
-cat_file "$name:.topmsg" $head_from
-echo
-[ -n "$(git grep $diff_opts '^[-]--' ${diff_committed_only:+"$name"} -- ".topmsg")" ] || echo '---'
-
-# Evil obnoxious hack to work around the lack of git diff --exclude
-git_is_stupid="$(get_temp tg-patch-changes)"
-git diff --name-only $diff_opts "$base_rev" ${diff_committed_only:+"$name"} -- |
- fgrep -vx ".topdeps" |
- fgrep -vx ".topmsg" >"$git_is_stupid" || : # fgrep likes to fail randomly?
-if [ -s "$git_is_stupid" ]; then
- cd "$root_dir"
- cat "$git_is_stupid" | xargs git diff -a --patch-with-stat $diff_opts "$base_rev" ${diff_committed_only:+"$name"} --
-else
+
+# put out the commit message
+# and put an empty line out, if the last one in the message was not an empty line
+# and put out "---" if the commit message does not have one yet
+cat_file "$name:.topmsg" $head_from |
+ awk '
+/^---/ {
+ has_3dash=1;
+}
+ {
+ need_empty = 1;
+ if ($0 == "")
+ need_empty = 0;
+ print;
+}
+END {
+ if (need_empty)
+ print "";
+ if (!has_3dash)
+ print "---";
+}
+'
+
+b_tree=$(pretty_tree "$name" -b)
+t_tree=$(pretty_tree "$name" $head_from)
+
+if [ $b_tree = $t_tree ]; then
echo "No changes."
+else
+ git diff-tree -p --stat $b_tree $t_tree
fi
echo '-- '
--- /dev/null
+#!/bin/sh
+# TopGit - A different patch queue manager
+# (c) Petr Baudis <pasky@suse.cz> 2008
+# (c) Bert Wesarg <Bert.Wesarg@googlemail.com> 2009
+# GPLv2
+
+name=
+head_from=
+
+
+## Parse options
+
+while [ -n "$1" ]; do
+ arg="$1"; shift
+ case "$arg" in
+ -i|-w)
+ [ -z "$head_from" ] || die "-i and -w are mutually exclusive"
+ head_from="$arg";;
+ -*)
+ echo "Usage: tg next [-i | -w] [NAME]" >&2
+ exit 1;;
+ *)
+ [ -z "$name" ] || die "name already specified ($name)"
+ name="$arg";;
+ esac
+done
+
+head="$(git rev-parse --abbrev-ref=loose HEAD)"
+[ -n "$name" ] ||
+ name="$head"
+base_rev="$(git rev-parse --short --verify "refs/top-bases/$name" 2>/dev/null)" ||
+ die "not a TopGit-controlled branch"
+
+# select .topdeps source for HEAD branch
+[ "x$name" = "x$head" ] ||
+ head_from=
+
+cat_file "$name:.topdeps" $head_from
graphviz=
sort=
deps=
-
+head_from=
## Parse options
while [ -n "$1" ]; do
arg="$1"; shift
case "$arg" in
+ -i|-w)
+ [ -z "$head_from" ] || die "-i and -w are mutually exclusive"
+ head_from="$arg";;
-t)
terse=1;;
--graphviz)
--deps)
deps=1;;
*)
- echo "Usage: tg [...] summary [-t | --sort | --deps | --graphviz]" >&2
+ echo "Usage: tg [...] summary [-t | --sort | --deps | --graphviz] [-i | -w]" >&2
exit 1;;
esac
done
current=' '
[ "$name" != "$curname" ] || current='>'
+ from=$head_from
+ [ "$name" = "$curname" ] ||
+ from=
nonempty=' '
- ! branch_empty "$name" || nonempty='0'
+ ! branch_empty "$name" $from || nonempty='0'
remote=' '
[ -z "$base_remote" ] || remote='l'
! has_remote "$name" || remote='r'
branch_contains "$name" "refs/top-bases/$name" || base_update='B'
if [ "$(git rev-parse "$name")" != "$rev" ]; then
- subject="$(git cat-file blob "$name:.topmsg" | sed -n 's/^Subject: //p')"
+ subject="$(cat_file "$name:.topmsg" $from | sed -n 's/^Subject: //p')"
else
# No commits yet
subject="(No commits)"
}
if [ -n "$deps" ]; then
- list_deps
+ list_deps $head_from
exit 0
fi
if [ -n "$terse" ]; then
echo "$name"
elif [ -n "$graphviz$sort" ]; then
- git cat-file blob "$name:.topdeps" | while read dep; do
+ from=$head_from
+ [ "$name" = "$curname" ] ||
+ from=
+ cat_file "$name:.topdeps" $from | while read dep; do
dep_is_tgish=true
ref_exists "refs/top-bases/$dep" ||
dep_is_tgish=false
recurse_deps branch_needs_update "$@"
}
-# branch_empty NAME
+# branch_empty NAME [-i | -w]
branch_empty()
{
- [ -z "$(git diff-tree "refs/top-bases/$1" "$1" -- | fgrep -v " .top")" ]
+ [ "$(pretty_tree "$1" -b)" = "$(pretty_tree "$1" ${2-})" ]
}
-# list_deps
+# list_deps [-i | -w]
+# -i/-w apply only to HEAD
list_deps()
{
+ local head
+ local head_from
+ local from
+ head_from=${1-}
+ head="$(git symbolic-ref -q HEAD)" ||
+ head="..detached.."
+
git for-each-ref refs/top-bases |
while read rev type ref; do
name="${ref#refs/top-bases/}"
continue;
fi
- git cat-file blob "$name:.topdeps" | while read dep; do
+ from=$head_from
+ [ "refs/heads/$name" = "$head" ] ||
+ from=
+ cat_file "$name:.topdeps" $from | while read dep; do
dep_is_tgish=true
ref_exists "refs/top-bases/$dep" ||
dep_is_tgish=false