Search code examples
git

How to preserve newer commits timestamps when squashing older ones?


Let's say I have this series of commits:

A -> B -> C -> D -> E

With A being the oldest one and E the newest one. I want to squash A and B, but that would need to recommit everything and then all the timestamps of also C, D and E would be rewritten by the current time. How to squash A and B without touching C, D and E timestamp?


Solution

  • Not exactly.

    First of all, just a tip: when you ask something about git, draw the arrows from the child commit to its parent (or parents, if it's a merge), as it is how git works. I'm also including the parent of A:

    parent <- A <- B <- C <- D
    

    What you can do here is an interactive rebase:

    1. run:
    git rebase -i <hash of the parent of A>
    

    It will open a text editor (set on EDITOR environment variable, typically vim or nano, but you can change to vscode, emacs, whatever you want). It will show something like this (the hashes will be different):

    pick f6e81ab A
    pick 282939d B
    pick acb8411 C
    pick bb08045 D
    
    1. Change the pick in B to squash (in the bottom of the opened file there's an explanation about this, I strongly recommend you to read to know what you're doing, and to know the other options). Now, save and close this file.

    2. Now, git will open the editor again and will ask you to type the new commit message. You can keep its suggestion, or write a new one. I changed it to squashed. Save and close this file.

    3. The new commit history is the following:

      parent <- squashed <- C <- D

    If you run git log, you'll see that original timestamp is kept. But there's a detail about it. If you run git log --pretty=fuller, you'll see that there's an AuthorDate and a CommitDate. By default, they are the same for new commits, but when you're cherry-picking (with git cherry-pick or git rebase), the AuthorDate is kept, but CommitDate is updated with the timestamp of the rebase. This way git tracks both commit creations but, by default, it shows the original commit timestamp.

    I suggest you to take a look at https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History, I hope it helps you!