Search code examples
gitgit-rebase

How to change part of commit messages in git history automatically in batch


We prefix all git commits with ticket numbers. Sometimes I need to batch rename the ticket number for a range of commits. For example, I want to rename change all JIRA-1111 occurrences in commit messages to JIRA-2222 in all commits from between origin/master and master. So this git history:

* JIRA-1111 commit message 5 (master)
* JIRA-1111 commit message 4
* JIRA-42   commit message 3
* JIRA-2222 commit message 2
* JIRA-1111 commit message 1 (origin/master)

would be changed to:

* JIRA-2222 commit message 5 (master) # <- renamed from 1111 to 2222
* JIRA-2222 commit message 4          # <- renamed from 1111 to 2222
* JIRA-42   commit message 3
* JIRA-2222 commit message 2
* JIRA-1111 commit message 1 (origin/master)

I know how to change the commit messages for individual commits using either --amend, or interactive rebase and editing each commit message manually. But my question is:

How can I modify the commit message for a range of commits in batch without manually editing each commit message?


(If you wonder why I need this: The commit dialog in IntelliJ IDEA shows the last commit message which contains the ticket number I'm working on. But sometimes (if not all files are committed), it doesn't remember the last message and shows an older one. When this older message contains a different ticket number, we often end up committing under the wrong ticket number.)


Solution

  • Running git rebase -i opens an editor where the commit messages can be changed. Git documentation states that:

    By default, Git uses whatever you’ve set as your default text editor ($VISUAL or $EDITOR) or else falls back to the vi editor to create and edit your commit and tag messages. To change that default to something else, you can use the core.editor setting

    Replacing the editor with, e.g., a sed command that changes the commit messages will do the trick:

    FROM=JIRA-1111
    TO=JIRA-2222
    export EDITOR="sed -e 's/^${FROM}/${TO}/' -e 's/^pick /reword /' -i ''"
    

    The first -e option changes the commit messages appropriately, the second -e changes the pick keyword to reword, and -i forces sed to edit the file in place without a backup copy.

    Once the EDITOR variable is exported, run git rebase for the required range of commits:

    git rebase -i origin/master master
    

    Edit: as suggested by @torek, the export EDITOR=... part can be changed to

    export GIT_SEQUENCE_EDITOR="sed -e 's/^pick /reword /' -i ''"
    export EDITOR="sed -e 's/^${FROM}/${TO}/' -i ''"