Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ


Choose your language

InfoQ Homepage News Git 2.23 Adds Switch and Restore Commands

Git 2.23 Adds Switch and Restore Commands


Git 2.23 introduces two new commands meant to replace two common uses of git checkout: git switch to switch to a new branch after creating it if necessary, and git restore to restore changes from a given commit.

As mentioned, both functions implemented through git switch and git restore were previously available using git checkout, which was the source of some confusion for new Git users and considered detrimental to Git user experience. The main argument for this was that operating on branches is logically different from modifying your working copy, so having a single command for both operations was not a good idea. Interestingly, the git checkout command was not born overloaded with such heterogeneous functions. Indeed, originally git checkout could only switch to a branch, optionally creating it if not present when the -b switch was given. Instead, to copy a file from the index to your working copy, you would use git checkout-index. At some point though, git checkout was extended to support both copying a file from the stage/index to the working tree as well as copying a tree-ish. Differentiating the three semantics was –and still is– a matter of juggling with the -- separator and keeping in mind that some argument combinations may alter your index, not only your working copy. For example:

git checkout b           # switch to branch b
git checkout -- f        # copy f from the stage to the working tree
git checkout b -- g      # copy f from branch b
git checkout HEAD f      # this will alter your index, too!

The dynamics that led to this kind of design decisions were explained by Git maintainer Junio Hamano:

Another thing is because the system wasn’t really designed, but grew organically. So somebody came up with an idea of doing one thing. "Oh, this is a good idea, a good feature; let’s add it to this command as this option name." And the option name he chooses just gets stuck, but after a few months, somebody else notices, "Oh, this is a similar mode of operation with that existing command."

Thus, to improve this state of things, git switch and git restore were born. Using switch you will be able to write:

git switch my-branch              # same as git checkout my-branch
git switch -c my-branch           # same as git checkout -b my-branch
git switch -c my-branch HEAD~3    # branch off HEAD~3
git switch --detach HEAD~3        # checkout commit without branching

The git restore command supports three main options: --source to specify what you want to copy, and --staged and --worktree to specify the destination. This removes all kinds of ambiguity, at the expense of terseness, and allows you to write stuff like:

git restore --source HEAD~3 main.c  # --worktree is implied

rm -f hello.c
git restore hello.c

git restore '*.c'

git restore --staged hello.c    # same as using git reset

git restore --source=HEAD --staged --worktree hello.c   # same as git checkout

A note of caution about the restored source, in case it is not explicitly specified using --source, since it depends on the destination to restore to:

If not specified, the default restore source for the working tree is the index, and the default restore source for the index is HEAD. When both --staged and --worktree are specified, --source must also be specified.

Developers' reactions on Hacker News and Reddit have been generally positive, praising the greater intuitiveness of switch and restore over the multiple possible uses of checkout. Anyway, a few developers hinted at restore having a clumsy and unusual syntax. Specifically, besides the already mentioned glitch with default source resolution, restore requires three arguments –--source, --staged, and --worktree– for what is likely the most common use case, i.e., reverting a file to its state in a previous commit. Additionally, restore requires explicitly naming the source revision, while many commands allow you to just give it as an argument.

Switch and restore are not the only new features in Git 2.23, which also modifies the behaviour of many existing commands, including git for-each-ref, git merge, git cherry-pick, while also fixing bugs. Refer to the release notes or to this GitHub summary for full detail.

Rate this Article