DevToys Web Pro iconDevToys Web Proಬ್ಲಾಗ್
ಅನುವಾದ LocalePack logoLocalePack
ನಮಗೆ ರೇಟಿಂಗ್ ನೀಡಿ:
ಬ್ರೌಸರ್ ಎಕ್ಸ್ಟೆನ್ಶನ್ ಪ್ರಯತ್ನಿಸಿ:
← Back to Blog

Git Command Finder Guide: Undo, Branch, Stash, Rebase, and Recovery Recipes

15 min read

Nobody remembers git. Not the people who use it every day, not the people who wrote tutorials about it, and definitely not the person frantically googling "how to undo git push" at 11pm on a Friday. The porcelain is inconsistent, the flags collide, and half the answers on Stack Overflow start with "first, try this — but don't run it if you have uncommitted changes, untracked files, or a fear of data loss." The trick is not memorization. The trick is recognition: you know what you want to do, you just need the right incantation.

This is a scenario-to-command guide. Twenty recipes that cover 95% of the real git problems you hit in a working week — undoing commits, cleaning up branches, stashing, rebasing, recovering work you thought you lost. No reference manual dumps, no fifty-flag man-page excerpts. Copy the command, understand the "why," and move on. For the full searchable finder with 40+ scenarios, keep the Git Command Finder open in a tab.

The Five Problems Everyone Has

If you track every git question asked in a team chat for a month, they cluster into five buckets. Master these and you will answer 80% of your own future questions.

1. Undo

"I committed the wrong thing." "I pushed before running tests." "I need to roll back a change but keep the file." The undo family covers working tree, staged changes, local commits, and pushed commits, and each case needs a different tool. Jump straight to the undo-pushed-commit recipe when a bad commit is already on the remote — it walks you through git revert versus force-pushing a reset, and when each is safe.

2. Branch

"I made a branch off the wrong base." "I need to delete a branch from the remote without hacking at the UI." "I want to rename master to main." Branching is where git feels powerful and where most accidents start. The delete-remote-branch recipe shows the syntax that still surprises people after years of using git (hint: the leading colon).

3. Stash

"I need to switch branches right now but I'm in the middle of something." Stash is the context-switch tool — a local shelf for work-in-progress. The stash-changes recipe covers basic push/pop plus the three flags that matter: -u for untracked files, -k to keep staged changes, and named stashes so you can tell two stashes apart a week later.

4. Rebase

"My PR has fifteen 'fix typo' commits and the reviewer asked me to clean them up." "I want to rebase onto main without a messy merge commit." Rebase is feared and misunderstood, but the single most useful variant — interactive rebase for squashing — takes about ten minutes to learn. Start at interactive-rebase-squash.

5. Recovery

"I think I just deleted work." "I reset hard before pushing and now I can't find the commits." Almost nothing is truly lost in git for 90 days — the reflog remembers everything. The recover-deleted-commit recipe is the first thing to run before you panic.

Reset vs Revert vs Checkout: The Most-Confused Trio

These three commands all "undo" something, but they undo different things, in different ways, with different consequences for anyone else working on the branch. Picking the wrong one is how people lose a day of work.

CommandWhat It DoesHistory ImpactSafe on Shared Branch?
resetMoves HEAD (and optionally index/working tree) to a different commitRewrites history — commits after the target are "dropped" from the branchNo — destroys commits others may have pulled
revertCreates a new commit that inverts a previous onePreserves history — adds a commit, never removes oneYes — designed for shared branches
checkout (file mode)Replaces a file in the working tree with its version from a commitNo impact on history — only affects the working tree (and optionally the index)Yes — purely local operation

Reset comes in three flavors that trip everyone up:

# --soft: move HEAD, keep index and working tree
# Use when: you want to re-commit the same changes differently
git reset --soft HEAD~1

# --mixed (default): move HEAD and reset index, keep working tree
# Use when: you want to un-stage changes but keep the edits on disk
git reset HEAD~1

# --hard: move HEAD and wipe index and working tree
# Use when: you want the commits AND the changes gone completely
git reset --hard HEAD~1

Warning: git reset --hard is the command that destroys work. If you have uncommitted changes in the working tree or index, they are gone — not in the reflog, not in any pack file, gone. Run git status first. If you see unstaged changes you want to keep, stash them before resetting.

Revert is the right call for anything that has left your machine:

# Revert a single commit (creates a new inverse commit)
git revert abc1234

# Revert a merge commit (specify the parent to preserve)
git revert -m 1 abc1234

# Revert a range of commits in reverse order
git revert --no-commit HEAD~3..HEAD
git commit -m "Revert last 3 commits"

Checkout in file mode is the "discard changes to this file" escape hatch:

# Discard unstaged changes to a specific file
git checkout -- path/to/file.ts

# Modern equivalent (git 2.23+)
git restore path/to/file.ts

# Restore file from a specific commit
git checkout abc1234 -- path/to/file.ts

Rule of thumb: if the commit has been pushed, use revert. If it's still local, reset is fine. If you only need to throw away file edits, restore or checkout --.

