0

I have a git repository in which there have been a bunch of merge conflicts, especially due to CRLF vs LF issues (ugh). Anyway, I want to change a commit message on some past commit, and otherwise keep everything as-is in the code. I neither have rerere.enabled, nor do I have a historical database, nor do I want to have one. I just want to tell git-rebase to "Keep everything just the same", except for a commit comment which is pure meta-data.

Can I do this?

Related questions:

Guildenstern
  • 2,179
  • 1
  • 17
  • 39
einpoklum
  • 118,144
  • 57
  • 340
  • 684
  • 1
    So, what is different in your situation from the first one you linked to? And why does the answer to that question, including the links to a description of the rerere-train.sh script, not also answer your question? – IMSoP Sep 27 '21 at 09:25
  • @IMSoP: 1. The first one uses `-r`. Maybe I should mention that. 2. I explicitly said I want to _not_ use rerere nor train anything, just preserve what already exists. – einpoklum Sep 27 '21 at 09:34
  • 1
    I would use [git-filter-repo](https://github.com/newren/git-filter-repo) for this task. – j6t Sep 27 '21 at 09:36
  • @j6t: That sounds like it could make an answer. – einpoklum Sep 27 '21 at 09:36
  • @einpoklum Sorry, I don't follow. If you want to rebase merges, then you need "-r" (or some variation of it) regardless of whether there were conflicts; if you *don't* need to rebase merges, then there aren't any merge conflicts to worry about. And you haven't said **why** you don't want to use "rerere"; you don't have to use it ever again, but it's a tool which can do this job. The linked answer even goes into great detail about why there's no such thing as a "no-changes rebase" under the hood, because rebase has to recreate every commit even if it's *not* changed. – IMSoP Sep 27 '21 at 09:49
  • @IMSoP: I don't want to use rerere because it's not the right tool. I don't want git to user some database which may-or-may-not-have been gathered correctly, I want it to maintain everything as is and not risk changes to the code. Also, recreating commits is just fine - I want that to happen. But there aren't, nor can there be, any unresolved conflicts in this recreation when the only change I've made is to meta-data. – einpoklum Sep 27 '21 at 10:47
  • With git-filter-repo, depending on which kind of editing of the commit message you want to do, you can get away with `--replace-message `, or you have to write a full `--message-callback `. The latter requires some Python skills. – j6t Sep 27 '21 at 11:51
  • You *don't* want to use `git rebase` (with or without `-r`) here as this *could* produce the wrong result even if you did have rerere enabled and/or trained here. The reason is that rerere only applies to actual conflicts, and it's possible that someone deliberately made some sort of non-conflicting changes during merges (by running `git merge -n` and then editing and adding files). So you really *do* want a tool like filter-branch or filter-repo here. – torek Sep 27 '21 at 20:48
  • @torek: It's very strange to me that git rebase would insist on messing up the commit DAG for merely changing a commit message. – einpoklum Sep 27 '21 at 20:59
  • With `-r`, you'd have a fine *DAG* copy (without `-r`, rebase will flatten the graph). The issue isn't the copying of the commit subgraph. It's the copying of the *contents*. A merge made with `-n` and then additional changes—also known as an [*evil merge*](https://stackoverflow.com/q/1461909/1256452)—will lose these changes when the merge is re-performed without re-doing the evil step. – torek Sep 27 '21 at 21:02

1 Answers1

2

(a variation on on @j6t 's suggestion:)

You can use the commit editing feature of git-filter-repo. This tool is generally interesting for applying callback-based or analysis-based transformations on git repositories, but the specific capability you would likely use is the ability to run a given Python script on each commit:

$ cd /path/to/repository
$ git-filter-repo --commit-callback 'SCRIPT BODY HERE'

Now, when the script is run, an object named commit will be defined. This object has, among others, the fields commit.original_id holding the hash, and commit.message holding the commit message. Thus your script might be something like:

'if (commit.hash.startswith(b"0xdeadbeaf")):
    commit.message.replace(b"Hello world", b"Goodbye world")
'

You can also look at a few more examples of git-filter-repo scripts.

Caveat: Haven't tried this myself yet.

einpoklum
  • 118,144
  • 57
  • 340
  • 684