Question

I have two Git repos, foo/master and bar/master:

In foo:

code_root
->dirA
  ->dirB
    -> *some files*

In bar:

code_root
  -> *same files as above*

Now someone has made changes to *some files*... how do I get those changes merged into *same files as above*?

When I say "merged" I mean I need the history (commit messages, log hashes etc.) of the deltas to come over as well.

Was it helpful?

Solution

You can split the changes out to the subtree level, and then merge with your other branch:

# from your foo project
git subtree split --prefix=dirA/dirB/ --branch=temp-branch [--onto=<onto-sub-note1>] [<commit-sub-note2>]

onto sub-note 1: It seems like since bar project exists at all, you must have copied it at some point in time, and started this as the new library, in which case, if you want all changes made after that, you'd specify this bar commit id when the changes were brought in.

commit sub-note 2: You'd then want to specify the commit id that was used when you copied the sub-project in the first place, so that you only get the changes since then to merge into the copy of bar you already have (this will maintain the history of what you missed). Use syntax like this to include the commit id itself up to the latest: 0abc210^..

You can also use --rejoin to make a commit back into your foo project, which will make it easier to push changes later if you would like to continue development on bar from withing your foo project. The commit back into foo is kind of pointless other than to help the subtree command base it's split changes more easily in the future.

After running the split command, you'll be in a branch of foo, which only has those files. From there you can do a normal merge with your bar project or start a new project and merge bar into that (since it probably doesn't have a proper history). You may want to rebase to the diverge point or something before trying to do that merge though.

Edit: Also here's the reference for git subtree commands

OTHER TIPS

So, you are saying the files are essentially the same in both in foo & bar, just that the ones in foo are newer than those in bar:

If yes, then you can just take a diff:

diff -b /path_to/foo/dirA/dirB/ /path_to/bar/ > diff.patch

and then apply the patch onto bar:

cd bar

patch -p1 < diff.patch

Update: As per OPs updated, he's looking to maintain commit history, above won't work in that case.

Check out the git book and git magic. Depending on the exact changes, perhaps a round of history rewriting (git filter-branch and friends; or brute-force application of git rebase --interactive, straightening out each commit) can restore sanity to the mangled clone, and then allow a clean merge.

Other alternative is to export each commit as a patch (essentially run git format-patch), recover the commit data from there and reverse engineer the patches to apply. You could even use the oportunity to rewrite a cleaner/simpler history when doing this.

Clearly the viability depends on the extent of the divergence, and how many "wrongly applied" commits are at stake.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top