Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reorder git commit history by date

I have merged 3 different git repos into one now my history looks something like this:

A1-A2-A3-B1-B2-B3-C1-C2-C3

Now i want to re-order all these commits by date. So finally it may be something like C1-A1-A2-B1-C2-... you get the idea

I am ok if I loose all the original SHA commit ids. And of course I cannot do the reordering by hand so I need some script or some ideas how to approach this.

like image 333
AdrianS Avatar asked Dec 02 '14 08:12

AdrianS


1 Answers

This is just an idea, I did not test it for this scenario but I used it (in a different way) to join two Git repositories and keep the original commit dates.

If the history has branches and merges I think it's impossible to re-order them and keep the structure, even manual. The best you can get is a linear history.

Save the commit hashes and the timestamps (%ct = commit date, %at = author date) into a file, sort them by author date:

$ git log --pretty='%H %at %ct' --author-date-order --reverse > /tmp/hashlist

If the order provided by the command above does not satisfy you then force the order by sorting the output using its second field (the author date):

$ git log --pretty='%H %at %ct' | sort -k 2 > /tmp/hashlist

Create a new repository to hold the history ordered by author date. Create an initial commit setting the committer date in the past (before the oldest commit in your repository):

$ GIT_COMMITTER_DATE='2010-01-01 12:00:00' GIT_AUTHOR_DATE='2010-01-01 12:00:00' git commit --allow-empty

Put your own date into the command above.

Add the old repository as a remote into the new one, fetch all its commits. DO NOT set the master branch of the new repo to track the one of the old repo.

Create a script that will cherry pick the provided commit and apply it on top of the current branch, keeping the original author date and commit date:

$ echo 'GIT_AUTHOR_DATE=@$2 GIT_COMMITTER_DATE=@$3 git cherry-pick $1' > /tmp/pick
$ chmod +x /tmp/pick

If you don't want to keep either the original author date or the committer date (or both) then just remove the corresponding assignment from the above command line.

Use the new script with xargs to pick each commit in the selected order and commit it on top of your new master branch.

$ cat /tmp/hashlist | xargs -n 3 /tmp/pick

If everything went well then remove the temporary files created during the process.

$ rm /tmp/hashlist
$ rm /tmp/pick

Remarks:

  • You will get a linear history. The original branches and merges won't be re-created into the new history timeline.
  • The unmerged branches will not be copied at all. You can use git rebase to copy and attach them to the new commits.
  • Even if your repo does not have branches, there is still a high probability to get conflicts on cherry picks; it depends a lot of the changes introduced by the commits in the new order.
  • If it doesn't work you can always remove the new repository and start over (or quit trying); the old repository is not changed.
like image 77
axiac Avatar answered Oct 08 '22 01:10

axiac