From: Carl Baldwin <hidden> Date: 2016-06-15 22:42:04
Hello,
So, one thing that I liked about GNU Arch when I tried it out was the
ability to undo and redo changes in the local working copy. I decided
to try to do this with git. What I have is preliminary. I'm sure it
could use some work.
So, I started with the assumption that all changes in the working copy
have been updated to the cache. My scripts check this (with
git-diff-files) and abort if this is not the case.
Undo calls git-write-tree to write the changes to the object store. It
stores that tree's hash and the current HEAD's tree's hash in a file.
Then it reverts the working copy to HEAD.
Redo grabs these two trees from the file, does git-write-tree to produce
a third tree and merges the three using the old HEAD's tree as the base
of the merge. This way, new commits can happen and the local copy can
be modified since the undo and it should still work assuming no
conflicts emerge.
Attached are the two scripts. Comments and criticism are welcome.
Cheers,
Carl
--
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Carl Baldwin Systems VLSI Laboratory
Hewlett Packard Company
MS 88 work: 970 898-1523
3404 E. Harmony Rd. work: Carl.N.Baldwin@hp.com
Fort Collins, CO 80525 home: Carl@ecBaldwin.net
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
From: Carl Baldwin <hidden> Date: 2016-06-15 22:42:04
Oops. I forgot to actually exit from the script if git-diff-files is
non-empty.
Also, looking at it now, I don't think keeping undo information in a
stack is the right thing. But keeping more than just one would be good.
Oh well, my first shot is never perfect. ;-)
Carl
On Wed, Aug 24, 2005 at 11:23:39AM -0600, Carl Baldwin wrote:
Hello,
So, one thing that I liked about GNU Arch when I tried it out was the
ability to undo and redo changes in the local working copy. I decided
to try to do this with git. What I have is preliminary. I'm sure it
could use some work.
So, I started with the assumption that all changes in the working copy
have been updated to the cache. My scripts check this (with
git-diff-files) and abort if this is not the case.
Undo calls git-write-tree to write the changes to the object store. It
stores that tree's hash and the current HEAD's tree's hash in a file.
Then it reverts the working copy to HEAD.
Redo grabs these two trees from the file, does git-write-tree to produce
a third tree and merges the three using the old HEAD's tree as the base
of the merge. This way, new commits can happen and the local copy can
be modified since the undo and it should still work assuming no
conflicts emerge.
Attached are the two scripts. Comments and criticism are welcome.
Cheers,
Carl
--
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Carl Baldwin Systems VLSI Laboratory
Hewlett Packard Company
MS 88 work: 970 898-1523
3404 E. Harmony Rd. work: Carl.N.Baldwin@hp.com
Fort Collins, CO 80525 home: Carl@ecBaldwin.net
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#!/bin/sh
. git-sh-setup-script || die "Not a git archive"
if [ -n "$(git-diff-files)" ]; then
echo The following files should be updated!
echo
git-diff-files | awk '{print $6}'
fi
undostack=$GIT_DIR/undostack
if [ ! -s $undostack ]; then
echo "No undo information in $undostack"
else
# Read the top of the stack
basetree=$(cat $undostack | tail -n 2 | head -n 1)
redotree=$(cat $undostack | tail -n 1)
# Pop the stack
cat $undostack | head -n -2 > $undostack.tmp
mv $undostack{.tmp,}
currenttree=$(git-write-tree)
git-read-tree -u -m $basetree $currenttree $redotree
git-merge-cache git-merge-one-file-script -a
fi
#!/bin/sh
. git-sh-setup-script || die "Not a git archive"
if [ -n "$(git-diff-files)" ]; then
echo The following files should be updated!
echo
git-diff-files | awk '{print $6}'
fi
undostack=$GIT_DIR/undostack
headtree=$(git-cat-file commit $(cat $GIT_DIR/HEAD) | head -n 1 | sed -e 's/tree //')
undotree=$(git-write-tree)
if [ $headtree == $undotree ]; then
echo There are no changes to undo.
else
{
echo $headtree
echo $undotree
} >> $undostack
echo Saved current state as tree $undotree.
echo Reverting to HEAD, $headtree...
git-checkout-script -f
fi
From: Junio C Hamano <hidden> Date: 2016-06-15 22:42:04
Carl Baldwin [off-list ref] writes:
Attached are the two scripts. Comments and criticism are welcome.
An obligatory non-technical comment. I would have liked to see
this not in a MIME multipart format, which made commenting on it
a bit harder than necessary.
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=git-undo-script
#!/bin/sh
. git-sh-setup-script || die "Not a git archive"
if [ -n "$(git-diff-files)" ]; then
echo The following files should be updated!
echo
git-diff-files | awk '{print $6}'
fi
There is nothing wrong with the above, but I would have written
it like this (I think you forgot to exit after showing the list
of files):
git-update-cache --refresh || exit
Also nice to learn here is "git-diff-files --name-only".
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=git-redo-script
#!/bin/sh
. git-sh-setup-script || die "Not a git archive"
if [ -n "$(git-diff-files)" ]; then
echo The following files should be updated!
echo
git-diff-files | awk '{print $6}'
fi
Same here.
currenttree=$(git-write-tree)
git-read-tree -u -m $basetree $currenttree $redotree
git-merge-cache git-merge-one-file-script -a
Oops. I forgot to actually exit from the script if git-diff-files is
non-empty.
Also, looking at it now, I don't think keeping undo information in a
stack is the right thing. But keeping more than just one would be good.
Oh well, my first shot is never perfect. ;-)
I would actually argue that
git checkout -b newbranch <undo-point>
is the perfect undo.
It leaves the old state in the old branch, and creates a new branch (and
checks it out) with the state you want to revert to. The advantage is
exactly that there is no "stack" of undo's: you can have multiple
independent undo's pending, and you can continue development at any of
them. And merge the results together.
Of course, right now we don't have a "delete branch" command, but it's
really as simple as
rm .git/refs/heads/branchname
(and eventually you may want to do a "git prune" to get rid of stale
objects, but that's a separate issue).
Linus
From: Carl Baldwin <hidden> Date: 2016-06-15 22:42:04
On Wed, Aug 24, 2005 at 11:51:32AM -0700, Linus Torvalds wrote:
On Wed, 24 Aug 2005, Carl Baldwin wrote:
quoted
Oops. I forgot to actually exit from the script if git-diff-files is
non-empty.
Also, looking at it now, I don't think keeping undo information in a
stack is the right thing. But keeping more than just one would be good.
Oh well, my first shot is never perfect. ;-)
I would actually argue that
git checkout -b newbranch <undo-point>
is the perfect undo.
Yes, this does the job nicely. I've used it like this effectively. I
meant for undo/redo to be a lighter weight way of moving (uncommitted)
changes out of the way briefly and then replaying them onto the working
directory later.
It leaves the old state in the old branch, and creates a new branch (and
checks it out) with the state you want to revert to. The advantage is
exactly that there is no "stack" of undo's: you can have multiple
independent undo's pending, and you can continue development at any of
them. And merge the results together.
The "stack" was the wrong thing to do. I think I would have undo pick a
name like undo-1, undo-2 etc. Or something like that. redo would pick
the most recent unless told to do otherwise.
A possible advantage of undo is having the freedom to stay on the
current branch or switch to another.
Of course, right now we don't have a "delete branch" command, but it's
really as simple as
rm .git/refs/heads/branchname
(and eventually you may want to do a "git prune" to get rid of stale
objects, but that's a separate issue).
Linus
This brings up a good point (indirectly). "git prune" would destroy the
undo objects. I had thought of this but decided to ignore it for the
time being.
Carl
--
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Carl Baldwin Systems VLSI Laboratory
Hewlett Packard Company
MS 88 work: 970 898-1523
3404 E. Harmony Rd. work: Carl.N.Baldwin@hp.com
Fort Collins, CO 80525 home: Carl@ecBaldwin.net
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
From: Carl Baldwin <hidden> Date: 2016-06-15 22:42:04
On Wed, Aug 24, 2005 at 11:18:42AM -0700, Junio C Hamano wrote:
Carl Baldwin [off-list ref] writes:
quoted
Attached are the two scripts. Comments and criticism are welcome.
An obligatory non-technical comment. I would have liked to see
this not in a MIME multipart format, which made commenting on it
a bit harder than necessary.
quoted
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=git-undo-script
#!/bin/sh
. git-sh-setup-script || die "Not a git archive"
if [ -n "$(git-diff-files)" ]; then
echo The following files should be updated!
echo
git-diff-files | awk '{print $6}'
fi
There is nothing wrong with the above, but I would have written
it like this (I think you forgot to exit after showing the list
of files):
git-update-cache --refresh || exit
I'll take this. This is what I was going for but being new to git I
didn't know all that was available. A good reason to request comments
:-)
Also nice to learn here is "git-diff-files --name-only".
Also good to know, thanks.
Carl
--
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Carl Baldwin Systems VLSI Laboratory
Hewlett Packard Company
MS 88 work: 970 898-1523
3404 E. Harmony Rd. work: Carl.N.Baldwin@hp.com
Fort Collins, CO 80525 home: Carl@ecBaldwin.net
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
From: Daniel Barkalow <hidden> Date: 2016-06-15 22:42:04
On Wed, 24 Aug 2005, Carl Baldwin wrote:
This brings up a good point (indirectly). "git prune" would destroy the
undo objects. I had thought of this but decided to ignore it for the
time being.
If you made undo store the tree under refs somewhere, git prune would
preserve it.
-Daniel
*This .sig left intentionally blank*
From: Carl Baldwin <hidden> Date: 2016-06-15 22:42:04
This is interesting. Can a ref be to a tree rather than a commit? And
it still works? I guess it would. I hadn't thought about that.
Will prune preserve any tree mentioned in any file in refs? How does
this work exactly?
Cheers,
Carl
On Wed, Aug 24, 2005 at 04:44:48PM -0400, Daniel Barkalow wrote:
On Wed, 24 Aug 2005, Carl Baldwin wrote:
quoted
This brings up a good point (indirectly). "git prune" would destroy the
undo objects. I had thought of this but decided to ignore it for the
time being.
If you made undo store the tree under refs somewhere, git prune would
preserve it.
-Daniel
*This .sig left intentionally blank*
From: Daniel Barkalow <hidden> Date: 2016-06-15 22:42:04
On Wed, 24 Aug 2005, Carl Baldwin wrote:
This is interesting. Can a ref be to a tree rather than a commit? And
it still works? I guess it would. I hadn't thought about that.
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.
Will prune preserve any tree mentioned in any file in refs? How does
this work exactly?
It keeps any object reachable from an object that there's a ref to in
refs.
-Daniel
*This .sig left intentionally blank*