<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Prasad MK</title>
    <description>The latest articles on DEV Community by Prasad MK (@prasadmk).</description>
    <link>https://dev.to/prasadmk</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3957831%2F2b306458-eebf-4ada-8733-a882b13258c2.png</url>
      <title>DEV Community: Prasad MK</title>
      <link>https://dev.to/prasadmk</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/prasadmk"/>
    <language>en</language>
    <item>
      <title>Rescuing a Broken Master from a Tag, Cleanly Through a PR</title>
      <dc:creator>Prasad MK</dc:creator>
      <pubDate>Fri, 29 May 2026 06:46:14 +0000</pubDate>
      <link>https://dev.to/prasadmk/rescuing-a-broken-master-from-a-tag-cleanly-through-a-pr-416i</link>
      <guid>https://dev.to/prasadmk/rescuing-a-broken-master-from-a-tag-cleanly-through-a-pr-416i</guid>
      <description>&lt;p&gt;It happens on real teams. Someone merges the wrong thing, a dependency update silently breaks the build, or a hotfix lands without a proper review. Whatever the reason, &lt;strong&gt;master is broken and you still have work to ship.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The good news: if you have a working release tag, you have everything you need. This guide walks through the full recovery arc, branching from the tag, adding new code on top, and raising a clean pull request that merges back to master with no surprise conflicts.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why branching from the tag is the right move
&lt;/h2&gt;

&lt;p&gt;The instinct is often to "fix master directly." Resist it. You do not know the full extent of what broke, and working on master violates the PR policy anyway. The tag is a precise snapshot of code that worked. Treating it as your new baseline keeps every subsequent decision clean and reviewable.&lt;/p&gt;

&lt;p&gt;The strategy has three phases: &lt;strong&gt;establish&lt;/strong&gt; a branch at the good commit, &lt;strong&gt;build&lt;/strong&gt; your new work on top of it, then &lt;strong&gt;reconcile&lt;/strong&gt; the divergence before raising a PR so the reviewer sees nothing but your intentional changes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Phase 1: Create a branch from the tag
&lt;/h2&gt;

&lt;p&gt;This single command is the foundation of everything that follows. It tells Git to set your new branch's starting commit to exactly where &lt;code&gt;v1.3&lt;/code&gt; points, not to the current tip of master.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create the branch rooted at the v1.3 tag&lt;/span&gt;
git checkout &lt;span class="nt"&gt;-b&lt;/span&gt; fix/restore-from-v1.3 v1.3

&lt;span class="c"&gt;# Push it to Bitbucket so the team can see it&lt;/span&gt;
git push &lt;span class="nt"&gt;-u&lt;/span&gt; origin fix/restore-from-v1.3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before writing a single line of new code, take a moment to understand exactly what diverged. This pays off when you reconcile later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# What commits exist on master that are not in v1.3?&lt;/span&gt;
git log v1.3..origin/master &lt;span class="nt"&gt;--oneline&lt;/span&gt;

&lt;span class="c"&gt;# What do those changes actually look like?&lt;/span&gt;
git diff v1.3 origin/master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key insight:&lt;/strong&gt; The diff above tells you exactly which files the broken commits touched. Those are the files you will need to consciously handle when you reconcile later. Keep a mental note of them.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Phase 2: Add your new work on top
&lt;/h2&gt;

&lt;p&gt;You are now on a stable foundation. Build your features or fixes as normal, with one discipline: commit small and commit often. This is not just good practice in general, it becomes essential when you need to explain your PR to a reviewer who is looking at a branch that diverges from a broken master.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Work on your files normally&lt;/span&gt;
git add src/feature-x.js src/utils.js

&lt;span class="c"&gt;# Write commit messages that will read well in the PR&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"feat: add validation layer for incoming payloads"&lt;/span&gt;

git add tests/feature-x.test.js
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"test: unit coverage for payload validator"&lt;/span&gt;

&lt;span class="c"&gt;# Push regularly : this keeps Bitbucket in sync&lt;/span&gt;
git push origin fix/restore-from-v1.3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Phase 3: Reconcile before you raise the PR
&lt;/h2&gt;

&lt;p&gt;This is the step most guides skip or handle lazily. If you raise a PR now, Bitbucket will show conflicts because your branch started at &lt;code&gt;v1.3&lt;/code&gt; and master has moved (to broken commits) since then. The reviewer gets a noisy, confusing diff.&lt;/p&gt;

&lt;p&gt;The correct approach is to resolve all of this &lt;strong&gt;locally on your branch&lt;/strong&gt; before the PR goes up. Bitbucket then shows a clean diff of exactly what you intended to change.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Pull master's current state into your branch
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Make sure you have the latest remote state&lt;/span&gt;
git fetch origin

&lt;span class="c"&gt;# While ON your fix branch, merge master in&lt;/span&gt;
git checkout fix/restore-from-v1.3
git merge origin/master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Resolve conflicts, keeping your code
&lt;/h3&gt;

&lt;p&gt;Git will flag every file where your branch and the broken master diverge. For each conflict, you decide: keep your code, keep master's code, or blend them. In a recovery scenario, you almost always want to keep your branch's version.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Option A: Accept your branch's version for a specific file&lt;/span&gt;
git checkout &lt;span class="nt"&gt;--ours&lt;/span&gt; src/api/handler.js
git add src/api/handler.js

