Improve "how to recover" experience
tkellogg opened this issue · 4 comments
The readme outlines how to use a dura
branch to recover, but it involves a lot of git-fu. It could be a lot easier
Idea: sub-commands
Add dura
subcommands to do things like
- Get the branch corresponding to HEAD, e.g.
dura head
- Get a commit by time frame, e.g.
dura head 4h
. I imagine this searching acrossdura
branches, since we can indeed go prior to the HEAD commit. - Recover to a specific commit hash (or a time frame).
Idea: Add help messages in relevant places
Documentation in the readme is great, but it could be better if we added help directly into messages that dura
has to leave anyway. For example, why not set the commit message to something like:
dura auto-backup
To recover to this commit, run this:
<<git commands>>
Using a recent-enough git version, you can use https://git-scm.com/docs/git-restore, and combine this with some git rev-list
magic to automatically get the latest snapshot from eg. 1 hour ago, and even restrict to some files only. Stuff it all in a git alias, and here is your magic:
# You need to do this only once and for all
git config --global alias.dura '!restore () { local when="$1"; shift; cd "$GIT_PREFIX"; git restore --worktree --staged --source $(git rev-list -n 1 dura-$(git rev-parse HEAD) --until "$when") ${@:-:/} ; }; restore'
# Then in your repo you can restore things like they were 1 hour ago:
git dura 1hour
# Or longer:
git dura 2month
# You can also give an exact date:
git dura 2021-03-04
# And restrict to some files (any git pathspec will work here):
git dura 15min README 'src/*.c'
Note that by default it will restore all the files in your repository, even if you are in a subdirectory (that's the magic part done by ${@:-:/}
).
As it turns out, you don't even need git restore
, using --staged --worktree
is equivalent to git checkout
hence:
git config --global alias.dura '!restore () { local when="$1"; shift; cd "$GIT_PREFIX"; git checkout $(git rev-list -n 1 dura-$(git rev-parse HEAD) --until "$when") -- ${@:-:/} ; }; restore'
The alias will fail if you don't provide a date, which is working as intended (but the error message is confusing, let me know if you want error handling for it).
And if you want to list from all dura branches, and not only the one deriving from HEAD, it's even easier:
git config --global alias.dura '!restore () { local when="$1"; shift; cd "$GIT_PREFIX"; git checkout $(git rev-list -n 1 --branches=dura-* --until "$when") -- ${@:-:/} ; }; restore'
Can you send a pull request to add this to the README?
If you're feeling brave, you could even add this to dura serve
, somewhere around here so that it gets set every time dura
starts up. Libgit2 docs are here, but I think it would look roughly like this:
fn set_git_alias() -> Result<(), Error> {
let git_alias = "...";
let cfg = Config::open(Config::find_global()?)?;
cfg.set_str("alias.dura-reset", git_alias)?;
Ok(())
}