Reputation: 30195
Normally, when you rebase another author's commit with git, git adds a Commit:
header with your name and email address. I have a situation where I don't want this to happen. I want the rebased commit to end up with the same SHA1 as it would have if the original author had done the equivalent rebase him/herself. Is this possible?
Upvotes: 38
Views: 15722
Reputation: 10086
You can preserve the original committer information when rebasing by using Interactive Rebase with instructionFormat
.
In your config file .gitconfig
, set this:
[rebase]
instructionFormat = %s%nexec GIT_COMMITTER_DATE=\"%cI\" GIT_COMMITTER_NAME=\"%cN\" GIT_COMMITTER_EMAIL=\"%cE\" git commit --amend --no-edit%n
[alias]
rb = rebase --interactive
Explanation:
rebase.instructionFormat
- a configuration for interactive rebase to give a custom instruction in the to-do file.%s
- the subject of the commit message (the default value of instructionFormat
).%n
- a line break; can double-up (%n%n
) to add a blank line for readability.exec
- instructs git rebase
to execute the rest of the line as a shell command.
x
(useful if you're using abbreviateCommands = true
).GIT_COMMITTER_DATE=\"%cI\"
- get the commit date in strict ISO 8601 format.GIT_COMMITTER_NAME=\"%cN\"
- get the name of the committer.GIT_COMMITTER_EMAIL=\"%cE\"
- get the email address of the committer.
.mailmap
file if any found. To disregard the file, use %cn
and %ce
instead.git commit --amend --no-edit
- amend the commit with the above three environment variables, without opening an editor for the commit message.%n
- a line break (to add a blank line for readability in the to-do file; can repeat for more blank lines).alias.rb
- for convenience, an alias is defined to quickly call interactive rebase with git rb [new base]
To use it, be sure you're checked out on the branch you wish to rebase, then run the command git rb [new base]
where [new base]
is the branch or commit-ish on top of which you want to rebase the checked-out branch. (Example: git rb main
)
An editor will open with the interactive rebase to-do. Simply close the editor. If you know what you're doing and want to edit it, note the following:
exec
line below each commit.exec
line as well.exec
lines.Note 1: This is only possible via Interactive Rebase, since the regular rebase doesn't support instructionFormat
. You have to bear with the editor opening for no good reason, and just close it (if you have no plans to edit it).
Note 2: Even if you preserve all of the committer information, you may still not get the same SHA1 because the SHA1 is dependent on the parent commit. When the parent changes, the SHA1 changes too. However, if the parent didn't change, you will always get the same SHA1. So this is a deterministic operation.
Note 3: For Windows, you need to use Git Bash or WSL2. This won't work in Command Prompt and PowerShell since DOS doesn't support inline environment variables. (I'm not sure if multiple exec
lines with SET
commands can work. YMMV but it's so much easier to just use Git Bash or WSL2 than trying to make it work in DOS.)
Upvotes: 8
Reputation: 231113
All git commits have a committer field internally; you can see this by typing git cat-file commit HEAD
immediately after committing something. As such you cannot erase it; you can only make it equal to the author field.
That said, you might be seeing git porcelain showing the commit field because the datestamp has changed. It's not possible to predict what someone else would get for the commit datestamp if they were rebasing, obviously, but you can alter it to be equal to the original commit timestamp, at least.
git filter-branch --commit-filter 'export GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"; export GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"; export GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"; git commit-tree "$@"' -- basecommit..HEAD
This will alter commits after basecommit, in the history of HEAD (including HEAD, not including basecommit), making their committer field identical to the author field in all respects. If the original author agrees to do the same thing, then you can get a consistent SHA1.
Upvotes: 34
Reputation: 74750
Try setting the environment variable GIT_COMMITTER_NAME
and GIT_COMMITTER_EMAIL
when rebasing (maybe also GIT_COMMITTER_DATE
, too). (This will effect all commits created now, though.)
Upvotes: 9