Search code examples
gitgit-filter-branch

How to add a new initial version of a tracked file in a separate commit?


NOTE: I have solved my question before publishing it. I have since written a guide for myself. As the question and the answer were already written and I didn't find any post on SO dealing with this specific issue I thought publishing it and sharing the solution would not cost much and maybe help some people :)

Question

The context I have is that I am saving configuration files on my system in a git repo. Some time ago in the repo I added someconf.conf file, and since then I have modified it in multiple commits. In the future I realize this file was automatically generated by the system at first and then I started modifying it. Thus the first commit comporting someconf.conf (let's call it A1) will have the {initial system config} + {modif1} and the subsequent commits will have {modif N} (let's call them AN) each.

So now I want to be able to create a commit B1 that would be the new one to originally add someconf.conf in my repo and only include {initial system config} then the A1 would be transformed into A1' that would now only include {modif1} compared to B1 and thus the new history would be ...,B1,A1',...,A2',...A3'


Solution

  • I managed to do it like so

    # Add a new initial version of a file in the past
    
    # <file> Path of file in git worktree
    # <file_b1> New initial version of file
    # <file_a1> Original initial version of file
    
    # Keep <file_b1> in an untracked location so that it won't be overwritten by git
    cp <file_b1> <file>
    git add <file>
    git commit -m 'b1' # this is <commit_b1>
    # Now keep a safe untracked copy of <file_a1> with the following
    git checkout <commit_a1>
    git cp <file> <file_a1>
    # Resume Operations
    git ckeckout master # or your other branch
    git rebase -i HEAD~<count_to_commit_a1>
    -> pick <commit_b1> # Pick this line from the bottom and add it to the top before the next line
    -> pick <commit_a1>
    # Resolve merge conflict of inserting <commit_b1> by forcing state b1
    cp <file_b1> <file>
    git add <file>
    git rebase --continue
    # Resolve merge conflict of adding <commit_a1> after <commit_b1> by forcing state a1
    cp <file_a1> <file>
    git add <file>
    git rebase --continue
    
    # vim: ft=sh