This is how I git
daniel.haxx.se
daniel.haxx.se
Er, no. Right tool for the right job.
Whilst I agree that the idea of putting differing lines of work into different branches is great, that's not what stash is for. That's what checkout is for.
Stash is used to record the current state of the working directory and index while also returning to a clean working state.
I guess for the author, stash is used to preserve changes when pulling in upstream changes you missed. It can, but it does waaaay more.
What happens if, like many people, you're working on a few branches at a time. Could be a monorepo, could be a couple long living branches, w/e. What do you do if you've done work against a branch and want to lift and shift to another branch?
You could commit and rebase and all sorts of clever mangling of the history.
OR you could use the right tool for the job
---
Follow up
[0] https://medium.com/@yankee.exe/mastering-git-stash-workflow-...
[1] https://git-scm.com/book/fa/v2/Git-Tools-Stashing-and-Cleani...
Yes, it's useful to quickly stash your work, switch to a different branch, do some quick fix, then go back to your original branch.
But in practice, what often happens is that your quick fix takes way longer than expected, and you don't immediately go back to your original branch.
Then you pull in some changes, maybe someone else pushed something to the branch you were working on, and you end up with a bunch of stashes on outdated branches and it's really hard to make sense of it all. Most of my working copies have at least half a dozen old stashes that I don't remember any details about anymore.
One approach to avoid this mess that git stash can lead to is to never use it, and just commit all your work before switching to a different branch. Clean up the current state of the repo, try to document your changes in the commit message, and commit them. Then switch branches.
You can always squash or rewrite the commits later, and it's a lot easier rebasing or merging a few old commits than working with stashes.
If you like stashes, please use them!
But I agree with the author, using them a lot can lead to a mess, and temporary branches are usually a cleaner way of saving your work.
I had to resort to git's assume-unchanged[O] to keep these changes out of commits made in the heat of battle.
> this isn't a best practice for config files
Have had great results (in dotnet land) with MS' Secrets Manager[1].
[0] https://www.git-scm.com/docs/git-update-index [1] https://docs.microsoft.com/en-us/aspnet/core/security/app-se...
The technique is not applicable all the time, but for those instances when you really think it's valuable to preserve the knowledge that was gained in trying and abandoning a particular approach it's great.
Like the article writer, I never myself use stash. I personally don't understand why they were added to the git ux. I think they needlessly make git more complex. Under the hood, a stash is just a commit anyway. You might retort that this is an implementation detail but as usual with Git, this leaks into the way it is used: if you ever lose a stash by mistake, you will have to go fish the corresponding commit in the reflog.
Perhaps a Mercurial user can say if shelves are more useful? (And if so, why?).
So I can `git pull --rebase --autostash` and this works even with local modifications.
One "right tool for the job" I really underappreciated until recently is git worktree, which fits this use case neatly, I think, without the risk of losing your stash.
Why is stash better than this? Because it avoids the rebase? Many people do this anyway, early commit messages often need rewording. Because it maintains the separate state of the current working directory and the index? Is that it? I don't think that's really a compelling enough reason to claim the author's avoidance of stash is the wrong way to work.
git add .
git commit -m "wip"
when you're back git reset HEAD^
Keeps working changes nice and tidy in the branch they belong to, you can push them, and they are easily recoverable from the ref log, unlike stashes.Also, god help you when a stash fails to apply.
But this workflow (which seems so very obvious in retrospect), keeps my current workflow, with so many benefits. The only place where it even requires extra steps is when you want to apply the stash to a different branch, and even there, it just feels right:
“Oh yeah, I was working on that feature over there, let’s pop it off and go put it on this feature over here.”
Since this generally requires careful diffing anyway to make sure things end up in the right place, there’s not much lost here, and without the downsides of stash.
Each time you run `wip`, all current work is committed. When you run the squashing utility `naenae` (autocomplete: `nae + Tab`), the most recent line of "WIP" commits is saved to a `wip-archives/[branch]/[timestamp]` branch for safe keeping, the commits are all squashed in place, and you're left in your default git editor to define the commit message. It also handles unusual situations, like using `wip` for the first commit (in which case, `git reset HEAD^` will return an error).
Being able to set a sort of "WIP checkpoint" in the current working directory makes it really easy to start or back out of big changes, and it can be very useful to check back in past WIP commits to grab segments of code you previously threw away.
Stashes are just another form of DAG node with their own special syntax and commands and quirks. I've already learned one set of commands for all that, why learn a second, less general set of commands?
I have started using stashes in one very specific case:
1. I realize I'm on the wrong branch 2. I've made no commits 3. The right branch has changes to files I've modified
git stash push
git checkout -b newbranch upstream/right
git stash apply
...verify...
git stash list
git stash drop [id]
Careful and safe, but not actually much faster than my old workflow, and I haven't the foggiest idea how to fix things up with stash if I've made several commits, if that's even a thing. git checkout -b dead/wrong
git add -A .
git commit -m "WIP"
git checkout -b newbranch
git rebase --onto upstream/right upstream/wrong
...verify...
# optional
# git branch -D dead/wrong
# git reset --soft HEAD~1
Depending on if you count the optional commands, that's one more or one less command. "Those aren't optional!" you might say - but yes, they are. I'll often merely amend my WIP commit into a real one instead of resetting. I'll often keep dead branches long term - perhaps some of my work relied on things that haven't landed on upstream/right yet, and can't be brought over sanely until upstream/wrong lands on upstream/right, or just for peace of mind that I might've forgotten something. Good dead branch names makes this less painful than... numbered stashes? Eww, gross.I like making all my commits “canonical at all times,” but that’s just something I can see it’s time for me to evolve beyond.
I find the power of the stash in "stash pop", which applies, and drops if there were no conflicts:
git stash push
git checkout -b newbranch upstream/right
git stash pop
and yeah, if your keep your branches long-term stash is not a good solution for this.The advantage of stash is that it's quicker and easier than creating and cleaning up branches. If you're naming stashes and keeping them longterm, then you're basically using them like branches and should consider what benefit you're getting from adding a separate workflow.
Sometimes those botched mergeds have been due to my own incompetence, sometimes due to P4Merge literally corrupting my file and saving out something totally different than what I'd resolved, and sometimes due to unexpected refactoring between branches causing enough of a mess that reapplying the work by hand is easier than "resolving" the conflict.
But what I'm not doing is saying "you should always use stash". I'm providing use cases, for me personally, where stash is the correct approach.
"Ah", but you might be inclined to argue, "such and such a reason". Yes, but also no.
Right tool for the right job is also an argument for competency and context. Sometimes a hammer is useful for more than just hammering, but very rarely.
The point is there is usually more than just 1 approach, and niche/edge cases can be real nasty if approached with the attitude that everything is a nail
They are for short terms manipulations, but it's easy to make mistakes with them and lose data (dropped stashes don't show up in the reflog for instance).
Things to be preserved for longer should be committed and saved in temporary branches.
Er, no. Stash does not return to a clean working state. Stash stashes modifications, not new files. And it makes a real mess if those new files happen to exist on another branch you want to check out.
Stash seems like a half-implemented feature tbh, if only for the infuriating limitation above. It's really just not safe to use.
https://www.atlassian.com/git/tutorials/saving-changes/git-s...
"One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision."
-Bertrand Russel
Er, no. Right tool for the right job.
Yup. pull --rebase --autostash for example. Technically also stashing, and would be insane not to use it :)
More serious note: agreed. I use stashing multiple times a day and never have problems with things being messy. Though I admit I usually look t stashed in a gui, not from the terminal.
> right tool for the right job
I'll give you that this is (slightly) ambigious. But here's the gist
>you can safely ignore the opinion of anyone who says "never do X"
There are lots of alternative tools listed in this comment tree.
Stash has a purpose. You should know what that purpose is. A tool is only as good as its user
I’d be willing to bet they sometimes, even if rarely, use stash when as you say it’s the right tool to use.
I think the point is not stashing meaningful amounts of changes, as if they can be recalled later. Sounds like solid advice that requires some discipline
Of course, not every project is the kernel and to each their own, but I find it's useful to know how git is used in the project for which it was originally made.
[0] https://www.mail-archive.com/dri-devel@lists.sourceforge.net...
[1] https://www.kernel.org/doc/html/latest/maintainer/rebasing-a...
> When merging fixes and features into master, we avoid merge commits and use rebases and fast-forward as much as possible.
Rebasing feature branches, and avoiding non-ff merges has been the best change I've ever made to my workflow. Makes it very easy to keep a clean, readable history that is actually useful when doing code archeology months later. Resolving conflicts is far easier than via merging too.
* It's clear which states master has actually been in, without having to resort to squashing each merge into a single commit. This means that you know which commits actually passed CI and are therefore good rebase targets. People often claim that when merging multiple commits each commit should individually pass CI, but that's almost impossible to achieve in practice.
* Development can split single features into multiple commits for easier review and understanding later. This can be particuarly important if the changes depend on each other, but different people need to review different parts of the overall change. That's another thing that most tooling is really bad at.
* The history is basically linear. The merge commits are all empty, and there is one linear history for all the states of master (the first parent of each merge commit) and one linear history for all the individual commits (the second parent of each merge commit and only parent of each non-merge commit).
Of course this approach isn't well supported by mainstream tooling (e.g. GitHub) and probably requires a custom bot to do all the rebase-and-merge operations. It is pretty well supported by git itself, however.
We use it in our organization and between us we know to always manually rebase before merging. However, when we receive an external PR from someone else it's a pain. It's also easy to accidentally forget to rebase before merging.
[1]: https://docs.github.com/en/free-pro-team@latest/github/admin...
[2]: https://docs.github.com/en/free-pro-team@latest/github/admin...
o-o-o o-o-o o-o
/ \ / \ / \
o-------o-------o-----o
We like doing that because, as the grandparent poster said, it clearly delineates the point where each PR was merged. AFAIK, the Gihub option to require a linear history assumes that you would want to flatten all the commits without any merge commits at all: o-o-o--o-o-o--o-oThis will "REuse REcorded REsolutions" of conflicted merges.
Once enabled, it will record how a merge conflict was resolved, and replay it back the next time it encounters it. Saves a lot of time in cases where you already solved the merge once before.
You end up doing a lot of conflict resolution when rebasing, increasing the chances that you make an error.
And if you do make an error during conflict resolution, there will be no record of it because you've rewritten history.
We stopped most rebases for this reason, and just do normal merges. Conflict resolution is easier, and if we do make a mistake, it's at least documented in the history, and it's easier to fix.
Git is decentralized, and works kind of like a blockchain. With Bitcoin, the foundation is that everyone share the same history, no one should be able to rewrite transactions. I expect the same behavior from decentralized version control systems.
And if you make a mess, too bad, it is here to stay. It is ugly, but it is what really happened.
If it really is a huge mess, call the admin so that he can fix the thing, notify everyone that the history has changed, and have your name added to the hall of shame.
But that's a personal opinion. I know some people prefer a clean (but fake) history over a messy (but true) history. Continuous integration tools tend to like clean histories for instance. You can even have both system coexist. A messy/true history branch where developers work and a whitewashed version running in parallel for integrators.
I wonder if this is an exaggeration, or if the author truly has that git-heavy of a workload?
Assuming you're working an 8-hour day, that's 480 minutes. If you're issuing "several hundred" git commands, I'd take that to mean a minimum of 300. So that's a git command every 96 seconds. When do you have the time to write the actual software in between all of those git commands?!
git add .
git commit -m “update”
git push
Although if you’re doing it that often I’d want to set up .bashrc to condense it to a single command.
So, an individual commit can easily hit 5 commands. I always do a `git status` before and after (2), plus maybe a few git adds (2), the commit (1), then potentially a push (1). That's already 6 commands for each commit. In a day I usually do approx 15 commits(±10), as well as re-bases. That's around 90 git commands just for committing. Through in a few rebases, a fetch, and an amend, and you're easily over 100.
The quoted OP said "several hundred" commands. Just with commits on a pretty typical workflow, I'm at over a hundred. It doesn't surprise me that someone could double it.
I often wear the hat of the "git expert" on a project, and there are some days I'm doing significantly more than just commiting and pushing code too. I have a lot of extra commands I'll run like `git log HEAD..@{u}` which shows the diff in the logs between my current branch and the upstream. And I use `git diff --cached` pretty heavily. Git blame is also invaluable when debugging. These tools don't take a way from actually writing software, they enhance it.
Is certainly key. Most git frontends seem to be really quite bad for many reasons. Though "Push failed, want to pull, merge and push again? [Yes]" => constant "merged ssh://upstream.server/foo/bar/repo.git merged into branch master" commits being added to the history certainly irks my OCD the most. These frontends also seem to try and hide what git does, which leads to incorrect and confused mental models and much more frustration down the line than just learning to do it the git way directly. Yes, git is a "my way or the high way" tool, that's not great or something to emulate, but it is what it is. Trying to work around that only results in more pain.
Only use the git command line, use gitk for browsing history graphically if need be, and git-gui for preparing commits. git-gui seems to be the best GUI for making commits (and is probably written in Perl with Tk).
Logical conclusion from "only use the git command line": Also never make a dirty merge from your web browser.
I never understood why people feel the need do this. If you are working on a bug or feature, why put unrelated changes in that branch? It only creates confusion and probably messes up your tests too. And for what? It seems like a chaotic way of working to me.
You know what, typing it out I can totally see why people do it the other way. A matter of personal preference probably.
Once it's done I will split the changes into commits that make logical sense, for someone wondering how the new code changes the behaviour of the existing code.
It has great discoverability while at the same time being an amazingly streamlined power user tool.
In other words, there can be great git front ends. It's just that most of them suck, usually because of a desire to dumb down the git UI. If you don't do that, and accept Git's complexity it can work out great.
It also helps to provide sane defaults, for example -f being force-push-with-lease instead of a regular force push when pushing.
Therefore, I use the GUI that comes with Visual Studio Code and the "Git Graph" plugin.
I work with juniors, which for some reason always want to do things in the command line. A lot of times I have to help them out with git issues, and can always to that using the GUI. When I see them work in the command line, it's always so slow for them to type in things.
Want to switch branches? Click lower left and select your branch. Want to sync with server? Click lower left on the sync icon Want to commit? Just type your commit message and CTRL-Enter. Stop wasting time adding files on the command line. Want to prune your origin branches? Click on the Git menu and prune pull.
For this last one, I always need to look up the syntax when doing it on the command line.
Git is already complex enough (compared to SVN), so if you're junior, for god sake use the GUI menu!
I have had precisely the opposite. Junior Devs using the GUI ( in VSCode ) but breaking things badly.
And then I have to help them out using the command-line
My juniors get stuck on the command line and then contact me :).
So maybe it is indeed better that they use their limited knowledge of the command line ;).
One guy kept having to comb through dozens of local branches that had since been deleted from GitLab because he never pruned any of them. Fortunately, this is the most common type of breakage or mess - one that only affects the developer locally, because we protect the master branch on our server and use pull requests.
In VS Code I only have to know `Ctrl+Shift+P` to use their git "GUI" (if you can even call it that). One thing I like about it that you don't get with the cli (out of the box) is an instant overview of all the available commands without having to type much or switch views.
The juniors where I work have also been brainwashed to use Macs which they struggle with; mostly due to the bad window management, non-discoverable features and their lack of will to spend any time learning their tools deeply or customizing them. Meanwhile, I've been using Linux since the start of my career in the late 90s, I learned the basic Git flow over 10 years ago and have almost never had to use the git cli in that entire time while churning out hundreds of project.
You don't even need to know that; the operations are available through a fairly straightforward, reasonably discoverable GUI, without using the command palette, which has a nice heiriachical structure.
OTOH, neither of those paths is much good if you don't already understand the semantics of git operations.
You can also do merge by dragging branches in the GUI which for me lowers the risk of taking the wrong branch. And it has a nicer looking interactive rebase than the command line which is very good for beginners.
This bit resonated particularly:
begin quote
Never merge with GitHub!
There’s a button GitHub that says “rebase and merge” that could theoretically be used for merging pull requests. I never use that (and if I could, I’d disable/hide it). The reasons are simply:
I don’t feel that I have the proper control of the commit message(s)
I can’t select to squash a subset of the commits, only all or nothing
I often want to cleanup the author parts too before push, which the UI doesn’t allow
end quote
Not being able to selectively squash and edit the multiple commit messages is a big missing feature in my workflow.
But this comment will just descend into a dull, tedious flame war. I don't care. git merge is totally fine.
It feels like not a simple thing to explain.
As an example someone sent me a PR with 15 commits. github claims only 1 file has changed and it's a new file so no conflicts (which AFAIK is correct) but git complains that somewhere around commit 4 there's a conflict.
The person sending the PR is not git comfortable, otherwise they wouldn't have this PR with 14 old unrelated commits showing up.
I have no idea what state they are currently in as well. meaning, I know the state of the PR but I don't know the state of their local machine.
I can clone their branch and make the merge myself but their next PR will just be the same branch they continue to work on.
Explaining to them how to fix what they have and how to proceed going forward seems like it requires a very large reply. Several pages. (here's how to fix this PR, this how to fix the state of your main/master branch, here's how to make different branches, here's how to update after each PR, here's what to do if the conflicts are real, here's what to do if you haven't made any more changes to your main branch., here's what to do if you have already made changes to your main branch.
I have no suggestions for solutions except to try to point them to other articles/pages/tutorials on the web
That sounds like a rebase merge, which might be the setting in the repo. A normal merge wouldn't attempt commit by commit.
> Version control is an underrated skill. Most software engineers use it daily, and yet, many are not willing to invest more than necessary to learn it. That’s fine, but knowing more than commit/push/pull will at least make you more efficient. It will also help you solve issues you (and your colleagues) may encounter.
I've had this issue a lot in the past, but mostly at work. So yes, I will spend the time to help my colleague debugging their issue. Eventually, they will get fewer issues, but the time I have to spend for their "learning by doing" would have been better invested in learning Git fundamentals.
I've also had some open source contributions during Hacktoberfest, and I went with the easy way out of doing the clean-up work myself. But as you've stated, people might not learn from this, so that's not optimal.
I often have interdependent branches (large pieces of related work chopped into small tasks) and take my previous branch along in my new one, this leads to an order in PRs sometimes when a big tasks is followed by a small/fast one. Sometimes I think, come on team, pick up my PR!
This is so true, if the automatic detection of the PR merger vs. closure is hard (and I can see some reasons why) there should at least be a switch for maintainers to update the outcome message.
This UX-flaw is why I'm currently "forced" by my coworkers to use the buttons on GH. My git merge-scripts have some "cleanup" which I now need do manually (and thus get forgotten) for example.
https://github.com/lyze/posh-git-sh (bash)
https://github.com/dahlbyk/posh-git (powershell)
Besides displaying which branch you're on, it also shows changed, added,... files and other useful info
As long as you're the only one modifying the branch, rebasing works nicely.
In a team environment, somebody always insists on using rebase and then invariably they push a rebase to master and hijinks ensue. I wish there was a fork of git with rebase disabled.
I am mostly using the Git history when going through past changes. Why does this line do X? I just git blame this line and see exactly what happened. This is the time I really hate all those "oops, fixed mistake" and "forgot this change" commits. I don't care about those things, even if it's the "truth". They're just useless and distracting. Doing an amend/rebase/squash would have been perfectly fine in such a scenario. I have written more about rewriting Git history here [1].
> In a team environment, somebody always insists on using rebase and then invariably they push a rebase to master and hijinks ensue. I wish there was a fork of git with rebase disabled.
That's why shared branches like master are usually protected, so you cannot push an alternative history.
We never squash when we go into master either.
A few utility commands and a most important safety net against git reset --hard throwing away work.
- double quoting the command expansion would lead to `brname` being executed once at shell startup (unless this assignment is happening in a `PROMPT_COMMAND` function or something[1]).
- A literal backslash before the dollar sign gives a "#" at the end of the prompt for root.
[1] https://gitlab.com/victor-engmark/tilde/-/blob/4dc4077a19250...
I used to like tabbing over to terminal to run my git commands and do my diffs.
Now I use the git flow plugin and do my full process including amends, push, etc interactively.
Much of it can be done by keyboard and the closeness to the auto linting and reformatting has caught many small errors, left behind little items and generally improved code quality greatly.
While I agree with the spirit of this comment, in practice I do this:
1. Update:
git pull --rebase
2. Clean up my commits: git rebase -i HEAD~X
3. Push: git push origin BRANCH -f
4. Merge in GitHubWorks pretty well for me. That being said, I would love to be able to take care of 2 and 3 within GitHub for branches that are already updated to the parent branch.
I agree, it's pretty vanilla git usage. I was curious to see any insightful take of whimsical twist, but it boils down to a basic take of good old git flow, which is git 101 for a long time.
https://nvie.com/posts/a-successful-git-branching-model/
The only surprising thing in the article was the refusal to use git stash, which can't really be explained on a rational level.
It is one of the more standard workflows, and it's a concise overview of how the maintainer of curl does their job.
For a more complex workflow, I recommend reading the notes from the maintainer of the git project [0].
I fail to see how that is relevant. I mean, the only possible impact that has is if individual commits within a feature branch are recorded or not, which is arguably irrelevant. You wouldn't get a different workflow if instead of reading you simply did a squashed merge.
> It is one of the more standard workflows, and it's a concise overview of how the maintainer of curl does their job.
It's gitflow, and leaving out feature branch commits doesn't make a difference.
Look at any post on git-flow (or even just the original [0]), and you will see a myriad of merges.
Quoting the original git-flow post:
> When the source code in the develop branch reaches a stable point and is ready to be released, all of the changes should be merged back into master somehow and then tagged with a release number. How this is done in detail will be discussed further on.
The examples further on all use `git merge --no-ff` (ie no fast forward).
This is very different to what is described in this post:
> When merging fixes and features into master, we avoid merge commits and use rebases and fast-forward as much as possible. This makes the branch very easy to browse, understand and work with – as it is 100% linear.
So no, this is not git-flow.
[0] https://nvie.com/posts/a-successful-git-branching-model/
Your statement makes no sense at all. Gitflow is a workflow. What do you believe it's supposed to be? It's irrelevant how you see commit histories, because with regards to the master/mainline branch it's always linear, isn't it?
What do you personally believe gitflow is?
> Quoting the original git-flow post:
I don't know what you expected to show, but you are only describing a workflow. Changes are made in dedicated branches, and later these changes are merged back into the master/mainline branch in a single commit, which is expected to have been validated and tested and working. That's a workflow. How the log ends up looking is entirely indifernet or irrelevant, isn't it?
Again, what do you personally believe is the whole point of a workflow like git flow, specially in light of allowing large teams to continuously integrate their work ? I mean, what do you believe is the whole point of getting devs to work on branches independent of what changes go into master/mainline, and leave merging as a last step that's the responsibility of the developer prposing a change?
I guess that first sentence should have been "I don't know what you think git-flow is, but it does not produce a linear history" or soemthing like that.
The history is very much not linear in git-flow, and for good reason - but it makes things more complicated and most people don't need it.
If, as you can find examples in other parts of thread, you use rebase-and-merge with git-flow you end up with something very similar to the methodology used in the article, but it is still different.
One of the main downsides to the featured method is that it's not clear which commits "go together" from the git history - you have to look at the pull requests in github. With git-flow, or rebase-and-merge, you always have a merge commit that lets you distinguish between commits that are 'releases' and commits that are part of a series.
So that is the key difference - the structure of the git log.
The article describes a pretty standard git rebase workflow that is simple and works well.
I've heard its benefits explained as "more security for the business", while in practice it only leads to extra complications and accomplishes nothing a git tag couldn't.
With that said, I don't think this need is particularly common. Most projects are happier to throw away merge history in favor of a linear history with ephemeral branches and semantic versioning, and that's perfectly fine. The repository layout should be dictated by the project's needs, be it a glorified personal Undo Log, or a management tool on top of a Subversion repository.
The main feature of git flow is having multiple redundant branches for no reason. Namely a separate develop and master. There is no point of that at all. Look at the diagram, move all tags from master to develop, delete master and rename develop to master. There, you now have the workflow you've described without redundant branches.
This statement is simply wrong and ignorant.
The reason why mainline and develop branches exist is due to the fact that production-ready code and unstable code are not the same ops-wise.
Nowadays, with the dissemination of CICD practices, that difference has been shifted away from the source code repository and into the Delivery/Deployment phase of a CICD pipeline. Yet, the overall principle is the same, and arguably its still here. Calling those differences "redundant and for no reason" is just ignorant at multiple levels, from software engineering to the fact that the sofware lifecycle process for commercial software projects, the kind that had to "go gold", had very specific requirements.
https://www.endoflineblog.com/oneflow-a-git-branching-model-...
If you can tell me something GitFlow buys you which OneFlow doesn't, I'd be very intrigued.
I see no relevant difference between that workflow and GitFlow, besides the rebranding of old concepts and some unexplained focus on merging options.
I've also revisited the author's old rant from 2015 regarding gitflow and the only tangible criticism he had was the separation of the master/mainline and development branches, which is extremely shortsighted and miopic as it fails to acknowledge the reality of non-CICD/old-fashined software release lifecycles.
GitFlow has one main concept: using feature branches to do develop work, use release-specific branches to integrate changes, establish and enforce upstream/downstream relationships between branches. The rest is just rebranding and nit-picking over semantics.
If you want to add a complex feature to a project, you could do it via several branches, one after the other. For instance, the first branch could introduce a feature flag and the second branch implement part of the new feature, and so on.
If you're working in a large codebase and the function in question is part of your API, don't mutate it, add another function and deprecate the older function.
In any case, either developer A or developer B has to pay the cost of mutating the function at some point.
Maybe it's PEBCAC, and to be fair it is documented[0], but the big red warning in the docs is missing from the page where you actually do the action. To make it more confusing there's also a disabled 'Merge pull request' button that implies that resolving the conflicts and merging the PR are separate actions
0: https://docs.github.com/en/free-pro-team@latest/github/colla...