I'd rephrase and simplify this article a bit.
`git switch` and `git restore` are better alternatives to the `git checkout` command, as they have a lower cognitive overhead and fewer footguns to avoid. Although these commands are marked in the documentation as experimental, they work extremely well in practice. Experimental in this sense means that these may gain or lose behavior over time, not that these commands are unstable for use. As a community, we should use `switch` and `restore` commands rather than `checkout` when documenting / teaching git so that newer users start with a greater ability to reason about how the commands affect their workflow.
For more about the introduction of these commands and the details of the above see https://github.blog/open-source/git/highlights-from-git-2-23...
Less sensational, but also more concise and more direct.
I feel like the value of changing from `git checkout -b` to `git switch -c` is not worth the cognitive overhead of making the change.
Not to mention the official docs for "switch" still state "THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE."
I felt that way about the master to main debacle, but some angry people online won anyway.
I made that exact thought many years ago and came to the direct opposite conclusion. It was worth the cognitive overhead to make the change and I haven't looked back. Most of the time I'm just hitting aliases (from OMZ's git plugin) https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/git e.g.
gsw git switch
gswc git switch -c
gswd git switch $(git_develop_branch)
gswm git switch $(git_main_branch)
Do people really type these out, instead of just making a bash alias?
Checkout is fine; it makes sense when you realize that the entire point of checkout is that it updates your current working tree to whatever you instruct it to. What "whatever" is: it's anything that git can understand as a reference; branch names (including those on remotes), commit IDs, HEAD and offsets (carets) on top of any of them.
ie. If you do "checkout master" it will checkout your working tree to the master branch. If you do "checkout HEAD", you get whatever's the current HEAD of your repository (in practice, this discards your changes).
Checkout can also do a partial checkout on a specific part of your working tree; "checkout [filename]" makes it so that you update that specific file to how it is on whatever you point it at.
The only weirdness is "checkout -b [branch]" making a new branch and switching you to it. It's a bit syntactically off/breaks the previous thing, but makes a lot of sense when you realize that your average workflow will combine git branch and git checkout anyway (since you're pretty much always making a branch to them work on it.)
Git switch and restore both feel like syntactic sugar that doesn't really help enough to warrant the mental switch of going from checkout to switch/restore. (Not to mention that checkout and restore do different things; restore also merged some functionality from git reset, a command whose main purpose is to update the index.)
git checkout is not fine.
git checkout <commit> requires a clean working tree, and will change HEAD to the specified <commit>.
git checkout [<commit>] <paths> does not require a clean working tree, will replace the specified paths (i.e. files or directories), and does not change HEAD.
These are extremely different behaviors. I agree with the article that git switch vs. git restore are better replacements.
Since you bring up the topic of git reset, I also disagree with what you said; I don't think its main purpose is to update the index; rather, it is to update the current branch's pointer to an arbitrary commit with the possibility of orphaning children (unlike git commit or git merge, which never lose children). Factually speaking, git reset can update just the branch (--soft), the branch and then index (--mixed), or the branch then index then working tree (--hard). Of course, if you perform git reset and stay at the current HEAD commit, then you have the choice of updating just the index, or the index and the working tree.
can't upvote this enough. the only (minor) issue i see is the checkout -b shortcut feature is unnecessary and could be confusing if learned before a canonical approach that emphasizes that those are two things - checking something out to the working tree and creating a named branch pointing at it.
other than that, contrary to sibling comments, no the rest of checkout is fine. yes it has guardrails that are perhaps not 100% consistent, but i don't think they every could be. but guardrails or not, when you say `git checkout <versionish>` it trys to checkout the <versionish> version to the working tree. it's highly intuitive that `git checkout <versionish> <filename>` it doesn't do the whole tree, but only that file (excellent for reverting a single file).
i don't want git checkout to be called git switch or any other nonsense. git checkout checks out a version and that is terminology common with just about every cm tool ever.
git reset is a hot mess. the blog post should be about that mess, not checkout.
Some things bug me in checkout; it should never have had a -b option so that it does "git branch" things along with checking out. It was probably done that way because early in Git's development, there was a lot of fuss about it having light weight branching, and what looks even more light weight is when you can instantly create a branch and switch to it with one command.
There is a consistency in checkout and reset.
Both checkout and reset can be whole or partial (terms I made up). Partial checkouts and resets specify paths. Whole specify at most a revision.
The checkout operation updates the indexed and working copies of files to be like what is specified in a given revision.
- A whole checkout to another revision, if it succeeds, will update the working files and index to what is in that revision, and move HEAD to it.
- A partial checkout updates the specified files, working and index, to what they look like in the given revision, without moving HEAD.
- A whole reset to to another revision updates just the index to that revision, and moves the current branch and HEAD to it. Working files stay the same.
- A partial reset updates the index entries for the specified files, to the given revision, without moving HEAD or branch. Working files stay the same.
There are obviously more details, due to various options like reset --hard and so on, plus considerations of what happens with a dirty index. But that's the basic paradigm:
(starting with clean tree)
checkout reset
whole moves: HEAD moves: HEAD and branch
updates: working + index updates: index
result: clean result: working diff, nothing staged
partial moves: nothing moves: nothing
updates: working + index updates: index
result: working diff, staged result: working diff, opposite change staged
The basic consistencies are:- the partial operations don't move the HEAD or current branch in both cases; the whole operations do move HEAD or HEAD + branch.
- whole or partial checkout updates working + index.
- whole or partial reset updates index.
Wholeheartedly agree with this suggestion.
I don't think I have used the incomprehensible `checkout` command once since I learned that `switch` and `restore` exist, and the previous years-long state of perpetual low-grade irritation I had felt toward git has diminished accordingly.
What do you use for navigating in the branch history when doing a git bisect? Can you use switch for that?
> … the only way to really understand deeply how git checkout works, you have to fundamentally understand the internal workings of git.
This is, and always has been, the primary UX problem with git. You use commands to manipulate the program’s model of the data, rather than to demonstrate your intent. It works only as long as your mental model of git matches git itself, but it doesn’t easily afford abstraction, and abstraction is the essence of efficient manipulation.
Put another way, a good tool allows you to use it well even if you don’t understand how it works. Git OTOH will quickly punish you for not understanding its model of the world.
A good UX for git would maintain the complexity for experts and provide a clear and simple surface area for most people who just want to perform familiar tasks. The fact that each person and team seems to have a unique incantation just for everyday tasks is an awful smell, and a sign of git’s immaturity.
I must admit that when I first learnt git, I thought that the only way to correctly use git was to know the object model of git. I thought this was important because git is at the end a data manager and I then though that one should know the data model you are manipulating in order to manipulate it in correct way. In that respect, I always found git commands mostly intuitive.
Much later in my career I learnt that people were using git without even knowing anything about what a Merkle tree is and I must say I was extremely surprised. I'm not saying its good or bad, just describing my younger days.
The article writes:
> they had not asked me to explain git, they had asked me to explain GitHub
This is often the case for me as well.
Hey, at least git owns it by calling the shell commands "porcelain" (with git itself being the plumbing -- https://stackoverflow.com/questions/6976473/what-does-the-te... ).
The core value proposition of GitHub, GitLab, etc is to provide a nice GUI atop git. That's huge. I think that user-studies to improve one of the many existing foss git GUIs would be much better use of brain than deprecating git checkout.
What should the ui layer atop porcelain be called? Gilding?
checkout is one of the few git commands that makes sense to me. I use it a lot, to get back to a known state, after I screw up my working files with other git commands. E.g.
Copy my changed files to a temporary directory.
Delete my working directory.
Checkout the latest version from the repo.
Copy my changed files back.
The article says that git checkout confuses things that could be better accomplished with one of (git restore, git switch, git reset)
What you're doing sounds like git reset/git switch would be fine. I think I'm in favor of what the author suggests, conflating switch and reset/restore seems bad. It's going to take some effort to fix my habits though.
Use `git stash` instead of copying files around manually to save yourself some time.
The one bad point about checkout is that is one of the few git commands that can destroy data irretrievably, even without --force or -f or so. That is unexpected behaviour.
What you want is 'git reset --mixed'
I am so deeply pissed off at people who look at some completely useful, universal, widely-used-for-decades canonical command that's at the center of tens of millions of manual and automated deployments, picks out some esoteric details they decide are important and then proclaim, "OK when can we deprecate this debacle?" People who think you can just point "DEPRECATE" around at anything that they've decided is distasteful like a magic wand show their deep inexperience in tech as well as life overall and have no business making such proclamations.
Conversely, it's an exceptional way of getting a highly engaging discussion. It's meant to elicit an emotional reaction and get people to read their article. I don't think they made any convincing arguments to actually deprecate the command, but highlights the complexity of a command that thousands of people issue on a daily basis without thinking about it.
I'm surprised no one has mentioned what is in my mind the cardinal sin of checkout: the parameter can be either a path or a ref and it automatically infers which one you mean. That's magic and relies on your ref namespace and your file namespace not conflicting (of course you can be explicit but no one is)
I think if the "only operate on certain files" mode of checkout was a flag, it would be much less confusing and easier to explain and we never would have gotten into this mess to begin with.
Hm. It doesn't look like git checkout does "too many things" or is overly complicated. It does one thing basically, which is changing the files in your working directory. It can work on single files or on the whole working directory, and it can optionally shortcut the creation of a new branch.
Then again, until today I never knew about "git switch" so I, too, learned something today :)
The problem is that it doesn't just change your working tree, it also (sometimes) changes HEAD. So the two behaviors both work very differently and are intended for very different use cases.
Maybe I am a rube, but people bemoaning "complexity" of git just never strikes home with me. I started using it when I was 14, so maybe that is it (it was still fairly new, but it's all I've ever known) - I still only use a handful of commands.
git checkout, git checkout -b
git pull
git merge (mostly to merge master back into a development branch, or something like that)
git push
git restore (much more rarely)
git reset (even much more rarely)
Barely ever have I had to do anything but these for 99.999% of my workflow, and none of them seem particularly complicated unless you run into merge conflicts, but on every team there seems to be at least one pro "merge conflict" guy. Idk. Checkout is occasionally annoying when it forces you to stash unrelated changes to what you're doing, that's about all I can come up with.
I’ve found that people are either die hard rebase fans or die hard merge fans. Neither side can understand the other and I’ve never had it properly explained to me what the difference is or why I should care.
I think everyone needs to know the existence of git bisect. That has the side effect of improving individual commits as you'll make sure whatever functionality they implement is atomic.
Amen brother haha I have not evolved at all in my git usage and it hasn't really hurt me in any way.
Its not really part of the job to deal with 'insane merge issues', or crazy git tricks and things, only once in a while...
Also, rebasing is so confusing at least in the cmdline sense, I don't see the point.
This isn't about complexity it's about git putting multiple commands into one and potentially doing stupid things as a result. (Even though I don't think I've ever actually had a problem where I said "git checkout <file>" and git interpreted it as a branch or vice versa. I mean, that happens but I think in every instance no such file/branch has existed so git did nothing.)
In any case, I think checkout does in fact conflate things that should be (at least) two separate commands. That's not "less complex" it's about having more predictable behavior. And arguably it's more complex than the status quo.
have you ever worked with other people on the same project? or Gerrit?
There's really nothing simple, quick or logical about Git when you need to do things like:
copy some files from another repo into yours while preserving file history
copying files within a repo while preserving file history (if you just copy+paste you lose, if you edit the files after moving with git mv, but before comitting the move first, you lose all history)
deleting 1 file from all commits in a repo (almost impossible without using an external non-git tool)
dealing with a rebase that was pushed that shouldn't have happened
I could go on and on with examples of things that should be trivial but aren't.
It seems you don't think it's complex because you only learned a bunch of commands, and do basic things
And I'd bet you have little familiarity with its documentation, which in itself is one of the worst I've ever ran into.
The fandom around it, furthermore, with most saying it's awesome to not admit that they don't know it, makes things much worse
The most important one is
git rebase
Never have I read Git Pro or have the deep understanding of git’s internals. But I use checkout almost every day, as a shortcut to create a new branch and switch to it, throw away changes that I don’t need and…well, that’s pretty much it.
Now that I have read this article half way, I decided to stop. Because I am learning a few extra things that’s kind of messing up my mental model of what that command does. I think a fair % of git users might be in my boat. Our knowledge, hence our burden is limited.
So community might not be as confused with checkout as the author or those who grok git.
I wanted to stop using git checkout, so I set up a little .bashrc magic to prevent me from calling 'git checkout' and to suggest which command I should be using instead. Here's the script:
# Paste this snippet into your .bashrc to help you learn `git switch`.
#
# Turn on the extdebug mode so that our `scold_git_checkout` can prevent
# us from running git-checkout by exiting 1; forcing us to re-learn our
# muscle memory.
# If we *really* need to use git checkout for something, we can do that
# by using the full path to the git executable e.g.:
# /usr/bin/git checkout # isn't caught by our scolding
shopt -s extdebug
scold_git_checkout() {
if [ "$1" != "git" ]; then
return 0
fi
if [ "$2" != "checkout" ]; then
return 0
fi
cat >&2 <<EOF
////// DON'T use git checkout! //////
The 'git checkout' command of git has been replaced with two other
commands: 'git switch' and 'git restore'. You used:
$@
EOF
if [ "$3" == "-b" ]; then
PASTESAFE="$(printf "%q " "${@:4}")"
cat >&2 <<EOF
You should use the following:
git switch -c $PASTESAFE
EOF
elif [ "$3" == "--" ]; then
PASTESAFE="$(printf "%q " "${@:4}")"
cat >&2 <<EOF
You should use the following:
git restore $PASTESAFE
EOF
else
PASTESAFE="$(printf "%q " "${@:3}")"
cat >&2 <<EOF
You can try the following:
git switch $PASTESAFE
EOF
fi
return 1
}
trap 'scold_git_checkout $BASH_COMMAND' DEBUG
Gist with this special scold commit hook, should I ever change it more: https://gist.github.com/lelandbatey/b42b527bfa41b761d0aec287...The title and first 2/3s of the article are excessively hyperbolic and it detracts from the message. The title would be improved by adding "in favor of git switch/restore". The body would be improved by leading with the last 3 paragraphs, and tucking the rest under a "why not just use `git checkout`?" section.
I appreciated finding out about `switch` and `restore` as alternatives to `checkout`. But they are minor, incremental improvements. Framing it like `checkout` is the devil doesn't help, because it really isn't that bad, especially to people who consider git as a means to an end.
It's not hard to change to git switch. I used to have a "co" alias for "checkout" which I removed. I'd say I lost maybe 60 seconds of typing time over the few weeks it took to unlearn the muscle memory.
60 seconds of time investment to be better at mentoring the next generation of technologists is worth it.
I haven't used it in a year. That's how long ago I switched from git to jujutsu. jj new is all you need.
I am horrified by the article's last paragraph.
Teach RESET instead of checkout???
The command with the most likelihood to make you lose work, and leave you with permanent errors??
And with the most convoluted usage and documentation?
What is wrong with me that I dont have any problems with this? Maybe it’s how we name branches? I think I’ve only seen a few cases where I use checkout and it complains about being ambiguous.
Huh. I use checkout multiple times a day every day. It's how I switch branches, including creating new branches. I guess I could use other commands, but why change what's working fine?
As much as I conceptually agree with everything in this article... git checkout -b {branch} is not leaving my muscle memory any time soon
The crux of it, and the reason why I see it as a lost cause:
> the only way to really understand deeply how git checkout works, you have to fundamentally understand the internal workings of git.
Thing is, there's no way around fundamentally understanding the internal workings if you're going to use git on the command line.
Checkout and reset can be tough, but for instance reflog also makes no sense if you don't understand the commit model.
Newer user and occasional git users will be better served with a nice GUI. VSCode has extensions that will help deal with the basic operations etc.
The issue to me has never been that commands are cryptic, and more that git isn't made for people enjoying simplicity. For those, an extra layer above git is the best choice IMHO.
I regularly learn and promptly forget about git switch.
I guess that's what 15 years of (near) daily git usage does to you.
can we communally deprecate using monospaced fonts with full browser width content blocks for free form text?
Well, since the author is sharing their pet peeve, I'll share mine and it's unrelated to Git: People that post XKCD without the title text!
Git is not that complicated. If you can't grok git I am seriously concerned about your ability to be an effective software engineer.
Edit: I had assumed the OP was one of the many people I have met who have a Tech Lead title but are not really very technical due to the grandiose request to deprecate checkout. But looking into the blog more I realize that instead the author is more new in their career and I don't mean to be as harsh to someone in that position. Instead to them I would say; when you encoutner something established you don't understand, take it as an opportunity to learn. Git isn't beyond you, it won't take as long to fully understand as you think.
[dead]