Skip to content
ExponaBLOG
GIT & GITHUB FOR PROFESSIONAL DEVELOPERS · DAY 087 / 100

git switch -c vs git checkout -b: lessons from production

Two ways to create branches.

Expona Admin6 min read

The branch creation dilemma

Over the years, we've seen countless merge conflicts and accidental file restores traced back to a single source: confusion between git switch -c and git checkout -b. Both commands create and switch to a new branch, yet they carry very different mental models. Understanding when and why to use each one—and more importantly, why you should standardize on one—can save your team hours of debugging and prevent subtle production issues.

Both commands do the same thing—mostly

Let's start with what they have in common. Both git switch -c and git checkout -b accomplish the same outcome: they create a new branch and immediately switch your working directory to it.

bash
# Using git switch -c
git switch -c feature/user-auth

# Using git checkout -b (older syntax)
git checkout -b feature/user-auth

From a practical standpoint, both commands leave you on the new branch, ready to start committing work. Your .git/HEAD file now points to refs/heads/feature/user-auth, and your working directory reflects the state of that branch. For years, teams used git checkout -b without incident because it worked. But "working" and "designed for this specific purpose" are different things.

Why git switch is clearer and focused

Git 2.23, released in August 2019, introduced git switch as a purpose-built replacement for the checkout subcommand when dealing with branch operations. The distinction matters more than it seems at first.

git switch has a single, focused responsibility: switching between branches. The -c flag (short for --create) extends that responsibility to creating a new branch first. When a developer reads git switch -c feature/payment, the intent is unmistakable—we are switching to a branch, and if it doesn't exist, create it first.

Compare that to reading git checkout -b feature/payment. The word "checkout" historically referred to many operations: switching branches, restoring files, and even checking out specific commits. A junior developer might reasonably wonder, "Am I checking out a file? A commit? What does the -b flag do?" The ambiguity compounds when team members have different Git versions or workflows.

In a real production scenario, we've seen developers mix up commands and accidentally run git checkout HEAD -- src/ expecting it to switch branches, when it actually restored all files in src/ to their HEAD state. The command worked, but the intention and the outcome didn't align.

git checkout also restores files—easy to misuse

Here's where the distinction becomes critical. git checkout does far more than create branches. It also restores file contents from the repository.

bash
# Switch to a branch
git checkout my-feature

# Restore a file from HEAD
git checkout HEAD -- config.js

# Restore all files in a directory
git checkout HEAD -- src/

# Restore a file from a specific commit
git checkout abc1234 -- utils.js

Because git checkout has multiple purposes, its behavior depends entirely on context. If you pass a branch name, it switches branches. If you pass a path, it restores files. If you pass both a commit and a path, it restores files from that commit. This flexibility is powerful for experienced developers but dangerous for teams with mixed experience levels.

We've seen situations where a developer intended to create and switch to a branch but accidentally typed the wrong command, resulting in file restoration that wiped out unsaved work. The command executed without error because it was syntactically valid—just semantically wrong for the task at hand.

In contrast, git switch cannot restore files. If you run git switch with a path, Git will reject it outright. This design prevents accidental file restoration masquerading as branch operations.

bash
# This works—switches to the branch
git switch my-feature

# This fails—git switch has no file restoration capability
git switch HEAD -- config.js
# error: invalid reference: HEAD

The failure is immediate and clear, which is exactly what you want. There's no silent misunderstanding.

Teach new developers switch and restore

When onboarding developers or establishing team standards, the recommendation is straightforward: teach git switch for branch operations and git restore for file restoration. This mental separation reflects how Git itself is organized.

git restore was introduced alongside git switch specifically to handle file restoration tasks. It replaces the file-restoration behaviors of git checkout with a command whose name accurately describes what it does.

bash
# Old way (ambiguous intent)
git checkout HEAD -- src/app.js

# New way (clear intent)
git restore src/app.js

# Restore from a specific commit
git restore --source=abc1234 src/app.js

# Restore all changes in a directory
git restore src/

By establishing this convention early, you prevent a class of mistakes entirely. New developers learn that branch operations use git switch and file restoration uses git restore. There's no overlap, no ambiguity, and no confusion when reading code review comments or onboarding documentation.

We've found that teams adopting this convention report fewer accidental file restorations and clearer Git history discussions. When someone says, "Run git switch -c to create the branch," there's no room for misinterpretation.

Common mistakes

Mixing checkout and switch in the same codebase: If your team uses both commands interchangeably, newer developers won't understand the distinction. Pick one convention and stick to it. Since git switch is the modern standard and provides better separation of concerns, it should be your default.

Assuming checkout -b and switch -c are identical: While they produce the same outcome, their design intentions differ. checkout is a legacy command with multiple purposes, while switch is purpose-built for branch operations. This difference becomes important when training or reviewing code.

Using checkout for file restoration without thinking about the syntax: The -- separator in git checkout HEAD -- file.js exists to distinguish paths from branches. Many developers treat it as magic without understanding why. This leads to errors when the syntax is slightly different. git restore eliminates this cognitive load.

Not updating documentation when switching commands: If your team decides to standardize on git switch, make sure your onboarding docs, style guides, and code review checklists reflect this. A developer seeing git checkout -b in old documentation might use it in a new pull request, defeating the purpose of the standard.

Forgetting to specify -c when creating a branch: git switch without the -c flag expects the branch to already exist. Running git switch feature/new-api when the branch doesn't exist will fail with an error. Always use git switch -c feature/new-api when creating. This is actually a safety feature—it prevents typos that might accidentally switch you to an unexpected branch.

Key takeaways

  • Use git switch -c to create and switch to a new branch. It's purpose-built for this task and makes intent explicit.
  • Use git restore to restore files from the repository. It replaces the file-restoration capabilities of git checkout with a clearer name and safer syntax.
  • Teach new developers this modern workflow from day one. It prevents a class of mistakes and makes Git commands more predictable across your team.
  • If your codebase still uses git checkout -b, consider it technical debt worth addressing during onboarding or code review processes.
  • The distinction between branch operations and file restoration is fundamental to Git. Reflecting this in your commands makes collaboration clearer and reduces production incidents.
ShareXLinkedInReddit

Found this useful? Support the writing.

Buy me a coffee
Written by
Expona Admin
Site administrator

Comments

Loading comments…

Leave a comment

Comments are reviewed before they appear. Be kind and stay on topic.

Related articles