big_gie
big_gie

Reputation: 3009

Create new git repo from already existing repo's subdirectory

I want to create a separate repo from an already existing repo's subfolder.

Detach (move) subdirectory into separate Git repository shows exactly that. BUT, I can't get a clean repo with it. I end up with two problems with the new repo:

  1. The history seems duplicated;
  2. I can't keep the branches history.

Here is what I did:

$ git clone ssh://.../repo.git
$ cd repo
$ git filter-branch --subdirectory-filter subdirectory HEAD -- --all
$ git reset --hard
$ git gc --aggressive
$ git prune

After this, it seems I have the original history of the repo AND the new history. I type "git log --all --graph" (or gitk --all) I see, as the first commit, the initial commit of the first repo. The graph then shows the original repo's full history until the last commit. Then, I have a SECOND history on top of the first one showing the history of only the subfolder I want. But in that part of the history I only have "master" and no branches/merges.

"git log", gitk or gitg all show the "flatten" history only: they don't show the initial repo's history before the the subfolder's flatten history.

I tried using just the "filter-branch" command, cloning the resulting repo (with --no-hardlinks), using:

$ git filter-branch --subdirectory-filter subdirectory -- --all

instead of:

$ git filter-branch --subdirectory-filter subdirectory HEAD -- --all

But with the same result.

Am I am doing something wrong or git is broken? I'm really out of ideas... Using git 1.7.6. Thanks.

EDIT: I think the problem might come from the fact that merge commits are ignored by filter-branch, thus giving a flat history with no branches or merges...

Upvotes: 12

Views: 5636

Answers (4)

Ken Prince
Ken Prince

Reputation: 1496

Github has a straight forward method:

https://help.github.com/articles/splitting-a-subpath-out-into-a-new-repository

  1. Clone the full repo: git clone https://github.com/USERNAME/REPOSITORY-NAME
  2. Go to the root of the repo: cd REPOSITORY-NAME
  3. Filter out subfolder A/B/C: git filter-repo --path A/B/C/
    • install git-filter-repo: pip install git-filter-repo (or any other method)
    • Provide the path structure relative to the root
    • Use forward slashes, even on Windows (the path refers to a git object, not to a location on the file system)

Upvotes: 4

saltycrane
saltycrane

Reputation: 6661

I think you need to remove your remotes. e.g.

git remote rm origin

I thought the same thing you did when I ran git log --all and gitk --all and saw all the commits. Then I realized the extra commits were from the remote.

Upvotes: 1

ebneter
ebneter

Reputation: 21475

You have two problems here:

(1) As Kevin Ballard points out, you need to delete the refs/original directory in your .git directory to get rid of the spurious log entries; IIRC this is mentioned in the question you referred to.

(2) You have to convert the branches one at a time. As far as I know, this isn't mentioned anywhere, but it's pretty easy to discover empirically. A script to do this would look something like this:

for branch in $(git for-each-ref --format='%(refname:short)' refs/remotes/origin | grep -v HEAD); do
  git checkout -b $(basename $branch) $branch
  git filter-branch -f --subdirectory-filter subdirectory HEAD -- --all
done

Note that you need the -f or else something like --original $(basename $branch)-original to force git to reuse or rename the namespace where it stores the original refs. Also note that you may see messages like "Found nothing to rewrite" if subdirectory does not exist on a particular branch -- you will probably want to delete those branches from your new repository. (Or delete them before running the script.)

Upvotes: 4

Lily Ballard
Lily Ballard

Reputation: 185653

git filter-branch saves all the original refs into their own namespace (under original/). It sounds like your git log --all is showing those refs too. You should instead inspect all the refs you care about, and if they look good, then you can throw away the original/ namespace.

Upvotes: 0

Related Questions