Remove other peoples' commits on my branch after rebase gone wrong
Asked Answered
M

5

16

I got myself into some git-funk here. I need to git-fu myself out of this.

I joined a new team and created a feature branch:

git checkout -b feature_branch

Made some changes and then committed/pushed them up to the branch.

git commit -am "Changes"
git push origin feature_branch

Someone left a review on my PR, so I made the changes, and then checked out to master and rebased my branch before committing/pushing again to that branch:

// from feature_branch make some changes
git commit -am "New changes"
git checkout master
git checkout feature_branch
git rebase origin/master
git push feature_branch

Once I did this, I noticed my PR (on Github) picked up someone elses' commit. I was then informed that the typical method within this new team is to checkout to master and merge back into my branch INSTEAD of rebasing.

Here is the funky part now -- I started mucking around with git reset --hard and picked the commit I wanted that was before that commit from someone else.

All was well, or so I thought. I then pushed that up and it seemed to have removed that other persons' commit from my PR.

I checked this morning and now there are a bunch of other commits from someone else that got picked up.

So now I'm in this weird state. I look at my PR and there are almost 30 commits (with 6 from different people). The actual diff (files changed) are only the files that I touched, which is good, but the history itself looks ridiculous.

What's the best approach to clean this up? Everything is suggesting to use git rebase, however, I was advised not to use rebase.

Unfortunately, I need to keep this branch. What's the best way to clean it up and remove all the other commits except only mine? Just reset it completely and then cherry-pick the changes back onto the branch?

Please help :|

EDIT: Here's an example of what the history looks like:

Commits on Jul 30, 2018
<SOMEONE ELSES>

Commits on Jul 31, 2018
<SOMEONE ELSES>
<MY ORIGINAL COMMIT>
<SOMEONE ELSES>

Commits on Aug 1, 2018
<SOMEONE ELSES>
<MY COMMIT [Merge branch master into my feature branch]>
<MY COMMIT>
<SOMEONE ELSES>
<MY COMMIT>
<MY COMMIT>
<SOMEONE ELSES>
<MY COMMIT>

etc etc
Mudslinging answered 3/8, 2018 at 23:29 Comment(0)
C
7

Your best bet to clean stuff up is probably to use git rebase -i to rebase on a previous change already in you branch1 before all the stuff you want to clean up, and then delete the changes you don't want from the list of changes in the editor (leaving just the changes you do want). That will rewrite the changes to include just your changes and get you back into a "clean" (relatively) state.

Once you've done that, you can then git merge from master (or wherever) as recommended by your git flow.


1Possibly the change you originally branched from if you want to clean out everything you prevously rebased/merged into your branch, or possibly some later refpoint. The earlier the point you choose, the more stuff you (can) clean out, but also potentially the more work you need to do.

Charmainecharmane answered 4/8, 2018 at 0:51 Comment(1)
Thanks for the info. I ended up going down this route per your comment but ended up not pushing it (with --force) but held off while I tried an approach before. Now I know how to use it for the future :)Mudslinging
M
12
// from feature_branch make some changes
git commit -am "New changes"
git checkout master
git checkout feature_branch
git rebase origin/master
git push feature_branch

Once I did this, I noticed my PR (on Github) picked up someone elses' commit.

If all you did was rebase on top of origin/master that should not have been possible.

However, this sequence is a bit fishy. You never do a git fetch so origin/master is not known to be up to date. If a rebase did happen, git push feature_branch should have failed because a rebase cannot be fast forwarded. You would have had to use git push -f feature_branch.

I suspect something else went wrong that you're not showing us. A complete history of your commands would help.

The proper sequence for updating a branch with rebase is this.

# Update all your remotes
git fetch

# Rebase your branch on top of origin/master
git checkout feature_branch
git rebase origin/master

# Force push the branch
git push -f

Fortunately your old commits are not lost after a rebase, they're just not connected to anything. To find them, use git reflog. This will show every time HEAD (ie. your current checkout) changed.

In the reflog, look for something like this...

081abed HEAD@{8}: rebase finished: returning to refs/heads/feature_branch
081abed HEAD@{9}: rebase: the last commit message from your branch
0a5b366 HEAD@{10}: rebase: another commit message
e9c4d18 HEAD@{11}: rebase: the first commit message from your branch
e6780bf HEAD@{13}: rebase: checkout origin/master
0ee63b1 HEAD@{14}: checkout: moving from master to feature_branch

