Skip to main content

Overview

Branches are fundamental to Git workflows, allowing you to develop features, fix bugs, and experiment without affecting the main codebase. GitHub Desktop makes branch management intuitive and visual.

Create Branches

Create new branches from any commit or branch

Switch Branches

Quickly switch between branches with automatic stashing

Merge Branches

Merge branches with conflict detection and resolution

Track Remote

Automatically track branches with upstream remotes

Understanding Branches

Branch Basics

A branch is a pointer to a specific commit in your repository’s history. Branches allow you to:
  • Develop features in isolation
  • Fix bugs without affecting production code
  • Experiment with new ideas safely
  • Collaborate with others on specific changes

Default Branch

Every repository has a default branch (usually main or master):
  • New commits are made to this branch by default
  • Pull requests typically merge into this branch
  • The default branch represents the production or stable code

Creating Branches

Create from Current Branch

1

Open Branch Menu

Click the Current Branch dropdown in the toolbar
2

Click New Branch

Click the New Branch button
3

Name the Branch

Enter a descriptive branch name (e.g., feature/add-login, fix/crash-on-startup)
4

Create Branch

Click Create Branch to create and switch to the new branch

Create from Specific Commit

1

Open History

Switch to the History tab
2

Find Commit

Locate the commit you want to branch from
3

Right-Click Commit

Right-click the commit and select Create Branch from Commit
4

Name and Create

Enter a branch name and click Create Branch

Branch Creation Implementation

// From app/src/lib/git/branch.ts
export async function createBranch(
  repository: Repository,
  name: string,
  startPoint: string | null,
  noTrack?: boolean
): Promise<void> {
  const args = startPoint !== null 
    ? ['branch', name, startPoint] 
    : ['branch', name]
  
  // Don't track if branching from a remote branch
  // This prevents pushing to the upstream of a fork
  if (noTrack) {
    args.push('--no-track')
  }
  
  await git(args, repository.path, 'createBranch')
}
When creating a branch from a remote branch, GitHub Desktop automatically adds --no-track to prevent accidentally pushing to the fork’s upstream.

Switching Branches

Switch to Existing Branch

1

Open Branch List

Click the Current Branch dropdown
2

Select Branch

  • Click a branch to switch to it
  • Or search for a branch by typing
3

Handle Uncommitted Changes

If you have uncommitted changes:
  • Bring changes: Move changes to the new branch
  • Stash changes: Save changes for later
  • Cancel: Return to current branch

Automatic Stashing

When switching branches with uncommitted changes:
  1. GitHub Desktop automatically creates a stash
  2. Switches to the target branch
  3. Attempts to apply the stash
  4. If conflicts occur, leaves the stash for manual application
GitHub Desktop uses a special marker (!!GitHub_Desktop<branch>) to identify stashes it creates, allowing automatic cleanup.

Branch List Organization

The branch dropdown organizes branches into sections:

Default Branch

  • Shows the repository’s default branch at the top
  • Usually main or master

Recent Branches

  • Branches you’ve worked on recently
  • Sorted by last checkout time

Other Branches

  • All other local branches alphabetically

Pull Request Branches

  • Branches associated with open pull requests
  • Grouped by PR status

Remote Branches

  • Branches on the remote that don’t exist locally
  • Can be checked out with one click

Renaming Branches

Rename the current branch or any other branch:
1

Open Branch Menu

Click Current Branch dropdown
2

Find Branch to Rename

Right-click the branch you want to rename
3

Select Rename

Click Rename… from the context menu
4

Enter New Name

Type the new branch name
5

Rename

Click Rename to update the branch name

Rename Implementation

// From app/src/lib/git/branch.ts
export async function renameBranch(
  repository: Repository,
  branch: Branch,
  newName: string,
  force?: boolean
): Promise<void> {
  try {
    await git(
      ['branch', force ? '-M' : '-m', branch.nameWithoutRemote, newName],
      repository.path,
      'renameBranch'
    )
  } catch (error) {
    // Handle case-only renames on case-insensitive filesystems
    if (isGitError(error) && error.result.gitError === DugiteError.BranchAlreadyExists) {
      const stderr = coerceToString(error.result.stderr)
      const m = /fatal: a branch named '(.+?)' already exists/.exec(stderr)
      
      if (m && m[1].toLowerCase() === newName.toLowerCase()) {
        // Case-only rename - retry with -M flag
        return renameBranch(repository, branch, newName, true)
      }
    }
    throw error
  }
}
If you rename a branch that’s been pushed to a remote, you’ll need to delete the old remote branch and push the renamed one.

Deleting Branches

Delete Local Branch

1

Open Branch Menu

Click Current Branch dropdown
2

Find Branch

Right-click the branch to delete
3

Delete

Click Delete from the context menu
4

Confirm

Confirm the deletion in the dialog
Deleting a branch removes the branch pointer, but commits remain in Git’s object database. If you delete a branch with unmerged commits, you may lose access to those commits.

Delete Remote Branch

1

View Remote Branches

In the branch dropdown, find branches under the remote section
2

Right-Click Remote Branch

Right-click the remote branch
3

Delete on Remote

Select Delete on remote
4

Confirm

Confirm you want to delete the branch from the remote repository

Delete Implementation

