Combining pull, push, rebase, revert, restore, amend, commit, and add
Learn how to combine Git commands effectively for various development scenarios. Each workflow shows the exact sequence of commands to handle common situations.
Keep your feature branch current with the latest changes from main
# Start from your feature branch
git checkout feature/new-feature
# Fetch the latest changes from remote
git fetch origin
# Rebase your feature branch on top of main
git rebase origin/main
# Resolve any conflicts if they occur
# git add . (after resolving conflicts)
# git rebase --continue
# Force push the updated branch (safe with
--force-with-lease)
git push --force-with-lease origin feature/new-feature
Revert changes both locally and remotely after a bad push
# First, revert the commit locally
git revert HEAD
# Then push the revert to remote
git push origin main
# Alternatively, if you need to completely remove the
commit
# Reset to the previous commit (only if no one else has
pulled)
git reset --hard HEAD~1
# Force push to update remote (use with extreme
caution!)
git push --force-with-lease origin main
Add forgotten changes or edit the commit message
# Make your changes to the files
echo "Forgotten change" >> file.txt
# Stage the changes
git add file.txt
# Amend the previous commit
git commit --amend
# If you've already pushed, you'll need to force push
git push --force-with-lease origin feature-branch
# To just change the commit message (no file changes)
git commit --amend -m "New commit message"
Stage and commit specific parts of files, not entire files
# Add changes interactively
git add -p
# For each change, choose: (y) stage, (n) don't stage, (s)
split, (e) edit
# Commit the staged changes
git commit -m "Commit only specific changes"
# Restore (discard) the unstaged changes if needed
git restore file.txt
# Or keep working on the unstaged changes
Safely undo changes that are already in the remote repository
# Create a revert commit
git revert <commit-hash>
# Push the revert commit
git push origin main
# If you need to revert multiple commits
git revert
<older-commit-hash>..<newer-commit-hash>
# If you want to revert but modify the changes
git revert -n <commit-hash>
# Make your adjustments
git add .
git commit -m "Adjusted revert"
git push origin main
Recover work that seemed to be lost
# First, check the reflog for recent actions
git reflog
# Identify the commit where your work existed
# abc1234 HEAD@{2}: commit: My important work
# Restore files from that commit
git restore --source=abc1234 file.txt
# Or create a new branch from that commit
git branch recovery-branch abc1234
# Cherry-pick specific commits if needed
git cherry-pick abc1234
# Once recovered, add and commit the changes
git add .
git commit -m "Recover lost work"
Merge or rebase with changes made by other team members
# First, fetch the latest changes
git fetch --all
# Checkout your teammate's branch
git checkout teammate/feature
git pull origin teammate/feature
# Go back to your branch
git checkout my-feature
# Merge their changes into yours
git merge teammate/feature
# Alternatively, rebase your changes on top of theirs
git rebase teammate/feature
# Resolve any conflicts, then add and continue
# git add . && git rebase --continue
# Push the integrated changes
git push origin my-feature
Handle the common situation where you can't push because the remote has new commits
# First, fetch the remote changes
git fetch origin
# Option 1: Merge the remote changes
git merge origin/main
# Resolve any merge conflicts
# git add . && git commit -m "Merge remote changes"
# Option 2: Rebase your changes on top of remote
git rebase origin/main
# Resolve any conflicts during rebase
# git add . && git rebase --continue
# After either approach, push your changes
git push origin feature-branch
# If you rebased, you might need to force push
git push --force-with-lease origin feature-branch
Squash, edit, or reorder commits to create a clean history
# Start interactive rebase for the last 5 commits
git rebase -i HEAD~5
# In the editor, change 'pick' to:
# - 'squash' or 's' to combine with previous commit
# - 'edit' or 'e' to modify a commit
# - 'reword' or 'r' to change commit message
# If you choose to edit a commit:
# Make your changes, then stage them
git add .
# Continue the rebase
git rebase --continue
# If you need to abort at any point
git rebase --abort
# After completing, force push (if already pushed)
git push --force-with-lease origin feature-branch
Selectively revert certain changes while preserving others
# Create a revert commit but don't commit it yet
git revert -n <commit-to-revert>
# Now unstage the changes
git reset
# Interactively add only the changes you want to revert
git add -p
# Commit the partial revert
git commit -m "Partial revert of <commit>"
# Restore the changes you don't want to revert
git restore .
# Push the changes
git push origin feature-branch
Reconcile major differences between your feature branch and the main branch
# Checkout your feature branch
git checkout feature/major-changes
# Fetch the latest changes from remote
git fetch origin
# Rebase interactively to clean up your commits first
git rebase -i HEAD~10
# Squash, fixup, or reorder commits as needed
# Now rebase onto the latest main
git rebase origin/main
# Resolve conflicts systematically
# For each conflict:
git status
# Review conflicts, edit files, then:
git add .
git rebase --continue
# If it gets too complicated, abort and try a different
approach
git rebase --abort
# Alternative: create a merge commit instead
git merge origin/main
# Resolve conflicts, then:
git add .
git commit -m "Merge main into feature"
# Push the resolved branch
git push --force-with-lease origin
feature/major-changes
Find and restore a deleted branch that hasn't been pushed to remote yet
# First, check the reflog to find the commit
git reflog
# Look for the commit where your branch was last active
# abc1234 (HEAD -> main) HEAD@{0}: commit: Some commit
# def5678 (feature/my-work) HEAD@{1}: commit: My important
work
# Note the commit hash (def5678) and recreate the
branch
git branch feature/my-work def5678
# If you can't find it in reflog, check for dangling
commits
git fsck --full --no-reflogs --unreachable --lost-found
# Look for dangling commit objects
# dangling commit
def5678abcdef1234567890abcdef123456789
# Check what's in that commit
git show def5678
# If it's your work, create a branch from it
git branch recovered-work def5678
# Verify the content is correct
git checkout recovered-work
git log --oneline -5
# Once verified, push to remote
git push -u origin recovered-work
Break down a monolithic commit into smaller, focused commits
# Start an interactive rebase
git rebase -i HEAD~5
# Mark the commit you want to split with 'edit'
# When rebase pauses at that commit, reset it
git reset HEAD~
# This keeps changes in working directory but removes the
commit
# Now add changes piece by piece
git add -p
# For each logical change, stage and commit separately
git add path/to/file1.js
git commit -m "Add feature X component"
git add path/to/file2.js
git commit -m "Implement feature Y logic"
git add path/to/test/file1.spec.js
git commit -m "Add tests for feature X"
# Continue the rebase
git rebase --continue
# Force push if already pushed to remote
git push --force-with-lease origin feature-branch
Completely remove sensitive data from Git history
# First, install git-filter-repo if not available
# pip install git-filter-repo
# Backup your repository first!
git clone --mirror repo-url repo-backup
# Remove the sensitive file from entire history
git filter-repo --path config/database.yml
--invert-paths
# Or to remove a specific string from all files
git filter-repo --replace-text <(echo "PASSWORD==>REDACTED" )
# Force push to all branches (warn your team first!)
git push origin --force --all
git push origin --force --tags
# Every team member must reclone or reset
# For those who can't reclone:
git fetch origin
git reset --hard origin/main
# For each branch: git reset --hard origin/branch-name
# Note: This rewrites history, so coordinate with your
team
Systematically resolve complicated merge conflicts across multiple files
# Start the merge process
git merge feature/conflicting-branch
# If conflicts occur, see which files are affected
git status
# Both modified: path/to/conflicting-file.js
# Use a visual merge tool if available
git mergetool
# Or resolve manually by editing files
# Look for conflict markers: <<<<<<<,=======,>>>>>>>
# For each conflicted file, resolve and stage
git add path/to/resolved-file.js
# If you want to abort the merge and try a different
strategy
git merge --abort
# Alternative: use theirs or ours version for specific
files
git checkout --ours path/to/file.js
# Or
git checkout --theirs path/to/file.js
# After resolving all conflicts, complete the merge
git commit -m "Merge feature/conflicting-branch"
# If it's a particularly complex merge, consider using a
merge driver
# Or break it into smaller merges
Use binary search to efficiently locate the problematic commit
# Start the bisect process
git bisect start
# Mark the current commit as bad
git bisect bad
# Find a known good commit from the past
git log --oneline --since="2023-01-01"
# Identify a commit hash where things worked
# Mark that commit as good
git bisect good abc1234
# Git will now checkout a commit in the middle
# Test if this commit has the bug
npm test
# Or manually test the specific functionality
# Based on test results, mark as good or bad
git bisect bad
# Or
git bisect good
# Repeat until Git identifies the first bad commit
# abc1234 is the first bad commit
# Examine what changed in that commit
git show abc1234
# End the bisect session
git bisect reset
# Now you can revert or fix the problematic commit
Use Git worktree to avoid constant branch switching
# Create a new worktree for a bugfix while working on a
feature
git worktree add ../myproject-bugfix
bugfix/urgent-issue
# Now you can work on both simultaneously
# Your main repository continues on the current branch
# The worktree is in ../myproject-bugfix on the bugfix
branch
# Work on the bugfix in the separate directory
cd ../myproject-bugfix
# Make changes, commit, push as needed
# When done, remove the worktree
git worktree remove ../myproject-bugfix
# You can create multiple worktrees for different tasks
git worktree add ../myproject-docs docs-update
git worktree add ../myproject-refactor
refactor/component
# List all worktrees
git worktree list
# This avoids the overhead of multiple clones
# and keeps everything in sync automatically
Use advanced stashing techniques for complex context switching
# Stash your current work with a descriptive message
git stash push -m "WIP: authentication feature"
# Work on something else, then come back
# See what's in your stash
git stash list
# Apply a specific stash without removing it from the
stack
git stash apply stash@{1}
# If you have conflicts when applying, resolve them
# Then you can drop the stash if applied successfully
git stash drop stash@{1}
# Create a branch from a stash
git stash branch authentication-feature stash@{1}
# Stash only untracked files
git stash -u
# Stash only specific files
git stash push path/to/file1.js path/to/file2.js
# View the content of a stash
git stash show -p stash@{1}
# Clean up old stashes
git stash clear
# Or drop specific stashes
git stash drop stash@{2}
git reset --hard HEAD~3
You did a hard reset but later realized you needed changes from those commits.
Solution: Use git reflog to find the lost commits and restore files from them.
# Find the lost commits
git reflog
abc1234 HEAD@{0}: reset: moving to HEAD~3
def5678 HEAD@{1}: commit: Important feature
ghi9012 HEAD@{2}: commit: Bug fixes
# Restore files from specific commit
git restore --source=def5678 path/to/important-file.txt
git push origin main
You pushed API keys, passwords, or other sensitive data to a remote repository.
Solution: Use git filter-repo to completely remove the file from history.
# 1. Remove file from history (install git-filter-repo
first)
git filter-repo --path secrets.txt --invert-paths
# 2. Force push (warn your team first!)
git push --force
# 3. Everyone else must reclone or reset their repos
git fetch origin
git reset --hard origin/main
git push origin main
You pushed multiple commits that introduced a bug and need to identify which specific commit caused it.
Solution: Use git bisect to perform a binary search through your commit history.
# Start the bisect process
git bisect start
# Mark the current commit as bad
git bisect bad
# Mark a known good commit from the past
git bisect good abc1234
# Git will checkout a commit in the middle - test your
code
# Then mark it as good or bad:
git bisect good
# OR
git bisect bad
# Repeat until Git identifies the first bad commit
# End the bisect session
git bisect reset
git commit -m "Wrong commit"
You made a commit but want to undo it while keeping all the changes in your working directory.
Solution: Use git reset --soft to remove the commit but keep changes staged.
# Remove the last commit but keep changes staged
git reset --soft HEAD~1
# Now you can make a new commit with the correct changes
git commit -m "Correct commit message"
# If you want to unstage the changes too:
git reset HEAD~1
# This keeps changes in working directory but unstaged
git commit -m "Bad commit"
You made a commit with errors and want to completely remove it and discard all changes.
Solution: Use git reset --hard to completely remove the commit and all changes.
# Completely remove the last commit and all changes
git reset --hard HEAD~1
# If you've already pushed to remote, you'll need to force
push
# WARNING: This can cause issues for collaborators
git push --force-with-lease
# For multiple commits back:
git reset --hard HEAD~3
# This will remove the last 3 commits
git reset --hard HEAD
You had uncommitted changes in your working directory, but
accidentally ran
git reset --hard and lost everything. You never
committed these changes, so they're not in your commit history.
# 1. First, check if Git has stored your changes as
dangling blobs
git fsck --lost-found
dangling blob
1676c54c5aa0b98c5badc70d6dcd5f40c2562d0d
dangling commit
45d9e2ae8495a2bfbdee59b2f44ec0c7c5e33bf2
...
# 2. Look for 'dangling blob' entries - these might be your
lost files
git show 1676c54c5aa0b98c5badc70d6dcd5f40c2562d0d >
recovered_file.txt
# 3. Alternatively, check the reflog for any possible
references
git reflog
# 4. Search for specific content in dangling blobs
git fsck --lost-found | grep blob | awk '{print $3}' |
xargs -I{} sh -c 'echo "=== {} ==="; git show {}' |
less
If you're using an IDE like VS Code, IntelliJ, or WebStorm, check if it has local history features that might have preserved your changes:
# IDE-Specific recovery options:
# VS Code: Check "Local History" extension or timed
backups
# IntelliJ/WebStorm: Right-click file -> Local History ->
Show History
# Eclipse: Right-click file -> Replace With -> Local
History
If the above methods don't recover your files, you might try these system-level approaches:
# 1. Check your OS trash/recycle bin
# Files might have been moved to trash instead of being
deleted
# 2. Use file recovery software
# Tools like Recuva (Windows), TestDisk (Cross-platform),
or
# PhotoRec (Cross-platform) can recover recently deleted
files
# 3. Check for temporary files or backups
# Many editors create backup files (e.g., file.txt~, .swp
files)
find . -name "*~" -o -name "*.swp" -o -name "*.swo"
To avoid this situation in the future:
git stash to temporarily store changes
instead of resetting
git add -p to selectively stage
changes
git branch backup/before-reset
Many modern IDEs automatically save versions of your files as you work:
# VS Code (check these locations):
# Windows: %APPDATA%\Code\Backups
# macOS: ~/Library/Application Support/Code/Backups
# Linux: ~/.config/Code/Backups
# IntelliJ/WebStorm: Check the "Local History"
feature
# Right-click on file or directory -> Local History -> Show
History
git clone repository-url
You want to give a junior developer only code from a specific commit, not the entire history.
Solution: Clone the repository then checkout the specific commit, or use shallow clone.
# Method 1: Clone then checkout specific commit
git clone https://github.com/user/repo.git
cd repo
git checkout abc1234
# Method 2: Shallow clone with specific depth
git clone --depth 1 https://github.com/user/repo.git
# This clones only the latest commit
# Method 3: Clone then create new branch at specific
commit
git clone https://github.com/user/repo.git
cd repo
git checkout -b stable-version abc1234
git clone repository-url
You want to clone only a specific branch to save time and bandwidth, especially for large repositories.
Solution: Use the --branch and --single-branch options to clone only the desired branch.
# Clone only the main branch
git clone --branch main --single-branch
https://github.com/user/repo.git
# Clone only the development branch
git clone --branch develop --single-branch
https://github.com/user/repo.git
# Clone with limited history (last 10 commits)
git clone --branch main --single-branch --depth 10
https://github.com/user/repo.git
# To later fetch other branches from this clone:
git remote set-branches origin 'other-branch'
git fetch --depth 1 origin other-branch
git checkout other-branch
git reset --hard origin/main
You lost days of uncommitted work after a hard reset.
Solution: Use git's internal file system check to find lost blobs.
# Search for lost data
git fsck --lost-found
# Look for blobs (file contents)
git show [blob-hash]
# Search for specific content
git fsck --lost-found | grep "blob" | xargs -I{} sh -c 'git
show {} | grep -q "unique string" && echo {}'
git rebase -i HEAD~10
You need to completely rewrite commit history (change messages, reorder, squash, or delete commits).
Solution: Use interactive rebase to rewrite history, then force push.
# Start interactive rebase for last 10 commits
git rebase -i HEAD~10
# In the editor, change 'pick' to:
# - 'reword' to change commit message
# - 'edit' to modify the commit
# - 'squash' to combine with previous commit
# - 'drop' to remove the commit entirely
# Save and exit, follow prompts for each change
# Force push the rewritten history
git push --force-with-lease
# WARNING: This rewrites history - notify your team!
# Anyone with the old history will need to reset their
branches
git branch -D feature
You accidentally deleted a branch that hadn't been merged yet.
Solution: Use git reflog to find the last commit on the branch and recreate it.
# Find the commit where the branch was last referenced
git reflog
abc1234 HEAD@{0}: checkout: moving from feature to main
def5678 HEAD@{1}: commit: Final feature work
# Recreate the branch from that commit
git branch feature def5678
# If you can't find it, check remote tracking branches
git fetch origin
git checkout -b feature origin/feature
git branch -m new-name
You want to rename a branch, both locally and on the remote repository.
Solution: Rename locally, push to remote, and delete the old remote branch.
# Rename the local branch
git branch -m old-branch-name new-branch-name
# Push the new branch to remote
git push origin -u new-branch-name
# Delete the old remote branch
git push origin --delete old-branch-name
# If someone else already has the old branch:
git fetch origin
git remote prune origin
Before doing any destructive operations, create a backup branch:
git branch backup/before-dangerous-operation. This gives
you a safe point to return to if things go wrong.
Create aliases for complex Git workflows. For example, add this to
your ~/.gitconfig:
[alias]
cleanup = "!git fetch --prune && git branch --merged main | grep -v
\"main\" | xargs -n 1 git branch -d"
prepush = "!git fetch origin && git rebase origin/main && npm test"
wip = "!git add -A && git commit -m \"WIP\" && git push"
Always be cautious with history rewriting commands like
rebase, reset --hard, and
push --force. These can cause work to be lost if used
incorrectly. When in doubt, create a backup branch first:
git branch backup/before-dangerous-operation.
Create aliases for complex command combinations. For example:
git config --global alias.sync-branch '!git fetch origin && git
rebase origin/main && git push --force-with-lease origin'
Then you can simply run: git sync-branch
Be extremely careful with force push (git push --force or
git push --force-with-lease). Always use
--force-with-lease when possible as it's safer. Never
force push to shared branches like main or develop without team
coordination.