chiark / gitweb /
Tests: tartree-edit: gitfetchinfo: Better commit messages for dirty tress
[dgit.git] / tests / tartree-edit
index 2e0c01791b8f6a77352ea257f63c25043cf68c31..bf5238cd3f57e8df5238892cf6d1e192c87e122c 100755 (executable)
@@ -2,10 +2,72 @@
 set -e
 fail () { echo >&2 "$0: $*"; exit 1; }
 
+play=.git/tartree-edit-work
+
+git_manip_play () {
+       local wd=$(pwd)
+       case "$wd" in
+       *.edit) fail "bad idea to run gitfetchinfo into a .edit tree!" ;;
+       esac
+       rm -rf $play
+       mkdir $play
+}
+
+gitfetchdiff_list () {
+       git for-each-ref --format '%(refname) %(objectname)' \
+               refs/remotes/"$1" \
+       | sed 's/^refs\/remotes\/[^\/]*\///' \
+       | sort >"$play/$2"
+}
+
+gitfetchdiff () {
+       local how="$1"
+       local a="$2"
+       local b="$3"
+       git_manip_play
+
+       rrab=refs/remotes/"$a+$b"
+
+       ulf=\
+"delete refs/remotes/$a/%l
+delete refs/remotes/$b/%l
+"
+       case "$how" in
+       diff)
+               git for-each-ref --format 'delete %(refname)' $rrab \
+                       | git update-ref --stdin
+               ;;
+       merge)
+               ulf=\
+"create $rrab/%l
+$ulf"
+               ;;
+       *)
+               fail "internal error bad how ($how)"
+               ;;
+       esac
+
+       gitfetchdiff_list "$a" a
+       gitfetchdiff_list "$b" b
+
+       diff --old-line-format='' --new-line-format='' \
+               --unchanged-line-format="$ulf" \
+               $play/a $play/b >$play/updates \
+       || test $? = 1
+
+       git update-ref --stdin <$play/updates
+       exit 0
+}
+
 case "$#.$1" in
 2.edit|2.done) mode="$1"; arg="$2" ;;
-2.-*)          fail "no options understood"                    ;;
-*)             fail "usage: tartree-edit edit|done DIRECTORY"  ;;
+3.gitfetchinfo)        mode="$1"; arg="$2"; remote="$3" ;;
+3.gitfetchinfo-diff)   gitfetchdiff diff "$2" "$3"     ;;
+3.gitfetchinfo-merge)  gitfetchdiff merge "$2" "$3"    ;;
+?.-*)  fail "no options understood"                    ;;
+*)     fail "usage:
+    tartree-edit edit|done DIRECTORY|TARBALL
+    tartree-edit gitfetchinfo DIRECTORY|TARBALL REMOTE"        ;;
 esac
 
 case "$arg" in
@@ -39,6 +101,83 @@ tryat_edit () {
        fi
 }
 
+gitfetchinfo_perhaps_commit () {
+       local m="$1"
+       set +e
+       git diff --cached --quiet --exit-code HEAD
+       local rc=$?
+       set -e
+       case "$rc" in
+       0)   return ;;
+       1)   git commit --allow-empty --author='tartree-edit <>' -m "$m" ;;
+       *)   fail "git diff failed ($rc)" ;;
+       esac
+}
+
+tryat_gitfetchinfo () {
+       git_manip_play
+
+       if test -d "$b.edit"; then
+               cp -a "$b.edit"/. "$play"/.
+       else
+               exec 3<"$b.tar"
+               tar -C $play -f - <&3 -x
+               exec 3<&-
+       fi
+
+       local innerwd="$(echo $play/*)"
+
+       git for-each-ref --format='%(refname)' refs/remotes >$play/l
+       perl -w -ne '
+           our %remerge;
+           use strict;
+           chomp;
+           next unless m#^refs/remotes/([^/]+)/#;
+           my $old = $_;
+           my $ab = $1;
+           my $rhs = $'\'';
+           my @ab = split /\+/, $ab;
+           next unless @ab == 2;
+           next unless (grep { $_ eq "'"$remote"'" } @ab) == 1;
+           $remerge{"@ab"} = 1;
+           print "update refs/remotes/$_/$rhs $old\n" or die $! foreach @ab;
+           print "delete $old\n" or die $!;
+           END {
+               open REMERGE, ">&3" or die $!;
+               print REMERGE "$_\n" or die $! foreach sort keys %remerge;
+               close REMERGE or die $!;
+           }
+       ' <$play/l >$play/unmerge 3>$play/remerge
+       git update-ref --stdin <$play/unmerge
+
+       git remote remove "$remote" 2>/dev/null ||:
+       git remote add "$remote" $innerwd
+       git fetch --no-tags -p "$remote" \
+               +"HEAD:refs/remotes/$remote/TT-HEAD"
+       cd $innerwd
+       GIT_AUTHOR_DATE=$(git log -n1 --pretty=format:'%ai')
+       GIT_COMMITTER_DATE=$GIT_AUTHOR_DATE
+       export GIT_COMMITTER_DATE GIT_AUTHOR_DATE
+       git checkout -b WORKTREE
+       gitfetchinfo_perhaps_commit 'UNCOMMITTED INDEX'
+       git add -Af .
+       gitfetchinfo_perhaps_commit 'UNCOMMITTED WORKING TREE'
+       cd ../../..
+       git fetch --no-tags "$remote" --refmap \
+               +"refs/*:refs/remotes/$remote/*" \
+               +"refs/*:refs/remotes/$remote/*"
+
+       exec 3<$play/remerge
+       # $play will be destroyed by what follows, but we have
+       # an fd open onto remerge, so this will work
+       while read <&3 a b; do
+             echo "Updating gitfetchinfo-merge $a $b"
+             "$0" gitfetchinfo-merge $a $b
+       done
+
+       exit 0
+}
+
 tryat_done () {
        local b="$1"
        if test -d "$b.edit"; then