🚀 Advanced Remote Operations in Git
The Post Office Analogy
Imagine Git remotes as post offices. Your local repository is your home desk where you write letters (code). The remote is the post office where letters get collected and shared with others.
Sometimes, mail delivery isn’t simple. You need to:
- Reorganize letters before sending (rebase)
- Replace a wrongly sent package (force push)
- Recall a letter already delivered (undo pushed commits)
- Set up a regular mail route (upstream)
- Clean old mailboxes nobody uses (prune)
Let’s master these advanced delivery skills!
📬 Pull with Rebase
What Is It?
When you git pull, Git normally merges remote changes into yours. This creates a “merge commit” — like putting two stacks of letters together with a paperclip.
Pull with rebase is different. It takes YOUR letters, sets them aside, gets the NEW letters from the post office, then puts YOUR letters back on top. No paperclip needed!
Why Use It?
- Cleaner history: No extra merge commits
- Easier to read: Changes flow in a straight line
- Professional look: Most teams prefer linear histories
The Command
git pull --rebase origin main
What Happens Step by Step
graph TD A["Your commits: A → B → C"] --> B["Remote has: A → X → Y"] B --> C["Rebase picks up C"] C --> D["Places C after Y"] D --> E["Result: A → X → Y → C"]
Simple Example
You made a change to app.js. Your teammate pushed changes too.
Without rebase:
* Merge commit (ugly!)
|\
| * Your change
* | Teammate's change
|/
* Original
With rebase:
* Your change (moved on top)
* Teammate's change
* Original
Pro Tip 🧙♂️
Make rebase your default pull behavior:
git config --global pull.rebase true
Now every git pull automatically rebases!
💥 Force Pushing
What Is It?
Normal push says: “Add my changes to the post office.”
Force push says: “REPLACE what’s at the post office with MY version!”
The Command
git push --force origin main
Or the safer version:
git push --force-with-lease origin main
When Do You Need It?
- After rebasing — Your commits have new IDs
- After amending — You changed the last commit
- Cleaning mistakes — Removing sensitive data pushed by accident
⚠️ DANGER ZONE
Force push OVERWRITES history. If teammates pulled the old version, their work conflicts badly!
graph TD A["You force push"] --> B["Remote history changes"] B --> C[Teammate's local is outdated] C --> D["Teammate pulls = CONFLICT!"]
Safe Force Push
Use --force-with-lease instead:
git push --force-with-lease origin feature
This checks: “Did anyone else push since I last fetched?”
- If yes → Push BLOCKED (saves teammates!)
- If no → Push proceeds
Example Scenario
You rebased your feature branch:
# 1. Rebase onto latest main
git checkout feature
git rebase main
# 2. Your commit IDs changed
# Normal push fails!
git push origin feature
# ERROR: rejected, non-fast-forward
# 3. Force push (with safety)
git push --force-with-lease origin feature
# SUCCESS: History replaced safely
⏪ Undoing Pushed Commits
The Problem
You pushed something you shouldn’t have:
- Wrong code
- Secret API keys 😱
- Commits to wrong branch
Two Solutions
Solution 1: Revert (Safe)
Creates a NEW commit that undoes the bad one. History preserved!
git revert abc123
git push origin main
graph TD A["Bad commit: abc123"] --> B["git revert abc123"] B --> C["New commit: 'Revert abc123'"] C --> D["Push: History shows the fix"]
Best for: Shared branches, public repos, team projects
Solution 2: Reset + Force Push (Destructive)
Removes the bad commit entirely. History rewritten!
# Go back 1 commit
git reset --hard HEAD~1
# Force push the fix
git push --force-with-lease origin main
Best for: Your own feature branches, before anyone pulls
Example: Removing Secrets
You accidentally committed .env with passwords:
# Option A: Revert (safe, but secret stays in history)
git revert HEAD
git push
# Option B: Remove completely (use with caution!)
git reset --hard HEAD~1
git push --force-with-lease origin main
⚠️ For real secret leaks, you also need to rotate the exposed keys!
🎯 Setting Upstream Branches
What Is It?
An upstream branch is the remote branch your local branch “tracks”. It’s like setting your default mail route.
Without upstream, you must always say:
git push origin feature
git pull origin feature
With upstream set, just say:
git push
git pull
The Command
When pushing a new branch for the first time:
git push -u origin feature
The -u (or --set-upstream) links your local feature to origin/feature.
Check Your Upstream
git branch -vv
Output shows tracking info:
* feature abc123 [origin/feature] Your commit
main def456 [origin/main] Latest commit
Setting Upstream Manually
If branch exists but isn’t tracking:
git branch --set-upstream-to=origin/feature
Or shorter:
git branch -u origin/feature
Example Workflow
# Create new branch
git checkout -b new-feature
# Make changes and commit
git add .
git commit -m "Add new feature"
# Push AND set upstream (first time)
git push -u origin new-feature
# Future pushes are simple!
git push # Knows where to go
git pull # Knows where to fetch from
🧹 Remote Branch Pruning
What Is It?
Over time, remote branches get deleted (after merging PRs). But YOUR computer still remembers them!
Pruning cleans up these “ghost” branches.
See the Problem
git branch -r
Shows remote branches your computer knows about:
origin/main
origin/feature-old ← Deleted on GitHub!
origin/bugfix-done ← Deleted on GitHub!
The Fix: Prune
git fetch --prune
Or set auto-prune forever:
git config --global fetch.prune true
Now every git fetch automatically cleans ghosts!
Prune Just Once
git remote prune origin
Example Session
# Check stale branches
git branch -r
# Shows: origin/old-feature (but deleted remotely!)
# Prune them
git fetch --prune
# Output: "Pruned origin/old-feature"
# Check again
git branch -r
# Clean! Only active branches remain
Cleaning Local Branches Too
Pruning only removes remote-tracking references. Local branches remain.
Delete merged local branches:
# See merged branches
git branch --merged main
# Delete one
git branch -d old-feature
# Delete all merged (except main)
git branch --merged main |
grep -v main |
xargs git branch -d
🎯 Quick Reference
| Task | Command |
|---|---|
| Pull with rebase | git pull --rebase |
| Force push (safe) | git push --force-with-lease |
| Undo last pushed commit | git revert HEAD && git push |
| Set upstream | git push -u origin branch |
| Prune remotes | git fetch --prune |
🧙♂️ Summary
You’ve learned the advanced post office skills:
- Pull with rebase — Keep history clean and linear
- Force push — Replace remote history (carefully!)
- Undo pushed commits — Revert or reset+force
- Set upstream — Link local to remote branches
- Prune — Clean up deleted remote branches
These operations give you power over your Git history. With great power comes great responsibility — always communicate with your team before force pushing!
🚀 You’re now ready for professional Git collaboration!
