I accidentally merged a co-workers branch into the branch I was working on. I've made several commits since then so ideally I don't want to revert to the state the branch was before the merge. However, I haven't done anything that has altered his files.
Is there a way I can remove his branch's files from mine?
(Sorry, I am new to git - hope I've got the terminology down).
The git revert command will have generated a commit that restores your branch's state to where it was before the faulty merge. If your merge was remote (i.e. happened on GitHub) you can push this commit like any other and you'll be set to go.
When you're done with a branch and it has been merged into master, delete it. A new branch can be made off of the most recent commit on the master branch. Also, while it is ok to hang onto branches after you've merged them into the master they will begin to pile up.
How do I cancel a git merge? Use git-reset or git merge --abort to cancel a merge that had conflicts. Please note that all the changes will be reset, and this operation cannot be reverted, so make sure to commit or git-stash all your changes before you start a merge.
When you perform a merge, you effectively merge one branch into another—typically a feature branch or bug fix branch into a main branch such as master or develop. Not only will the code changes get merged in, but also all the commits that went into the feature branch.
Perhaps the easiest and safest option here would be to revert the merge commit which you made a few commits ago. To do this, find the merge commit in your history using git log
, and record the SHA-1 hash of that commit. Then, do the following:
git revert -m 1 <SHA-1>
Here <SHA-1>
is the hash of the merge commit you want to undo. The -m 1
option tells Git to revert to the first parent, which is the branch on which the merge originated, which should be your branch.
If you have not pushed (published) your commits anywhere, the simplest fix is to rebase the merge away. (You can do this even if you have published them, but see the caveat.)
The command git rebase
copies commits, but by default, it discards merge commits. The normal goal of git rebase
is to copy commits so that they come at a different point. For instance, you might have this:
...--o--*--o--o <-- master
\
A--B--C <-- yourbranch
in your repository after you pick up some new master
commits from some "upstream" repository (origin
), and now you'd like to make your A-B-C
sequence come after the last commit on master
, rather than coming after commit *
(commit *
is the first commit that is on both master
and yourbranch
).
You then git checkout yourbranch && git rebase master
and Git copies the commits to new ones, A'-B'-C'
(copies of the originals), and tosses your old ones:
A'-B'-C' <-- yourbranch
/
...--o--*--o--o <-- master
\
A--B--C [abandoned]
But, since git rebase
normally discards merges, you can rebase to where you are now, and in the process, toss out a merge:
...--o--*--o--o--o--...
\ \
A--B--X--C--D <-- yourbranch
Here, your merge commit X
is a mistake and you wish to get rid of it (I've drawn it as merging the mainline, but it could merge something else—it doesn't really matter what you merged, just that it is a merge commit, with two backwards-pointing arrows coming out of it, when Git looks at it). So you find the hash ID of commit *
and run:
git checkout yourbranch; git rebase <hash-id>
Git lists the commits to copy as "those after *
, up to the tip of yourbranch
, except for any merges". That's A-B-C-D
. It then "copies" A
(it doesn't have to so it actually re-uses the original A
by default), "copies" B
(again it doesn't have to), copies C
(it has to this time—the original C
connects to X
and the new one must connect instead to B
), and copies D
, making yourbranch
point to the last copied commit and abandoning the old chain:
...--o--*--o--o--o--...
\ \
A--B--X--C--D [abandoned]
\
C'-D' <-- yourbranch
With D
abandoned, all three of D
, C
and X
simply vanish off the map entirely:
...--o--*--o--o--o--...
\
A--B
\
C'-D' <-- yourbranch
With C
and D
having vanished, we don't even need the C'
and D'
markings. I will leave them in, though, and merely straighten out the kink we also no longer need:
...--o--*--o--o--o--...
\
A--B--C'-D' <-- yourbranch
The commit message for C'
looks like the one for C
, and the one for D'
looks like the one for D
; and C'
and D'
are "just as good as" the originals—or, actually, even better: they're new and improved! :-) because they omit the merged stuff.
Caveat: Because these are "new and improved", they have new hash IDs. This means that if you have published them, anyone who has the old ones will still have them, and will know them by their old hash IDs. You must now convince these other Git users, with their other repositories, to take the new-and-improved copies and discard the old-and-lousy ones, just like you did.
If you haven't published these commits anywhere, no one else has the old ones, and there is nothing to worry about.
Note, by the way, that you can git rebase
onto a new base, just as you would for updating to the latest master
. This just copies all the commits (to the new location), instead of re-using whichever commits it can (at the old location) and copying the rest. (But you'll face any update-related issues when you do this, just as you would for any such rebase. That is, if whoever updated master
, or whatever it is you are updating to, touched the same code in the same files, you will have to resolve any merge conflicts that occur. If you're only deleting a merge, and there were no merge conflicts in the merge, there won't be any in the rebase.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With