fabsenet
fabsenet

Reputation: 374

Merging/cherry-picking between orphan branches

I managed to get a git repo with an orphan branch. To reproduce it, you can do it like this ("subl code.txt" means editing the code file):

C:\g\orphanrepomerge> git init
C:\g\orphanrepomerge> subl code.txt
C:\g\orphanrepomerge> git add -A
C:\g\orphanrepomerge> git commit -m "added starting point (best fit for parent later)"
C:\g\orphanrepomerge> subl code.txt
C:\g\orphanrepomerge> git commit -am "simulate some dev in first branch"
C:\g\orphanrepomerge> subl code.txt
C:\g\orphanrepomerge> git commit -am "simulate some more dev in first branch"
C:\g\orphanrepomerge> git checkout --orphan second
C:\g\orphanrepomerge> git rm -rf .
C:\g\orphanrepomerge> md ./sub/folder | cd
C:\g\orphanrepomerge\sub\folder> subl code.txt
C:\g\orphanrepomerge\sub\folder> git add -A
C:\g\orphanrepomerge\sub\folder> git commit -m "initial copy of first branch"
C:\g\orphanrepomerge\sub\folder> subl code.txt
C:\g\orphanrepomerge\sub\folder> git commit -am "some dev originally in second"

So this is:

*...the copy is done in a subfolder!

the sample looks like this in git:

C:\g\orphanrepomerge> git log --graph master...second
* commit 0a3c91a4e72c331514fd68618febcf721d161a82
| Author: Fabian Wetzel
|
|     some dev originally in second
|
* commit f9f4718294258daee50bd89859e0626ddb0fad40
  Author: Fabian Wetzel

      initial copy of first branch

* commit ae53574452997a4be674d2d33e3fe1a3cb2bb3e6
| Author: Fabian Wetzel
|
|     simulate some more dev in first branch
|
* commit c32f6417cf818f11844a9ffb569232d65b2d5229
| Author: Fabian Wetzel
|
|     simulate some dev in first branch
|
* commit 1d8aace9312b5c51848c9fdadeac8cac53a4e7ad
  Author: Fabian Wetzel

      added starting point (best fit for parent later)

what I would like to do is cherry picking in both directions and it somehow works but the desired outcome is disappointing:

C:\g\orphanrepomerge> git checkout second
C:\g\orphanrepomerge> git cherry-pick c32f6417cf818f11844a9ffb569232d65b2d5229
error: could not apply c32f641... simulate some dev in first branch
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' or 'git rm <paths>'
hint: and commit the result with 'git commit'
C:\g\orphanrepomerge> dir -Recurse


    Directory: C:\g\orphanrepomerge


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----        29.06.2015     13:54            sub
-a---        29.06.2015     14:29         25 code.txt


    Directory: C:\g\orphanrepomerge\sub\folder


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---        29.06.2015     13:55         30 code.txt

git added the original code.txt back to the root folder instead of actually merging the changes into the code.txt in the subfolder. I can understand why it does this but nevertheless it is wrong for me.

I somehow need to introduce a parent to the first commit in [second] to retroactively transform the orphan branch into a real branch, but I do not know how?!

Upvotes: 2

Views: 1190

Answers (1)

Alex Wolf
Alex Wolf

Reputation: 20128

The by far easiest approach would be the usage of a graft point.

Explanation

So, what's a graft point? Using a graft point you can fake the ancestry of commits. This can be used for a variety of purposes, for example to remove the history of a repository prior to a specific commit.

How do we use them? You can define graft points by editing the .git/info/grafts file. The syntax is very straightforward, the first hash is the commit which parents you want to define and all following hashes will be it's parents. It's important that you use full hashes, otherwise the graft point won't work.

Origin: Graft points were mainly introduced to smooth the transition from other VCS to git, where merges didn't contain information about the merged in branch (looking at you, older SVN versions).

Action

In your case you can use a graft point to connect the initial commit of your orphan branch with a parent of your choice. Here is an abstract example:

<initial orphan branch commit hash> <parent commit hash>

Using the hashes from your question this would look like this:

f9f4718294258daee50bd89859e0626ddb0fad40 1d8aace9312b5c51848c9fdadeac8cac53a4e7ad

Make it permanent

If you want to make the change permanent, instead of relying on the graft point, you can use git filter-branch -- --all. From the filter-branch documentation:

This command honors .git/info/grafts file and refs in the refs/replace/ namespace. If you have any grafts or replacement refs defined, running this command will make them permanent.

The -- --all appendix just includes all references so you don't have to specify the references manually.

IMPORTANT: This will make your orphan-branch history incompatible with any pushed history of the branch. Be sure to understand the implications of this.

Upvotes: 1

Related Questions