A branch in Git is a movable pointer to a commit. Instead of copying your whole project into a new folder, Git lets you create a lightweight branch and continue work there.
This is one of Gitâs biggest strengths. You can build a feature, fix a bug, or test an idea without disturbing the main line of development.
Tip: A branch is not a second copy of the project. It is a label that points to a specific place in commit history.
Imagine the main branch contains stable application code. You want to add a login page, but the work may take several commits. Instead of changing main directly, you create a feature branch.
Benefits of branching:
In real teams, short-lived feature branches are common because they keep the shared branch clean.
To list local branches:
git branchThe current branch is marked with *.
To see both local and remote branches:
git branch -aA typical result might be:
* main
feature/login
remotes/origin/mainCreate a new branch called feature/login:
git branch feature/loginThis creates the branch, but you stay on your current branch until you switch.
To create and switch in one step, use:
git switch -c feature/loginOlder tutorials may use git checkout -b feature/login, which still works, but git switch is clearer for branch changes.
Move to an existing branch:
git switch mainSwitch back:
git switch feature/loginWhen you switch branches, Git updates your working directory to match the selected branchâs latest commit.
git switch -c feature/navbar
echo "Add navigation" >> README.md
git add README.md
git commit -m "Document navbar plan"
git switch mainAfter switching back to main, that change is no longer visible there because it belongs to the feature branch.
HEAD is Gitâs way of saying âyour current position.â Most of the time, HEAD points to the branch you are currently on.
If you are on main, HEAD points to main, and main points to the latest commit on that branch.
You can inspect recent history with:
git log --oneline --decorate -5You may see output like:
7fa12cd (HEAD -> feature/login) Add login form markup
1ab93e0 (main) Create app skeletonThat means HEAD currently points to feature/login.
After a branch has been merged and is no longer needed, delete it to keep the repository tidy.
Delete a fully merged branch safely:
git branch -d feature/loginForce delete a branch that has unmerged commits:
git branch -D feature/loginNote: Use
-Dcarefully. It can remove a branch pointer before its work is merged elsewhere.
A detached HEAD happens when HEAD points directly to a commit instead of a branch.
For example:
git checkout 1ab93e0Now you are no longer âonâ main or feature/login. You are looking at a specific past commit.
This can be useful for inspection, testing, or reproducing an old state. But if you make commits here, they are not attached to a branch unless you create one.
If you decide to keep that work, create a branch immediately:
git switch -c investigate-old-releaseThat gives the new commits a proper branch name and keeps them easy to find.
Teams usually prefer simple, descriptive names such as:
feature/login-pagefix/pipeline-timeoutdocs/git-tutorialhotfix/rollback-scriptA good branch name helps everyone understand the purpose of the work.
Here is a realistic beginner workflow:
git switch main
git pull
git switch -c feature/add-footer
echo "Footer content" >> index.html
git add index.html
git commit -m "Add footer to homepage"
git switch mainAt this point, main stays stable while the new work lives on feature/add-footer until it is reviewed and merged.
Branches are lightweight and powerful. Use them to isolate work, protect stable code, and make collaboration easier. HEAD represents your current location in history. Most of the time it points to a branch, but during detached HEAD it points directly to a commit.
If you remember one best practice, remember this: create a branch before doing meaningful new work.
Scenario: main is stable and you want to build a new navbar without disturbing it.
Question: Which command both creates and switches to the feature branch in one step?
<MCQExercise
exercise={{
id: 'git-branching-q1',
title: 'Exercise 1: Creating isolated work',
description: 'Choose the one-step command for creating and switching to a new branch.',
options: [
{ id: 'a', text: 'git merge feature/navbar' },
{ id: 'b', text: 'git switch -c feature/navbar' },
{ id: 'c', text: 'git log --oneline --decorate -5' },
{ id: 'd', text: 'git branch -d feature/navbar' },
],
correctId: 'b',
explanation: 'The tutorial introduced git switch -c as the clearer modern way to create a branch and move HEAD to it immediately. That keeps the new work isolated from main.',
wrongExplanations: {
a: 'Merge combines history from an existing branch; it does not create a new feature branch for you.',
c: 'Log inspection helps you read history, but it does not create or switch branches.',
d: 'That deletes a branch instead of creating one.',
},
}}
/>
Question: In git log --oneline --decorate, you see (HEAD -> feature/login) next to the latest commit. What does that mean?
<MCQExercise
exercise={{
id: 'git-branching-q2',
title: 'Exercise 2: Reading HEAD correctly',
description: 'Interpret a decorated log entry where HEAD points to a branch.',
options: [
{ id: 'a', text: 'Git is in detached HEAD state on an unnamed commit.' },
{ id: 'b', text: 'The remote branch origin/feature/login has been deleted.' },
{ id: 'c', text: 'The feature/login branch is merged and can no longer receive commits.' },
{ id: 'd', text: 'Your current position is on the feature/login branch, and that branch points to the shown commit.' },
],
correctId: 'd',
explanation: 'The tutorial described HEAD as your current position. When the log says (HEAD -> feature/login), HEAD is attached to that branch and the branch points to the displayed commit tip.',
wrongExplanations: {
a: 'Detached HEAD would mean HEAD points directly to a commit rather than through a named branch.',
b: 'The decorate output says nothing about deletion of the remote branch.',
c: 'A branch being checked out does not imply it is merged or closed to new commits.',
},
}}
/>
Scenario: You checked out an old commit to investigate a bug and now want to keep new work you started there.
Question: What is the safe next step from the lesson?
<MCQExercise
exercise={{
id: 'git-branching-q3',
title: 'Exercise 3: Escaping detached HEAD safely',
description: 'Choose the action that preserves new work created from a detached HEAD state.',
options: [
{ id: 'a', text: 'Create a branch immediately with git switch -c investigate-old-release.' },
{ id: 'b', text: 'Run git branch -D main so the old commit becomes permanent.' },
{ id: 'c', text: 'Push directly to origin without creating any branch.' },
{ id: 'd', text: 'Use git checkout main and expect Git to carry detached commits automatically.' },
],
correctId: 'a',
explanation: 'The tutorial explicitly recommended creating a branch right away when you decide detached HEAD work should be kept. That attaches future commits to a named branch so they remain easy to find.',
wrongExplanations: {
b: 'Deleting main is unrelated and dangerous. It does not solve detached HEAD bookkeeping.',
c: 'Without a proper branch, the new commits are easy to lose and the workflow stays unclear.',
d: 'Switching away without creating a branch can leave detached commits difficult to locate later.',
},
}}
/>
HEAD normally points at a branch name, which in turn points at a commit. When you check out a commit, tag, or remote-tracking branch directly, HEAD points straight at that commit with no branch attached, that is detached. You can look around and even commit, but those commits belong to no branch and become unreachable once you leave. If you have made commits you want to keep, git switch -c <new-branch> right where you are captures them. If you have not, git switch main returns you to normal.
git branch -d <name> deletes a local branch and refuses if it holds commits not merged anywhere, which is a safety net worth keeping; -D forces it. For the remote, git push origin --delete <name>. Deleting a remote branch does not remove other people's stale local copies of it. They need git fetch --prune, or git config --global fetch.prune true to have it happen automatically on every fetch.
git branch -m <new-name> renames the branch you are on, or git branch -m <old> <new> for another one. Renaming a branch that exists on the remote takes three steps, because the remote branch is a separate reference: rename locally, push the new name with git push origin -u <new-name>, then delete the old one with git push origin --delete <old-name>. Anyone else working on it needs to re-point their local branch, so agree the change first.
Use a short prefix that says what kind of change it is, then a brief description in kebab-case: feature/user-search, fix/login-redirect, chore/bump-deps. Many teams add the ticket number, feature/PROJ-412-user-search, which lets tooling link branches to issues automatically. Keep them lowercase and avoid spaces and unusual characters, since branch names become part of URLs and filesystem paths. The value is not aesthetic: a consistent scheme makes git branch --list 'fix/*' and automated cleanup possible.
No, and this is why Git branching is fast where older systems were slow. A branch is a 41-byte file containing a commit hash. A pointer, nothing more. Creating one writes that file and does not touch your working directory at all, which is why git switch -c is instant even in a huge repository. Switching branches then updates only the files that actually differ between the two commits.
Learn git merge: fast-forward versus three-way merges, resolving conflict markers step by step, --no-ff and squash merges, and aborting a bad merge.
Use git rebase for a linear history: basic and interactive rebase, squashing, recovering with --abort and reflog, force-with-lease, and when to merge instead.
Work with Git remotes confidently: fetch versus pull, fixing a rejected push without force, upstream tracking, pruning branches and origin versus upstream.