Marcin Zalewski
Marcin Zalewski

Reputation: 512

How to undo changes matching a pattern in multiple commits?

I am working on a project where a large chunk of code was converted from C to C++. During the conversion process, multiple instances of the restrict keyword were removed in multiple commits.

Now, I want to undo all the removals of the restrict keyword, but the problem is that the commits responsible for the removal introduced some useful changes as well. Is there a way to create a patch that will only undo the removals of the restrict keywords (throughout the whole history) but nothing else?

Upvotes: 2

Views: 61

Answers (1)

mkrieger1
mkrieger1

Reputation: 23256

  1. Find the most recent commit <id> where restrict was not yet removed.

  2. From the newest commit, where the port to C++ is completed, run

    $ git checkout -p <id>
    

    which will interactively prompt you to apply the individual changes in reverse.

  3. Reject all hunks that are unrelated to restrict by entering n, accept all hunks that are related to restrict by entering y. If you are brave and it is necessary, enter hunk-editing mode by entering e. You should be able to directly jump to hunks containing restrict by doing a search using /.

  4. If necessary, do manual cleanup afterwards.

  5. Create a new commit from the staged changes which hopefully restore all occurrances of restrict as required.

Should this become too tedious you can abort the interactive part using q, and create a commit containing the work done so far. You can always squash them to a single, clean commit later.

Alternative approach

To pretend that the restrict keywords were never removed:

  1. same as above

  2. From the newest commit, create a new branch (in order to not lose the original branch), and rebase the port to C++:

    $ git checkout -b restore-restrict
    $ git rebase -i <id>
    
  3. Mark all commits where restrict keywords were removed with edit.

  4. For each commit to be edited, restore restrict either by manually editing the files or by git checkout -p HEAD^ (similar to first approach, only on individual commits). Then,

    $ git commit --amend
    $ git rebase --continue
    

Upvotes: 1

Related Questions