Get AI summaries of any video or article — Sign up free
13 Advanced (but useful) Git Techniques and Shortcuts thumbnail

13 Advanced (but useful) Git Techniques and Shortcuts

Fireship·
5 min read

Based on Fireship's video on YouTube. If you like this content, support the original creators by watching, liking and subscribing to their content.

TL;DR

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?

Using `git commit -a` (the transcript calls it the “am flag”) automatically stages changes in the current working directory, removing the need for a separate `git add` step. That reduces friction for routine updates and makes it easier to keep momentum when the changes are already in the right place.

What’s the difference between fixing the latest commit with `--amend` and undoing a pushed change with `git revert`?

`git commit --amend` rewrites the latest commit by updating its message and/or adding missing files (optionally with `--no-edit` to keep the message). If that commit was already pushed, the remote must be overwritten with `git push --force`, which can discard remote-only commits. `git revert` instead creates a new commit that returns the project to the state of an earlier commit, preserving history and avoiding force-push risk.

When should `git stash` be used, and how can stashes be managed later?

`git stash` is for work-in-progress that can’t be committed yet—changes that would break the build or reveal unfinished experiments. It removes changes from the working directory while saving them for later. The transcript highlights naming stashes (`git stash save <name>`), listing them (`git stash list`), and restoring a specific one (`git stash apply <index>`).

How does `git bisect` find the commit that introduced a bug?

`git bisect` starts from a known-good commit (for example, “it worked a few hours ago”) and a range that includes the suspected bad commits. Git then performs a binary search through the intervening commits. After checking out each candidate, the developer marks it with `git bisect good` (or the equivalent bad marking, implied by the flow) until the exact bad commit is identified.

What does interactive rebase do for commit history, and how do `squash` and `fixup` change the result?

Interactive rebase (`git rebase -i`) opens a plan listing commits on a branch. Commands like `pick` keep commits, `reword` edits messages, and `squash` combines commits into the original commit while prompting for a combined message. `fixup` combines commits but discards the extra commit messages. The transcript also notes `--fixup` during commit creation and the `--autosquash` option to automate the squashing during rebase.

How do Git hooks and `husky` fit into a developer workflow?

Git hooks run scripts automatically before or after certain Git events (like commits) by using configurable scripts in the hidden `.git/hooks` directory. For JavaScript projects, `husky` simplifies setting up these hooks so developers can validate, lint, or link code automatically before commits, improving code quality without relying on manual checks.

Review Questions

  1. 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?
  2. Describe a scenario where `git revert` is safer than `git reset --hard` or force-pushing.
  3. How would you use `git rebase -i` to turn three feature-branch commits into a single clean commit for merging?

Key Points

  1. 1

    Use `git commit -a` to stage and commit changes in the current working directory without a separate `git add`.

  2. 2

    Create Git aliases to shorten frequent commands and reduce repetitive typing.

  3. 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. 4

    Prefer `git revert` to undo a pushed change without rewriting history, since it adds a new commit that restores an earlier state.

  5. 5

    Use `git stash` to park unfinished work safely, and manage stashes with `save`, `list`, and `apply` by index.

  6. 6

    Speed up debugging with `git bisect` by binary-searching between a known-good commit and the range that includes the bug.

  7. 7

    Clean up local messes with `git fetch` + `git reset --hard`, then remove leftover untracked files using `git clean`.

Highlights

`git commit -a` removes the need for `git add` in many everyday workflows by auto-staging changes in the working directory.
`git revert` undoes a bad commit by adding a new “restore” commit, avoiding the history-rewrite hazards of force-pushing.
`git bisect` turns “it broke sometime recently” into a binary search that can pinpoint the exact offending commit.
Interactive rebase with `squash`/`fixup` can turn noisy feature-branch history into a single, merge-friendly commit.
Git hooks (often via `husky` for JavaScript) can enforce quality checks automatically before commits.

Topics

  • Git Aliases
  • Amend vs Revert
  • Stashing Work
  • Bisect Debugging
  • Interactive Rebase Squash
  • Git Hooks
  • Reset and Clean
  • Branch Naming