Get rid of git unneeded merged branch?

房东的猫 提交于 2020-05-14 02:23:19

问题


I made a branch (folders) that was deliberately experimental, did stuff on it, eventually liked it, rebased interactively to reduce the number of commits, and rebased or cherry-picked into master. I deleted the branch-name and waited for the commits on that "branch" to die of their own accord.

But then for some reason the nameless "branch" got itself merged into master. I have no idea how that happened; I think it had something to do with pushing and pulling.

So now I've got these two extraneous commits, as shown in this screenshot from Sourcetree (they are the red commits on the right-hand track):

And they really are extraneous; what the red commits do (be937ba and 33b3b01) is exactly the same as what the first commit at the bottom of the rebase does (4fc6b63), because the latter is squashed from the former.

For the sake of completeness, here's the relevant part of the reflog:

6464656 HEAD@{24}: commit: finished splitters, about to reorg again
a1fc825 HEAD@{25}: commit: finished writing switch, renamed splitter partitioners
d822ddc HEAD@{26}: pull --no-commit origin master: Fast-forward
1d2b83f HEAD@{27}: commit (merge): chugging some more
6a0d405 HEAD@{28}: rebase -i (finish): returning to refs/heads/master
6a0d405 HEAD@{29}: rebase -i (pick): a bunch more pages
0b4f305 HEAD@{30}: rebase -i (pick): chugging along once again
bd9aa4f HEAD@{31}: rebase -i (pick): okay reorg into folders, looks okay to me
1a80352 HEAD@{32}: rebase -i (pick): wrote a bunch more pages
4fc6b63 HEAD@{33}: rebase -i (squash): revise nextprevs and breadcrumbs so we use folders but maintain just one nextprevs organized hierarchically
be937ba HEAD@{34}: rebase -i (start): checkout 28c6f1c81b36790b212727adaf209f30c0c0a031
a8f44e6 HEAD@{35}: rebase finished: returning to refs/heads/master
a8f44e6 HEAD@{36}: rebase: a bunch more pages
e6468f0 HEAD@{37}: rebase: chugging along once again
5c32d8e HEAD@{38}: rebase: okay reorg into folders, looks okay to me
d323c8c HEAD@{39}: rebase: wrote a bunch more pages
33b3b01 HEAD@{40}: rebase: checkout folders
9937608 HEAD@{41}: checkout: moving from folders to master
33b3b01 HEAD@{42}: reset: moving to 33b3b01717af3845160ce5b576099264b538a016
db95dc0 HEAD@{43}: merge master: Merge made by the 'recursive' strategy.
33b3b01 HEAD@{44}: commit: fix atrocious previous implementation
be937ba HEAD@{45}: checkout: moving from master to folders
9937608 HEAD@{46}: rebase -i (finish): returning to refs/heads/master
9937608 HEAD@{47}: rebase -i (pick): a bunch more pages
f6e20ea HEAD@{48}: rebase -i (pick): chugging along once again
debb94b HEAD@{49}: rebase -i (pick): okay reorg into folders, looks okay to me
08b072e HEAD@{50}: rebase -i (pick): wrote a bunch more pages
be937ba HEAD@{51}: rebase -i (squash): revise nextprevs and breadcrumbs so we use folders but maintain just one nextprevs organized hierarchically
092014e HEAD@{52}: rebase -i (start): checkout 28c6f1c81b36790b212727adaf209f30c0c0a031
fbf96a0 HEAD@{53}: reset: moving to HEAD
fbf96a0 HEAD@{54}: commit: a bunch more pages
52f19d0 HEAD@{55}: commit: chugging along once again
3251531 HEAD@{56}: commit: okay reorg into folders, looks okay to me
0a8a991 HEAD@{57}: commit: wrote a bunch more pages
54fa472 HEAD@{58}: commit: modified breadcrumbs to go with modification of nextprevs of previous commit
092014e HEAD@{59}: commit: experiment: can we use folders but maintain just one nextprevs organized hierarchically
28c6f1c HEAD@{60}: commit: tweaks to css for iPhone

I'd like to get rid of 33b3b01 (HEAD@{44}) and be937ba (HEAD@{45}) and force that change up to the remote (github). I am the only consumer so this is safe; I use this repo on multiple machines but I'm happy to delete the work folder on the other machine and clone afresh.

