Git revise is especially useful for this commit stack workflow, as I call it. I’m a huge fan.
It’s a better rebase. So much better that it should be obligatory.
You can split commits, batch rename them, and you don’t have to stash your work first.
rebase also has --autostash. The benefit of revise is that it’s fast and atomic :) But having to move to the front and index (and then cleanup the working directory) instead of dropping gets kinda annoying when you drop a lot.
This is almost an implementation of trunk-based development, which is quite fascinating as a workflow and used by some of the largest, most successful engineering teams. The only thing missing from the OP’s workflow is feature flags.
Forgive my ignorance, but it would seem to me we already did this with Subversion, and CVS before that.
This totally falls apart when you need to collaborate with, well, anyone.
Actually it doesn’t. I’ve used this style in multiple organisations starting around mid 90s starting with CVS, later subversion, and now git.
It was called “Concurrent Version System”, because multiple people could productively work on the same codebase at the same time. We created “branches” (tags you could check out later) only for releases in case we ever needed to apply an emergency bugfix to something we shipped.
Funny, I also work in this way because it is easier for me than switching branches. Good to know that others do it this way, too!
Me too. I suppose it’s convergent evolution, and everyone will eventually figure this out.
I’ve tried something like this from time to time and I always go back to one branch per topic. When I work on multiple nontrivial changes in the same branch (or in master), all the accumulated time savings from not switching branches gets consumed in one burst of activity the first time “pluck out one of the changes and push it while still working on the others” involves sifting through the edits to files that are touched by more than one of the changes.
I admire people who can keep this kind of state in their head. I really, really, really hate any kind of mental overhead like order of commits, which branch etc.
Obviously I can debug code that goes in several layers but if it comes to stuff like this (maybe because I see it as totally avoidable and need to look up stuff constantly) it doesn’t work. Mostly this “if feature A in commit 1-20 touch file a1 then feature B in commit 21-25 can’t touch a1, but all the other files or it will be rebase hell”
This article reads to me: “I never use branches, except I use branches”. “My local master” is already using branches.
Should have named the key concept of avoiding branch merges by rebase. We also do that at osmocom.org. Avoiding branch merges works well and gives nicely trivial linear history. But rebase-separating patches can turn out to be a massive, sometimes prohibitive effort, when the patches touch same code paths. If you branch-merge, you resolve conflicts only once in the end. If you rebase to get linear history, you potentially get conflicts for each and every branch commit. Like this I’ve ended up with practically unseparable code bombs several times already at osmocom.org, usually for larger refactoring work.
I’ve played around working like this with Git but I feel like this kind of workflow is so much better served by VCSs like Darcs and the more recent Pijul. You can often end up fixing a lot of trivial conflicts when doing things like reordering commits due to their snapshot nature in Git.
I usually have a ‘staging’ branch that I use for collecting smaller changes. The benefit is that I can push the staging branch to Git*b and have CI run on it without affecting master until I merge the changes there.
Mine is called “dev”. Doing it for personal projects. This way master is always green in CI and I can test & force-push until CI is green. Also I can always apply single hot-fixes to master if something should come up.
My bucket of bits branch name of abuse is wip. Or abuse of git stash if i’m exploring and aren’t sure its worth even committing into any history.
I don’t agree with the viewpoint I’m about to describe, but it’s a counterpoint I’ve heard to using git this way. I used to work with some engineers who were against this method because it changes the meaning of a commit. In their eyes, a “commit” was interpreted quite literally. Meaning, it should leave the code in a reasonably presentable state, and definitely compilable. By using git add -p, you are committing a set of code that has never been tested.
git add -p
I am a kind of person who prefers commits to be atomic and ideally compilable state (not that I’m fanatic about it, but that’s what I’m striving for). I thing add -p combined with interactive rebase only helps with that – if you discovered a typo or need some amendment, you can surgically squash it into one of your previous commits, instead of having a ‘broken’ commit and a useless separate commit with an amendment
You’re right in theory, but I always use git -p and the only things I usually leave out are single debug log lines, or some CSS changes when I work on the app itself, etc.pp, not huge swaths of code. The amount of times this has bitten be can be counted on one hand. So yes, technically it’s “never tested” but if you at any point push before running tests locally… I don’t think it matters most of the times, that’s what CI is for.
This counterpoint (which I understand isn’t yours) isn’t even one: always work in tiny increments, commit anytime the tests are green.
Your tests aren’t green fo long stretches of time? Fix that.
All green tests don’t mean that code can be committed? Fix that.
Sorry for the late (months late) comment but I think this is quite a narrow view that applies really well to easily tested things and awfully to everything else.