Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

copy author and date from other commit, but _not_ the message

In this QA we learn how to use git commit -c or git commit -C to copy the commit metadata from a different commit. This includes author, date and message.

What I would like to do is copy the author and date, but not the message.

Background / motivation

I want to use interactive rebase to improve the commit history from another developer (with their consent), by splitting up existing commits. But I want to keep the commit author for credit, and the date too.

Typically, I will use this method to split commits:

  • git rebase -ir SOME_PARENT_COMMIT.
  • put break after those commits I want to split.
  • When it stops, I run git reset HEAD^.
  • Now I stage with git add -p and make multiple new commits, which have me as the author.

I would now want to alter these new commits to set author and date back to the original commit that was split.

Known solutions

I know I can do this with git commit --amend -c, but this will also change the commit message, and I have to manually restore it with the editor.

Another option is to use interactive rebase to pick the origional commit, then revert it, then apply the new commit, then squash them all together, while editing the message. Squashing always leaves the date and author from the first commit.

Both of these solutions are clumsy, and not nice as an everyday repeatable operation. And they are not something I would want to teach to other team members.

like image 214
donquixote Avatar asked Oct 26 '25 12:10

donquixote


2 Answers

Here are some solutions that work but are not ideal. They might be useful until somebody provides a better solution.

Quick but incomplete

The task gets a lot simpler if you forget about the date, and only care about the author.

In this case, you can do this:

  • Do your git rebase -ir START_REF to do all the modifications and splits. Now many of the commits will have you as the author.
  • Run git rebase -ir START_REF again.
  • In the editor, after each commit, insert a line with exec git commit --amend --author=... with the original commit author.

After this second rebase, all the commits get the original author, but they have a new date and message.

I remember for the second rebase there is actually a more automatic way (filter-branch). But I find the manual way easy enough that I don't bother.

Complete but unpleasant

This requires a lot of extra steps, but these extra steps are easily repeatable and you can separate them from the main splitting task.

Starting point

A branch mybranch with e.g. 10 commits from another developer, and you agreed with that develper that you want to split all of them.

Step 1

Run git rebase -ir START_REF. (for START_REF you insert the starting commit, branch or tag you want to rebase onto)

In the editor, paste this line after each commit: exec git commit --allow-empty -c HEAD. Save and exit the editor, to start the rebase.

Each time the commit message editor opens, insert "EMPTY: " before the commit message, or anything that helps to distinguish these new commits.

After the rebase, in the new history, every original commit will be followed by one "EMPTY: ..." commit with the same date and author.

(After the rebase is finished, run git diff mybranch@{1} to verify that the code is still the same. You can run this after every rebase.)

Step 2

Run git rebase -ir START_REF again.

In the editor, swap every two lines, so that the EMPTY: ... commit appears before the respective original commit. Let the rebase run through.

Step 3

Run git rebase -ir START_REF again.

In the editor, put a break or b after each commit you want to split.

Each time it stops, run git reset HEAD^, then do your new commits and run git rebase --continue.

Your git history should now have a bunch of "EMPTY: ..." commits each followed by one or more rewritten commits. The "EMPTY: ..." commits have the original author and date, while the rewritten commits have not.

Step 4

Run git rebase -ir START_REF again.

In the editor, duplicate the "EMPTY: ..." commits so that one such commit appears before every rewritten commit. Then replace the "pick" with "squash" (or "s") on the rewritten commits. Save and close to let the rebase run.

When the editor opens to edit the commit message (from the squash), delete the first message (from the old commit) and keep the second message (from the new commit).

Notes

The -ir parameter for rebase is a combination of --interactive and --rebase-merges. The second part is not technically needed in this specific scenario, but I find it good practice to always use it.

like image 106
donquixote Avatar answered Oct 29 '25 01:10

donquixote


Extract information from that commit using git log, and set these env vars:

export GIT_AUTHOR_DATE=$(git log -1 --pretty=%ad <commit>)
export GIT_AUTHOR_NAME=$(git log -1 --pretty=%an <commit>)
export GIT_AUTHOR_EMAIL=$(git log -1 --pretty=%ae <commit>)
# will reuse authorship information:
git commit

git commit also has --author and --date options, and again, you can get the values via git log:

author=$(git log -1 --pretty="%an <%ae>" <commit>)
date=$(git log -1 --pretty=%ad <commit>)
git commit --author="$author" --date="$date"
like image 21
LeGEC Avatar answered Oct 29 '25 01:10

LeGEC