top of page

Git: Common Workflows

Jul 30, 2025
5 min read

Updated: Aug 31

This post outlines some of the most common git workflows I've come across while working as a software engineer.

Move current changes to new branch and revert parent branch to a previous commit


Suppose you have finished a feature in a feature branch and created a PR to merge the feature into main. While the PR is being reviewed (it could be days), you forgot to checkout to a new branch for the next work and kept committing further changes in the same branch. First of all, the PR reviewer will see those new changes in the PR automatically. Second, if the reviewer returns something back from the PR, how will you send him back just that fix and none of the new changes you've accidentally added to the branch.


You need a way to move all of the new changes to a separate branch (as they should have been from the beginning), revert the branch that's connected with the PR to the point when you requested the review, and then add to it, the fix the reviewer requested. So that in the end, your PR contains work that's only related to the feature it's for and you can also continue on the new changes in a separate branch going forward.


Here’s how you can create a new branch with the new changes and revert the parent branch to a previous commit using Git:


1. Create a New Branch from Current State


First, make sure you’re on the parent branch (e.g., main or develop):

git checkout main

Create a new branch (replace feature-branch with your desired branch name):

git checkout -b feature-branch

This new branch will contain all the current changes from main.


2. Revert Parent Branch to a Previous Commit


Switch back to the parent branch:

git checkout main

Find the commit hash you want to revert to (use git log to see commit history):

git log

Reset the parent branch to the desired commit (replace <commit-hash> with the actual hash):

git reset --hard <commit-hash>
Warning: --hard will discard all changes after the specified commit. If you want to keep the changes as uncommitted files, use --soft instead.

3. Push Changes to Remote (if needed)


If you want to update the remote branch:

git push origin main --force

Warning: Force pushing will overwrite the remote branch history. Make sure this is what you want, and coordinate with your team if necessary.

Delete Local Branches with Deleted Remotes


When a branch is deleted on the remote repository (e.g. GitHub/GitLab), your local Git repository still keeps both the remote-tracking ref and your local branch until you prune and clean them up.

Here is the step-by-step process:


  1. Prune remote-tracking references


Update your local view of the remote repository and remove tracking branches for remotes that no longer exist:

git fetch -p
# or: git fetch --prune

  1. Identify local branches whose tracking branch is gone


Run the following command to list all local branches and their upstream status:

git branch -vv

Branches whose remote counter-part was deleted will show [gone] next to the commit message:

feature/old-login  a1b2c3d [origin/feature/old-login: gone] remove old form
* main               e4f5678 [origin/main] update docs

  1. Delete the local branches


  • Delete a single branch:

git branch -d feature/old-login

(If Git warns that the branch isn't fully merged, use -D to force delete: git branch -D feature/old-login)

  • Delete ALL local branches marked as [gone] in one command:

git branch -vv | grep ': gone]' | awk '{print $1}' | xargs git branch -d

Recovering from an Accidental Push to main with Dependent Branches


The Problem: Silent Upstream Mapping


When creating a local feature branch using git checkout -b [branch-name] origin/main, Git can automatically configure upstream tracking directly to refs/heads/main on the remote.


Running a routine git push or clicking "Sync Changes" in an IDE doesn't push to a new feature branch—it pushes the unreviewed code directly into the production main branch.


To check your branch merge configurations:


git config --get-regexp "branch..*.merge"

The Complications


  • Subsequent Commits by Collaborators: Another maintainer pushed several commits on top of our accidental commits. Rewriting history with a force-push would alter their commit hashes and break their local repositories with divergence errors.

  • Production Deployments: Live deployments connected to main (such as Vercel) immediately deployed the unreviewed feature.

  • The "Reverted Merge" PR Trap: When you revert a merge commit on main, Git remembers the original commit ID as already merged. When you try to open a new Pull Request later from that feature branch, GitHub shows: "There isn't anything to compare."


Step 1: Reverting the Feature on main Without Rewriting History


To cleanly remove the feature from main without breaking other developers' commit histories, use git revert on the merge commit with the -m 2 flag (targeting parent 2, the feature branch):


# 1. Switch to main and sync the latest commits
git checkout main git pull origin main

# 2. Revert the merged feature branch cleanly in a forward commit
git revert -m 2 5059a670 --no-edit

# 3. Push the rollback to remote main
git push origin main

Why -m 2? A merge commit has two parents: Parent 1 (the target branch, main) and Parent 2 (the merged branch). Reverting with -m 2 tells Git to reverse only the changes brought in by the feature branch while preserving 100% of the other maintainer's work.

Step 2: Fixing the "There Isn't Anything to Compare" PR Issue


Because Git marked the original feature commit as "already merged into main", the PR branch needed a fresh commit hash rebased on top of the revert commit:


# 1. Switch to the feature branch
git checkout feature/356-pdf-download-filenames

# 2. Reset the branch to current main (which contains the revert
git reset --hard main

# 3. Re-apply the isolated feature commit cleanly
git cherry-pick d11e4040

# 4. Push the branch to update the Pull Request
git push --force-with-lease origin feature/356-pdf-download-filenames

Result: GitHub now detects a fresh, complete diff and displays the green "Able to merge" banner.

Step 3: Cleaning the Sibling Branch & Syncing


Our second active branch (bugfix/355-co-display-numbering) was branched when the first feature was still on main. Pulling the reverted main automatically removed the unwanted feature dependencies from the second branch:


# 1. Switch to the second branch
git checkout bugfix/355-co-display-numbering

# 2. Pull the reverted main into the branch
git pull origin main

# 3. Resolve any shared component import conflicts and commit
git add src/components/change-orders/print-change-order-form.tsx git commit -m "merge: sync with main"

# 4. Push the clean second branch
git push origin bugfix/355-co-display-numbering

Key Takeaways & Permanent Safeguards


To prevent Git from ever pushing a feature branch directly to main again:


  1. Configure Safe Git Defaults:

git config --global push.default current
git config --global push.autoSetupRemote true

push.default current: Ensures git push only pushes to a remote branch matching the current local branch name.

push.autoSetupRemote true: Automatically sets up upstream tracking to that branch without needing -u.


  1. Enable GitHub Branch Protection:

    In Repository Settings -> Branches / Rulesets: Enable "Require a pull request before merging" and check "Do not allow bypassing" for main

    Direct pushes to main will be automatically blocked by GitHub with an HTTP 403 error.


 
 
 

Comments


bottom of page