Shaul Behr
Shaul Behr

Reputation: 38033

Fixing a bad merge that got baked in

So our team is pretty new to Git. We got a situation like this one, only much worse: a developer made a bad merge, and the bad merge has since been buried under about 20 subsequent commits, because we only noticed the bad merge a day later.

How do we fix this?

EDIT: Looks like the git revert -m command might be the trick, but there's only one file we really need to revert... a big edmx file that got badly mangled. Any way to restrict the revert to just that file?

Upvotes: 2

Views: 124

Answers (2)

torek
torek

Reputation: 489223

Given your edit, I'd suggest extracting a good copy of the file "pre-merge" plus any needed changes. There are multiple ways to do this: you can reverse-apply changes brought in by the merge, hoping that any subsequent changes don't conflict or overlap; you can extract a good pre-merge version and check for any updates needed; and so on.

For example, if <revspec> is a commit with a known-good version of the file:

$ git log <revspec>..HEAD -- path/to/file # find changes to file

(this will show all commits reachable from HEAD but not from <revspec> or its parents, that touched the file; this should include the merge itself, which obviously you don't want to keep, but will also show commits that made changes you might want to keep after all).

$ git checkout <revspec> -- path/to/file

(this simply extracts the old version into the work directory, writing it to the index as well, i.e., it's staged for commit already).

Now if there are revisions that you do want changes from:

$ git show <rev> -- path/to/file | git apply
... repeat for all <rev>s, make sure they all apply;
    do manual work if needed ...
$ git add path/to/file

If three are no such revisions you don't need to apply anything, nor add the result; you're now ready to git commit.


A different method, but now you must pick which "side" of the merge introduced bad stuff. Let's say the bad stuff came in from the second parent (the branch merged-in, rather than the branch-merged-into):

$ git diff <mergerev>^1 <mergerev> -- path/to/file | git apply -R

Here we get git diff to show how the file changed from "good" (first-parent of mergerev) to "bad" (mergerev, with changes brought in from second parent), and "reverse apply" those changes to the work-tree.

If all goes well, git add the fixed-up file and commit.

Upvotes: 5

Nick Volynkin
Nick Volynkin

Reputation: 15119

If there's only one corrupted file, you could find a commit where it was alright and checkout it from there:

git checkout <revision> -- path/to/file 

And then save it in the next commit.

Upvotes: 5

Related Questions