ChatGPT解决这个技术问题 Extra ChatGPT

What's the difference between git switch and git checkout <branch>

Git 2.23 introduces a new command git switch -- after reading the docs, it seems pretty much the same as git checkout <branchname> can someone explain the difference or use case?

Two new commands "git switch" and "git restore" are introduced to split "checking out a branch to work on advancing its history" and "checking out paths out of the index and/or a tree-ish to work on advancing the current history" out of the single "git checkout" command.

There's a good article at InfoQ about this topic: infoq.com/news/2019/08/git-2-23-switch-restore
Is the Git team planning to deprecate git checkout? I see no deprecation warnings when using it. But with git switch and git restore, I now see no need for checkout. However, if it is not deprecated, the Git team has just made things more confusing, not less. Does anyone know the plans for git checkout? If it does still have a use case, can someone add or edit an answer to elaborate its use case.
@MikeWilliamson I don't think so, you still need git checkout <commit>.
@BastianVenthur That's right, thanks! Unfortunately, that means checkout will stick around just for its "corner case" that is used the minority of the time. This will stretch out the time of confusion. But I guess we'll just have to help each other out through it. :)
@BastianVenthur you can git switch --detach <commit>

I
IMSoP

Well, according to the documentation you link to, its sole purpose is to split and clarify the two different uses of git checkout:

git switch can now be used to change branches, as git checkout does

git restore can be used to reset files to certain revisions, as git checkout -- does

People are confused by these different ways to use git checkout, as you can see from the many questions regarding git checkout here on Stackoverflow. Git developers seem to have taken this into account.


This seems like a good change. Make a branch? git checkout Switch branch? git checkout Get a certain version of a file? git checkout Remove changes to one file? git checkout Honestly I'm wondering how much of the normal git workflow could be done with various flags to git checkout.
So is the idea now that git checkout isn't technically needed for anything anymore? Or is it still in use for certain things, such as checking out a commit that isn't a branch head (moving to "detached head" mode)?
@Mike How can you say checkout doesn't make branches one sentence after you say checkout makes branches? It doesn't matter the internal workings of the -b flag. It still makes a branch.
@Mike I understand your point about operations versus commands, but this discussion is about commands. Unless we're using super low level APIs we don't have direct access to the "operations". We only have access to the commands. It's a needlessly pedantic distinction here.
Helpful note: for those used to git checkout -b <branch name> you can use git switch -c <branch name> to get the same effect
S
SteveTurczyn

git checkout is a bit of a swiss army knife in that has several unrelated uses.

If you modify a file but haven't staged the change, then git checkout <filename> will reverse the modifications... a quick and easy way to cancel changes to a file. You remain in the same branch.

git checkout <branchname> (as you noted) switches branches.

Two completely different purposes, which could lead to confusion if a file name and a branch name are similar.

Having it as two commands is clearer.


As you mentioned having a branch and file with the same name is confusing. I assume the branch takes priority over the file, as that would be often more desirable? Or how does that work?
@AgentM Yes, that is correct. If a branch and a file have the same name then doing git checkout <name> gives preference to the branch instead of the file.
If you want to checkout the file instead of the branch you have to separate it with -- from the options. This is a common idiom for many Git and other Unix commands.
@bjhend and SteveTurczyn, git checkout <filename> frequently does work, but git checkout -- <filename> is better, as the -- clearly indicates to the git parser that the options being passed to git checkout have ended, and a list of file or directory paths has begun. This may be important, for instance, if your filename begins with a dash, such as -myfile. Doing git checkout -- -myfile should work in that case, whereas without the preceding --, the -myfile would look like a messed-up option passed to git checkout.
M
M. Justin

The switch command indeed does the same thing as checkout, but only for those usages that switch branches. In particular, unlike checkout it cannot restore working tree files — that is instead done using the restore command that was introduced alongside switch.

Detailed explanation

As you noted in the 2.23.0 release notes section you quoted, the switch and restore commands were introduced to split the checkout command into two separate pieces:

"checking out a branch to work on advancing its history"

"checking out paths out of the index and/or a tree-ish to work on advancing the current history"

In other words, checkout does two different things, and this release split each of those different things into its own focused command.

This dual purpose of checkout can be seen in its summary description in the documentation:

git-checkout - Switch branches or restore working tree files

The commit that added the switch command explains the rationale for the new commands in its commit message:

"git checkout" doing too many things is a source of confusion for many users (and it even bites old timers sometimes). To remedy that, the command will be split into two new ones: switch and restore. The good old "git checkout" command is still here and will be until all (or most of users) are sick of it.

From this, it's clear that the new commands were introduced to reduce confusion by having two focused commands, rather than one multi-purpose command.

Note that as of December 2021, the new commands are still listed as experimental (switch, restore):

THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.

Command comparison

I have not found a full comparison of the commands anywhere. From reading through the documentation, I think this should be a fairly complete comparison:

previous command new command git checkout git switch git checkout N/A (use git status) git checkout -b [] git switch -c [] git checkout -B [] git switch -C [] git checkout --orphan git switch --orphan git checkout --orphan N/A (use git switch then git switch --orphan ) git checkout [--detach] git switch --detach git checkout --detach [] git switch --detach [] git checkout [--] … git restore [--] … git checkout --pathspec-from-file= git restore --pathspec-from-file= git checkout [--] … git restore -s [--] … git checkout --pathspec-from-file= git restore -s --pathspec-from-file= git checkout -p [] [--] […] git restore -p [-s ] [--] […]

As shown in this comparison, some prior usages can be converted to the new commands by replacing the old command name (checkout) to the new one (switch, restore), whereas others require additional adjustment. Notable changes include:

The -b/-B options for creating a new branch before switching are renamed to -c/-C

--detach is now always required when switching to a detached head, where it was previously optional for commits but required for branches

The source tree for restoring is now given by the -s option, rather than being an inline argument


d
daGo

switch has some limitations: at the moment you can switch from any commit to <branch name>, however it's impossible to switch from <branch name> to a particular commit with a status of detached HEAD. So you need to use git checkout 5efb (where 5efb is an example of a hash reference to arbitrary commit)


I'd argue that this is acutally a feature and not a bug (limitation). switch is created for the single purpose of changing branches, and when you do that, you do want to be at the HEAD of that branch. checkout is a more general operation which brings your working copy in line with any given state in the history (= commit). Since any branch name is an alias for the HEAD commit of that branch, checking out a branch is technically no different than checking out any other commit.
with -d you can: git switch -d 6c13
M
Maëlan

here is an extract from the git manual — man git-switch.

Synopsis git switch [] [--no-guess] git switch [] --detach [] git switch [] (-c|-C) [] git switch [] --orphan Description Switch to a specified branch. The working tree and the index are updated to match the branch. All new commits will be added to the tip of this branch. Optionally a new branch could be created with either -c, -C, automatically from a remote branch of same name (see --guess), or detach the working tree from any branch with --detach, along with switching. Switching branches does not require a clean index and working tree (i.e. no differences compared to HEAD). The operation is aborted however if the operation leads to loss of local changes, unless told otherwise with --discard-changes or --merge. THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.


k
kd4ttc

You get different effect. When you checkout you get the files of the branch you checkout. If you switch the branch changes but the files don’t change. If you commit then the commit goes to that branch. If you are editing but you checkout then the files are reset to the file state of the checkout potentially losing work or getting a desired reversion.


This is not accurate.