2

we are working on a git repo with several branches. The system only allows to deploy changes onto the live system, if all commits have feature-ids as the beginning of the commit comment that must be approved by the company for this project.

We have a typo in one commit that is more than 100 commits back in the past (several people working on this repo), that leads to the feature-id being wrong (and therefore not approved for this project). So now we are not able to push our changes into the live system because of this one commit.

Therefore I need to change the commit message of this one commit to solve my problem.

I researched and came across this solution using git rebase. I'm aware of the fact that I would change git history here and I'm aware of the implications. That would be fine so far. Now my problem is that (to my understanding), git rebase takes all the ~140 commits, deletes them from the history and tries to apply them again. This works well if you don't have any merges in your commits. But boy do we have a lot of merges. There were many merge conflicts, that have all been resolved (obviously).

But when the rebase is done, the information on how to resolve the conflicts seems to be lost and git asks me to merge everything again. That is not a viable option because re-doing merges for ~140 commits would take about four weeks or more (also information on how to merge might not be available any more).

So we need to make git resolve these conflicts automatically, using the information given in the repo.

I can't figure out how to do that. I read about the git rerere command (see here), but to my understanding I should have enabled that option before resolving all the conflicts and while doing so, git would have recorded the necessary information for later.

What are my options to get this one commit renamed? Seems like a simple tasks, but I'm out of ideas.

Thanks a lot for any help!

2 Answers 2

2

You can use git amend to change the commit message. Then replace your current commit with new commit in all branch.

$ git branch backup                                 # backup your branch just for safety

$ git checkout <commit-hash>                        # checkout the commit trying to modify
$ git commit --amend -m 'Change message here'       # change the author name and mail

$ git log                                           # copy the new-commit-hash
$ git replace <old-commit-hash> <new-commit-hash>   # replace the old commit by new one
$ git filter-branch -- --all ^<old-commit-hash>     # note '^' before hash, rewrite all futures commits based on the replacement                   

$ git replace -d <old-commit-hash>                  # remove the replacement for cleanliness 

$ git checkout <branch>                             # go to branch HEAD and see if the commit is changed perfectly

$ git push -f origin HEAD                           # force push as history is changed.
Sign up to request clarification or add additional context in comments.

3 Comments

This is the way to go. I will add that it is possible to do this with a single --msg-filter filter-branch (without the amend and replace steps), but that's a lot trickier to get right. You can speed up the filtering by adding ^<hash> after --all in the filter-branch, where <hash> is the replaced commit (we don't need to copy earlier commits, only later ones).
"+1 I agree". Thanks for --msg-filter idea (may be more tricky as regex may be needed to match commit message). I edited post adding ^<hash>.
I was thinking ^<old-hash> but ^<new-hash> should work too. You wouldn't need a regex, you would need to test $GIT_COMMIT for the old hash ID.
1

Try using --preserve-merges on your rebase

git rebase --preserve-merges HEAD~100

It should try to recreate the merge commits and might help you out. If using with -i just make sure you don't change the order of the commits or it might mess things up.

2 Comments

The OP noted that those merges had merge conflicts. Since rebase -p has to re-create the merges, this method is usually not suitable. Using filter-branch (as in sajib khan's answer) is the way to go, although using filter-branch is painful.
Tried that one - leads to merge conflicts :-/

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.