gitmergegit-rewrite-history

Restore git history from split repositories


When our project started we where not too familiar with git, and at some point decided to re-start the repository. This meant that we imported all files into the new repository, losing all history.

Today I'd like to know if there would be a way to re-combine these 2 repositories. Basically the history of a file in the "old-repo" should be added to the history of that file in "new-repo".

Does anyone have an idea how to get started with that?


Solution

  • You can do this pretty easily by fetching the commits from the old repository then using git rebase to replay the history of the new repository on top of the old one.

    First, fetch the commits from the old repository.

    git remote add old_repo <url-for-old-repo> # Add old repository as a remote
    git fetch old_repo # Fetch commits from old repo
    

    Next, find the commit in the old repository that matches the root commit of your new repository. You might find git log helpful for this purpose. You can verify that the contents of the commits match by running git diff <commit in old repo> <commit in new repo> and checking to make sure there is no output from that command. If there is output from that command, either keep looking until you find a commit in the old repository that doesn't produce that output, or make one (by checking out a similar commit in the old repository, making the necessary changes to the working directory, and committing).

    Once you've found this commit, find the immediate child commit of the root commit in the new repository. This should be the first commit in the new repo that introduces new changes that aren't in the old repository. You will use this commit, along with the commit you found in the old repository earlier, in the following command.

    Run:

    git checkout master
    git rebase --onto <commit from old repo> <commit from new repo> --preserve-merges
    

    This should replay the commits from the new repository onto the old repo. Assuming the output of the earlier git diff was blank as I suggested, you should encounter no merge conflicts. Once the command completes, the master branch should include history from the old repository.

    Since this procedure involved changing the history of the repository, you'll need to use the --force option next time you push the master branch to the remote repository.

    If you have any other branches besides master, you will need to follow a similar procedure as the one above to move them over to the new repository:

    git checkout branchname
    git rebase --onto <base on new master branch> <first commit in branch> --preserve-merges
    

    Tags probably should not be moved, as they are meant to be immutable. If you really want to move a tag to the new history, see How can I move a tag on a git branch to a different commit?.