So the question is, can I do that, is it safe to do, and how do I do it?

Supplementary question is, how did this happen? I think what I mean by "this" is, how did HEAD@{27} become a merge commit? I thought I had this Cunning Plan to use a temporary branch as an experimental world and let its commits die, and it went wrong somehow. I know for a fact that I didn't deliberately merge, but of course pull does merge so that's probably the answer.

EDIT Here's more info from a fuller printout of git log -g, showing the part of the graph where the unintended merge happened.

commit 6464656c1de2f127ae38836bc834382477beda9e
Reflog: HEAD@{24} Reflog message: commit: finished splitters, about to reorg again

    finished splitters, about to reorg again

commit a1fc8250746a5fce6b66272e4ac11bb1f337d29c
Reflog: HEAD@{25} 
Reflog message: commit: finished writing switch, renamed splitter partitioners

    finished writing switch, renamed splitter partitioners

commit d822ddc6372bb92d50155de83b8f570b52e8cc73
Reflog: HEAD@{26} 
Reflog message: pull --no-commit origin master: Fast-forward

    starting to write switchToLatest

commit 1d2b83f0f024ae8efdd9c4a90a99353b502ad532
Reflog: HEAD@{27} 
Reflog message: commit (merge): chugging some more
Merge: 6a0d405 33b3b01

    chugging some more

commit 6a0d405394fc7a172e4987bd785ad8d8d7fb7d5b
Reflog: HEAD@{28}
Reflog message: rebase -i (finish): returning to refs/heads/master

    a bunch more pages

commit 6a0d405394fc7a172e4987bd785ad8d8d7fb7d5b
Reflog: HEAD@{29} 
Reflog message: rebase -i (pick): a bunch more pages

    a bunch more pages

The mystery is how "chugging some more" became a merge commit (Merge: 6a0d405 33b3b01). I think it has something to do with pushing, pulling on another machine, and pushing there. But I assure you I never specifically asked 33b3b01 to be merged; there's no obvious way I could, as it had no branch name (I had deleted the name).


回答1:


You can use a interactive rebase, which you seem quite familiar with.

git rebase -i 638723a

An editor will come up with each commit in a line. Delete the lines with the offending commits, including the merge. Then save and exit.

If you want to undo that, use git reset --hard ORIG_HEAD, or remember the commit ID where your branch is at before the rebase and reset to that.




回答2:


And the answer is:

  • Step 1. git replace --edit 1d2b83f

  • Step 2. A textual description of the commit opens in the editor. It has two parent lines. Delete the parent line you don't like; in this case, that's the one with the parent 33b3b01.... Save and exit the editor.

    The unwanted commits have vanished in a puff of smoke. The history is now a single straight line. If you do a git log --pretty=raw and walk through it, you can see that the history is now a single straight line from one commit to the next (meaning the previous one).

  • Step 3. git filter-branch — This (thanks, @torek) writes the replacement into the actual history, so that clones of this repo will see what I'm seeing.

I then deleted the remote and create a new remote and pushed to it, just to make sure we have a clean upstream.

This was an easy case because there was no other history to rewrite, and because no one else was sharing the work, there were no other branches, etc., and because there was nothing coming from the unwanted branch that I was trying to get rid of. I was trying to simplify the story of what happened, not to change what did happen.




回答3:


I would simply manually recreate the history that you want via Reset and Cherry-Pick (and maybe Rebase), and then use git push --force to change your remote to the state of local repo.

  • Checkout the master branch
  • Hard Reset local master to 6a0d405 (the commit before the erroneous merge)
  • Cherry-pick the subsequent good commits.
  • Your new branch will not have the bad commits or the merge.
  • Force-push the branch to overwrite the bad merge version on the server.

I too use SourceTree quite a bit, and all of the above except the force push can be done via easy commands in the UI via your mouse. I like doing it in SourceTree for the visualization as you're working.

I often do the rebuilding work on a separate branch to prevent accidentally losing any work, then reset/push master only at the end.

IMO using the common commands and then force pushing seems much simpler and less error prone than the more esoteric route of git replace and git filter-branch to rewrite the history.



来源:https://stackoverflow.com/questions/60728074/get-rid-of-git-unneeded-merged-branch

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!