0ee63b1 will be your old branch tip. git reset --hard 0ee63b1 and you've undone the rebase.


There's an alternative explanation: that you've made your PR against the wrong branch. Double check that.

Morton answered 4/8, 2018 at 1:33 Comment(1)
Thank you! SO here's what I realized happened. There is a CI bot that updated my PR a few days ago and merged in 2 branches. Those 2 branches contained commits (6 in total) from the other people which is why it was so confusing to me. I can't believe I ignored that but once I clicked through to see what it actually merged, it was a revelation. I also did end up cleaning up my history a bit and I LOVE this tip for the future (e.g. basically resetting everything to the first "clean" commit on that branch).Mudslinging
C
7

Your best bet to clean stuff up is probably to use git rebase -i to rebase on a previous change already in you branch1 before all the stuff you want to clean up, and then delete the changes you don't want from the list of changes in the editor (leaving just the changes you do want). That will rewrite the changes to include just your changes and get you back into a "clean" (relatively) state.

Once you've done that, you can then git merge from master (or wherever) as recommended by your git flow.


1Possibly the change you originally branched from if you want to clean out everything you prevously rebased/merged into your branch, or possibly some later refpoint. The earlier the point you choose, the more stuff you (can) clean out, but also potentially the more work you need to do.

Charmainecharmane answered 4/8, 2018 at 0:51 Comment(1)
Thanks for the info. I ended up going down this route per your comment but ended up not pushing it (with --force) but held off while I tried an approach before. Now I know how to use it for the future :)Mudslinging
D
7

What's the best approach to clean this up? Everything is suggesting to use git rebase, however, I was advised not to use rebase.

Even though the team does not use a rebase workflow themselves, it might be the better approach to fix unmerged branches. As long as you are sure that no one else is using and you are aware of the possible implications if that's not the case.

Note: I assume your remote is named origin and that the branch was created on master. If that's not the case, just replace them with the appropriate ones.

Before anything, stash all modifications (if any):

git stash save

And checkout to your branch:

git checkout mybranch

(Recommended) Backup the branch as is with a temporary tag:

git tag mybranch_bkp_rebase

Rebase

As mentioned, you can rebase to the point where the branch was created and delete the lines whose commits are not relevant to your branch.

git rebase -i "$(git merge-base origin/master HEAD)"

With that, the only commits left in your branch will be the ones that already were there when you created the branch, plus the commits from the lines that weren't deleted.

(Optional) After checking that everything is in order, you can rebase to the current master:

git rebase origin/master

Reset

If you don't want to rebase, you could just reset to a previous known good state. That could be either a commit in your own branch, the commit it was created on or the current master:

# Pick one
last_known_good_rev=hash_of_last_good_commit
last_known_good_rev="$(git merge-base origin/master HEAD)"
last_known_good_rev='origin/master'
git reset --hard "$last_known_good_rev"

Then check with git log for commits that might be missing:

git log --oneline mybranch_bkp_rebase..HEAD

And cherry-pick them:

git cherry-pick hash1 hash2 hash3
Dumyat answered 4/8, 2018 at 1:46 Comment(2)
I want to give you a bounty for this. Extremely useful. I'll attempt to when this allows me.Mudslinging
Looks like I can only bounty non-accepted answers. Went ahead and helped you out elsewhere ;)Mudslinging
P
0

If you have multiple of your own commits on your branch, you may be able to just rebase and squash all of your commits into your latest commit, which would put all of your changes on the tip of the branch which would stop GitHub from pulling in all of the changed that happened between your commits.

From there you can force push the rebased branch up to the remote and it should only show your newly squashed and rebased commit.

Pomatum answered 11/2, 2021 at 20:22 Comment(0)
V
0

Kelvins post worked great for me, only I had to delete my remote branch which was already tainted with the unwanted extra commits. I dont have enough points yet to directly comment on their post or upvote it so Ill comment that small difference here.

Vandalize answered 27/3, 2023 at 22:2 Comment(1)
This does not provide an answer to the question. Once you have sufficient reputation you will be able to comment on any post; instead, provide answers that don't require clarification from the asker. - From ReviewRoughish

© 2022 - 2024 — McMap. All rights reserved.