switch Git Command Guide
The git switch command switches branches and creates new branches safely. Introduced in Git 2.23, it provides a dedicated command for branch switching operations, separating them from the overloaded git checkout command for better clarity and safety.
git switch Syntax:
Section titled “git switch Syntax:”git switch [<options>] [--no-guess] <branch>git switch [<options>] --detach [<start-point>]git switch [<options>] (-c|-C) <new-branch> [<start-point>]git switch [<options>] --orphan <new-branch> [<start-point>]Branch Switching Options:
Section titled “Branch Switching Options:”| Option | Description |
|---|---|
<branch> | Switch to existing branch |
--detach | Switch to detached HEAD state |
-c <new-branch> | Create and switch to new branch |
-C <new-branch> | Create and switch to new branch (force) |
--orphan <new-branch> | Create orphan branch |
--guess | Guess branch name (default) |
--no-guess | Don’t guess branch name |
Branch Creation Options:
Section titled “Branch Creation Options:”| Option | Description |
|---|---|
--track | Set up tracking for new branch |
--no-track | Don’t set up tracking |
-t, --track | Set up tracking (same as —track) |
--no-track | Don’t set up tracking |
Conflict Resolution Options:
Section titled “Conflict Resolution Options:”| Option | Description |
|---|---|
--merge | Perform three-way merge if needed |
--conflict=<style> | Conflict resolution style |
-X <option> | Pass merge strategy option |
--ignore-other-worktrees | Ignore other worktrees |
--recurse-submodules | Recurse into submodules |
Output Control Options:
Section titled “Output Control Options:”| Option | Description |
|---|---|
-q, --quiet | Suppress feedback messages |
-v, --verbose | Verbose output |
--progress | Force progress reporting |
--no-progress | Disable progress reporting |
Advanced Options:
Section titled “Advanced Options:”| Option | Description |
|---|---|
--force-create | Force create branch |
--force | Force switch (discard local changes) |
--discard-changes | Discard uncommitted changes |
--merge | Merge uncommitted changes |
--abort | Abort switch operation |
Parameters:
Section titled “Parameters:”| Parameter | Description |
|---|---|
<branch> | Name of branch to switch to |
<new-branch> | Name for new branch to create |
<start-point> | Commit/branch to start new branch from |
Understanding Switch Concepts:
Section titled “Understanding Switch Concepts:”Switch vs Checkout:
Section titled “Switch vs Checkout:”Command Comparison:├── git switch: Dedicated for branch operations│ ├── Safe branch switching│ ├── Clear intent for branch operations│ ├── Better error messages│ └── Modern Git approach│└── git checkout: Legacy command (overloaded) ├── Branch switching + file operations ├── Can be confusing ├── Still works for file operations └── Backward compatibilityBranch States:
Section titled “Branch States:”Branch Switching States:├── Clean Working Tree: Safe to switch├── Uncommitted Changes: May need merge or stash├── Untracked Files: Generally safe to switch├── Detached HEAD: HEAD points to commit, not branch├── Orphan Branch: New branch with no history└── Tracking Branch: Local branch tracking remoteSafe Switching Rules:
Section titled “Safe Switching Rules:”Switch Safety Guidelines:├── ✓ Clean working tree: Always safe├── ✓ Untracked files: Safe (not in Git tracking)├── ⚠ Modified files: May conflict or need merge├── ⚠ Staged changes: May conflict or need merge├── ✗ Uncommitted changes in target: May overwrite└── ✗ Force switch: Discards uncommitted workBasic Switch Operations:
Section titled “Basic Switch Operations:”Switching Branches:
Section titled “Switching Branches:”# Switch to existing branchgit switch maingit switch develop
# Switch with verbose outputgit switch -v feature-branch
# Switch quietlygit switch -q release-branchCreating and Switching:
Section titled “Creating and Switching:”# Create and switch to new branchgit switch -c new-feature
# Create from specific commitgit switch -c bug-fix abc123
# Create from another branchgit switch -c feature-ui develop
# Force create (overwrite existing)git switch -C existing-branchDetached HEAD State:
Section titled “Detached HEAD State:”# Switch to detached HEADgit switch --detach v1.0
# Switch to specific commitgit switch --detach HEAD~3
# Switch to taggit switch --detach v2.1.0Orphan Branches:
Section titled “Orphan Branches:”# Create orphan branch (no history)git switch --orphan experimental
# Useful for complete rewrites# Working tree preserved, history starts freshAdvanced Switching Scenarios:
Section titled “Advanced Switching Scenarios:”Handling Uncommitted Changes:
Section titled “Handling Uncommitted Changes:”# Automatic merge of uncommitted changesgit switch --merge feature-branch
# Discard uncommitted changesgit switch --discard-changes feature-branch
# Force switch (dangerous)git switch --force feature-branchTracking Branches:
Section titled “Tracking Branches:”# Create tracking branchgit switch --track origin/feature-remote
# Create tracking with custom namegit switch -c local-feature --track origin/remote-feature
# Switch to tracking branchgit switch main # If main tracks origin/mainRemote Branch Operations:
Section titled “Remote Branch Operations:”# Switch to remote branch (creates local tracking)git switch remote-branch
# Create local branch from remotegit switch -c local-copy origin/remote-branch
# Update all remote tracking branchesgit fetch --allgit switch remote-branchSubmodule Handling:
Section titled “Submodule Handling:”# Switch with submodule updatesgit switch --recurse-submodules feature-branch
# Ignore other worktreesgit switch --ignore-other-worktrees mainConfiguration and Best Practices:
Section titled “Configuration and Best Practices:”Git Configuration for Switch:
Section titled “Git Configuration for Switch:”# Configure switch behaviorgit config switch.defaultBranch main # Default branch namegit config switch.defaultRemote origin # Default remotegit config switch.defaultMergeOptions --no-edit # Default merge options
# Configure tracking behaviorgit config branch.autosetupmerge always # Auto setup mergegit config branch.autosetuprebase always # Auto setup rebase
# Configure colorsgit config color.branch.current yellowgit config color.branch.local greengit config color.branch.remote redSwitch Best Practices:
Section titled “Switch Best Practices:”# Always check status before switchinggit status
# Use descriptive branch namesgit switch -c feature/user-authentication
# Keep branches focused# One feature or fix per branch
# Regular cleanupgit branch --merged | grep -v main | xargs git branch -d
# Use tracking branchesgit switch --track origin/featureSafe Switch Operations:
Section titled “Safe Switch Operations:”# Check for uncommitted changesif ! git diff --quiet || ! git diff --cached --quiet; then echo "Uncommitted changes detected" git stash push -m "Auto-stash before switch" git switch "$branch" git stash popelse git switch "$branch"fi
# Verify switch successcurrent_branch=$(git branch --show-current)if [ "$current_branch" = "$target_branch" ]; then echo "Successfully switched to $target_branch"fiIntegration with Development Workflows:
Section titled “Integration with Development Workflows:”Feature Branch Workflow:
Section titled “Feature Branch Workflow:”#!/bin/bash# Feature branch workflow with switch
start_feature() { local feature_name="$1" local base_branch="${2:-develop}"
# Switch to base branch git switch "$base_branch" git pull origin "$base_branch"
# Create feature branch git switch -c "feature/$feature_name"
# Push and set upstream git push -u origin "feature/$feature_name"
echo "Feature branch 'feature/$feature_name' created and ready"}
# Usagestart_feature "user-dashboard" "develop"Hotfix Workflow:
Section titled “Hotfix Workflow:”# Emergency hotfix workflowcreate_hotfix() { local issue_number="$1" local base_branch="${2:-main}"
# Switch to stable branch git switch "$base_branch" git pull origin "$base_branch"
# Create hotfix branch git switch -c "hotfix/issue-$issue_number"
echo "Hotfix branch created. Make your changes and:" echo "git add . && git commit -m 'Fix issue $issue_number'" echo "git push origin hotfix/issue-$issue_number"}
create_hotfix "123" "main"Release Branch Management:
Section titled “Release Branch Management:”# Release branch workflowprepare_release() { local version="$1" local release_branch="release/v$version"
# Switch to develop git switch develop git pull origin develop
# Create release branch git switch -c "$release_branch"
# Perform release preparation echo "Release branch $release_branch ready for testing"
# After testing, merge to main and develop # git switch main # git merge --no-ff "$release_branch" # git switch develop # git merge --no-ff "$release_branch"}
prepare_release "3.2.1"Troubleshooting Common Issues:
Section titled “Troubleshooting Common Issues:”Uncommitted Changes Blocking Switch:
Section titled “Uncommitted Changes Blocking Switch:”# Stash changes before switchinggit stash push -m "Work in progress"git switch feature-branchgit stash pop
# Merge changes during switchgit switch --merge feature-branch
# Discard changes (dangerous)git switch --discard-changes feature-branchBranch Doesn’t Exist:
Section titled “Branch Doesn’t Exist:”# Create branch if it doesn't existgit switch -c new-branch
# Check available branchesgit branch -a
# Fetch remote branchesgit fetch --allgit switch remote-branchDetached HEAD State:
Section titled “Detached HEAD State:”# Check if in detached HEADgit branch --show-current # Empty output = detached
# Create branch from detached HEADgit switch -c new-branch
# Return to branchgit switch mainRemote Branch Issues:
Section titled “Remote Branch Issues:”# Remote branch not visiblegit fetch origingit switch remote-branch
# Create local tracking branchgit switch -c local-branch origin/remote-branch
# Set upstream manuallygit switch local-branchgit branch --set-upstream-to=origin/remote-branchPermission and Access Issues:
Section titled “Permission and Access Issues:”# Check repository permissionsls -la .git/
# Handle file permission conflictsgit switch --force feature-branch
# Clean untracked files if neededgit clean -fdgit switch feature-branchSubmodule Issues:
Section titled “Submodule Issues:”# Switch with submodulesgit switch --recurse-submodules feature-branch
# Update submodules after switchgit submodule update --init --recursive
# Handle submodule conflictscd submodule/git switch appropriate-branchcd ..git add submodule/Performance Issues:
Section titled “Performance Issues:”# Speed up switch operationsgit switch -q feature-branch # Quiet mode
# Pre-fetch branchesgit fetch --all
# Use local operations when possiblegit switch local-branch # No network neededConfiguration Issues:
Section titled “Configuration Issues:”# Reset switch configurationgit config --unset switch.defaultBranch
# Check current configurationgit config --list | grep switch
# Fix tracking issuesgit config branch.autosetupmerge trueReal-World Usage Examples:
Section titled “Real-World Usage Examples:”Development Workflow Integration:
Section titled “Development Workflow Integration:”#!/bin/bash# Integrated development workflow with switch
dev_workflow_switch() { echo "=== Development Workflow Switch ==="
# Show available branches echo "Available branches:" git branch -v | head -10
# Smart branch switching switch_smart() { local target_branch="$1"
# Check if branch exists if ! git show-ref --verify --quiet "refs/heads/$target_branch"; then echo "Branch $target_branch doesn't exist locally" # Try remote branch if git ls-remote --heads origin "$target_branch" | grep -q .; then git switch -c "$target_branch" "origin/$target_branch" return $? else echo "Branch $target_branch not found" return 1 fi fi
# Check for uncommitted changes if ! git diff --quiet || ! git diff --cached --quiet; then echo "Uncommitted changes detected" read -p "Stash changes? (y/n): " stash_choice if [[ "$stash_choice" == "y" ]]; then git stash push -m "Auto-stash before switch to $target_branch" git switch "$target_branch" git stash pop else git switch --merge "$target_branch" fi else git switch "$target_branch" fi
echo "Switched to $(git branch --show-current)" }
# Command dispatcher case "$1" in to) switch_smart "$2" ;; feature) switch_smart "feature/$2" ;; bugfix) switch_smart "bugfix/$2" ;; release) switch_smart "release/$2" ;; *) echo "Usage: $0 {to <branch>|feature <name>|bugfix <name>|release <name>}" ;; esac}
dev_workflow_switch "$@"Branch Cleanup and Organization:
Section titled “Branch Cleanup and Organization:”# Automated branch managementbranch_housekeeping() { echo "=== Branch Housekeeping ==="
# Switch to main branch first git switch main 2>/dev/null || git switch master 2>/dev/null || { echo "No main/master branch found" return 1 }
# Update from remote git pull origin main 2>/dev/null || true
# Find and clean merged branches echo "Checking for merged branches..." merged_branches=$(git branch --merged | grep -v "main\|master\|develop" | grep -v "^\*" | sed 's/^ //')
if [ -n "$merged_branches" ]; then echo "Merged branches to consider deleting:" echo "$merged_branches" echo ""
read -p "Delete merged branches? (y/N): " delete_choice if [[ "$delete_choice" == "y" ]]; then echo "$merged_branches" | xargs git branch -d echo "Merged branches cleaned up" fi else echo "No merged branches to clean up" fi
# Check for stale branches echo "" echo "Checking for stale branches..." git branch -v | while read -r branch commit rest; do branch=$(echo "$branch" | sed 's/^* //') # Skip main branches [[ "$branch" == "main" || "$branch" == "master" || "$branch" == "develop" ]] && continue
# Check if last commit > 90 days ago if ! git log -1 --since="90 days ago" "$commit" >/dev/null 2>&1; then echo "Stale branch: $branch (last commit: $(git log -1 --format='%ci' "$commit"))" fi done
echo "Housekeeping complete"}
branch_housekeepingCI/CD Pipeline Integration:
Section titled “CI/CD Pipeline Integration:”# CI/CD branch switchingci_branch_switch() { echo "=== CI/CD Branch Switch ==="
local target_branch="${CI_BRANCH:-main}" local commit_sha="${CI_COMMIT_SHA:-HEAD}"
# Ensure clean working tree if ! git diff --quiet --exit-code || ! git diff --cached --quiet --exit-code; then echo "ERROR: Working tree not clean in CI" git status exit 1 fi
# Switch to target branch if git show-ref --verify --quiet "refs/heads/$target_branch"; then git switch "$target_branch" else echo "Creating branch $target_branch from $commit_sha" git switch -c "$target_branch" "$commit_sha" fi
# Verify switch current_branch=$(git branch --show-current) if [ "$current_branch" != "$target_branch" ]; then echo "ERROR: Failed to switch to $target_branch" exit 1 fi
# Update submodules if present if [ -f .gitmodules ]; then git submodule update --init --recursive fi
echo "Successfully switched to $target_branch" echo "Current commit: $(git rev-parse HEAD)"}
ci_branch_switchCollaborative Development:
Section titled “Collaborative Development:”# Team collaboration workflowteam_collaboration() { echo "=== Team Collaboration Workflow ==="
# Switch to team branch switch_team_branch() { local team_branch="$1"
# Check if team member has local changes if ! git diff --quiet || ! git diff --cached --quiet; then echo "Local changes detected - stashing" git stash push -m "Team switch: $team_branch" stashed=true fi
# Switch to team branch git switch "$team_branch" 2>/dev/null || { echo "Team branch $team_branch not found locally" # Try to create from remote git switch -c "$team_branch" "origin/$team_branch" 2>/dev/null || { echo "Cannot access team branch $team_branch" return 1 } }
# Pull latest changes git pull origin "$team_branch" || { echo "Failed to pull latest changes" return 1 }
# Restore stashed changes if any if [ "$stashed" = true ]; then if git stash pop 2>/dev/null; then echo "Local changes restored" else echo "WARNING: Could not restore local changes - manual merge may be needed" fi fi
echo "Successfully switched to team branch $team_branch" }
# Create pair programming branch create_pair_branch() { local feature="$1" local pair_name="$2" local pair_branch="pair/$feature-$pair_name"
git switch -c "$pair_branch" git push -u origin "$pair_branch"
echo "Pair programming branch created: $pair_branch" echo "Both team members can now work on this branch" }
# Merge team branch back merge_team_branch() { local team_branch="$1" local target_branch="${2:-develop}"
# Switch to target git switch "$target_branch" git pull origin "$target_branch"
# Merge team branch git merge --no-ff "$team_branch" -m "Merge team branch: $team_branch"
if [ $? -eq 0 ]; then git push origin "$target_branch" echo "Team branch $team_branch successfully merged" else echo "Merge failed - resolve conflicts and try again" return 1 fi }
case "$1" in switch) switch_team_branch "$2" ;; pair) create_pair_branch "$2" "$3" ;; merge) merge_team_branch "$2" "$3" ;; *) echo "Usage: $0 {switch <branch>|pair <feature> <name>|merge <branch> [target]}" ;; esac}
team_collaboration "$@"Emergency Response Workflow:
Section titled “Emergency Response Workflow:”# Emergency branch switchingemergency_response() { echo "=== Emergency Response Workflow ==="
# Quick switch to emergency branch emergency_switch() { local emergency_branch="emergency-fix"
# Force immediate switch (preserve current work) git switch -c "$emergency_branch" 2>/dev/null || git switch "$emergency_branch"
echo "Switched to emergency branch: $emergency_branch" echo "Make critical fixes now" echo "To return to previous work: git switch -" }
# Return from emergency emergency_return() { # Switch back to previous branch git switch -
# Check if emergency branch exists if git show-ref --verify --quiet "refs/heads/emergency-fix"; then echo "Emergency branch still exists" echo "Review and merge emergency fixes when ready" fi }
# Merge emergency fixes emergency_merge() { local target_branch="${1:-main}"
git switch "$target_branch" git pull origin "$target_branch"
git merge --no-ff emergency-fix -m "Emergency fix: $(git log --oneline -1 emergency-fix)"
if [ $? -eq 0 ]; then git push origin "$target_branch" git branch -d emergency-fix echo "Emergency fixes merged and cleaned up" else echo "Emergency merge failed" return 1 fi }
case "$1" in start) emergency_switch ;; return) emergency_return ;; merge) emergency_merge "$2" ;; *) echo "Usage: $0 {start|return|merge [target-branch]}" ;; esac}
emergency_response "$@"What’s the difference between git switch and git checkout?
Section titled “What’s the difference between git switch and git checkout?”git switch is dedicated to branch operations only, while git checkout handles both branch switching and file restoration. switch provides clearer intent and better error messages.
How do I create a new branch and switch to it?
Section titled “How do I create a new branch and switch to it?”Use git switch -c
Can I switch branches with uncommitted changes?
Section titled “Can I switch branches with uncommitted changes?”Yes, but only if the changes don’t conflict. Use —merge to merge uncommitted changes, or stash them first.
What’s detached HEAD state?
Section titled “What’s detached HEAD state?”When HEAD points to a commit instead of a branch. You can make commits but they’ll be lost when switching away unless you create a branch.
How do I switch back to the previous branch?
Section titled “How do I switch back to the previous branch?”Use git switch - to switch to the previously checked out branch.
Can I switch to a remote branch?
Section titled “Can I switch to a remote branch?”Yes, git switch
What’s the difference between -c and -C?
Section titled “What’s the difference between -c and -C?”-c creates a new branch, -C creates a new branch even if one with that name already exists (force create).
How do I abort a switch operation?
Section titled “How do I abort a switch operation?”If conflicts occur during switch —merge, you can abort with git switch —abort (though this may not always be available).
Can I switch branches in a dirty working tree?
Section titled “Can I switch branches in a dirty working tree?”Yes, but it’s safer to commit, stash, or use —merge. Force switching discards uncommitted changes.
What’s an orphan branch?
Section titled “What’s an orphan branch?”A branch created with —orphan starts with no commit history, useful for complete project rewrites.
How do I see which branch I’m on?
Section titled “How do I see which branch I’m on?”Use git branch —show-current or git status to see the current branch.
Can I switch to a commit hash?
Section titled “Can I switch to a commit hash?”Use git switch —detach
What’s the —guess option for?
Section titled “What’s the —guess option for?”—guess (default) allows Git to guess branch names from partial matches, like “git switch feat” matching “feature-branch”.
How do I handle switch conflicts?
Section titled “How do I handle switch conflicts?”Resolve conflicts manually by editing files, then use git add to stage resolved files. The switch operation will complete automatically.
Can I switch with submodules?
Section titled “Can I switch with submodules?”Use —recurse-submodules to update submodules when switching branches.
What’s the performance impact of switching?
Section titled “What’s the performance impact of switching?”Generally fast, but can be slower with large working trees or many untracked files.
How do I switch to a branch that doesn’t exist locally?
Section titled “How do I switch to a branch that doesn’t exist locally?”First fetch from remote, then git switch
Can I undo a switch operation?
Section titled “Can I undo a switch operation?”Switching itself is reversible with git switch -, but if you made commits in detached HEAD, they may be lost.
How do I switch to a tag?
Section titled “How do I switch to a tag?”Use git switch —detach
Applications of the git switch command
Section titled “Applications of the git switch command”- Branch Navigation: Safely switch between different development branches
- Feature Development: Create and switch to feature branches for isolated work
- Bug Fixes: Switch to bug fix branches for targeted repairs
- Release Management: Switch between release branches for version control
- Code Review: Switch to branches under review for testing and validation
- Collaborative Development: Coordinate branch switching in team workflows
- Emergency Response: Quick switching for critical fixes and hotfixes
- Workflow Automation: Scripted branch operations in CI/CD pipelines