Along similar lines, I've adopted a hyper-frequent commit pattern in git. I do a bunch of meaningless micro-commits as I'm making progress, and then rewrite them all into one or two meanginful commits once I've reached a working state of whatever I was trying to do.
I find it's helpful for not losing work / easily backing up if as I'm going along I realize I want to change approach.
(For the micro commit I have a git command "git cam" that just commits all changes with the message "nt". Then once I'm ready to do a "real commit", I have "git wip" which rolls back all the nt commits but leaves them in checkout; then I can make one or two "real" commits.)
I wonder if dura would be even better, or if the commit frequency would end up being too fine-grained and obscure?
What you're describing is how git should be used. I would add it's important to push your branch to the remote just in case something happens to the local copy. I tend to squash/rebase to get the same type of results, but I can't imagine not saving work regularly or being concerned with the commit history while I'm actively working.
I usually commit often locally and push to remote right away. Then when I want to open up my PR, I use `git reset --soft <target>` where target is the local version of the target branch in my PR. That resets all the commits, but keeps all the changes in the staging area, and then I can clean up my history. Then I force push to override what's there.
This works well for my workflow because we squash all commits into target branches and don't really rely on commit history auditing during review. I understand that's not the case everywhere, but works for me.
different strokes for different folks. I like to use my staging area as "I want to save this" until I get to a logical stopping point in my work. Then I commit it with its descriptive message. This way I can diff/reset against master while making progress, and show a nice clean progression of my work for who reviews it.
also, sometimes I just lump the whole thing into a PR because there arent more than one logical unit.
I use the local history in Jetbrains/IntelliJ/PyCharm all the time. Can use it on a current file, or even mark a folder if you accidentally deleted something.
It annotates the checkpoints with metadata as well. Like "this is how the file looked when you ran a test that failed".
Clearly, my JetBrains IDEs paid themselves multiple times by saving me from « oh shit » situations. Best investment my employer did without never knowing it :D
Local history saves my bacon about once a month. It's incredibly helpful as it lets me adopt a fearless refactoring approach knowing that I can always get back.
I'll just throw out there that ever since I picked up Doom Emacs and the associated Magit, I have been doing the same thing and loving it, I'll commit every time I finish writing a logical scope of code, and then commit and push and know that everything is there in case anything happens, it also has made my commit comments much more descriptive as I know am actually able to describe exactly what the commit has done beyond "Added feature X, refactored function Y". Big fan of the continuous commit workflow.
I've tried that as well. For me it was really difficult as I use the current changes quite a lot, and it makes it a lot more difficult to grasp the work I've done so far without having a meaningful change set.
you can use separate dev/release branches, and do something like "git diff master" (if you dont git push, you don't even need a separate branch, git diff origin/master works, but you lose half the point of frequent commits then)
I do something similar but a little more manual that your solution. I `git commit -am "WIP"` to save random, odd-ball intermediate working states. Occasionally the commits get real messages but I try not to let it interrupt the flow.
Then when I'm ready to commit or cut PRs, I just squash them all down if it's trivial. If it's a bigger change: I push things to a backup branch, `git branch Branch-BK`, reset to a base commit, and use difftools to pull over the subset of changes I want and commit them repeatedly until there's no diff left.
I have a `git snap` command that's similar to your `git cam` command with a small twist. The commit is added to a special snapshots branch that isn't checked out. I push the snapshots branch and don't rewrite it, but rather keep it around as an accurate chronological record of things I've tried, warts and all. I also like that `git diff` continues to show the changes compared to the last "real" commit this way.
Edit: I guess my script is somewhere between your `git cam` command and Dura in terms of functionality and complexity.
I do something similar, but with larger intermediate commits than yours and more meaningful messages. Then at the end, I do an interactive rebase, squash the ones I don't care about, and reword the final commit message based on the hints I left myself in the squashed ones.
I do a combination of the two: the first commit gets a meaningful (but still draft) message, and their follow-ups are all committed with "." as a message - but only until "switching gears", i.e. until a commit comes that is logically separate from the bunch before it. Those commits that have messages then provide logical milestones for squashing.
This breaks down sometimes if you have to switch back and forth between different parts of code, breaking the linear sequence. But even then, the messages make it easier to connect the pieces when it's time to clean up history before the pull request.
(I use just external scripts rather than git aliases because I find it a little nicer to work with; git has a feature where if you enter "git foo", it will look for a command "git-foo" to execute.)
Yep, exactly. My terminal autocompletes to previous commands, so it's pretty easy to get to 'git commit --fixup HEAD', likewise for a rebase with --autosquash.
This workflow sounds similar to the one we use at my company! I use the git-ps tool we made to make stacks of usable micro-commits, and using the tool to keep things logical and working as things change and the code develops. https://github.com/uptech/git-ps
Have you considered using `git commit --amend --no-edit` after making your first commit? It simplifies the unwinding step.
This is pretty much my workflow, too. I’ll make some changes, `git commit -m wip`, and then `g can`. When you’re ready to prepare the PR/diff, `reset HEAD^`. Then, a few cycles of `add -p`, `commit -v`.
`commit --amend` and `add --patch` are super powers!
It's a handful of commands because git-cam and git-wip referenced other little utility scripts, so hopefully I got them all. Probably it would be easy to rewrite to be standalone.
I'm on a mac, and I have ripgrep installed as "rg". Ymmv, glhf :-)
So:
"git cam" commits everything with message "nt"
"git wip" undoes all the nt commits but leaves the results staged, ready to be commited as a single properly worded commit (or play w/ what's staged and do as several commits)
This is also my pattern. To further assist with this, I wrote a short(ish) rebase script intended to be run when you want to squash your series of commits, also bringing your local branch up-to-date with the upstream. It relies on your initial commit in your feature branch having a commit message which corresponds to the branch name, but that's it. This does a great job of minimising unnecessary merge conflicts, even after working offline for an extended period.
I would like to go this approach. I simply forget to commit until I’ve wrapped up something big, but I’d like to submit more frequently so others can see my work. Is there something that will remind me to commit? Esp. In VSCode
> Along similar lines, I've adopted a hyper-frequent commit pattern in git. I do a bunch of meaningless micro-commits as I'm making progress, and then rewrite them all into one or two meanginful commits once I've reached a working state of whatever I was trying to do.
Aren't you describing a feature branch? That frankly sounds like git 101.
Nope. A feature branch is still expected to have meaningful commits, and is usually used for collaboration between several coders. Its history doesn't get rewritten.
What OP describes is a temporary work branch that belongs to a single person, and has a bunch of meaningless commits. So nobody else should be using it - or if they do, they need to sync with the owner, since the latter can squash or otherwise mutate commits at any time.
I think what you're doing is better because it's more explicit. I feel like Dura is yet another tool for people that don't know, and don't want to learn, Git.
Eh. I do tens of commits and then squash into 1 or a few, sometimes by resetting back and a few add --patch and sometimes by interactive rebasing.
But I can see times where Dura could be kind of nice. When I'm doing CAD or other not-very-source-code things, having a few snapshots be grabbed along the way sounds nice. Going to try and git commit in intermediate states feels a little too mode-switchy to me.
JetBrains "local history" for InteliJ IDEs has saved me several times. It has all of the diffing tools that are available for git commits. This looks to be a generic implementation of that. We should not live in a world where unsaved data is lost.
1. dura runs as a daemon while git-sync-changes is a one shot execution.
2. dura saves locally, while git-sync-changes syncs with a remote repo.
3. dura only does the save and the restore is manual, whereas git-sync-changes does both steps automatically.
I’m glad to see more people exploring this space. I think there’s a lot of untapped potential in tracking pending changes similarly to how we track committed changes.
I wrote it because I wanted to have a complete snapshot of a build context. Sometimes composer or npm can't be relied upon to reproduce dependencies in the state they used to be, or I just want a cache of artifacts. It has been pretty handy.
It's kind of insane to that in 2022 were still dealing with "save early, save often."
Our tools are so antiquated. Storage is cheap and computers are fast, every keystroke should be persisted somewhere I can recover from rather than having to manually save and commit works in progress.
Well, it's funny because the Apple stuff works like this, but not Xcode.
I pretty much never save anything with Page/Numbers/TextEdit. I just quit
Not only do I not lose changes, I don't lose editions. I can go back to older versions. And that's not including Time Machine. It's simply "built in".
From a user experience, it's really wonderful and no stress. I don't even think about it. At the same time, I have no idea where these extra versions are stored but, honestly, I don't care.
I do wish other applications worked similarly. Source code is tricky, but it probably wouldn't be awful to have a similar experience.
vim had an undo tree for 10 years (or longer?) [0] and there are plugins (eg [1]) that make it very easy to go back in history and also to explore different branches of your undo/edit history. Dura will not track changes that are not saved to disk IIUC
Saving a log of every keystroke is basically what a CRDT for an editor does today. We really just need to make local editors behave more like Google Docs and de-emphasize use of the save button (everything is always saved at all times).
A lightweight way to accomplish this is to at least set up frequent autosaves in your editor. I had `au FocusLost * :wa` in vim to save all buffers to disk whenever it loses focus. Now that I've converted to the church of VS Code (with vim bindings, of course), there's an "Auto Save: onFocusChange" config option to do the same thing. I don't know how people live without it!
You don't always want to save to disk though, you want to save in a consistent state. Vim allows you to set up a persistent undo that will let you load the modified buffer from a backup file without touching the original until you're ready. Or undo back to the saved on disk version. Or undo even further to previous versions. That's true persistence.
> It's kind of insane to that in 2022 were still dealing with "save early, save often."
Those of us who don't code in autosynced folders, that is. There is tons of software (IMO better than the approach in TFA) that has solved this problem for years now. Dropbox or Google Drive if you trust the cloud. Unison or looping rsync or syncthing if you don't.
It's rare, but I have lost history once or twice, possibly after a computer restart. It's great when it works (which is almost always) but not foolproof.
Navigating in this history might be a challenge. But I agree. My disk is filled by dozens of random docket images yet few megabytes of diffs are not stored.
LOL — author here — I definitely didn't intend it that way, but it does kind of jive with "Git's" other meaning. I should have known that all 4-letter words are an insult in some language.
I had originally named it "duralumin" after a magical metal in [a novel that I'm reading](https://www.amazon.com/Well-Ascension-Mistborn-Book/dp/07653...). I shortened it to "dura" after realizing that I can't even remember the name, so there's no chance anyone else will. Plus is has that "durable" vibe to it, which seemed appropriate.
As a Russian speaker, I would say that I feel our swear words become truly offensive when they are explicitly targeted at a person. "Dura" is also not considered to be an expletive, and I have not heard it being used in its original meaning after I finished 5th grade. Pronunciation in Russian is also different, word sounds like "doo-ra".
FWIW the same word "dura" may also be used as a slang word for a large and unwieldy inanimate object.
Not sure if it was obvious to you, but years after reading the novel I found out it’s not just a ‘magical metal’, it exists and is/was used in aircraft construction.
Not to mention Latin. The French equivalent is "dur[e]". The membrane surrounding the brain is "dura mater" to an anatomist, which is Latin for "hard mother".
I thought most every Russian was over it after laughing for a bit about the last name of the VKontakte founder, Pavel Durov. At least I didn't make this association immediately when I saw the name of this project.
It's pretty hard to name something without having it accidentally stand out in one of thousands of languages (or even a few major ones). I wouldn't read too much into the intention.
I’ve had this idea for about 10 years - it really pays off to wait and eventually someone will build all my ideas :)
There are many things to build on top:
- Squash history so that it doesn’t grow indefinitely.
- Be somewhat language aware to provide better commit messages
- IDE integration
Fossil has no such feature. Fossil sync synchronizes the remote and local saved state (checked-in/saved state only). It does not do anything with un-checked-in state.
That said, you can use fossil's stash to periodically take a (non-sync'd) snapshot using something like 'fossil stash snapshot -m "snapshot @ $(date)"' (i have that aliased and use it often). That does not enter the SCM history and is lost if you destroy the checkout dir.
My biggest question after looking at the readme: What happens if your computer crashes while dura is making a commit? Can it corrupt your local git repository?
From my own experience, git is not crash safe, i.e., it can leave the .git directory in an inconsistent state if the computer crashes during certain git operations.
This is an interesting concept. I'd think it would need some kind of system tray icon to be aware if it stops running, otherwise, it might provide a false sense of security and you could lose work because you thought you were safe but Dura actually crashed three days ago. It also probably needs some sort of automatic syncing to a remote repo, so it isn't affected by spilling your coffee on your laptop.
Yes! I'm the author and this is the next feature I was planning on adding, I was even planning on naming it `dura status`. First I need to get better logging (to a JSON file), and then expose it via `dura status`. It occurs to me that having all that data could tell me a lot about how I work, so it could unlock some very interesting usages of dura.
Would you mind creating a Github issue? The project could benefit from more discussion around this.
I find it's helpful for not losing work / easily backing up if as I'm going along I realize I want to change approach.
(For the micro commit I have a git command "git cam" that just commits all changes with the message "nt". Then once I'm ready to do a "real commit", I have "git wip" which rolls back all the nt commits but leaves them in checkout; then I can make one or two "real" commits.)
I wonder if dura would be even better, or if the commit frequency would end up being too fine-grained and obscure?
This works well for my workflow because we squash all commits into target branches and don't really rely on commit history auditing during review. I understand that's not the case everywhere, but works for me.
also, sometimes I just lump the whole thing into a PR because there arent more than one logical unit.
It annotates the checkpoints with metadata as well. Like "this is how the file looked when you ran a test that failed".
Repo here: https://github.com/zabel-xyz/local-history
Doesn't appear to mark checkpoints with metadata, though (test failed/passed, etc.).
Then when I'm ready to commit or cut PRs, I just squash them all down if it's trivial. If it's a bigger change: I push things to a backup branch, `git branch Branch-BK`, reset to a base commit, and use difftools to pull over the subset of changes I want and commit them repeatedly until there's no diff left.
Edit: I guess my script is somewhere between your `git cam` command and Dura in terms of functionality and complexity.
This breaks down sometimes if you have to switch back and forth between different parts of code, breaking the linear sequence. But even then, the messages make it easier to connect the pieces when it's time to clean up history before the pull request.
(I use just external scripts rather than git aliases because I find it a little nicer to work with; git has a feature where if you enter "git foo", it will look for a command "git-foo" to execute.)
I.e. just use "git add -A" instead of "git cam"
Then you don't need "git wip"
This is pretty much my workflow, too. I’ll make some changes, `git commit -m wip`, and then `g can`. When you’re ready to prepare the PR/diff, `reset HEAD^`. Then, a few cycles of `add -p`, `commit -v`.
`commit --amend` and `add --patch` are super powers!
It's a handful of commands because git-cam and git-wip referenced other little utility scripts, so hopefully I got them all. Probably it would be easy to rewrite to be standalone.
I'm on a mac, and I have ripgrep installed as "rg". Ymmv, glhf :-)
So:
"git cam" commits everything with message "nt"
"git wip" undoes all the nt commits but leaves the results staged, ready to be commited as a single properly worded commit (or play w/ what's staged and do as several commits)
https://gist.github.com/nicois/e7f90dce7031993afd4677dfb7e84...
Aren't you describing a feature branch? That frankly sounds like git 101.
What OP describes is a temporary work branch that belongs to a single person, and has a bunch of meaningless commits. So nobody else should be using it - or if they do, they need to sync with the owner, since the latter can squash or otherwise mutate commits at any time.
https://thoughtbot.com/blog/autosquashing-git-commits
But I can see times where Dura could be kind of nice. When I'm doing CAD or other not-very-source-code things, having a few snapshots be grabbed along the way sounds nice. Going to try and git commit in intermediate states feels a little too mode-switchy to me.
Both save uncommitted changes in a hidden ref.
Based on the README, the differences seem to be:
1. dura runs as a daemon while git-sync-changes is a one shot execution.
2. dura saves locally, while git-sync-changes syncs with a remote repo.
3. dura only does the save and the restore is manual, whereas git-sync-changes does both steps automatically.
I’m glad to see more people exploring this space. I think there’s a lot of untapped potential in tracking pending changes similarly to how we track committed changes.
Which saves all uncommitted changes to a tag.
I wrote it because I wanted to have a complete snapshot of a build context. Sometimes composer or npm can't be relied upon to reproduce dependencies in the state they used to be, or I just want a cache of artifacts. It has been pretty handy.
It sounds like it addresses roughly the same use case, but I couldn’t find any technical details about it in its docs in order to see how it compares.
It's kind of insane to that in 2022 were still dealing with "save early, save often."
Our tools are so antiquated. Storage is cheap and computers are fast, every keystroke should be persisted somewhere I can recover from rather than having to manually save and commit works in progress.
I pretty much never save anything with Page/Numbers/TextEdit. I just quit
Not only do I not lose changes, I don't lose editions. I can go back to older versions. And that's not including Time Machine. It's simply "built in".
From a user experience, it's really wonderful and no stress. I don't even think about it. At the same time, I have no idea where these extra versions are stored but, honestly, I don't care.
I do wish other applications worked similarly. Source code is tricky, but it probably wouldn't be awful to have a similar experience.
[0]: https://vimhelp.org/undo.txt.html#undo-tree [1]: https://github.com/mbbill/undotree
[0]: vim and emacs, at least.
Those of us who don't code in autosynced folders, that is. There is tons of software (IMO better than the approach in TFA) that has solved this problem for years now. Dropbox or Google Drive if you trust the cloud. Unison or looping rsync or syncthing if you don't.
Deleted Comment
"When Ctrl-Z is not enough"
As a french, I can only call this service Patricia. Because Patricia Kaas of course.
Perhaps it was intended, but I can’t quite make a connection.
I had originally named it "duralumin" after a magical metal in [a novel that I'm reading](https://www.amazon.com/Well-Ascension-Mistborn-Book/dp/07653...). I shortened it to "dura" after realizing that I can't even remember the name, so there's no chance anyone else will. Plus is has that "durable" vibe to it, which seemed appropriate.
FWIW the same word "dura" may also be used as a slang word for a large and unwieldy inanimate object.
I’d just never heard of it before.
Dura is also an anatomical term for the tissue encasing the brain.
Apparently it left quite an impression on early anatomists/neurosurgeons.
There are many things to build on top: - Squash history so that it doesn’t grow indefinitely. - Be somewhat language aware to provide better commit messages - IDE integration
(A long-time fossil contributor here.)
Fossil has no such feature. Fossil sync synchronizes the remote and local saved state (checked-in/saved state only). It does not do anything with un-checked-in state.
That said, you can use fossil's stash to periodically take a (non-sync'd) snapshot using something like 'fossil stash snapshot -m "snapshot @ $(date)"' (i have that aliased and use it often). That does not enter the SCM history and is lost if you destroy the checkout dir.
Git can operate on two local repos reasonably efficiently, IIRC, so diffing and applying commits should be doable.
Would you mind creating a Github issue? The project could benefit from more discussion around this.