Merge vs Rebase: Pick One Per Team

Both merge and rebase integrate changes from one branch into another. They produce different histories and different ergonomics for reviewers.

AspectMergeRebase
History shapeBranching graph with merge commitsLinear sequence of commits
Preserves original commits?Yes — unchangedNo — creates new commits with new hashes
Conflict resolutionResolve once, in the merge commitResolve at each replayed commit (potentially many times)
Good forPublic / shared branches; preserving the chronological storyPrivate feature branches; cleaning up before a PR; keeping main linear
Dangerous whenNever really — merge is additiveRebasing commits others have already pulled

Decision rule: rebase your local feature branch onto main while you're the only person working on it. Merge (or better, squash-merge via the PR UI) back into main when the feature lands. Never rebase a branch that other people have based their work on.

# Update your feature branch with the latest main
git checkout feature/my-thing
git fetch origin
git rebase origin/main

# If conflicts appear, resolve them, then continue
git add resolved-file.ts
git rebase --continue

# Or abort and go back to where you were
git rebase --abort

Warning: git rebase rewrites history. Once you have rebased, the commit hashes change, and any branch pointing at the old commits will diverge. Only rebase branches that live on your machine.

One small setting that prevents a lot of pain: configure git pull to rebase by default. This stops git from creating "merge pull from origin/main" commits every time you pull.

# Globally prefer rebase on pull
git config --global pull.rebase true

# Only fast-forward pulls; fail if a rebase/merge is needed
git config --global pull.ff only

The Reflog: Stop Panicking About Lost Commits

The reflog is git's local history of where HEAD has been. Every commit, reset, rebase, checkout, cherry-pick — anything that moves HEAD — is recorded. By default git keeps reflog entries for 90 days, which means almost nothing you do locally is truly unrecoverable for three months.

# Show the last 20 moves of HEAD
git reflog

# Typical output:
# abc1234 HEAD@{0}: commit: Add pagination to feed
# def5678 HEAD@{1}: reset: moving to HEAD~2
# 789abcd HEAD@{2}: commit: Broken draft I meant to keep

To recover a commit, grab the hash from the reflog and either reset to it or cherry-pick it:

# Jump HEAD back to where it was 3 moves ago
git reset --hard HEAD@{3}

# Or cherry-pick a specific "lost" commit onto the current branch
git cherry-pick 789abcd

# Recover a branch that was deleted entirely
git reflog                              # find the last commit on it
git checkout -b my-recovered-branch 789abcd

Worked example. Suppose you delete a feature branch before merging it: git branch -D feature/x. Panic. Now:

# Find the tip of the deleted branch
git reflog | grep feature/x
# -> abc1234 HEAD@{12}: checkout: moving from main to feature/x

# Re-create the branch at that commit
git branch feature/x abc1234

# Or check it out directly
git checkout -b feature/x abc1234

The reflog is per-repository and per-clone, so a deleted branch that was only pushed to a remote still requires the remote's reflog (which most services expose via admin tools, or you can ask a teammate who still has it locally).

Force-Push Safely: Lease vs Force

Sometimes you genuinely need to replace what's on a remote branch — usually after rebasing a feature branch to clean up history before merging. A plain git push --force blindly overwrites whatever was there. A git push --force-with-lease only overwrites if the remote is in the state you last saw, which is the difference between a clean rewrite and silently stomping on a teammate's new commit.

FlagBehaviorWhen to Use
--forceOverwrite remote ref unconditionallyAlmost never — you're asking for trouble
--force-with-leaseOverwrite only if the remote is still at the commit your local origin/x points atAfter a rebase of your own feature branch
--force-if-includesLike lease, plus verifies your local ref includes everything currently on remoteModern safer default (git 2.30+)
# The "I just rebased and need to push" workflow
git fetch origin
git rebase origin/main
git push --force-with-lease origin feature/my-thing

# Extra safety: also check your local is up to date
git push --force-with-lease --force-if-includes origin feature/my-thing

Warning: force-push, even with --force-with-lease, rewrites remote history. Anyone else with a local copy of that branch will have to hard-reset to the new tip. Never force-push to main, master, or any branch your team has agreed is append-only. Configure branch protection on the remote to make this impossible.

Bisect: Find a Bad Commit Without Thinking

git bisect binary-searches your history for the commit that introduced a bug. You mark a known-good commit and a known-bad commit; git checks out the midpoint, you test, tell it "good" or "bad," and it narrows the range in log2(n) steps.

# Start bisect; mark current HEAD as bad
git bisect start
git bisect bad

# Mark a commit (or tag) from before the bug as good
git bisect good v1.2.0

# Git checks out the midpoint; test your code, then tell it:
git bisect good    # or: git bisect bad

# When done, bisect reports the offending commit
git bisect reset   # return to where you started

The real superpower is git bisect run — hand it a script that exits 0 for good and non-zero for bad, and git bisects automatically:

# Automated bisect with your test suite
git bisect start HEAD v1.2.0
git bisect run npm test

# Or with a custom reproduction script
git bisect run ./scripts/reproduce-bug.sh

