This is my running log of Git moves I reach for when I do work. Each mini-how-to includes the exact commands plus a quick note on what to watch for.
Squash Multiple Commits Into One
Use interactive rebase to collapse the last n commits into a single, tidy changeset.
Optional safety: create a backup branch before rebasing:
git branch backup/feature-branch-before-squash
git rebase -i HEAD~3
Replace 3 with however many commits you want to include, counting the current HEAD as part of that total. HEAD refers to the current commit, HEAD~1 to its parent, HEAD~2 to the one before that, and so on. When you run git rebase -i HEAD~3, Git lists the last three commits including HEAD. Run git log --oneline to count backward until you reach the oldest commit you intend to squash.
Tip: Use
HEAD~3^if you need to include the fourth commit in the interactive list.
For example, if your history looks like this (newest first):
a1b2c3 (HEAD)
d4e5f6
g7h8i9
j0k1l2
The command git rebase -i HEAD~3 opens the editor with:
pick j0k1l2
pick g7h8i9
pick d4e5f6
In the editor:
- Leave the first commit as
pick - Change the rest to
squash(ors) - Save, then compose the final commit message
If conflicts appear, resolve them and resume with git rebase --continue.
To abort the squash at any point, run:
git rebase --abort
Force Push After Squashing
Once history changes, update the remote branch.
git push --force-with-lease origin feature/my-branch
--force-with-lease protects teammates by refusing to overwrite work you haven’t fetched.
Create a Local Repo and Wire Up a Remote
mkdir my-project && cd my-project
git init
# add files, then commit
git add .
git commit -m "Initial commit"
git remote add origin git@github.com:username/my-project.git
git push -u origin main
If the remote is empty, main (or master) becomes the default branch once you push with -u. Double-check the URL format (git@ for SSH, https:// for HTTPS) before adding the remote.
Track a Remote Branch Locally
When you create a local branch that should follow an existing remote branch, set the upstream explicitly.
git switch -c feature/api-integration origin/feature/api-integration
# or, if branch already exists locally
git branch --set-upstream-to=origin/feature/api-integration
Now git pull and git push know which remote branch to use. If Git complains that the remote ref is missing, fetch it first (git fetch origin feature/api-integration) and rerun the command.
Create a Branch and Push It Upstream
Shortcut to create a branch, commit, and publish it with upstream tracking in one go.
git switch -c feature/search-bar
git commit -am "Add search bar styles"
git push -u origin feature/search-bar
-u (or --set-upstream) wires the remote for future pushes. Remember that git commit -am only stages files Git already tracks—run git add first if you created new files.
Sync With the Latest From Main Without Merge Commits
Rebase your current branch onto main to replay your commits on top of the latest state.
Optional safety: create a backup before rebasing:
git branch backup/feature-search-bar-before-rebase
- Make sure you have no pending edits:
git status -sbshould report a clean tree. - Update
mainso you are rebasing onto the real latest code.git switch main git pull --ff-only origin main - Return to your feature branch (replace with your branch name).
git switch feature/search-bar - Replay your commits on top of the freshly updated
main.git rebase main
⚠️ Rebase pointer:
In merges: ours = current branch, theirs = incoming.
In rebases: ours = target branch, theirs = replayed commit.
Pick the pieces you need,git addeach resolved file, and continue withgit rebase --continue.
If the rebase turns chaotic, bail out withgit rebase --abort.
Once the history looks right, rerun your tests and publish the new linear history:
git push --force-with-lease origin feature/search-bar
If you prefer to preserve merge commits instead, use git merge origin/main.
Rebase Onto the Remote Version of Your Branch
When teammates update the remote feature branch, pull those commits in and resolve conflicts locally.
Optional safety: create a backup before rebasing:
git branch backup/feature-payment-before-rebase
- Ensure a clean tree first:
git status -sb. - Update your knowledge of the remote branch.
git fetch origin feature/payment - Switch to your local branch that you want to replay.
git switch feature/payment - Rebase onto the remote tracking branch you fetched.
git rebase origin/feature/payment
⚠️ Rebase pointer:
In merges: ours = current branch, theirs = incoming.
In rebases: ours = target branch, theirs = replayed commit.
Merge the pieces you want, stage them withgit add, and continue (git rebase --continue).
If the rebase turns chaotic, bail out withgit rebase --abort.
Alternatively, if your upstream is set, you can pull and rebase in one step:
git pull --rebase
After the rebase, rerun tests and share the rewritten history safely:
git push --force-with-lease origin feature/payment
Cherry-Pick a Fix Onto Another Branch
Grab a single commit and apply it elsewhere.
git switch release/1.2
git cherry-pick <commit-sha>
If conflicts arise, fix them, git add the files, and run git cherry-pick --continue.
For multiple commits, cherry-pick a range (the upper bound is exclusive):
git cherry-pick A..B
Tip: Use
A^..Bif you want to include commitAitself.
Quick Patch From a File Diff
Generate a patch for one file and drop it into another branch or repo.
git diff main..feature/payment checkout.swift > checkout.patch
git switch hotfix/payment-crash
git apply checkout.patch
Review the applied changes before committing.
git apply only affects the working tree; follow up with git add and git commit once you confirm the patch looks right.
Tip: Run
git am checkout.patchinstead if you want to preserve the original author and commit message from the patch.
Merge Main Into Your Branch (Keep the Merge Commit)
If your team relies on merge commits for context, integrate the latest main without rewriting history.
git fetch origin
git merge --no-ff origin/main
Resolve conflicts, run the test suite, and let Git create the merge commit message. --no-ff retains the merge node even when a fast-forward is possible, preserving the branch narrative.
See What Changed Between Two Branches
Compare your feature branch to main, highlighting only the files or commits that differ.
git log --oneline main..feature/billing
git diff --stat main...feature/billing
Two dots (..) show unique commits; three dots (...) reveal files that diverged from the common ancestor.
Undo the Last Commit (Keep Changes)
Keep your working tree but remove the most recent commit.
git reset --soft HEAD~1
HEAD is the current commit, so HEAD~1 targets the one before it. The changes remain staged. To unstage but keep edits, use git reset --mixed HEAD~1.
Recover Work You Thought Was Gone
If a commit vanished after a reset or rebase, scan the reflog.
git reflog
You can use git show <reflog-sha> to inspect the commit before checking it out.
git switch --detach <reflog-sha>
Create a new branch from that SHA to rescue the work: git switch -c rescue/forgotten <sha>.
Stash Selective Files
Avoid stashing the whole tree by selecting specific paths.
git stash push -- src/HomeView.swift
git stash list
git stash pop
Combine with --keep-index to stash only unstaged changes.
Stashes are stored in order; use git stash list to view entries and git stash pop stash@{1} to apply a specific one.
Clean Untracked Files Safely
Preview deletions before scrubbing untracked files and directories.
git clean -nd
git clean -fd
-n performs a dry run; -f is required to delete, and -d includes directories.
Double-check the dry-run output carefully—git clean is irreversible once it runs with -f.
Revert a Commit That Already Hit Main
Create a new commit that undoes a previous one (keeps history intact).
git revert <commit-sha>
Grab the commit SHA from git log --oneline. If the revert itself fails because of conflicts, resolve them, git add the files, and run git revert --continue.
Tip: Need to revert several commits in one go? Use
git revert -n <sha1> <sha2> ...to stage the reversions and commit once at the end.
Rename a Branch Locally and Remotely
git branch -m old-name new-name
git push origin --delete old-name
git push -u origin new-name
If the branch is protected, you may need admin permissions (or to lift protection temporarily) before deleting it remotely. Afterwards, clean up stale references locally:
git fetch --prune
Anyone else using the old branch should do the same and check out the new name.
I add to this page whenever I find myself repeating a Git flow. If you’re reading along and need another scenario covered, let me know and I’ll expand the list.