chiark / gitweb /
tg-files: list files changed by the topic branch
[topgit.git] / tg.sh
diff --git a/tg.sh b/tg.sh
index 1f6d3da6aab7949716a71efc8201fa6b62331eed..f1b323b7cbe543994f373523ab2b84b814fd0adc 100644 (file)
--- a/tg.sh
+++ b/tg.sh
@@ -14,7 +14,7 @@ info()
 
 die()
 {
-       info "fatal: $*"
+       info "fatal: $*" >&2
        exit 1
 }
 
@@ -25,20 +25,67 @@ cat_file()
        arg="$1"
        case "$arg" in
        '(w):'*)
-               arg=$(echo "$arg" | tail --bytes=+5)
-               cat "$arg"
-               return
+               cat "${arg#(w):}"
                ;;
        '(i):'*)
                # ':file' means cat from index
-               arg=$(echo "$arg" | tail --bytes=+5)
-               git cat-file blob ":$arg"
+               git cat-file blob "${arg#(i)}"
                ;;
        *)
                git cat-file blob "$arg"
+               ;;
        esac
 }
 
+# get tree for the committed topic
+get_tree_()
+{
+       echo "$1"
+}
+
+# get tree for the base
+get_tree_b()
+{
+       echo "refs/top-bases/$1"
+}
+
+# get tree for the index
+get_tree_i()
+{
+       git write-tree
+}
+
+# get tree for the worktree
+get_tree_w()
+{
+       i_tree=$(git write-tree)
+       (
+               # the file for --index-output needs to sit next to the
+               # current index file
+               : ${GIT_INDEX_FILE:="$git_dir/index"}
+               TMP_INDEX="$(mktemp "${GIT_INDEX_FILE}-tg.XXXXXX")"
+               git read-tree -m $i_tree --index-output="$TMP_INDEX" &&
+               GIT_INDEX_FILE="$TMP_INDEX" &&
+               export GIT_INDEX_FILE &&
+               git diff --name-only -z HEAD |
+                       git update-index -z --add --remove --stdin &&
+               git write-tree &&
+               rm -f "$TMP_INDEX"
+       )
+}
+
+# pretty_tree NAME [-b | -i | -w]
+# Output tree ID of a cleaned-up tree without tg's artifacts.
+# NAME will be ignored for -i and -w, but needs to be present
+pretty_tree()
+{
+       name=$1
+       source=${2#?}
+       git ls-tree --full-tree "$(get_tree_$source "$name")" |
+               awk -F '        ' '$2 !~ /^.top/' |
+               git mktree
+}
+
 # setup_hook NAME
 setup_hook()
 {
@@ -54,6 +101,8 @@ setup_hook()
        else
                hook_call="exec $hook_call"
        fi
+       # Don't call hook if tg is not installed
+       hook_call="if which \"$tg\" > /dev/null; then $hook_call; fi"
        # Insert call into the hook
        {
                echo "#!/bin/sh"
@@ -126,6 +175,13 @@ branch_annihilated()
        test "$(git rev-parse "$mb^{tree}")" = "$(git rev-parse "$_name^{tree}")";
 }
 
+# is_sha1 REF
+# Whether REF is a SHA1 (compared to a symbolic name).
+is_sha1()
+{
+       [ "$(git rev-parse "$1")" = "$1" ]
+}
+
 # recurse_deps CMD NAME [BRANCHPATH...]
 # Recursively eval CMD on all dependencies of NAME.
 # CMD can refer to $_name for queried branch name,
@@ -230,6 +286,27 @@ branch_empty()
        [ -z "$(git diff-tree "refs/top-bases/$1" "$1" -- | fgrep -v "  .top")" ]
 }
 
+# list_deps
+list_deps()
+{
+       git for-each-ref refs/top-bases |
+               while read rev type ref; do
+                       name="${ref#refs/top-bases/}"
+                       if branch_annihilated "$name"; then
+                               continue;
+                       fi
+
+                       git cat-file blob "$name:.topdeps" | while read dep; do
+                               dep_is_tgish=true
+                               ref_exists "refs/top-bases/$dep"  ||
+                                       dep_is_tgish=false
+                               if ! "$dep_is_tgish" || ! branch_annihilated $dep; then
+                                       echo "$name $dep"
+                               fi
+                       done
+               done
+}
+
 # switch_to_base NAME [SEED]
 switch_to_base()
 {