> I’ll just apply them to master, rebase them behind my WIP work, and then use git push origin HEAD~5:refs/heads/master to send them upstream, or something to that effect.
if you're going through the trouble of carefully rebasing to change the order of commits, and remembering exactly how many commits behind HEAD you should push, and remembering what state the remote is in (what is master is actually pointing at HEAD~4?)... why not just go through the comparatively minor trouble of using branches?
also it's not like working on branches excludes the possibility of sometimes committing directly to master. that's what I do for most of my personal projects: small cleanup and fixes happen on master, larger things happen in a branch on a PR until I'm happy with it. ~30% of the time I'm actually not happy with how it turns out, and then I'd rather just close the PR and delete the branch than carefully revert work in progress.
No time spent creating new branches for new features.
No time spent switching between branches to address feedback.
I'm sorry but these are non-issues with git. The approach you've outlined makes collaboration on features impossible. Cherry-picking and rebasing does not scale for either teams, or lots of parallel workstreams.
He may think that he is rebasing later anyway, but sorting all those commits into "need for my feature" vs. "don't need for my feature", followed by the rebasing within the feature certainly takes much longer than the split second of creating a branch and keeping those features separate from the beginning.
It's great if it works for him, but he's certainly not saving time.
Switching branches does get a bit annoying if you happen to work in multiple branches simultaneously and have to switch halfway through a task, or there's a lot of differences; however, that is also a matter of organization.
It's happened to me though; one scenario is that you created a couple of merge requests for the same repo over the course of a day, and the next day feedback from code review or testing comes in. You end up having to switch to various branches to fix the reviews.
But that's really not that big of a deal. The context switch is worse than the git checkout call.
git worktree[0] can help with working on multiple branches at once, especially if your workflow involves having a bunch of uncomitted changes. You could also stash them, but if there are more complex things like submodules, ignored build artifacts and so on you don't want to mess with then worktrees are a good alternative.
> Switching branches does get a bit annoying if you happen to work in multiple branches simultaneously and have to switch halfway through a task, or there's a lot of differences
Sure, but its not like the different changes just don’t exist if you use only master, branches are a way of managing them separately and only merging when you are ready, if you don’t use branches, you have to have some other way to manage this. If you don’t, and its not a problem, then you could also just not work on three branches at once.
Git checkout understands "hyphen expansion" for your previous branch (a la `cd -` to switch to your previous working directory), so switching between two branches is as easy as `git checkout -` or even `git co -` if you have an alias.
Seems like all the time you'd ostensibly save on not branching you instead spend doing very careful munging later and crafting very careful commits with git add -p and rebase and other equally time consuming tools.
> you instead spend doing very careful munging later and crafting very careful commits with git add -p and rebase
I mean, I already do this, because I like to be able to understand my commits as standalone historical artifacts. IMHO commits exist to be read (by your future self trying to figure out WTF you were on about most of all!) as much as they exist to change the state of the codebase.
Given that I'm already doing this, it wouldn't be any more work to use a workflow like this, I guess? (I still use branches. And have multiple git worktrees checked out at once from the same repo.)
And (if I understand the workflow correctly) you wouldn’t be able to test on your local at all... cross your fingers that your patch doesn’t break something!
>When I’m ready to present some or all of my changes to upstream, I grab git rebase and reorganize all of these into their respective features, bugfixes, and so on, forming a series of carefully organized, self-contained patchsets.
That seems like a lot of extra work to "not use" branches.
I do less work than that and don't use branches. I just tag the releases.
Whenever I want a certain commit to triger CI/CD for build/testing and preprod deploy, I just tag a git commit as "release-[most recent git commit 8char fingerprint]" using a little script and some cli aliasing.
Then push. Release is built, and I can keep pushing to master unfinished features. But because the working version is tagged, Ops can always rebuild, redeploy, or roll back to known good commits.
This workflow doesn’t seem weird or unorthodox to me, it just seems like a solo contributor workflow. There aren’t as many reasons to use branches when you aren’t working with other people in those branches. It seems fine to skip some of the overhead when you’re by yourself. The implicit suggestion that everyone else is always using branches does seem a bit strange, if that’s the implication. I use branches when I need them, but I don’t always use them, and usually on small teams we adopt a policy of checking self-contained single-commit features into master, and using branches for multi-person, multi-commit, and multi-day features.
No time spent creating new branches for new features.
No time spent switching between branches to address feedback.
All of my features are guaranteed to be mutually applicable to master, saving me time addressing conflicts.
Any conflicts with upstream are addressed in all of my workstreams at once, without switching between branches or allowing any branch to get stale.
To be honest all 4 of these are unconvincing. Creating branches and switching branches is a non-problem, these operations are faster than committing.
To the third and fourths points - that all “streams” resolve at the same time, that’s an okay point, but isn’t normally a problem in practice with branches. If you’re working on multiple branches than conflict with an incoming commit, it means you’ve touched the same code in multiple branches, and also someone else has too. It tends to indicate bad planning or bad communication or both. And it just doesn’t happen very often.
Here are a few reasons to use branching anyway when you’re alone:
- To do an experiment multiple ways on the same code.
- To avoid use of git stash. Branching is safer and adds no extra difficulty. Stash doesn’t have as good of a safety net (it’s in the manual).
- To write & test your feature without your other in-progress features getting in the way.
This is a very eclectic workflow that might work if you have very good mental organization. For most people this sounds a recipe for disaster. A good way to lose work and get confused about the scope of individual features.
I tend to think of git as tool to aid organization and not an opportunity to flex my prowess at mental gymnastics. Crazy, I know.
Local testing would become meaningless as “features” are not being tested in isolation. It’ll lead to the classic “but the tests work on my machine” because half the changed code isn’t in the published changeset.
Here's better rationale for this kind of approach: it requires a lot less rebasing and merging:
1) If you branch a lot, keeping up with upstream changes can be tedious: you have to rebase each branch separately just to keep up. With this method, to keep up, you rebase just once, on your one branch.
2) If you branch a lot, merging each branch can cascade into a bunch of rebasing. As you build your feature, you might clean up unrelated code. Your "implement feature" commits could be interspersed with "fix unrelated code" commits. If you're creating a branch for each cleanup commit, as you submit them for review earlier than your feature, you have to rebase all your branches one by one. With this method, you rebase just once.
People are quick to dismiss this, but I think it's a fish-in-water kind of thing, where they are so used to the normal git flow, they can't see any way that it might be non-ideal.
I am excited about the promise of patch-based VCs. In theory they are clearly a better, more flexible model, that is a closer match to how we actually think of changes.
As an example, the branch-free model of this post just falls out naturally, w/o the need to rebase at the end.
However, we're still missing a great implementation to make this promise a practical reality (perhaps the upcoming version of Pijul will be that implementation?).
I much prefer separate local branches and rebase against master to start the daily workflow. If you are regularly keeping your feature branch on the up to date with master head there is little conflict day to day. When there is a conflict it's because you have to make a decision between two features or collaborator updates and your feature. As long as you haven't pushed your local branch you can rebase it all you want.
I think the success of such a workflow says a lot of positive things both about drewdevault and git.
With respect to git, this is yet another successful workflow conducted through git. While git may have its flaws, one cannot deny that many different workflows are enabled by it.
And with respect to this particular workflow, I think it says that drewdevault makes largely self-contained commits with good commit messages and that constantly work. I have been on projects using branched development with people who sometimes make commits that break things, but that then fix them in other commits, with a does-it-really-matter-before-it's-merged-anyway attitude. And I have been on projects where the default commit message is absolutely lousy. (And I am currently involved in a project where both of these are true).
But to be able to successfully rebase and reorder and cherrypick commits says a lot to me about highly disciplined organization. I would expect many workflows to be enabled by such habits.
> I think the success of such a workflow says a lot of positive things both about drewdevault and git.
There's a massive flaw in this approach if the repo is not private (collaboration is mentioned in the post in terms of "review some incoming patches") in that you can't push works in progress to the remote as you are doing it all in master. If you did push those then when you tidy it up you will cause problems for other collaborators.
If you can't push WIP out then you have the only copy, and you're losing some of the distributed advantages of git: distributed backups of your WIP changes being one of those.
> But to be able to successfully rebase and reorder and cherrypick commits says a lot to me about highly disciplined organization.
Yeah, rebases and cherry-picks are great features. Just use branches as the starting point.
I do something kind of similar using stgit[1]. I do everything on a single branch creating patches with stgit. stgit lets you easily change the order of commits (a lot like quilt[2], but more robust because it's using git underneath). When features are ready, I just cherry pick them over to master and push upstream.
He understands the power of rebasing, but he doesn't address how you use that power and also coordinate your work with other people.
He seems to be implying that it's OK to rebase against master and/or force push the remote ref, as long as the only person you are pleasing is yourself.
I mean, a lot of people progress in their Git knowledge until they reach the point where they want to minimize the clutter of merge commits. That's almost a cliche.
But how you do that when you are working with others, some of whom may have advanced Git knowledge while others are complete novices, that's what the real world looks like.
When I go rock climbing, I don’t use ropes. It saves me time of having to set anchors.
The git advice works for either experts or small projects. If you’re an expert, choose your own workflow. I find in large projects with many users, branches help to recover quickly from mistakes and help define testing history. My primary concern is for novices to go at it without branches because they’re hard to deeply understand without experience and they see experts managing without.
Learn how to use rock climbing equipment before you rely on it. Experts, do whatever works best for you!
Isn't it incredibly annoying to edit a git change that isn't at the branch (HEAD) tip?
Our workplace uses gerrit, and while it sort of supports this workflow I personally use a lot of short-lived branches, one for each gerrit review, simply in order to get at them easily to make changes.
This is an interesting article. I do find it pleasant to use git without branches. It allows you to invent a different type of agility and resourcefulness with git operations. I would not recommend this to new users or teams.
if you're going through the trouble of carefully rebasing to change the order of commits, and remembering exactly how many commits behind HEAD you should push, and remembering what state the remote is in (what is master is actually pointing at HEAD~4?)... why not just go through the comparatively minor trouble of using branches?
also it's not like working on branches excludes the possibility of sometimes committing directly to master. that's what I do for most of my personal projects: small cleanup and fixes happen on master, larger things happen in a branch on a PR until I'm happy with it. ~30% of the time I'm actually not happy with how it turns out, and then I'd rather just close the PR and delete the branch than carefully revert work in progress.