RockyMountainHigh
RockyMountainHigh

Reputation: 3021

Copy folder (and everyhting in it) from one git repo to another

I have found a couple of examples [here's one] of how to move a folder from one git repo to another. However, it seems to be destructive to the original repo (if I'm reading it correctly). What I need is to just copy a folder from one repo to another, with history, to another. something like the following:

Repo A:

/myApp/
    /deploy/...
    /src/...
    /test/...
    /bin/...

Repo B:

/myDeploymentCode/
    /projects/
      /myWebService/...
      /myWebsite/...

After the copy I would like it to look like this:

Repo A:

/myApp/
    /deploy/...
    /src/...
    /test/...
    /bin/...

Repo B:

/myDeploymentCode/
    /projects/
      /myWebService/...
      /myWebsite/...
      /myApp/... << full copy of the deploy folder from myApp

I will likely get rid of the original deploy folder but want to keep it around until I know we are in the clear.

I'm guessing this is possible and I'm just blind. If it isn't, I could just manually move the files over. Losing all of the history but capturing the current state. But that is less than ideal.

Upvotes: 2

Views: 98

Answers (1)

kostix
kostix

Reputation: 55563

You can do that via the git subtree command (built-in since some time; available in contrib earlier):

  1. Use git subtree split -P myApp/deploy in repo "A" to create a synthetic history containing only the contents of that "myApp/deploy" folder.
  2. Fetch the resulting commit into repo "B".
  3. Use git subtree add -P myDeploymentCode/projects/myApp ... to "plant" that history using a merge commit.

The only problem with the result is that all the commits in that extracted history line—except the one which merged it with the new code base—will not record the fact the files in them are under the "myDeploymentCode/projects/myApp" prefix so commands which trace the history of a pathname or pathname prefix, like

git log -- myDeploymentCode/projects/myApp/foo.txt

might fail to advance back past that merge commit which "planted" the extracted history into the new code base (in this example, the file "foo.txt" will be there in those commits but located at the top level rather than under that prefix).

If you're OK with this then just do it. Otherrwise you might need to first run a git filter-branch encantation on the extracted history to rewrite all commits forming it to have their files under that new prospective prefix the history will be planted at.

One way to do that is

git filter-branch -f --tree-filter \
       'test -e myDeploymentCode/projects/myApp || mkdir -p myDeploymentCode/projects/myApp
       find . -mindepth 1 -maxdepth 1 \
           -type d -path ./myDeploymentCode -prune -o -print \
       | xargs -n 30 mv -t ./myDeploymentCode/projects/myApp' temp

(Assuming you've created a branch named "temp" out of the SHA-1 name of the commit git subtree split told you at step (1).)

Please see this for the same example accompanied by an in-depth explanation of how it works.


It might worth noting that the history git subtree split produces is synthetic, that is, the SHA-1 names of the commits comprising it do not exist in the source repository. That's obvious to those familiar with the Git internals—while blobs are reused by the extracted history, tree and commit objects are not—but be warned just in case.

Upvotes: 1

Related Questions