I actually popped on the git development irc channel a few months ago to make this suggestion. The two people I talked to (at least one of whom seemed to be a core developer, although I did not verify this) did not see how, if you're going to conflate the actions of creating a branch and checking it out, it makes more sense to do this as a flag on the primary action, branch creation.
They were nice enough to have an in-depth conversion with a complete newcomer, though, so it was not a negative experience overall. Maybe someone else could convince them :)
That said, I do vaguely recall this seeming weird at first.
---Succinct argument---
What happens if you remove the flag? Put differently, how much does the flag change the semantics?
`git branch newbranch` will gracefully fall back to creating a new branch at HEAD.
`git checkout newbranch` will fail (error: pathspec 'newbranch' did not match any file(s) known to git), because the regular version of the command involves operating on something that already exists.
---Less succinct further argument---
checkout's `-B` variant. Here's how the man page explains it:
> If -B is given, <new_branch> is created if it doesn’t exist; otherwise, it is reset. This is the transactional equivalent of > > $ git branch -f <branch> [<start point>] > $ git checkout <branch>
If it were a flag on branch, you wouldn't need a separate flag, just `git branch -fs newbranch` (-s for --switch).
Actually, looking through the man page for `checkout` now, I see 4 other options I didn't know about (-t|--track, --no-track, --guess, --no-guess), apparently for the sole purpose of being used with -b.
---
I don't think I thought of this argument when I originally chatted in #git-devel, maybe I'll give it another try.
Thank you for the edit; this is where our mental models diverge. Yours is the technically correct version, but when I'm working, I introduce a small abstraction on top. I've never written this particular part out explicitly, so please bear with me and feel free to suggest better names or phrasing.
I'll call it, "the checked-out branch" (or other <tree-ish>, but let's leave out detached HEAD for simplicity). It's like your model, but also includes the state of the repo at that commit. This is a really subtle difference, but the key is that checkout is one atomic operation.
I think the easiest way to explain is by analogy[0] to editing a regular text file. You've got the file on disk, and the version in your editor's buffer (working tree), and every time you save, you're making a commit (with `--amend`, on most filesystems). When you decide to edit a different file, and open it, technically there's two independent operations -- switch which file handle you're writing to, and replace the contents of the buffer with the contents of the new file -- but I seldom think of it this way (and I can't think of an editor that separates them).
This is also why I don't like overloading with `git checkout <commit> -- <files>...`, which does not update the HEAD. It shatters the "open file" analogy; it's like changing the contents of your buffer without changing which file you're writing to. In my mind, that's a totally separate function (typically accomplished by opening the other file separately and then copying its contents into the buffer, an inefficient operation that I'm grateful git provides a better alternative to).
Aside, I also prefer to think of each branch (not commit!) as having its own persistent working tree and staging area; I'd prefer not to have to push and pop a stash each time I check out a new branch if I already had some work in progress. `git worktree` comes close, but lacks the ability to navigate between worktrees but stay in the same directory relative to the root, like `checkout` does. Also you have to initialize other worktrees with a different root, which pollutes the file system or forces you to use an extra level of nesting.
It's been on my list of projects for a while to write a git porcelain that works the way I'd like, but it's pretty low priority (despite my complaints, git works pretty well for me), so I doubt I'll get to it for a few years.
[0] Come to think of it, maybe "analogy" is not the best word. It's more like, I prefer to view git as an extension of my filesystem, so I want a consistent mental model across the whole thing.
It seems like the conflict is that there actually are some separate things going on "under the hood", and you're not satisfied with the way that git has combined them? To be explicit, some distinct steps we're discussing are:
1) Update the working tree to match the tree-ish
2) Create a new branch
3) Update HEAD to point at the branch (or other tree-ish)
As is currently implemented, "git checkout somebranch" does 1 and 3, "git checkout somebranch -- <files>" does just 1, "git branch somebranch" does just 2, and "git checkout -b newbranch" does 2 and 3. AFAIK, there's not a "git branch" argument that causes it to update HEAD, but the standard version of "git checkout" does exactly that. From the perspective of a new git user, maybe "git branch" is the obvious command to look at for making and using a new branch, but I think "git checkout" is the obvious command for using a branch.
So, perhaps "checkout" could have a better name; maybe "use" or "work" instead?
I must admit that I don't understand what you mean by "state of the repo at that commit" - is that related to the idea of each branch having a persistent working tree and staging area? When I run in to a situation where the second would be relevant, I tend to do "git commit -am WIP" then on return to that branch, "git reset HEAD~1". It very rarely happens that I'm in the middle of composing a commit (staging things) but need to switch to a different branch in the same project, so it doesn't really matter that the staging area and working directory all got munged together.