`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.
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.
Yes. This warning in the documentation (and the same warning for "git restore") is doing nothing to help the situation. I've had to put a stake in the ground on this SO answer: https://stackoverflow.com/a/215731/893
> [At the time of writing, the git restore command has been marked as "experimental" for at least four years.]
Honestly I have not bothered to even learn switch or restore because of these warnings. If they keep them in after five years, then the commands might be removed in the next version, because clearly there's no champion behind them pushing them forward.
And the few times I have tried to learn what they do, I have not seen any benefit over my current knowledge. So why learn something that may go away and is not trusted even five years and many many versions after deployment?
This goes well with my experience from svn where "svn switch" had a high-enough chance to screw up your checkout that everyone I know just had multiple checkouts instead.
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.
Used to have bash aliases, but nowadays I work on so many different machine, without my dotfiles present, that aliases seem kinda pointless. I'm a fast typist.
I was always using 'co' for checkout. Made the change to switch ('git s') and revert ('git r') and it has been pretty seemless. I do wish 'git reset' defaulted to --keep.
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.
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.
I think you're asking for 'git switch -d' (for detached).
In practice you will still need 'git reset' but only with a branch parameter (all 'git reset -- paths' can be replaced with 'git restore'), usually with --keep, --soft, or --mixed.
That's usually a good thing, setting your HEAD to a symbolic ref or a commit are very different operations. Having a switch makes sense and probably catches beginner errors rather than letting them know afterwards.
I don't feel like typing 'git s -d <branch>' has slowed me down in practice but you're technically right of course (or I would add a 'd="switch -d'"' alias).
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.
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.
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.
Yeah git rubbed me the wrong way from the beginning and I never learned it properly. My way makes the most sense to me. Stash? where? How do I get my files back? None of that is intuitive. I understand my way.
I love git stash, but to be fair, if you've just had Git do something unexpected to your files, I can completely understand why you would not then trust Git to keep your changes safe while you use more Git commands to get back into a sane state! Sometimes simple and well understood is the best way.
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.
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.
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.
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.
Rebase rewrites history to an extent. What I do (and this is also the advice in Pro Git for what thats worth) is use rebase when I'm working in local because its cleaner, but the moment anything ends up on GitHub, I use merge because I don't want to rewrite history that other people are aware of.
I am fine rewriting my own history on local because I know what I did, but not when its on GitHub because other people don't neccecarily know what I did.
I think this nails the difference in my workflow against people that tend to say it is difficult. In infrastructure commit history, which is often tied to CI CD processes that reach far outside of a repository and org - commit history is sacred. I need the absolute order of when things got merged in, because it provides a clean timeline to backtrack any issues. maybe I’m doing it wrong but every mature sysyem I’ve worked in basically operates this way. I suspect you run into more merge conflicts but I’m by no means a git expert.
The best I've found is the kernel development process: use both intelligently and give your branches a clean commit history before they're sent for review.
Merge = Smooshes two branches together into one. It keeps all the commits from both branches and creates a new "merge commit" to combine them. Doesn't mess with the commit history.
Rebase = Takes all the commits from one branch and sticks them on top of another branch, like stacking them in front. It rewrites the commit history to make everything look like one straight line.
One of the disadvantages of rebase is that it leads to a history where most of the commit have never existed in that exact form an any machine and so have never been built or run. This may interfere negatively with git bisect, which assumes that you can run and test the software at every commit. A squash and rebase workflow doesn't suffer from this problem, but then you end up with huge commits that may make it hard to pinpoint the exact change that causes a new misbehaviour.
Of course, having a merge based workflow doesn't guarantee that people only commit source that runs, so bisect might be broken anyway, and you get a messy history on top of that, unlike the beautiful clean line of a rebase based workflow, that makes it look like the system was developed by people of superhuman mental clarity.
Wait. If `git bisect` is anyway identifying merge commits only (since those are the only on history), how are you supposed to get advantage of the supposedly superior smaller commits?
`git bisect` hits every commit, not only merge commits. They're saying if you used squash-merge (which is a special kind of rebase), the small commits don't exist anymore so there's no way for bisect to find the small commit that caused the problem. Regular merges and non-squashing rebases both keep the small commits so bisect will find them.
I think a lot of the people who use merge do so because that’s what they learned initially.
Anecdotally, a lot of my coworkers who use merge are conceptually trying to stack their commits on top of previous ones. My lukewarm take: most of the time, rebase is actually the intended operation and merge is used as a hammer.
`git merge` is for regular people who are measured by how much they can accomplish in a given timeframe.
`git rebase` is for academics and startups where no one gives a fuck about anything and no one bats an eye if you waste a day or two on a rebase gone wrong.
It's easy to undo a merge and a bit nasty if you already pushed the merge commit. But undoing a rebase? Oh god you're in for a lot of pain.
> But undoing a rebase? Oh god you're in for a lot of pain.
It's actually pretty easy. You either make a checkpoint tag before you start the rebase, and reset to it if you notice something went wrong; or, if you forgot to make the checkpoint, check the reflog and find the commit you started from, and reset to that.
Reflog has a flag which adds timestamps to every entry, which I find is helpful for this:
the old commits are still in your reflog, and if they belong to a branch that isn't only on your machine, you can nag a coworker if you don't know how to use that
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.
> 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:
Yes, I currently manage my team's merge process and review all code that gets merged into our main repository. I tend to only do trunk-based repositories, work mostly in infrastructure, so I imagine my process is a little different than some traditional "dev" ones, but it's largely uncomplicated on my 5 person team.
> copy some files from another repo into yours while preserving file history
I'm not really sure what this means - I don't often have to do this, can't imagine why I would have to do this. If by "file history" you mean the commits on the file from the other repo? I can't imagine why I'd do that and it sounds like an anti pattern to me, and I avoid doing things like that at all costs, or would just create a git submodule if I really, really had to have that history and file in my repo for whatever reason.
> 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)
Really never have felt a need for doing this in any repository I've worked in so I guess no, for similar reasons as my above comment
> deleting 1 file from all commits in a repo (almost impossible without using an external non-git tool)
Why would you have to do this with any kind of frequency? If I did, and it was sufficiently complicated, I would put it in automation and write it once and call it a day.
> dealing with a rebase that was pushed that shouldn't have happened
I'm seeing now from other comments what the difference here is, I don't really ever use rebase and never have felt the need to. If I ever worked for a team where I didn't get to decide that, we had tooling that managed that part or wrote it.
> I could go on and on with examples of things that should be trivial but aren't.
I am a little curious, because some of what you wrote sounds a little bizarre to me, but I guess I'm probably in a much different domain.
> 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)
This is much closer a description to svn (and probably other systems), and doesn't describe git at all. Git doesn't store file renames. It reconstructs them from the history based on how similar an "add" and a "delete" were in the same commit. There's even args to change the sensitivity and look for line sources in even broader scopes* - which means git can do one thing others can't, show you where lines came from when two or more files were merged. Others can only show you one of the source files, the one that was explicitly renamed.
* See "-C" in "git help blame", the broadest scope even looks for the source in other commits.
The classic example is accidentally committing a binary file or some other large-as-in-filesize garbage -- simply deleting the file preserves it in history, bloating the size of the repo.
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.
Often people arrive on a team that has committed a grave sin in the past and all future team members are forced to use workflows involving submodules as penance.
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?
"The new commands, by contrast, aim to clearly separate the responsibilities of git checkout into two narrower categories: operations which change branches and operations which change files."
> … 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.
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 think it's the other way around. GUIs that expose everything of Git to the end developer also expose a lot of ways to shoot yourself in the foot if you don't know what the fuck you are doing.
The times I had to assist people shooting themselves with whatever favorite GUI they use... man I was happy I'm firmly in the Git CLI camp.
I'm in agreement. GUIs when it comes to git should offer a more limited, but consistent and understandable set of actions for users.
I'd imagine something very close to what SVN or CVS offered, and mainly targeted at users who won't be professionally working with a full team on a shared code base.
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.
The author explicitly says "I'm not calling for Git to remove git checkout" and "I am not asking for an official deprecation". They are trying, rather, to build a community consensus that it should not be taught to new users going forward. The command itself isn't going anywhere.
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.
I am very new to web design - I appreciate the feedback! I changed it to a serif font (Merriweather) and increased the margins for the browser version. Is this more readable?
Per the sibling commits, you don't want to use "margin" to control width. Use margin to control spacing between elements / the edge of the screen. What you want here is to put "max-width" on the content.
Specifically I'd suggest:
* Change "margin" on the <p> tags to "1.5rem 0"
* Change "margin" on .blog-page to "1.5rem auto" to keep the grey background centered based on width
* Add "max-width: 800px" (or whatever) to .blog-page
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
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.
> It's meant to elicit an emotional reaction and get people to read their article
I'll grant it for an article for wide readership but as a general tool of technical discourse used in places like github issues etc., highly inappropriate.
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.
If you work on a multi-disciplinary team, the consequence of not making your tools simple enough for others to use, is that you are forced to use other tools, which is why we have to use a horrible mix of sharepoint, teamforge, and github.
If your non-engineers have to deal with git you have an org or process problem. Git is pretty clear and easy to use to a competent software engineer. I'm tired of this meme that Git is hard. It doesn't get enough pushback.
While I strongly disagree with the conclusion of an org or process problem, I agree that basic concepts are simple and straightwordard. Plus majority (an assumption based on what I've seen) of those users use a GUI tool. GUI makes it simple to work with. A few clicks here and there and you're done. If something goes very wrong, there is usually a collegue who can help using CLI magic
My dude it's not hubris. Git is pretty damn simple compared to many problems you will have to reason about as a software engineer. If you can't understand file versioning, branching and merging then you aren't going to be able to think effectively about much more complicated problems.
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.
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.
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."
https://git-scm.com/docs/git-switch
Yes. This warning in the documentation (and the same warning for "git restore") is doing nothing to help the situation. I've had to put a stake in the ground on this SO answer: https://stackoverflow.com/a/215731/893
> [At the time of writing, the git restore command has been marked as "experimental" for at least four years.]
Honestly I have not bothered to even learn switch or restore because of these warnings. If they keep them in after five years, then the commands might be removed in the next version, because clearly there's no champion behind them pushing them forward.
And the few times I have tried to learn what they do, I have not seen any benefit over my current knowledge. So why learn something that may go away and is not trusted even five years and many many versions after deployment?
This goes well with my experience from svn where "svn switch" had a high-enough chance to screw up your checkout that everyone I know just had multiple checkouts instead.
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.
Do people really type these out, instead of just making a bash alias?
Used to have bash aliases, but nowadays I work on so many different machine, without my dotfiles present, that aliases seem kinda pointless. I'm a fast typist.
I would wager that 90% of people using git don’t have bash aliases.
I was always using 'co' for checkout. Made the change to switch ('git s') and revert ('git r') and it has been pretty seemless. I do wish 'git reset' defaulted to --keep.
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:
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?
I think you're asking for 'git switch -d' (for detached).
In practice you will still need 'git reset' but only with a branch parameter (all 'git reset -- paths' can be replaced with 'git restore'), usually with --keep, --soft, or --mixed.
I'm afraid I have no idea - I've never needed to use `git bisect`.
git switch --detach
But "git switch --detach master" leaves you detached.
So switch is just a dumber checkout that has to be told when to detach or not instead of inferring it from the kind of revision.
That's usually a good thing, setting your HEAD to a symbolic ref or a commit are very different operations. Having a switch makes sense and probably catches beginner errors rather than letting them know afterwards.
I don't feel like typing 'git s -d <branch>' has slowed me down in practice but you're technically right of course (or I would add a 'd="switch -d'"' alias).
or the shorter `git switch -d`
Not to be confused with `git switch -D`, a shorthand for `git switch --delete`
Are you being sarcastic? I can’t find the --delete option in git-switch man page.
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.
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.
Parent comment is the quintessential example from the article that most people who know git didn't learn git properly.
Yeah git rubbed me the wrong way from the beginning and I never learned it properly. My way makes the most sense to me. Stash? where? How do I get my files back? None of that is intuitive. I understand my way.
I love git stash, but to be fair, if you've just had Git do something unexpected to your files, I can completely understand why you would not then trust Git to keep your changes safe while you use more Git commands to get back into a sane state! Sometimes simple and well understood is the best way.
Now if git stash would support only stashing one specific file...
or
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'
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.
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.
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.
Rebase rewrites history to an extent. What I do (and this is also the advice in Pro Git for what thats worth) is use rebase when I'm working in local because its cleaner, but the moment anything ends up on GitHub, I use merge because I don't want to rewrite history that other people are aware of.
I am fine rewriting my own history on local because I know what I did, but not when its on GitHub because other people don't neccecarily know what I did.
I think this nails the difference in my workflow against people that tend to say it is difficult. In infrastructure commit history, which is often tied to CI CD processes that reach far outside of a repository and org - commit history is sacred. I need the absolute order of when things got merged in, because it provides a clean timeline to backtrack any issues. maybe I’m doing it wrong but every mature sysyem I’ve worked in basically operates this way. I suspect you run into more merge conflicts but I’m by no means a git expert.
The best I've found is the kernel development process: use both intelligently and give your branches a clean commit history before they're sent for review.
https://docs.kernel.org/maintainer/rebasing-and-merging.html
Merge = Smooshes two branches together into one. It keeps all the commits from both branches and creates a new "merge commit" to combine them. Doesn't mess with the commit history.
Rebase = Takes all the commits from one branch and sticks them on top of another branch, like stacking them in front. It rewrites the commit history to make everything look like one straight line.
I'm a rebase stan, but that's just my opinion.
One of the disadvantages of rebase is that it leads to a history where most of the commit have never existed in that exact form an any machine and so have never been built or run. This may interfere negatively with git bisect, which assumes that you can run and test the software at every commit. A squash and rebase workflow doesn't suffer from this problem, but then you end up with huge commits that may make it hard to pinpoint the exact change that causes a new misbehaviour.
Of course, having a merge based workflow doesn't guarantee that people only commit source that runs, so bisect might be broken anyway, and you get a messy history on top of that, unlike the beautiful clean line of a rebase based workflow, that makes it look like the system was developed by people of superhuman mental clarity.
Wait. If `git bisect` is anyway identifying merge commits only (since those are the only on history), how are you supposed to get advantage of the supposedly superior smaller commits?
`git bisect` hits every commit, not only merge commits. They're saying if you used squash-merge (which is a special kind of rebase), the small commits don't exist anymore so there's no way for bisect to find the small commit that caused the problem. Regular merges and non-squashing rebases both keep the small commits so bisect will find them.
I think a lot of the people who use merge do so because that’s what they learned initially.
Anecdotally, a lot of my coworkers who use merge are conceptually trying to stack their commits on top of previous ones. My lukewarm take: most of the time, rebase is actually the intended operation and merge is used as a hammer.
`git merge` is for regular people who are measured by how much they can accomplish in a given timeframe.
`git rebase` is for academics and startups where no one gives a fuck about anything and no one bats an eye if you waste a day or two on a rebase gone wrong.
It's easy to undo a merge and a bit nasty if you already pushed the merge commit. But undoing a rebase? Oh god you're in for a lot of pain.
> But undoing a rebase? Oh god you're in for a lot of pain.
It's actually pretty easy. You either make a checkpoint tag before you start the rebase, and reset to it if you notice something went wrong; or, if you forgot to make the checkpoint, check the reflog and find the commit you started from, and reset to that.
Reflog has a flag which adds timestamps to every entry, which I find is helpful for this:
the old commits are still in your reflog, and if they belong to a branch that isn't only on your machine, you can nag a coworker if you don't know how to use that
yeah, totally agree, it's so hard to type `git rebase --abort` (?)
Get out of here with your academic mumbo-jumbo
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.
> 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:
Yes, I currently manage my team's merge process and review all code that gets merged into our main repository. I tend to only do trunk-based repositories, work mostly in infrastructure, so I imagine my process is a little different than some traditional "dev" ones, but it's largely uncomplicated on my 5 person team.
> copy some files from another repo into yours while preserving file history
I'm not really sure what this means - I don't often have to do this, can't imagine why I would have to do this. If by "file history" you mean the commits on the file from the other repo? I can't imagine why I'd do that and it sounds like an anti pattern to me, and I avoid doing things like that at all costs, or would just create a git submodule if I really, really had to have that history and file in my repo for whatever reason.
> 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)
Really never have felt a need for doing this in any repository I've worked in so I guess no, for similar reasons as my above comment
> deleting 1 file from all commits in a repo (almost impossible without using an external non-git tool)
Why would you have to do this with any kind of frequency? If I did, and it was sufficiently complicated, I would put it in automation and write it once and call it a day.
> dealing with a rebase that was pushed that shouldn't have happened
I'm seeing now from other comments what the difference here is, I don't really ever use rebase and never have felt the need to. If I ever worked for a team where I didn't get to decide that, we had tooling that managed that part or wrote it.
> I could go on and on with examples of things that should be trivial but aren't.
I am a little curious, because some of what you wrote sounds a little bizarre to me, but I guess I'm probably in a much different domain.
> 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)
This is much closer a description to svn (and probably other systems), and doesn't describe git at all. Git doesn't store file renames. It reconstructs them from the history based on how similar an "add" and a "delete" were in the same commit. There's even args to change the sensitivity and look for line sources in even broader scopes* - which means git can do one thing others can't, show you where lines came from when two or more files were merged. Others can only show you one of the source files, the one that was explicitly renamed.
* See "-C" in "git help blame", the broadest scope even looks for the source in other commits.
> deleting 1 file from all commits in a repo (almost impossible without using an external non-git tool)
That seems like the exact opposite of the purpose of version control.
The classic example is accidentally committing a binary file or some other large-as-in-filesize garbage -- simply deleting the file preserves it in history, bloating the size of the repo.
It ends up being a worthwhile thing to do if someone has checked in a large file that shouldn't be in git or whatever
Somebody accidentally checks in an AWS private key and it gets found out much later.
Then removing it from history doesn’t do anything because you already need to rotate the key
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.
The most important one is
Don't think I've ever used this except by UI's from bitbucket/github etc. when doing a squash commit.
You never add files, create commits, or rebase?
Often people arrive on a team that has committed a grave sin in the past and all future team members are forced to use workflows involving submodules as penance.
i tried the newfangled commands and they are objectively worse.
maybe should fork a git lite that has only the commands you listed.
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?
https://github.blog/open-source/git/highlights-from-git-2-23... gives a good overview of the reason for the two new commands.
"The new commands, by contrast, aim to clearly separate the responsibilities of git checkout into two narrower categories: operations which change branches and operations which change files."
Simple, concise breakdown
> … 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.
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 think it's the other way around. GUIs that expose everything of Git to the end developer also expose a lot of ways to shoot yourself in the foot if you don't know what the fuck you are doing.
The times I had to assist people shooting themselves with whatever favorite GUI they use... man I was happy I'm firmly in the Git CLI camp.
I'm in agreement. GUIs when it comes to git should offer a more limited, but consistent and understandable set of actions for users.
I'd imagine something very close to what SVN or CVS offered, and mainly targeted at users who won't be professionally working with a full team on a shared code base.
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.
Ayup. The only downside of jujutsu is that it exposes how many places have become welded to the specifics of Git and Github.
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.
The author explicitly says "I'm not calling for Git to remove git checkout" and "I am not asking for an official deprecation". They are trying, rather, to build a community consensus that it should not be taught to new users going forward. The command itself isn't going anywhere.
You're right, that was me reading carelessly. I've removed that last part of my post (couldn't figure out how to do strikethrough on HN).
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!
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.
can we communally deprecate using monospaced fonts with full browser width content blocks for free form text?
I am very new to web design - I appreciate the feedback! I changed it to a serif font (Merriweather) and increased the margins for the browser version. Is this more readable?
Per the sibling commits, you don't want to use "margin" to control width. Use margin to control spacing between elements / the edge of the screen. What you want here is to put "max-width" on the content.
Specifically I'd suggest:
* Change "margin" on the <p> tags to "1.5rem 0"
* Change "margin" on .blog-page to "1.5rem auto" to keep the grey background centered based on width
* Add "max-width: 800px" (or whatever) to .blog-page
It's very difficult to read right now in Firefox mobile. Screenshot here https://ibb.co/x5xsXpB
Not really on mobile. The margins are too large. Screenshot from mobile Chrome: https://imgur.com/a/q4oa7aO
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:
Gist with this special scold commit hook, should I ever change it more: https://gist.github.com/lelandbatey/b42b527bfa41b761d0aec287...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.
> It's meant to elicit an emotional reaction and get people to read their article
I'll grant it for an article for wide readership but as a general tool of technical discourse used in places like github issues etc., highly inappropriate.
[dead]
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.
If you work on a multi-disciplinary team, the consequence of not making your tools simple enough for others to use, is that you are forced to use other tools, which is why we have to use a horrible mix of sharepoint, teamforge, and github.
Your non-engineers shouldn't have to understand or use git. If they do there's an org or process problem.
As the article explains, the problem with this attitude is that Git is increasingly used by people who aren't software engineers and don't want to be.
(Also, tools for software engineers still benefit from clarity and focus of purpose for simple use cases.)
Those people usually use GUI for that. They may even not know what CLI is.
If your non-engineers have to deal with git you have an org or process problem. Git is pretty clear and easy to use to a competent software engineer. I'm tired of this meme that Git is hard. It doesn't get enough pushback.
While I strongly disagree with the conclusion of an org or process problem, I agree that basic concepts are simple and straightwordard. Plus majority (an assumption based on what I've seen) of those users use a GUI tool. GUI makes it simple to work with. A few clicks here and there and you're done. If something goes very wrong, there is usually a collegue who can help using CLI magic
What do you think the people from the biomedical engineering lab and the physics lab from the article should be doing differently?
> Git is not that complicated. If you can't grok git I am seriously concerned about your ability to be an effective software engineer.
If your hubris is this high, I am seriously concerned about your seniority.
My dude it's not hubris. Git is pretty damn simple compared to many problems you will have to reason about as a software engineer. If you can't understand file versioning, branching and merging then you aren't going to be able to think effectively about much more complicated problems.