&lt;span class="c"&gt;# Option B: Open the file manually, remove conflict markers,&lt;/span&gt;
&lt;span class="c"&gt;# edit to the state you want, then stage it&lt;/span&gt;
&lt;span class="c"&gt;# &amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt; HEAD  (your branch)&lt;/span&gt;
&lt;span class="c"&gt;# =======       (divider)&lt;/span&gt;
&lt;span class="c"&gt;# &amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; origin/master  (master)&lt;/span&gt;
git add src/api/handler.js

&lt;span class="c"&gt;# Once all conflicts are resolved, commit the merge&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"merge: absorb origin/master, keep v1.3 baseline + new features"&lt;/span&gt;

&lt;span class="c"&gt;# Push the resolved branch&lt;/span&gt;
git push origin fix/restore-from-v1.3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Watch out with &lt;code&gt;--ours&lt;/code&gt;:&lt;/strong&gt; During a &lt;code&gt;git merge&lt;/code&gt;, "ours" refers to the branch you were on when you ran the merge your fix branch. "Theirs" refers to the branch being merged in master. This is the &lt;strong&gt;opposite&lt;/strong&gt; of how it works during a &lt;code&gt;git rebase&lt;/code&gt;. Keep this straight.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Step 3: Verify the diff before raising the PR
&lt;/h3&gt;

&lt;p&gt;This is your sanity check. The three-dot diff shows only the commits that exist on your branch but not on master, exactly what the reviewer will see in the PR.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Three-dot diff: "what does my branch add beyond master?"&lt;/span&gt;
git diff origin/master...fix/restore-from-v1.3

&lt;span class="c"&gt;# Cross-check: should show ONLY your new intentional changes&lt;/span&gt;
git diff v1.3 HEAD

&lt;span class="c"&gt;# If the output matches your intentions, you are ready to raise the PR&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Raising the pull request in Bitbucket
&lt;/h2&gt;

&lt;p&gt;With the branch pushed and conflicts pre-resolved, the PR creation is straightforward. In Bitbucket, navigate to your repository, go to &lt;strong&gt;Pull Requests&lt;/strong&gt;, and create a new PR from &lt;code&gt;fix/restore-from-v1.3&lt;/code&gt; to &lt;code&gt;master&lt;/code&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Source branch:&lt;/strong&gt; &lt;code&gt;fix/restore-from-v1.3&lt;/code&gt;. Target branch: &lt;code&gt;master&lt;/code&gt;. Bitbucket should now show no merge conflicts because you resolved them on your branch.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Write a clear PR description.&lt;/strong&gt; Mention that the branch was rooted at tag &lt;code&gt;v1.3&lt;/code&gt; due to the broken master state. Reviewers need this context to evaluate the diff correctly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Link the relevant issue or Jira ticket&lt;/strong&gt; if your team uses one. This anchors the PR to business context and keeps the audit trail intact.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The reviewer sees a clean, intentional diff.&lt;/strong&gt; No broken master code, no spurious conflict markers. Just your new work on top of the last stable release.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  What happens to master after the merge
&lt;/h2&gt;

&lt;p&gt;When the PR merges, master will contain: the complete history up to &lt;code&gt;v1.3&lt;/code&gt;, the merge commit that absorbed the broken state, and your new feature commits on top. The broken commits are still in the history, they are not erased, but they are effectively neutralized because your branch's code takes precedence in the final snapshot.&lt;/p&gt;

&lt;p&gt;This is the cleanest outcome achievable under a PR-only policy. You did not force-push, you did not rewrite shared history, and every change that landed in master went through a review.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A note on force-pushing master:&lt;/strong&gt; Some guides suggest resetting master to the tag and force-pushing. That works in a solo repo but is destructive on a shared branch, it rewrites history that other developers may have already pulled. The approach in this guide avoids that entirely.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Quick reference: the full command sequence
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Branch from the working tag&lt;/span&gt;
git checkout &lt;span class="nt"&gt;-b&lt;/span&gt; fix/restore-from-v1.3 v1.3
git push &lt;span class="nt"&gt;-u&lt;/span&gt; origin fix/restore-from-v1.3

&lt;span class="c"&gt;# 2. Understand the divergence (read-only, safe to run anytime)&lt;/span&gt;
git log v1.3..origin/master &lt;span class="nt"&gt;--oneline&lt;/span&gt;
git diff v1.3 origin/master

&lt;span class="c"&gt;# 3. Do your work, commit often&lt;/span&gt;
git add &amp;lt;files&amp;gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"feat: your message here"&lt;/span&gt;
git push origin fix/restore-from-v1.3

&lt;span class="c"&gt;# 4. Absorb master into your branch (pre-resolve before PR)&lt;/span&gt;
git fetch origin
git merge origin/master
&lt;span class="c"&gt;# resolve conflicts, then:&lt;/span&gt;
git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"merge: absorb master, keep v1.3 baseline + new features"&lt;/span&gt;
git push origin fix/restore-from-v1.3

&lt;span class="c"&gt;# 5. Verify the diff is clean&lt;/span&gt;
git diff origin/master...fix/restore-from-v1.3

&lt;span class="c"&gt;# 6. Raise the PR in Bitbucket: fix/restore-from-v1.3 -&amp;gt; master&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The principle worth keeping
&lt;/h2&gt;

&lt;p&gt;Tags are not just release markers. They are &lt;strong&gt;named, immutable recovery points&lt;/strong&gt;. Any time master becomes unstable and a working tag exists, you have a clean path back, without rewriting shared history, without bypassing your PR policy, and without making your reviewer's job harder than it needs to be. The work is in the reconciliation step. Get that right, and the merge is uneventful.&lt;/p&gt;

</description>
      <category>cicd</category>
      <category>git</category>
      <category>devops</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
