Few commits ago I accidentally did a nonlinear merge in my master branch. I have a habit of always trying to keep a linear history, so now I would like to restore the linearity.
One approach would be to use rebase.
Regardless of the approach you choose, you will have to rewrite the history of your repository. You have to accept that, otherwise you will have to accept your current history.
Let's summarize the different sections of your history:
To solve this, I would do the following:
Here's diagrams of the process, step by step (commands follows):
Status now:
master
v
1---2---4---5---8---M--10--11
\ /
3---6---7---9
New branch for 9:
master
v
1---2---4---5---8---M--10--11
\ /
3---6---7---9
^
TEMP1
Rebase on top of 8, this creates 3', 6', 7', 9' (the ' means "copy of commit, same contents, new hash")
TEMP1
v
3'--6'--7'--9'
/
1---2---4---5---8---M--10--11
\ / ^
3---6---7---9 master
Create a new branch for 11 (I don't like to mess with master)
TEMP1
v
3'--6'--7'--9'
/
1---2---4---5---8---M--10--11
\ / ^
3---6---7---9 master
^
TEMP2
Rebase this branch (10 and 11) on top of TEMP1:
TEMP1 TEMP2
v v
3'--6'--7'--9'-10'-11'
/
1---2---4---5---8---M--10--11
\ / ^
3---6---7---9 master
Verify that TEMP2 is identical to current master, nothing lost, nothing added, etc.
Then hard-reset master to TEMP2:
master
v
TEMP1 TEMP2
v v
3'--6'--7'--9'-10'-11'
/
1---2---4---5---8---M--10--11
\ /
3---6---7---9
I would then delete branches TEMP1 and TEMP2.
Note that commit 3, 6, 7, 9, M, 10 and 11 still exists in the repository but they're not directly available because nothing refers to them. They're thus eligible for garbage collection and in reality the actual history of your repository now looks like this:
1---2---4---5---8---3'--6'--7'--9'-10'-11'
^
master
The commands to perform these operations are:
(step 0: Make a complete copy of your local folder, complete with working folder and .git repository, then, if you can, do the following commands in that copy, if you screw up, delete the copy and start over, don't jump without a safety net)
git checkout git checkout -b TEMP1 (yes, you can do this and the previous command in one command with git checkout -b TEMP1 )git rebase -i --onto TEMP1 git checkout -b TEMP2 git rebase --onto TEMP1 TEMP2 git checkout mastergit reset --hard TEMP2Lastly, cleanup:
git branch -d TEMP1 TEMP2
git push -f
Only force-push when you know everything is OK