Suppose I have a repository with a folder structure like this:
Base
|-dir1
|-dir2
| |-subdir1
| |-subdir2
| |-subdir3
|-dir3
I perform 'git filter-repo' on the 'dir-2' directory. Now the folder structure I have is:
Base
|-dir2
| |-subdir1
| |-subdir2
| |-subdir3
After making some changes to files present in 'dir2', I want to merge it back to the original repo from where it was filtered out and have the structure back again like this:
Base
|-dir1
|-dir2 (updated with changes)
| |-subdir1
| |-subdir2
| |-subdir3
|-dir3
How do I do this while preserving history?
There is a general answer to this question—that is, how do I do _____ while preserving history?—in Git, for anything that fills this blank, and that is: History, in Git, is commits. The commits are the history. That is all the history there is. If you have all of the commits, you have all of the history.
Hence the answer to your particular question, about merging, is simply: do the merge and make sure the result is what you like. New commits just add to the existing commits, i.e., just add more history. The old history is all still there.
The subtlety here is that how you see history depends on where you stand. If you run
git log
from the point just before the merge, the history you will see is the history you saw before. But if you rungit log
from any point at or past the merge, the history you will see may be different. Though this analogy is suspect at best, think of this as viewing a field full of crops from up close, then trying to view that same field with a large city in between you and the field full of crops. The field has not changed, you just cannot see it now because of all the tall buildings in the way, blocking your view.When viewing history in Git, if you use
git log --follow
orgit diff --find-renames
, Git will attempt to detect renamed files. That is, we have two commits, and each commit represents a snapshot of all the files that Git knew about, at the time you (or whoever) made the commit. We place an older snapshot L on the left, and a newer snapshot R on the right, and ask Git: What changed between L and R?Perhaps, in L, there was a file named
O
, which no longer exists in R. But in R, there is a file namedN
, which does not exist in L. If the rename detector is turned on, Git will attempt to deduce whetherO
andN
represent the same file. (This gets into the metaphysics of identity as represented by the Grandfather's Axe or Ship of Theseus question.) If Git decides thatO
andN
are the same file, Git will claim thatO
was renamed to becomeN
, and show you the differences, if any, between those two files' contents. Otherwise, Git will claim thatO
was deleted andN
was created.This, again, is all that you can get in Git. It's important to know when Git will decide that a file is renamed, vs one file being deleted with another one being created, but it's also important to realize that these represent the same thing. Moreover, you can turn Git's rename detector on or off, and you can fine-tune it to some extent. There are some pitfalls around merge commits here and at present there is no simple way to work around them.
That said, as far as preserving history goes, just remember: the commits are the history. If you have all the commits, you have all the history.