13 Advanced (but useful) Git Techniques and Shortcuts
Based on Fireship's video on YouTube. If you like this content, support the original creators by watching, liking and subscribing to their content.
Use `git commit -a` to stage and commit changes in the current working directory without a separate `git add`.
Briefing
Git productivity often comes down to avoiding the two classic disasters: committing the wrong thing (or with the wrong message) and then trying to fix it after the fact. The most practical theme running through these “advanced but useful” techniques is that Git gives you surgical control over history and working state—so you can recover quickly without turning every mistake into a multi-hour debugging session.
A fast workflow starts with skipping redundant steps. Instead of running `git add` and then `git commit`, the `-a` (am) flag lets `git commit -a` automatically stage changes in the current working directory. For even more speed, Git aliases can compress longer commands into short custom shortcuts (for example, an `ac` alias that performs add+commit). When speed causes errors, `--amend` becomes the safety net: it updates the latest commit with a corrected commit message or missing/staged files. If the commit message needs to stay the same, `--no-edit` preserves it. But amending after pushing requires caution—using `git push --force` overwrites the remote branch with the amended local state, and any remote-only commits can be lost.
When the wrong code has already been pushed and should be undone without rewriting history, `git revert` provides a cleaner rollback. It creates a new commit that returns the repository to the state of a chosen earlier commit, leaving the original commit in history. For situations where local access isn’t available, GitHub’s web-based editing and GitHub Codespaces let developers make changes and submit pull requests from a browser or cloud VS Code environment.
To manage work-in-progress safely, `git stash` temporarily removes changes from the working directory while keeping them for later. Stashes can be named (`git stash save <name>`), listed (`git stash list`), and restored (`git stash apply <index>`), which is especially useful when experiments would otherwise block committing stable code.
The transcript also targets day-to-day repo hygiene and debugging. It notes the modern default-branch naming shift away from `master` toward `main` (or other names), and it improves commit history readability with `git log --graph --oneline --decorate`. For pinpointing the exact commit that introduced a bug, `git bisect` performs a binary search between a known-good commit and a suspected bad range, using `git bisect good` as you validate each step.
For cleaner pull requests, interactive rebasing enables commit squashing. Using `git rebase -i` on the target branch brings up a list of commits where `pick`, `reword`, `squash`, and `fixup` control what happens to each commit. Auto-squash options can preconfigure squashing behavior when commits were created with `--fixup`.
Finally, the transcript covers automation and cleanup. Git hooks let developers run scripts before or after Git events; `husky` is highlighted as a common way to set up JavaScript-friendly hooks. For recovery from a bad local state, `git fetch` followed by `git reset --hard` restores the local branch to match the remote, and `git clean` removes leftover untracked files/build artifacts. If Git is no longer desired, deleting the hidden `.git` directory effectively resets the project to non-Git status. A quick navigation shortcut—`git checkout -`—returns to the previous branch after switching. Together, these techniques aim to make Git feel less like a trap and more like a set of reliable tools for editing, debugging, and maintaining history.
Cornell Notes
Git becomes far less stressful when developers learn a small set of “recovery and control” commands. The workflow starts with speed (`git commit -a` to skip `git add`, aliases for shorter commands) and then moves to correction (`git commit --amend` and `--no-edit` for the latest commit, with `git push --force` only when rewriting remote history is acceptable). Mistakes that must be undone without rewriting history are handled with `git revert`, while `git stash` protects half-finished work until it’s ready. Debugging gets sharper with `git log --graph --oneline --decorate` for readable history and `git bisect` for binary-searching the commit that introduced a bug. For cleaner merges, interactive rebase (`git rebase -i`) supports squashing commits, and hooks (e.g., via `husky`) automate quality checks.
How can a developer commit changes without running `git add` first, and why does that matter?
What’s the difference between fixing the latest commit with `--amend` and undoing a pushed change with `git revert`?
When should `git stash` be used, and how can stashes be managed later?
How does `git bisect` find the commit that introduced a bug?
What does interactive rebase do for commit history, and how do `squash` and `fixup` change the result?
How do Git hooks and `husky` fit into a developer workflow?
Review Questions
- What are the risks of using `git commit --amend` after a commit has already been pushed, and how does `git push --force` change the outcome?
- Describe a scenario where `git revert` is safer than `git reset --hard` or force-pushing.
- How would you use `git rebase -i` to turn three feature-branch commits into a single clean commit for merging?
Key Points
- 1
Use `git commit -a` to stage and commit changes in the current working directory without a separate `git add`.
- 2
Create Git aliases to shorten frequent commands and reduce repetitive typing.
- 3
Use `git commit --amend` (and `--no-edit`) to fix the latest commit, but avoid rewriting remote history unless you’re prepared to force-push.
- 4
Prefer `git revert` to undo a pushed change without rewriting history, since it adds a new commit that restores an earlier state.
- 5
Use `git stash` to park unfinished work safely, and manage stashes with `save`, `list`, and `apply` by index.
- 6
Speed up debugging with `git bisect` by binary-searching between a known-good commit and the range that includes the bug.
- 7
Clean up local messes with `git fetch` + `git reset --hard`, then remove leftover untracked files using `git clean`.