If you’ve been using Git for a while and have the basics down there’s more power remaining to be seen. Git is packed with features that most developers never touch, and learning just a handful of them can improve your workflow.
Here are seven concepts that, once learned, you’ll find yourself reaching for regularly.
1. Git Worktree : Work on Multiple Branches Without the Stash
We’ve all been there. You’re deep in a feature, changes are halfway done, and suddenly you need to review someone’s code or jump on a hotfix. You will use git stash, switch branches, do your thing, switch back, git stash pop, and pray you remember which stash was which.
git stash
# ...do other work...
git stash pop
This works, but it has real downsides. If your codebase is large and takes 20–30 minutes to compile, switching branches means recompiling twice. And if you’re a serial stasher, you’ll inevitably lose track of what’s where.
Git worktree solves this elegantly. It lets you check out multiple branches into separate directories simultaneously, all backed by the same repository.
git worktree add -b code-review ../code-review release-branch
This creates a new directory ../code-review with the code-review branch checked out from release-branch. Your original working directory is untouched no stashing, no recompilation.
A few things to keep in mind. Always create your worktree in a sibling directory, not inside your main repo. Nesting worktrees causes duplicate file issues. The main worktree contains the .git folder with all repository metadata, while secondary worktrees have a .git file that points back to the main one.
You can list all active worktrees with git worktree list and clean them up when you're done:
git worktree remove ../code-review
Personally, I keep worktrees open for release branches and branches that need regular code review. It saves a surprising amount of context-switching time.
2. Git Squash : Keep Your History Clean
Over the course of a feature or hotfix, it’s easy to accumulate a trail of commits like “fix typo,” “change color,” “update docs,” and “refactor again.” These might be meaningful while you’re working, but they clutter the project history for everyone else.
Git squash lets you collapse multiple commits into one, giving you a clean, readable history. There are two common approaches.
Interactive rebase:
git rebase -i HEAD~3
This opens an editor showing your last three commits. You mark the ones you want to fold in with squash (or s), keep the top one as pick, and Git combines them. You'll get a chance to write a new commit message.
pick abc1234 Code refactor
squash def5678 Code refactor
squash ghi9012 Code refactor
Squash merge:
When merging a feature branch into your release branch, you can use the --squash flag:
git merge --squash feature-branch
This pulls in all the changes but doesn’t create a commit automatically. You then commit once with a clean message that summarizes the entire body of work. The result is a single, meaningful entry in your branch’s history instead of a dozen incremental ones.
3. Git Aliases : Stop Typing the Same Long Commands
If you’re anything like most Git users, you probably type certain commands dozens of times a day. Commands like:
git log --oneline --graph --decorate
That gets old fast. Git aliases let you create shortcuts for frequently used commands:
git config --global alias.logs "log --oneline --graph --decorate"
Now git logs runs the full command. You can alias complex or long frequently used commands . If you're maintaining an open-source project or spending a lot of time in the terminal, aliases add up to real time savings over the course of a day.
4. Git Bisect : Find the Exact Commit That Broke Things
Regression bugs are frustrating. Something that worked last week is now broken, and somewhere in the last 100 commits, something went wrong. You could manually check out commits one by one, but Git has a smarter tool built in.
git bisect performs a binary search through your commit history to find the exact commit that introduced the bug.
git bisect start
git bisect bad # current HEAD is broken
git bisect good abc1234 # this older commit was working
Git checks out a commit halfway between the two. You run your tests, then tell Git whether that commit is good or bad:
git bisect good # or: git bisect bad
It narrows the range and checks out the next candidate. For 100 commits, you’ll find the culprit in roughly 7 steps instead of 100.
*A practical tip * : If you’re using a test file to verify the bug, add it to .gitignore so it persists across checkouts. Otherwise, Git will remove it each time it switches to a different commit.
5. Git Cherry-Pick : Selectively Apply Commits Across Branches
Sometimes you need to move a specific commit from one branch to another without merging the entire branch. Maybe you fixed a bug on your feature branch that the release branch also needs, but the feature isn’t ready to merge yet.
git cherry-pick does exactly this:
git checkout release-branch
git cherry-pick <commit-hash>
This applies the changes from that single commit onto your current branch as a new commit.
Common use cases include applying a bugfix to a release branch without merging unfinished feature work, backporting fixes to a main or master branch that’s publicly visible, and recovering lost commits that you found via git reflog. It's far cleaner than copy-pasting code changes and committing them separately, which is something you see more often than you'd expect.
6. Git Reflog : Your Safety Net for Lost Commits
git log shows you commit history. git reflog shows you everything like every branch switch, every rebase, every cherry-pick, every checkout. It's a full activity log of what your HEAD has pointed to.
This becomes invaluable when something goes wrong. Say you accidentally delete a local branch that was never pushed to remote:
git branch -D feature-branch
The commits aren’t actually gone yet. Git only deleted the branch label; the commits persist until garbage collection runs, which can be weeks or months later.
To recover:
git reflog
# Find the commit hash from before the deletion
git checkout -b feature-branch <commit-hash>
Your branch and all its commits are back. This works for detached HEAD situations, careless rebases, and any number of “I’ve made a terrible mistake” moments. Think of git reflog as Git's undo history
7. Git Hooks : Automate Quality Checks Before You Commit
Git hooks are scripts that run automatically at specific points in your Git workflow like before a commit, before a push, after a merge, and more. They’re a powerful way to enforce quality standards without relying on memory or discipline.
The most commonly useful hook is the pre-commit hook. Here’s how to set one up from scratch.
Inside any Git repository, navigate to .git/hooks/. You'll find sample files there. To create a pre-commit hook, rename pre-commit.sample to pre-commit (removing the .sample extension) and write your script:
#!/bin/bash
# Pre-commit hook: compile Java files before allowing commit
echo "Running pre-commit checks..."
javac *.java
if [$? -ne 0]; then
echo "Compilation failed. Commit aborted."
exit 1
fi
echo "All checks passed."
exit 0
Now, every time you run git commit, this script executes first. If the compilation fails, the commit is blocked.
You can extend this pattern to run unit tests, static analysis tools like SonarQube, linting, or any validation your project requires. If the hook exits with a non-zero status, the commit is rejected. It’s a simple mechanism that prevents “I forgot to do this before pushing” problems.
✍️Conclusion
These seven concepts sit just beyond the basics, but each one addresses a real world problem that you as a developers face regularly. Worktrees eliminate context-switching overhead. Squash keeps your history readable. Aliases save keystrokes. Bisect turns debugging from a guessing game into a logarithmic search. Cherry-pick gives you precision. Reflog acts as your safety net. And hooks automate through lifecycle events.
Pick one that solves a problem you’re currently facing, try it out. You’ll be surprised how quickly these become part of your daily workflow.






Top comments (0)