{"id":2970,"date":"2026-07-09T14:17:31","date_gmt":"2026-07-09T14:17:31","guid":{"rendered":"https:\/\/blog.samarthya.me\/wps\/?p=2970"},"modified":"2026-07-09T14:18:50","modified_gmt":"2026-07-09T14:18:50","slug":"git-revert","status":"publish","type":"post","link":"https:\/\/blog.samarthya.me\/wps\/2026\/07\/09\/git-revert\/","title":{"rendered":"GIT &#8211; Revert?"},"content":{"rendered":"\n<figure class=\"wp-block-image size-large\"><img fetchpriority=\"high\" decoding=\"async\" width=\"1024\" height=\"559\" src=\"https:\/\/blog.samarthya.me\/wps\/wp-content\/uploads\/2026\/07\/git-history-2-1024x559.png\" alt=\"Image generated via Gemini. Indian man had to come out as a man wearning Dhoti! :)\" class=\"wp-image-2971\" srcset=\"https:\/\/blog.samarthya.me\/wps\/wp-content\/uploads\/2026\/07\/git-history-2-1024x559.png 1024w, https:\/\/blog.samarthya.me\/wps\/wp-content\/uploads\/2026\/07\/git-history-2-300x164.png 300w, https:\/\/blog.samarthya.me\/wps\/wp-content\/uploads\/2026\/07\/git-history-2.png 1408w, https:\/\/blog.samarthya.me\/wps\/wp-content\/uploads\/2026\/07\/git-history-2-300x164@2x.png 600w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"has-medium-font-size wp-block-paragraph\">Most of the blogs I write serve as a self reminder; things I have tried personally. In one of the recent encounters where a GUI tool wasn&#8217;t was possibility I was extra cautious while trying to roll back a production code that I had not committed to ensure no functionality gets broken.<\/p>\n\n\n\n<p class=\"has-medium-font-size wp-block-paragraph\">This blog serves as a step-by-step reference guide for rolling back changes on branches that are already pushed to a remote.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">&#8212;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>The Golden Rule<\/strong><\/h2>\n\n\n\n<figure class=\"wp-block-pullquote has-pale-cyan-blue-background-color has-background has-medium-font-size\"><blockquote><p><strong>If the branch is already pushed &#8211; use <code>git revert<\/code>. Never <code>git reset --hard<\/code>.<\/strong><\/p><cite>&#8211; Saurabh<\/cite><\/blockquote><\/figure>\n\n\n\n<p class=\"has-medium-font-size wp-block-paragraph\"><code>git revert<\/code> adds a new commit that<em> undoes<\/em> your changes. History is preserved, no force push is needed, and collaborators are not affected.<\/p>\n\n\n\n<p class=\"has-medium-font-size wp-block-paragraph\"><code>git reset --hard<\/code> + <code>git push --force<\/code> <em>rewrites<\/em> history. It is dangerous on shared branches and should only ever be used on branches that are 100% private and local.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">&#8212;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Quick Reference Card<\/strong><\/h2>\n\n\n\n<pre class=\"wp-block-code has-white-color has-black-background-color has-text-color has-background has-link-color has-small-font-size wp-elements-9625b6ba984b83a6568fca403ff7eac7\"><code># 1. See recent commits\ngit log --oneline -15\n\n# 2. Stage the revert (do NOT commit yet)\ngit revert --no-commit HEAD~N..HEAD   # replace N with how many commits back\n\n# 3. Inspect what will be undone\ngit diff --staged --stat              # summary (file names + line counts)\ngit diff --staged                     # full line-by-line diff\n\n# 4. Gold-standard validation (output should be empty)\ngit diff &lt;target-hash>                # compare staged result to intended target state\n\n# 5a. Everything looks good \u2192 commit\ngit revert --continue\n\n# 5b. Something is wrong \u2192 bail out completely\ngit revert --abort\n\n# 6. Push (no force needed)\ngit push<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">&#8212;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Step-by-Step Walkthrough<\/strong><\/h2>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Step 1 \u2014 Know where you are<\/strong><\/h3>\n\n\n\n<pre class=\"wp-block-code has-white-color has-black-background-color has-text-color has-background has-link-color has-small-font-size wp-elements-7f0829544fd0d7395c8628dbaa0d0e17\"><code>git log --oneline -15\ngit status\ngit branch -vv<\/code><\/pre>\n\n\n\n<p class=\"has-medium-font-size wp-block-paragraph\"><code>git log --oneline -15<\/code> shows recent commits in compact form. Note down the hashes you want to undo.<\/p>\n\n\n\n<p class=\"has-medium-font-size wp-block-paragraph\"><code>git status<\/code> confirms the working tree is clean before you start.<\/p>\n\n\n\n<p class=\"has-medium-font-size wp-block-paragraph\"><code>git branch -vv<\/code> shows whether your branch is tracking a remote and whether it is ahead or behind. This tells you if the branch has already been pushed.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Example output:<\/strong><\/h4>\n\n\n\n<pre class=\"wp-block-code has-black-color has-luminous-vivid-amber-background-color has-text-color has-background has-link-color wp-elements-885e9c781335be74fe793479f395daf2\"><code>a1b2c3d Added a broken feature                   \u2190 HEAD (latest, bad)\nd4e5f6g Updated configuration for new module     \u2190 HEAD~1 (also bad)\nh7i8j9k Fixed unrelated bug                      \u2190 HEAD~2 (this is where we want to land)\nk0l1m2n Initial setup<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">&#8212;<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Step 2 \u2014 Understand what each commit changed<\/strong><\/h3>\n\n\n\n<p class=\"has-medium-font-size wp-block-paragraph\">Before reverting anything, <em>read<\/em> the commits. Never revert blindly.<\/p>\n\n\n\n<pre class=\"wp-block-code has-white-color has-black-background-color has-text-color has-background has-link-color wp-elements-df3fafd08d78b397d3addb54429cb319\"><code># Summary of files changed in a specific commit\ngit show --stat &lt;hash>\n\n# Full diff of a specific commit\ngit show &lt;hash>\n\n# Full diff of a specific commit, scoped to certain files only\ngit show &lt;hash> -- path\/to\/file.py path\/to\/other.sh\n\n# Combined diff across a range of commits\ngit diff &lt;oldest-hash>..&lt;newest-hash><\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">&#8212;<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Step 3 \u2014 Stage the revert without committing<\/strong><\/h3>\n\n\n\n<p class=\"has-medium-font-size wp-block-paragraph\">This is the key safety move. The <code>--no-commit<\/code> flag applies the revert to the staging area but does <strong>not<\/strong> create a commit. You get a chance to inspect and abort before anything is permanent.<\/p>\n\n\n\n<pre class=\"wp-block-code has-white-color has-black-background-color has-text-color has-background has-link-color wp-elements-f5dad87c8d7504b8689ba0568258b581\"><code>git revert --no-commit HEAD~N..HEAD<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Understanding the range <code>HEAD~N..HEAD<\/code>:<\/strong><\/h4>\n\n\n\n<p class=\"has-medium-font-size wp-block-paragraph\">The <code>..<\/code> notation means the last N commits.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>You want to revert<\/th><th>Use this range<\/th><\/tr><tr><td>Last 1 commit<\/td><td><code>HEAD~1..HEAD<\/code><\/td><\/tr><tr><td>Last 2 commits<\/td><td><code>HEAD~2..HEAD<\/code><\/td><\/tr><tr><td>Last 3 commits<\/td><td><code>HEAD~3..HEAD<\/code><\/td><\/tr><tr><td>A specific commit<\/td><td><code>git revert --no-commit &lt;hash&gt;<\/code><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<figure class=\"wp-block-pullquote has-pale-cyan-blue-background-color has-background\"><blockquote><p><strong>Common mistake:<\/strong> <code>HEAD~1..HEAD<\/code> only covers the very last commit &#8211; not two commits. Use <code>HEAD~2..HEAD<\/code> when you mean two commits back.<\/p><\/blockquote><\/figure>\n\n\n\n<p class=\"has-medium-font-size wp-block-paragraph\">Git reverts commits in <strong>newest-first order<\/strong> automatically, which is the correct way to unwind a stack of changes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">&#8212;<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Step 4 \u2014 Validate before committing<\/strong><\/h3>\n\n\n\n<p class=\"has-medium-font-size wp-block-paragraph\">This is the most important part of the process. Never skip it.<\/p>\n\n\n\n<pre class=\"wp-block-code has-white-color has-black-background-color has-text-color has-background has-link-color wp-elements-e75c94e8d9e07248bba2bf1227b4bdd9\"><code># Quick check: which files are staged?\ngit status\n\n# Summary: file names and changed line counts\ngit diff --staged --stat\n\n# Full diff: read every line that will be undone\ngit diff --staged<\/code><\/pre>\n\n\n\n<p class=\"has-medium-font-size wp-block-paragraph\"><strong>The gold-standard check<\/strong> \u2014 compare the staged result directly against the commit you are targeting:<\/p>\n\n\n\n<pre class=\"wp-block-code has-white-color has-black-background-color has-text-color has-background has-link-color wp-elements-c60ad0fb82b69c76211c5605caf4b415\"><code>git diff &lt;hash-of-the-commit-you-want-to-land-on&gt;<\/code><\/pre>\n\n\n\n<p class=\"has-medium-font-size wp-block-paragraph\">If this command produces <strong>empty output<\/strong>, the staged state is byte-for-byte identical to that commit. The revert is perfect.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">&#8212;<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Step 5a \u2014 Commit when satisfied<\/strong><\/h3>\n\n\n\n<pre class=\"wp-block-code has-white-color has-black-background-color has-text-color has-background has-link-color wp-elements-f6abd78c6dc0c673d40cb8b193c979cc\"><code>git revert --continue<\/code><\/pre>\n\n\n\n<p class=\"has-medium-font-size wp-block-paragraph\">Git opens your editor with a pre-filled commit message. You can edit it or accept the default. Save and close to finalize the commit.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">&#8212;<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Step 5b \u2014 Abort if something looks wrong<\/strong><\/h3>\n\n\n\n<pre class=\"wp-block-code has-white-color has-black-background-color has-text-color has-background has-link-color wp-elements-eaf4db06d0692f7534785beceb8d0596\"><code>git revert --abort<\/code><\/pre>\n\n\n\n<p class=\"has-medium-font-size wp-block-paragraph\">This cancels everything and returns the repo to a clean state. No changes are made. Use this freely; it is completely safe.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">&#8212;<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Step 6 \u2014 Push<\/strong><\/h3>\n\n\n\n<pre class=\"wp-block-code has-white-color has-black-background-color has-text-color has-background has-link-color wp-elements-8bf1051eb18ecadb8c937f2a78e7eff7\"><code>git push<\/code><\/pre>\n\n\n\n<p class=\"has-medium-font-size wp-block-paragraph\">Because <code>git revert<\/code> preserves history, this is a plain push with no flags needed. The remote will accept it cleanly.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">&#8212;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Why Not <code>git reset<\/code>?<\/strong><\/h2>\n\n\n\n<pre class=\"wp-block-code has-black-color has-luminous-vivid-amber-background-color has-text-color has-background has-link-color wp-elements-b1477e95d6b9a2d7bd6babefe8a41e3c\"><code>Before revert:    A \u2192 B \u2192 C \u2192 D         (D is bad, you want to go back)\n\ngit revert:       A \u2192 B \u2192 C \u2192 D \u2192 D'     (D' undoes D, history intact)\ngit reset --hard: A \u2192 B \u2192 C             (D is erased, history rewritten)<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Description<\/th><th><code>git revert<\/code><\/th><th><code>git reset --hard<\/code> + force push<\/th><\/tr><tr><td>Rewrites history<\/td><td>No<\/td><td>Yes<\/td><\/tr><tr><td>Safe on pushed branches<\/td><td>Yes<\/td><td>No<\/td><\/tr><tr><td>Needs <code>--force<\/code> push<\/td><td>No<\/td><td>Yes<\/td><\/tr><tr><td>Undoable<\/td><td>Yes (revert the revert)<\/td><td>Very difficult<\/td><\/tr><tr><td>Affects collaborators<\/td><td>No<\/td><td>Yes \u2014 breaks their local branches<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The only situation where <code>git reset --hard<\/code> is acceptable is on a branch that <strong>has never been pushed<\/strong> and that <strong>only you<\/strong> are using.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">&#8212;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Cheat Sheet: Diagnosing the Range<\/strong><\/h2>\n\n\n\n<p class=\"has-medium-font-size wp-block-paragraph\">If you are unsure what a range covers, run this before reverting:<\/p>\n\n\n\n<pre class=\"wp-block-code has-black-color has-luminous-vivid-amber-background-color has-text-color has-background has-link-color wp-elements-4e7a20d07532e387ddb6e6ad7d715e09\"><code># List commits that would be reverted (dry run)\ngit log --oneline HEAD~N..HEAD<\/code><\/pre>\n\n\n\n<p class=\"has-medium-font-size wp-block-paragraph\">The output shows exactly which commits will be undone. Confirm this matches your intention before proceeding.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">&#8212;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Full Example<\/strong><\/h2>\n\n\n\n<pre class=\"wp-block-code has-black-color has-luminous-vivid-amber-background-color has-text-color has-background has-link-color wp-elements-dc93c35e730d55bd4ed3523b1de8e6ff\"><code># 1. Check state\n\ngit log --oneline -5\n# a1b2c3d Added a broken feature                  \u2190 HEAD\n# d4e5f6g Updated configuration for new module    \u2190 HEAD~1\n# h7i8j9k Fixed unrelated bug                     \u2190 HEAD~2 (target)\n\ngit status\n# On branch my-feature-branch \u2014 nothing to commit, working tree clean\n\ngit branch -vv\n# * my-feature-branch  a1b2c3d &#91;origin\/my-feature-branch] ...\n\n# 2. Verify what the commits changed\ngit show --stat a1b2c3d\ngit show --stat d4e5f6g\n\n# 3. Stage the revert of the last 2 commits\ngit revert --no-commit HEAD~2..HEAD\n\n# 4. Validate\ngit diff --staged --stat\ngit diff --staged\ngit diff h7i8j9k          # empty output = perfect\n\n# 5. Commit\ngit revert --continue\n\n# 6. Push\ngit push<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">&#8212;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Remembering It All<\/strong><\/h2>\n\n\n\n<p class=\"has-medium-font-size wp-block-paragraph\">Think of the process as: <strong>Look \u2192 Understand \u2192 Stage \u2192 Validate \u2192 Commit \u2192 Push<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code has-black-color has-luminous-vivid-amber-background-color has-text-color has-background has-link-color wp-elements-f0ebf888dc2603b3e7e1ca2f58d25934\"><code>git log                 \u2192  Look at the history\ngit show                \u2192  Understand what each commit did\ngit revert --no-commit  \u2192  Stage the undo (don't commit yet)\ngit diff --staged       \u2192  Validate the staged result\ngit diff &lt;target>       \u2192  Gold-standard: confirm empty output\ngit revert --continue   \u2192  Commit\ngit push                \u2192  Push (no force needed)<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">&#8212;<\/p>\n\n\n\n<p class=\"has-medium-font-size wp-block-paragraph\"><em>A practical guide to safe, history-preserving git rollbacks.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Most of the blogs I write serve as a self reminder; things I have tried personally. In one of the recent encounters where a GUI tool wasn&#8217;t was possibility I was extra cautious while trying to roll back a production code that I had not committed to ensure no functionality gets broken. This blog serves [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":2972,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_exactmetrics_skip_tracking":false,"_exactmetrics_sitenote_active":false,"_exactmetrics_sitenote_note":"","_exactmetrics_sitenote_category":0,"footnotes":""},"categories":[224,34],"tags":[209,363],"class_list":["post-2970","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-learn","category-technical","tag-git","tag-revert"],"_links":{"self":[{"href":"https:\/\/blog.samarthya.me\/wps\/wp-json\/wp\/v2\/posts\/2970","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.samarthya.me\/wps\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.samarthya.me\/wps\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.samarthya.me\/wps\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.samarthya.me\/wps\/wp-json\/wp\/v2\/comments?post=2970"}],"version-history":[{"count":2,"href":"https:\/\/blog.samarthya.me\/wps\/wp-json\/wp\/v2\/posts\/2970\/revisions"}],"predecessor-version":[{"id":2974,"href":"https:\/\/blog.samarthya.me\/wps\/wp-json\/wp\/v2\/posts\/2970\/revisions\/2974"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.samarthya.me\/wps\/wp-json\/wp\/v2\/media\/2972"}],"wp:attachment":[{"href":"https:\/\/blog.samarthya.me\/wps\/wp-json\/wp\/v2\/media?parent=2970"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.samarthya.me\/wps\/wp-json\/wp\/v2\/categories?post=2970"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.samarthya.me\/wps\/wp-json\/wp\/v2\/tags?post=2970"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}