git · level 4

Advanced

Stash, worktrees, hooks, reset vs restore, and disaster recovery via reflog.

250 XP

Advanced Git

These tools solve problems that the core workflow doesn't cover: juggling multiple tasks, splitting a repository, enforcing policy at commit time, and recovering from catastrophic mistakes.

Analogy

Advanced git is the toolkit a contractor keeps on the truck for bad days. stash is the tarp you throw over a half-built wall so you can drive off to a different job without losing the loose bricks. Worktrees are parking a second trailer at a different address so you can frame one house and re-shingle another without packing up between trips. Submodules are embedding a pre-fabricated shed on the property with a plaque noting exactly which factory batch it came from. Hooks are the inspector who stands at the gate and refuses to let sloppy lumber leave the yard. And the reflog is the site's private CCTV that keeps rolling even when you demolish a wall — if you swing the sledgehammer at the wrong one, you can replay the tape and rebuild.

git stash

Stash saves your uncommitted changes to a temporary stack and restores a clean working tree. Use it when you need to switch context without committing half-done work.

git stash                           # save everything (tracked + staged)
git stash -u                        # include untracked files
git stash push -m "wip: auth refactor"  # name the stash

git stash list                      # view all stashes
git stash pop                       # apply and remove the most recent stash
git stash apply stash@{2}           # apply a specific stash, keep it in the list
git stash drop stash@{0}            # delete a stash
git stash clear                     # delete all stashes

# Create a branch from a stash (useful for long-lived stashes)
git stash branch feat/auth-refactor stash@{0}

Stashes are local. They do not push to the remote. For anything you might need more than a day, push a WIP branch instead.

git worktrees

A worktree lets you check out two branches simultaneously in different directories, from the same repository clone. You do not need two separate clones.

git worktree add ../project-hotfix fix/payment-crash
# ../project-hotfix is now a directory with that branch checked out

git worktree list                   # list all worktrees
git worktree remove ../project-hotfix   # remove when done

Common use: you're mid-refactor on a feature branch and a hotfix arrives. Open a new worktree for the hotfix, fix it, merge, and remove the worktree — without touching your feature branch at all.

Submodules

A submodule embeds another repository inside yours at a specific commit. The parent repo tracks only the submodule's commit SHA, not its full content.

git submodule add https://github.com/org/lib.git vendor/lib
git submodule update --init --recursive    # clone all submodules after fresh clone
git submodule update --remote              # update to the latest commit on the submodule's remote

Submodules are powerful but operationally heavy. Alternatives: package managers, git subtree, monorepo tools. Use submodules only when you need to pin to a specific commit of an external repo that you don't own.

Hooks

Hooks are scripts that git runs at specific points in the workflow. They live in .git/hooks/ and are not committed by default.

Common hooks:

Hook When it runs Common use
pre-commit Before git commit executes Run linter, type-checker, tests
commit-msg After you write the commit message Enforce conventional commit format
pre-push Before git push sends to remote Run full test suite
post-merge After a merge completes Run pnpm install if lockfile changed

A pre-commit hook:

#!/bin/sh
# .git/hooks/pre-commit
pnpm lint-staged

To share hooks with the team, store them in a directory (e.g., .hooks/) and configure git to use it:

git config core.hooksPath .hooks

Or use a tool like Husky which wires this up automatically.

reset vs restore vs checkout

These three commands overlap historically. Git has been tightening the semantics:

Command Affects Use for
git restore <file> Working tree Discard unstaged changes to a file
git restore --staged <file> Index (staging area) Unstage a file
git reset HEAD~1 HEAD + index Undo last commit, keep changes staged
git reset --hard HEAD~1 HEAD + index + working tree Undo last commit and discard all changes
git checkout <sha> -- <file> Working tree Restore a file from a specific commit

The old way was to use git checkout for all three. The new restore command is more explicit and harder to misuse. Prefer it.

git reset --hard is the most dangerous command in everyday git use. It discards working-tree changes permanently — they do not go to the trash. Before running it, verify you're resetting to the right commit.

Recovering from disaster via reflog

The reflog is your safety net. It records every position HEAD has occupied, including commits that were "lost" by reset, rebase, or branch deletion.

git reflog                          # find the SHA you want to recover
git checkout -b recovery/lost-work <sha>    # branch from it
# or:
git cherry-pick <sha>               # apply just that commit to current branch

Scenarios and recoveries:

Disaster Recovery
git reset --hard to wrong commit git reflog → find old HEAD → git reset --hard <sha>
Deleted a branch git reflog → find last commit on it → git checkout -b <name> <sha>
Rebased and lost commits git reflog → find pre-rebase SHA → git reset --hard <sha>
Dropped a stash git stash list (if still there), or git fsck --lost-found

The reflog has a default expiry of 90 days. After that, unreachable commits become candidates for garbage collection.

The recovery playground

The playground below presents three disaster states — detached HEAD, dropped stash, force-pushed branch — and asks you to pick the right recovery command for each.