Branches, Stash & Undoing¶
"A branch is a lightweight movable pointer to one of these commits."
Branches¶
A branch is a lightweight movable pointer to a commit. Creating a branch means creating a new pointer to move around. main (or master) is the default branch.
Branch Commands¶
git branch <name> # Create a new branch
git switch -c <name> # Create and switch to new branch
git checkout -b <name> # Same as above (older syntax)
git checkout <name> # Switch to a branch
git branch -a # List all local and remote branches
git branch -r # List only remote branches
git show-branch # List branches with their commits
git rev-parse --abbrev-ref HEAD # Show current branch name only
git branch -m old-name new-name # Rename a branch
git branch -D <name> # Delete a local branch
git push origin <name> # Push and create remote branch
git push origin --delete <name> # Delete a remote branch
git branch --set-upstream-to=origin/<name> # Set branch to track remote
git push --set-upstream origin <name> # Push and set upstream in one command
Merging¶
git merge <branch> # Merge branch into current (be on target branch)
Branch Naming — Sub-branches Don't Exist in Git¶
Git has no concept of sub-branches. The / in a branch name is just a string character — purely a human convention for visual grouping.
feat/FeatureName
test/feat/FeatureName # only "related" by name — Git has no idea
Git sees both as equal, independent branches. The naming is for you, not for Git.
Common Naming Conventions¶
feat/<feature-name> # new feature
fix/<bug-description> # bug fix
refactor/<scope> # refactoring
chore/<task> # maintenance
test/<what-youre-testing> # local test branches
Moving Uncommitted Work to a New Branch¶
If you made changes on the wrong branch:
git switch -c feat/correct-branch # uncommitted changes travel with you
git add .
git commit -m "feat: your message"
If you already committed on the wrong branch:
git reset --soft HEAD~1 # undo commit, keep changes staged
git switch -c feat/correct-branch
git commit -m "feat: your message"
Git Stash¶
Note
Uncommitted changes live in the working directory and staging area, not in a specific branch. Always stash before switching branches when work is still in progress.
Basic Stash Commands¶
git stash # Stash current changes
git stash push -m "message" # Stash with a descriptive name
git stash list # List all stashes
git stash apply # Apply latest stash (keeps it in list)
git stash apply <index> # Apply a specific stash by index
git stash pop # Apply and drop latest stash
git stash pop <index> # Apply and drop specific stash
git stash drop <index> # Delete a specific stash
git stash clear # Delete all stashes
Stash Naming Convention¶
Always name stashes with a prefix for clarity:
git stash push -m "local/properties-logback" # config files reused across branches, never pushed
git stash push -m "wip/<branch>-description" # WIP code tied to a specific branch
git stash push -m "test/what-youre-testing" # local test data only
git stash push -m "drop/whatever" # marked for deletion
Golden rules:
- Keep one
local/config stash total — pop it, use it, re-stash it. Never duplicate - Never commit with local config applied — re-stash before
git push - Never mix
wip/andlocal/in the same stash — stash them separately - Drop a
wip/stash as soon as its branch is merged
Renaming a Stash¶
Git has no native rename command — pop and re-stash:
git stash pop stash@{N} # pop the one to rename
git stash push -m "proper/name" # re-stash with the correct name
Inspecting a Stash Before Applying¶
git stash show -p stash@{N} # full diff of stash N
git show stash@{N}:path/to/file # see one specific file from a stash
git diff stash@{N} -- path/to/file # compare stash version vs current
Applying Only Specific Files from a Stash¶
git checkout stash@{0} -- path/to/file.java # cherry-pick one file from a stash
Undoing & Reverting¶
Revert a Commit (Safe — Creates a New Commit)¶
Reverting creates a new commit that undoes the changes of a previous one. The original commit stays in history.
git revert <commit-id> # revert a specific commit
Revert a Repository to a Previous Commit¶
git revert --no-commit 0766c053..HEAD
git commit
git push
Delete the Last Commit Locally and Remotely¶
git reset HEAD^ --hard # reset local branch to parent commit
git push origin -f # force push to remote
Or using the commit hash directly:
git push origin +<commit-hash>^:master # force remote to parent of that commit
Delete a Local Commit (Interactive Rebase)¶
git rebase -i HEAD~x # x = number of commits back to edit
In the editor, change pick to drop for the commit you want to remove.
Git Prune¶
Cleans up unreachable or orphaned git objects and outdated remote branch references:
git prune # clean up unreachable objects
git fetch --all --prune # fetch and clean outdated remote branches
Divergent Branches on Pull¶
Happens when two sources commit to the same branch (e.g. you locally + GitHub Actions). Git refuses to pull without knowing how to reconcile.
Fix permanently:
git config --global pull.rebase true # always rebase instead of merge on pull
For a one-time fix:
git pull --rebase origin <branch-name>
Ways of Resolving git push rejected non-fast-forward¶
Start with:
git pull origin
If that doesn't work, fetch and rebase manually:
git fetch origin feature/my-branch:tmp # fetch remote branch to tmp
git rebase tmp # rebase on it
git push origin HEAD:feature/my-branch # push rebased changes
git branch -D tmp # clean up temp branch
Or the simpler approach:
git fetch
git rebase feature/my-branch
git push origin feature/my-branch
See more approaches here.