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.