For regressions you can identify by a specific string change (a removed API, a renamed variable), git log -S is often faster than bisect:

# Show commits that added or removed the string "oldFunctionName"
git log -S "oldFunctionName" --source --all

# Same but for a regex
git log -G "someRegex.*pattern" --all

Interactive Rebase: The Ten-Minute Tutorial

Interactive rebase is the feature that makes messy feature branches presentable before a pull request. It opens an editor listing your commits, you change the verb next to each one, save, and git replays the branch with your edits applied.

# Interactively rebase the last 5 commits
git rebase -i HEAD~5

Your editor will open with something like:

pick abc1234 Add pagination
pick def5678 fix typo
pick 789abcd fix typo again
pick 1a2b3c4 add missing import
pick 5d6e7f8 Extract helper function

# Commands:
# p, pick   = use commit
# r, reword = use commit, but edit the commit message
# e, edit   = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup  = like "squash" but discard this commit's log message
# d, drop   = remove commit

To collapse the three "fix typo" commits and the missing-import commit into the first one:

pick abc1234 Add pagination
fixup def5678 fix typo
fixup 789abcd fix typo again
fixup 1a2b3c4 add missing import
pick 5d6e7f8 Extract helper function

Save and close. Git replays the branch, and you end up with two clean commits.

Common uses:

  • Squash before merge: combine WIP commits into one coherent change
  • Reword commit messages: fix typos or improve clarity in past commit messages
  • Reorder commits: rearrange the order by moving lines up and down
  • Drop accidental commits: remove a commit that shouldn't be there
  • Split commits: use edit, then git reset HEAD^ and commit pieces separately

Warning: interactive rebase rewrites history. If the commits have already been pushed, you will need a --force-with-lease push afterward, and you must coordinate with anyone else working on that branch. Don't rebase pushed commits on shared branches.

Aliases Worth Setting

The five aliases below pay for themselves in the first day. Add them to your global git config and forget about them.

# ~/.gitconfig
[alias]
    # Pretty one-line graph log with colors, authors, and relative dates
    lg = log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit

    # Concise status, no mercy for verbosity
    st = status -sb

    # Uncommit the last commit but keep the changes staged
    undo = reset --soft HEAD^

    # WIP commit you can rebase away later; use when context-switching
    save = "!git add -A && git commit -m 'WIP savepoint'"

    # Amend the last commit without touching the message
    amend = commit --amend --no-edit

How each one earns its keep:

  • git lg — one-line graph log. Replaces every "what did I do last week" question.
  • git st — short status. Fits on one screen even with dozens of changed files.
  • git undo — soft-reset the last commit. Perfect when you committed to the wrong branch or need to split a commit into two.
  • git save — quick WIP commit so you can checkout elsewhere without stashing. Rebase or reset it away when you come back.
  • git amend — silently amend the last commit with newly-staged changes. Saves five seconds every time, and you will run it ten times a day.

Bonus: set a global ignore file for editor droppings you never want to commit:

# Create and register a global gitignore
cat > ~/.gitignore_global <<'EOF'
.DS_Store
Thumbs.db
.idea/
.vscode/
*.swp
*.swo
EOF

git config --global core.excludesfile ~/.gitignore_global

When to Reach for a GUI

Hardcore CLI users sometimes pretend the terminal is always the right answer. It isn't. Certain tasks — interactive staging, blame archaeology, bisect visualization — are dramatically faster in a good GUI. The trick is knowing which tool wins which task.

ToolPlatformStrength
TowermacOS / WindowsPolished UI, conflict resolution, submodule management
GitKrakenmacOS / Windows / LinuxVisual graph, integrated issue tracking, cross-platform
ForkmacOS / WindowsFast, keyboard-friendly, excellent interactive rebase editor
Sublime MergemacOS / Windows / LinuxNative performance, side-by-side diff, incremental file staging
git-gui / gitkEverywhereShips with git, zero-install blame and commit viewer
VS Code Source ControlEverywhereIn-editor diff, staging hunks, integrates with extensions

Use a GUI for: interactive staging of individual hunks, browsing blame across a file's history, visualizing a messy branch graph, resolving non-trivial merge conflicts, exploring a bisect result.

Stick with the CLI for: anything scripted or automated, fast commits and pushes, remote operations, working on a server or container without a display, and workflows you want to reproduce identically on every machine you use. Muscle memory for git status and git commit -am beats any UI when the task is trivial.

The Twenty-Recipe Payoff

Git becomes tractable the moment you stop trying to memorize it and start treating it as a lookup problem. Every scenario in this guide is one of twenty recipes. Bookmark the ones you hit this week, skim the rest when you need them, and let your fingers forget the flags — you don't need them in your head, you need them one search away.

The Git Command Finder covers 40+ scenarios with copy-paste commands, scenario tags, and direct anchor links so you can jump to exactly the recipe you need. It's the reference you wish existed the first time you rebased onto the wrong branch.


Pair this guide with the Git Command Finder for the complete scenario list — everything from "revert a merge commit" to "rewrite author in the entire history" — with examples you can copy and run without reading a man page.