I recently created a branch off master to revert a very large commit.
I first created a branch off master then,
I used git revert "commit tag from gitlab"
,
but I have a lot of merge conflicts now and would like to resolve them so that only the Head changes or from what I understand, resolve the merge so the changes from the large commit are excluded in the merge. The idea is to create a branch that has every commit after the faulty commit and then merge it with master after so that the faulty commit is excluded.
so if F was the bad commit the new branch would be:
Master: A->B->F->C->D
Hot fixed Branch: A->B->C->D
Thank you!
To anyone wondering, here is what the OP said helped him from my answer:
git revert F
and option 1 [git checkout --ours
] ended up helping a lot!
Now, here is my answer:
git reset --soft
techniqueScenario:
master
: A->B->F->C->D
You want to remove or revert commit F and end up with:
hot_fixed_branch
: A->B->C->D
If you run git revert F
, the reason you have conflicts is because changes in C and/or D have touched the same lines as changes from F. Therefore, there's no clean way to just "undo F". If you try to undo F, it will also undo parts of C and D, so you have to manually resolve those conflicts to keep the desired parts of C and D while removing the content of F from those same lines.
While you're in the middle of resolving the git revert F
conflicts, you can optionally try the following:
# Option 1:
# keep only the changes expressed by `git diff F..HEAD`, meaning: the changes
# done by C and D
git checkout --ours
# Option 2:
# keep only the changes expressed by `git diff F..F~`, meaning: the changes
# which are **the opposite of F**, thereby exactly undoing F
git checkout --theirs
Read also my git revert
section here, in case that helps you make sense of it: Who is "us"/"ours" and "them"/"theirs" according to Git?.
However, if you do Option 1 above, you'll still retain some changes from F, since C and D were built on top of F. And, if you do Option 2 above, it may break or remove changes added by C and D, since they were built on top of F. One of the two options above may get you close to what you want, but no matter which you choose, you're still going to break something. That's why the conflicts exist in the first place! The existence of conflicts tells you that C and/or D touched the same lines as F.
So, the best thing to do is to open a new terminal and run this while resolving all conflicts, so you can at least see what was added by F, and be able to then manually make sense of it and undo it properly as you manually resolve conflicts:
meld
is your difftool. See my instructions here: How to use meld as your git difftool in place of git diff. Meld is a great way to compare changes in a GUI.# see the changes added by F
git difftool F~..F
# OR, to specify just a particular folder to look at
git difftool F~..F -- path/to/dir
# OR, to specify just a particular file to look at
git difftool F~..F -- path/to/file
# OR specify a couple files
git difftool F~..F -- file1 file2
# etc.
If any of the git commands below don't make sense, read and study all my references. I literally had those tabs open all at once to write this answer myself, referencing all of my references live while writing this answer.
There are multiple ways to do this.
git revert F
(you'll end up with A->B->F->C->D->F'
, where F'
is the opposite of F
, thereby undoing F
's changes):
# create and check out hot_fix from B
git checkout -b hot_fix B
# Now revert F
git revert F
# manually fix conflicts, then commit them
git add -A
git revert --continue
git revert F
is too hard to resolve, then try simply cherry-picking C and D onto B instead (you'll end up with A->B->C->D
):
# create and check out hot_fix from B
git checkout -b hot_fix B
# Now cherry-pick C and D onto it
git cherry-pick C D
# manually resolve conflicts as necessary, and continue, as often as
# necessary
git add file1.c file2.c # etc.
git cherry-pick --continue
A->B->E
, where E
is a commit containing the changes of C
and D
squashed into a single commit):
# Create and check out a "master_copy" branch from "master" so you don't
# mess up master
git checkout -b master_copy master
# squash C and D on "master_copy" into a single commit
git reset --soft C~
git commit -m "Squashed commit containing both C and D"
# Now check out "hot_fix" from B and cherry-pick that squashed
# commit we just made onto it
git checkout -b hot_fix B
git cherry-pick master_copy
# manually resolve conflicts, then commit them
git add -A # or git add file1.c # etc.
# Once done fixing and adding ALL files, then do:
git cherry-pick --continue
git reset --soft
way" to squash commits. Search my git & Linux cmds, help, tips & tricks - Gabriel.txt document from my eRCaGuy_dotfiles repo for `git reset --soft` way