I accidentally committed a general change on a development branch and already merged it to the master
branch a while ago:
* HEAD
* ...
*
* 2c884bc Updated Gradle Root Project Name
* 4926f6a Merge branch 'wip-dev-Logger'
|\
| * 43161fb Revised Logger
| * 13c8303 Switched to JDA 4.4.0_351
* | 599c72e Added Answerer interface
|/
* 4b0dcb8 Switched to Java 17
*
* ...
*
Is it possible to move commit 13c8303
from the development to the master branch without destroying the merge/branch history?
It should then look like this:
* HEAD
* ...
*
* 2c884bc Updated Gradle Root Project Name
* 4926f6a Merge branch 'wip-dev-Logger'
|\
| * 43161fb Revised Logger
* | 13c8303 Switched to JDA 4.4.0_351
* | 599c72e Added Answerer interface
|/
* 4b0dcb8 Switched to Java 17
*
* ...
*
CodePudding user response:
Individual commits in git are immutable, because they are identified by a hash of:
- The entire code tree
- The commit message, date, and authorship information
- The hash identifying their parent, or multiple parents in the case of a merge commit
Meanwhile, branches can be changed at will, because they are simply a movable pointer to a particular commit.
So the outcome you have shown is impossible, because if the commit identified by hash 13c8303
had a different parent, it would have a different hash. The commits identified by 43161fb
and 4926f6a
would also have different parents, so different hashed - and so on for all commits "forwards" from the point in history you want to create.
It is possible to create that alternative history, using the git rebase command, but every working copy, and every branch after the change you make will need to be updated to refer to the new history. If you get it right, it will look something like this:
* HEAD
* ...
*
* 56fa78b Updated Gradle Root Project Name
* 12cd34e Merge branch 'wip-dev-Logger'
|\
| * ef78ab9 Revised Logger
* | 12ab34d Switched to JDA 4.4.0_351
* | 599c72e Added Answerer interface
|/
* 4b0dcb8 Switched to Java 17
*
* ...
*
If you try to use a branch from later in the original history without rebasing it onto the new history, you'll end up with two versions of all the commits after the ones you change - and probably a lot of conflicts when you try to merge them back together.
CodePudding user response:
Based on the answer from @IMSop, I came up with the follwoing solution:
- In my case there were no other branches apart from
master
and I have not yet pushed any of my mistakes on a remote
If you have an unmerged branch pointing to a newer commit, make sure you know how to handle the additional difficulties to come.
git rebase --root --interactive --rebase-merges
- Change the order of commits in the editor
...
pick 4b0dcb8 Switched to Java 17
label branch-point
pick 13c8303 Switched to JDA 4.4.0_351 <--- COMMIT TO MOVE ---
pick 43161fb Revised Logger
label wip-dev-Logger
reset branch-point # Switched to Java 17
pick 599c72e Added Answerer interface
merge -C 4926f6a wip-dev-Logger # Merge branch 'wip-dev-Logger'
pick 2c884bc Updated Gradle Root Project Name
...
to
pick 4b0dcb8 Switched to Java 17
label branch-point
pick 43161fb Revised Logger
label wip-dev-Logger
reset branch-point # Switched to Java 17
pick 599c72e Added Answerer interface
pick 13c8303 Switched to JDA 4.4.0_351 <--- COMMIT TO MOVE ---
merge -C 4926f6a wip-dev-Logger # Merge branch 'wip-dev-Logger'
pick 2c884bc Updated Gradle Root Project Name
...
Save and close the editor. Everything should work fine if you didn't touch any files in the moved commit that could conflict with this merge.
Confirm using
git log --graph --oneline
:
* HEAD
* ...
*
* c5d2985 Updated Gradle Root Project Name
* 31a26e4 Merge branch 'wip-dev-Logger'
|\
| * 13e0a2c Revised Logger
* | 5cebef6 Switched to JDA 4.4.0_351
* | 599c72e Added Answerer interface
|/
* 4b0dcb8 Switched to Java 17
*
* ...
*