git-annex/doc/todo/direct_mode_undo.mdwn
Joey Hess 13260ccc3a undo command
This commit was sponsored by Andrew Cant.
2014-11-14 14:41:07 -04:00

86 lines
3.9 KiB
Markdown

A fairly common request is that a repo is using direct mode, and the user
has made some change, and now wants to undo it. Since direct mode doesn't
allow using `git revert`, the repo would need to be switched to indirect
mode first, which can range from annoying to really annoying to impossible
(on eg FAT).
## general approach
`git annex proxy $gitcmd` could:
1. check out a local clone of the repo
2. run "git $gitcmd" inside the clone
3. Merge any changes from the clone back into the direct mode repo
and update the work tree the same as is done by `git annex merge`.
4. If a different branch was checked out in the clone, update the repo
to have that same branch checked out.
This is a general bypass for the direct mode guard. It should work anywhere
(even on FAT). It avoids problems like `git commit -a` being unsafe in
direct mode, since running such a command in a local clone, which does not
use direct mode is always safe.
Beyond handling undo, #4 means that this can be used to check
out past versions of the repo (eg, `git annex proxy checkout HEAD^^`)
One problem with it is that it can only operate on changes that have been
committed. If you've just accidentially deleted a file and want to undo
that, and haven't run `git annex sync` to commit it, you can't revert it.
The need to make a local clone will make it a bit slow, since the whole
work tree will need to be set up. It might be possible to reuse the clone
next time (after resetting it to reflect the current HEAD).
Some things like the reflog and local branches don't get cloned, so
git commands that try to act on those wouldn't work. Maybe it would be
better to make it use a separate work tree, but the same .git directory?
Then step #3 would instead update the direct mode work tree to refect
the new HEAD, and step #4 would not be needed.
> This is done.. But, I think an undo command would also be good
> to do, as a nicer user interface that can integrate well with a file
> manager. --[[Joey]]
## git annex undo
I don't want to recapitulate all of the git commands in git-annex for
direct mode. So I don't want to add `git annex revert` and `git annex
branch` etc, etc.
So, adding `git annex undo` feels like a step down a slippery slope. But it
might be justified as providing just enough functionality to make direct
mode a lot more useful, without trying to recapitulate all the flexability
of git. Like `git annex merge` and `git annex sync` also do.
Another use case is binding `git annex undo $file` to an action in a file
manager.
Here's a design for undo:
1. Can be passed one or more files. Which may or may not exist in the work tree.
2. First, commits the current state of the files as staged in the index,
or in the working tree. This may involve checksumming modified files.
3. Then, for each file, looks back through git history, to find the commit
just before the most recent change that was made to that file.
Stage the version of the file as it was in that commit.
4. Updates work tree, and leaves the changes staged
but not committed. (To allow the user to bundle up multiple undos in a
single commit).
6. Does not get or drop content. The content may even be completely
missing after an undo.
Note that undoing an undo should get back to the original state. This is
why #2 commits changes first. This way, if a file has a staged change,
it gets committed, and then that commit is reverted, resulting in another
commit. Which a later run of undo can in turn revert. If it didn't commit,
the history about the staged change that was reverted would be lost.
What about undoing changes to a whole directory? Recursively undoing
the last change to each file would be expensive, and likely confusing.
Instead, when a directory is passed, it could find the most recent commit
that touched files in that directory, and undo the changes to those files.
> [[done]] --[[Joey]]
Also, --depth could make undo look for an older commit than the most
recent one to affect the specified file.