Well, both are good ideas.  Both are stack oriented, though.

I see what you mean about adding an undo directory to .git/refs/.  I
will do some tests... (read further)

On Wed, Aug 24, 2005 at 03:48:21PM -0700, Junio C Hamano wrote:
> Daniel Barkalow <[EMAIL PROTECTED]> writes:
> 
> > Generally, each subdirectory of refs/ has refs to objects of the same
> > type, and heads/ is commits, but other directories are other things. tags/
> > is all tag objects, and you could have undo/ be trees.
> 
> That's OK from the prune front, but I am not sure what the
> ramifications of this for pulling, pushing, and resolving.
> I would not recommend it without really thinking it through.

So, I've tried cloning, pulling to|from, pushing to|from and resolving
merges in a repository with undo information stored under
.git/refs/undo.  None of these operations seem to notice the existence
of this directory.  I think this is good.

The cloned repository does not end up 'inheriting' the undo directory
(as I would expect) but does end up with any objects reachable from the
undo tree.  However, these objects get pruned on the next 'git prune'.
This, I think, is minor.

Pull seems to ignore the undo directory and, of course, the objects
reachable by the undo trees.  This is what I expected and wanted.

Resolving merges worked as expected.

I think undo trees should be considered local to the repository and this
is the behavior that I observed.  I think this is a positive.

Before reading your message, I polished up the scripts and changed them
so that they store the undo tree and the base tree's hashes in the
.git/refs/undo directory.  Also, git-redo-script can take an optional
argument...the name of the undo to replay.  I guess undo should also
take an optional argument to give the undo tree some symbolic name.

I think this is getting rather solid.  Let me know what you think.

Here is the git-undo-script:

#!/bin/sh

. git-sh-setup-script || die "Not a git archive"

git-update-cache --refresh || exit 1

undodir=$GIT_DIR/refs/undo

undoinfo=$undodir/$(date +%Y.%m.%d.%H.%M.%S)

headtree=$(git-cat-file commit $(cat $GIT_DIR/HEAD) | sed -n 's/^tree //p')
undotree=$(git-write-tree)

if [ $headtree == $undotree ]; then
    echo There are no changes to undo.
else
    mkdir -p $(dirname $undoinfo)
    echo $headtree > $undoinfo.base
    echo $undotree > $undoinfo.undo

    echo Saved current state in $undodir as $(basename $undoinfo)

    git-read-tree -m -u $undotree $headtree
fi

# --- SNIP ---

and here, is the redo script

#!/bin/sh

. git-sh-setup-script || die "Not a git archive"

git-update-cache --refresh || exit 1

usage () {
    echo >&2 "Usage: git-redo-script [undo name]"
    exit 1
}

undodir=$GIT_DIR/refs/undo

# If an 'undo name' was given on the command line then try to use it.
# If not, then automatically pick the most recent undo.
undoinfo=
case "$#" in
0)
    undoinfo=$undodir/$(ls -tr $undodir | sed -n 's/\.undo$//p' | tail -n 1)
    ;;
1)
    if [ -s $undodir/$1 ]; then
        undoinfo=$(echo $undodir/$1 | sed -n "s/\.[^.]*$//p")
    elif [ -s $undodir/$1.undo -a -s $undodir/$1.base ]; then
        undoinfo=$undodir/$1
    else
        usage
    fi
    ;;
*)
    usage
    ;;
esac

# Perform a three-way merge between the base tree, undo tree and current index
if [ ! -s $undoinfo.undo -o ! -s $undoinfo.base ]; then
    echo "No undo information available"
else
    git-read-tree -u -m $(cat $undoinfo.base) $(cat $undoinfo.undo) 
$(git-write-tree)
    git-merge-cache git-merge-one-file-script -a

    rm -f $undoinfo.*
    test -z "$(ls $undodir)" && rmdir $undodir
fi

# --- SNIP ---

I would be glad to write up documentation and provide a patch.

Cheers,
Carl

> Also note that tags/ is not all tag objects.  I think "git tag"
> by default creates a lightweight tag, not an annotated kind.
> 
> I think you could do either one of two things.  As usual, totally
> untested.  Just thinking aloud.
> 
> (1) A hack.
> 
>      - Have a single "undo-redo" branch, which was forked from
>        somewhere on the "master" branch.
> 
>      - When doing "undo", make a commit that has the current top
>        of undo-redo branch as the first parent and the current
>        HEAD commit as the second parent, using the tree that
>        represents your snapshot, to grow "undo-redo" branch.
> 
>        No, this commit does *not* represent a merge, but I am
>        abusing the capability to record more than one parent
>        commits.
> 
>      - When running "redo", you would want a handy way to name
>        what to redo.  You can say "undo-redo~N" to mean "Nth
>        from the top of undo-redo branch.
> 
>        Your implementation of "redo" can either be (patch way):
> 
>        git-diff-tree -p undo-redo~N^ undo-redo~N | git apply --index
> 
>        or (merge way):
> 
>        git-read-tree -m undo-redo~N^2 undo-redo~N HEAD &&
>        git-merge-cache -o git-merge-one-file-script -a
> 
> (2) Try StGIT.
> 
> 

-- 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 Carl Baldwin                        Systems VLSI Laboratory
 Hewlett Packard Company
 MS 88                               work: 970 898-1523
 3404 E. Harmony Rd.                 work: [EMAIL PROTECTED]
 Fort Collins, CO 80525              home: [EMAIL PROTECTED]
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to