blastron blastron - 19 days ago 4x
Git Question

Disentangle old, bad merge in Git

Two months ago, I was brought on board a freelance project to do some feature work to help out another developer. When I looked at the repository, I saw that there hadn't been any checkins on it in a month, and when I asked if the project was still being actively developed the other developer said "oh, sorry, I don't like source control so I rarely touch it" and then pushed a month's worth of code as a single commit. I tried to convince them to be more active with it, at least while I was on the project, but they were very resistant, so I eventually swallowed my objections, got my work done (using good source control practices!) and got out.

Fast forward to today. I've been off the project for a month, and a third developer has signed on. The clients recently discovered that my features have stopped working since the last time they checked on them, which was shortly after I left. Since I pride myself on my work, I took a peek to see what was wrong... only to find that literally all of my changes had been stomped on by another massive, month-long commit by the first developer. To make things worse, not only has that developer since left the project and is completely uncommunicative, but the new developer on the project has been making changes (following good check-in practices) on top of that wrecked check-in.

How do I get my code back, while preserving both the changes that the first developer should have made and the new work that the third developer has put in since? I can't figure out how to disentangle the changes that should have gone in from the bad not-merge that went in on literally the same commit.

j6t j6t

You have this history:

-o--1--2--3--4            <-- your changes (master)
               E          <-- the sloppy developer's commit
                 x--y--z  <-- third developer's changes

Notice the state after E is as if 1-2-3-4 had never happened. Therefore, you should create E' and merge it into master:

-o--1--2--3--4            <-- your changes
  \           \
   E'--------- o          <-- master

You achieve this with

git checkout -b E-repair E
git reset --soft 1~
git commit -m "E-prime"
git checkout master
git merge E-repair

Now you have the state that contains both your and the sloppy developer's changes. Finally, you rebase the third developer's changes on top of this merge:

git rebase --onto master E z