// From app/src/lib/git/branch.ts
export async function deleteLocalBranch(
  repository: Repository,
  branchName: string
): Promise<true> {
  await git(['branch', '-D', branchName], repository.path, 'deleteLocalBranch')
  return true
}

export async function deleteRemoteBranch(
  repository: Repository,
  remote: IRemote,
  remoteBranchName: string
): Promise<true> {
  const args = ['push', remote.name, `:${remoteBranchName}`]
  
  const result = await git(args, repository.path, 'deleteRemoteBranch', {
    env: await envForRemoteOperation(remote.url),
  })
  
  // Clean up local remote-tracking ref
  if (result.gitError === DugiteError.BranchDeletionFailed) {
    const ref = `refs/remotes/${remote.name}/${remoteBranchName}`
    await deleteRef(repository, ref)
  }
  
  return true
}

Merging Branches

Merge into Current Branch

1

Switch to Target Branch

Check out the branch you want to merge into (e.g., main)
2

Open Branch Menu

Click Branch > Merge into current branch
3

Select Source Branch

Choose the branch to merge from the list
4

Review Merge Info

GitHub Desktop shows:
  • Number of commits to merge
  • Potential conflicts detected
5

Merge

Click Merge [branch] into [current-branch]

Merge Strategies

GitHub Desktop uses standard Git merge strategies:
  • Fast-forward: When possible, simply moves the branch pointer forward
  • Merge commit: Creates a new merge commit when branches have diverged
  • Conflict resolution: Stops and asks for manual resolution when conflicts occur

Comparing Branches

View differences between branches:
1

Open Branch Menu

Click Branch > Compare to Branch
2

Select Branch

Choose the branch to compare with
3

Review Differences

See:
  • Commits that differ between branches
  • Files changed
  • Line-by-line diffs

Branch Status Indicators

Branches in the list show visual indicators:
  • Ahead/Behind: Shows how many commits ahead or behind the upstream
  • Current Branch: Bold text and checkmark icon
  • Default Branch: Star icon
  • Published: Cloud icon indicates the branch exists on remote
  • PR Indicator: Icon shows if there’s an associated pull request

Finding Merged Branches

Identify branches that have been fully merged:
// From app/src/lib/git/branch.ts
export async function getMergedBranches(
  repository: Repository,
  branchName: string
): Promise<Map<string, string>> {
  const args = ['branch', '--merged', branchName, '--format=%(refname)']
  const mergedBranches = new Map<string, string>()
  
  const { stdout } = await git(args, repository.path, 'mergedBranches')
  
  for (const branch of parse(stdout)) {
    // Don't include the comparison branch itself
    if (branch.canonicalRef !== canonicalBranchRef) {
      mergedBranches.set(branch.canonicalRef, branch.sha)
    }
  }
  
  return mergedBranches
}
Use this to safely clean up branches that have been merged into the main branch.

Upstream Tracking

Publishing Branches

Publish a local branch to the remote:
1

Create or Switch to Branch

Ensure you’re on the branch you want to publish
2

Click Publish

Click Publish branch in the toolbar
3

Confirm

GitHub Desktop pushes the branch and sets up tracking

Setting Upstream

When publishing a branch, GitHub Desktop automatically:
  1. Pushes the branch to origin
  2. Sets up upstream tracking with --set-upstream
  3. Enables pull/push for the branch

Branch Naming Conventions

Common branch naming patterns:
feature/user-authentication
feature/add-payment-processing
Use consistent naming conventions across your team. Common patterns include type/description or type/issue-number-description.

Protected Branches

When working with protected branches on GitHub:
  • Force push blocked: Cannot force push to protected branches
  • Review required: May require pull request reviews before merging
  • Status checks: CI/CD checks must pass before merging
  • Admin bypass: Repository admins may have special permissions
GitHub Desktop respects these protections and shows warnings when applicable.

Best Practices

  1. Use Descriptive Names: Branch names should clearly indicate their purpose
  2. Keep Branches Short-Lived: Merge or delete branches after completing work
  3. Update from Main Regularly: Keep feature branches up to date with the default branch
  4. Delete Merged Branches: Clean up branches after merging to avoid clutter
  5. Don’t Commit to Main Directly: Use feature branches for all changes
  6. Use Prefixes: Organize branches with prefixes like feature/, fix/, docs/

Keyboard Shortcuts

ActionWindows/LinuxmacOS
Switch branchCtrl+BCmd+B
New branchCtrl+Shift+NCmd+Shift+N
Find branchCtrl+PCmd+P

Troubleshooting

If you can’t switch branches:
  • Uncommitted changes conflict: Commit, stash, or discard changes
  • Unmerged files: Resolve merge conflicts before switching
  • Detached HEAD: Create a branch from current commit first
If you accidentally deleted a branch:
  1. Find the commit SHA in the History tab
  2. Create a new branch from that commit
  3. Or use git reflog in terminal to find the deleted branch’s tip
When merging causes conflicts:
  • GitHub Desktop highlights conflicted files
  • Resolve conflicts in your editor or using the conflict resolver
  • Stage resolved files and complete the merge
  • See Merge Conflicts for detailed help
Branches cannot be deleted if:
  • It’s the currently checked out branch (switch first)
  • It has unmerged commits (use -D flag to force)
  • It’s the default branch for the repository

Build docs developers (and LLMs) love