Git How-Tos I Reach For Daily Work
Table of Contents
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 [email protected]: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.