DDevLogTechnical writing
Tutorials

Git essentials: branching, staging, and undoing your mistakes

September 15, 2026

Most Git tutorials assume you already understand the model and just need commands. This one assumes the opposite. All you need is a way to run git, and we will build up from staging files to recovering a commit you thought was gone.

Set up a scratch repository

Do not practice on a real project. Make a throwaway directory and initialize it.

mkdir ~/gitscratch && cd ~/gitscratch
git init

Create a file and track it.

echo "hello" > hello.txt
git add hello.txt
git commit -m "add hello"

git status now shows a clean working tree. Run it after every step below and you will see Git's staging model in action.

Staging and committing

Git separates editing a file from recording it. git add moves a change into the staging area (the index); git commit records the staged snapshot permanently.

echo "world" >> hello.txt
git status          # hello.txt shows as modified
git add hello.txt   # stage it
git diff --cached   # see exactly what is staged
git commit -m "add world"

To stage every change at once, git add -A or git add . works. To commit only some files, git add the ones you want and leave the rest unstaged.

A common slip is staging a file by accident. Unstage it without losing your edits:

git restore --staged hello.txt   # unstage; keeps working changes

On older Git you will see git reset HEAD hello.txt for the same job. Both leave the file's edits untouched.

Branching

A branch is just a movable pointer to a commit. Creating one costs nothing.

git branch features/title    # create
git switch features/title    # move to it

git switch -c features/title creates and switches in one step. Older docs use git checkout -b, which still works. Once on the branch, your commits land there and leave main alone:

echo "a grand title" >> hello.txt
git commit -am "add title"
git switch main              # back to the original branch

git switch main; git log --oneline shows the commit is not on main. That is the whole point of a branch: isolated work you can merge or delete.

Undoing with reset and reflog

You will make mistakes. The best mental categories are: unstage, revert the last commit but keep your work, and undo a commit entirely.

To remove the most recent commit but keep your changes staged:

git reset --soft HEAD~1

To remove it and put the changes back in the working tree (unstaged), which is the usual "oops, I committed too early" case:

git reset --mixed HEAD~1     # --mixed is the default

To discard the last commit and its changes completely:

git reset --hard HEAD~1

--hard is dangerous, but not fatal, because of reflog. The reflog records where your HEAD pointers have been, including commits you reset away. Recover a "deleted" commit like this:

git reflog
git reset --hard a1b2c3d

That works even after --hard, because unreachable commits are not garbage-collected immediately. Reflog is your undo history for Git itself. If you are ever unsure what you did, git reflog is the first place to look.

A clean habit to keep

Commit small and often, and treat --hard as a sledgehammer you verify before swinging. Want to double-check what --hard HEAD~1 will destroy? Run git diff HEAD~1 first to see the changes, or git stash instead when you think you might want them back later. When in doubt, you can always copy the working directory to a temp folder before a destructive command.

← More Tutorials