1

Let's say I have Repo A, which consists of the following structure:

Repo A:

├── content/
│   └── themes/
│       ├── myproject/
│       └── otherproject/
└── otherstuff/

myproject/ doesn't rely on otherproject/ or otherstuff/, so I used git filter-branch to set up in Repo B with the following structure:

Repo B:

└── myproject/

I've made some commits to Repo B, but now, I would like to merge Repo B's myproject/ into Repo A's content/themes/myproject/, keeping Repo A's history, as well bringing over the history and commit messages I made into Repo B since I branched off

Is there a way for me to achieve this?

user3183717
  • 4,427
  • 6
  • 20
  • 42
  • Does this answer your question? [Merge two Git repositories without breaking file history](https://stackoverflow.com/questions/13040958/merge-two-git-repositories-without-breaking-file-history) – ThomasW Feb 01 '22 at 04:08

1 Answers1

1

edit: oops. I read the question exactly backwards, my apologies. You're trying to bring the sliced myproject history from repo A, plus any later additions, back in to repo B, not the other way around.

Fetch the repoB history back into your repoA repository as-is. Find the tips you sliced originally and the commits you sliced them from, checking tree id's will do it if you can't eyeball it from commit messages or other records. Graft those they-were-tips-when-you-sliced-them commits onto the commits they were sliced from, then merging the current tips with the subtree option git merge -Xsubtree repoB/branchnamehere will work normally.

So to find the oldest commit that has any particular set of content at content/themes/myproject, and the content id,

git log --pretty='%H:content/themes/myproject %H' --branches --tags \
        -- content/themes/myproject \
| git cat-file --batch-check='%(rest) %(objectname)'

will list the id of all the commits that touched that directory and the id of the content each committed there. After fetching repoB's current history you can list each commit and its committed tree id more simply,

git log repoB/branch --pretty=%H\ %T

and match up tree id's from there.

git replace --graft repoBcommit-with-tree-T repoAcommit-with-that-tree-too

and now the repo B history since that commit will appear locally to have branched off the repoA history there (but taken only that subdirectory). Then

git merge -Xsubtree repoBbranch-with-that-commit

and you can run an ancestry-only git filter-branch -- --all first to bake in the grafts either before or after that merge so the results are easier to understand when fetched elsewhere.

jthill
  • 55,082
  • 5
  • 77
  • 137
  • Appreciate the response, this sounds in-line with what I'm trying to achieve. Will this work with my subdirectory structure? Could you be more specific about which options to use with `filter-branch`? I'm pretty new to the concept of `filter-branch` and think I am probably not fully understanding it conceptually – user3183717 Jan 31 '22 at 23:54
  • If you already used filter-branch to split off that subdirectory, you already know how to do that part. The only other part is, filter-branch will also bake in any local ancestry rewrites.done by grafts, see git replace --graft`. Find the commit currently in repo A whose `myproject` should be grafted onto an existing `myproject` commit in repo B, split `myproject` off to a new history in any handy repo, just make a scratch clone is easy and safe, push that split history into your repo B, graft that commit, bake it in with (a no-args) filter-branch. – jthill Feb 01 '22 at 00:02