How can I split a single file from a git repository into a new repo?

I have a git repository with multiple directories and one file, MyFile.ext .

 / LargeDir1/ LargeDir2/ LargeDir3/ . . . MyFile.ext 

I would like to start a new repo using MyFile.ext in it and save the whole history related to it, but ignore everything else (all LargeDir s). How can i do this?

For directories, I have successfully used this answer , but I tried this in a single file and it does not work.

I also tried this answer , which removes everything except my file, but also leaves the whole story around.

+5
source share
3 answers

Use git fast-export .

First, you export the file history to a stream with quick import. Make sure you do this on the master branch.

 cd oldrepo git fast-export HEAD -- MyFile.ext >../myfile.fi 

Then you create a new repo and import.

 cd .. mkdir newrepo cd newrepo git init git fast-import <../myfile.fi git checkout 
+8
source

I had the same problem and I finally figured it out. I had an old old script directory - so old, they were originally controlled by RCS. A few years ago, I turned into a git repository (not knowing what I was doing), and I converted the RCS log and updated the git log. But I took the development of one of the scenarios and decided that he needed his own repo. The various solutions there (subtree and filter branch) depend on the part you split to be a directory. You can put the file in a directory and split it that way, but you won’t get a change history with it. So, here is how I found out how to extract the change history of one file and create a new repo with it:

  • Create a new repo branch [I did it at the same level as source-repo]

     git init <new-repo> 
  • Now go to the source repo and create a file that we will use later to cherry-pick the file:

     cd <source-repo> git log --reverse <target-file.ext> | \ grep ^commit | cut -d ' ' -f 2 | cut -c 1-7 | \ perl -ne 'print("pick $_")' > ../commits-to-keep.txt 
  • Create a temporary branch and push it to a new repo (then delete)

     git checkout -b tmpbranch git push ../new-repo tmpbranch git checkout master git branch -d tmpbranch 
  • Now go to your new repo and create an empty commit from which we will reload:

      cd ../<new-repo> git commit --allow-empty -m 'root commit' git rebase --onto master --root tmpbranch -i 
  • [The only manual step] In the editor that appears from the last command above, delete all the contents and paste the contents of the file that you created earlier: ../ commits-to-keep.txt

  • Now you can return to the main branch, merge, and then clear the temporary branch:

      git checkout master git merge tmpbranch git branch -d tmpbranch 

The only drawback here is that you get an extra empty root command. I found that there are ways to remove it, but for my purposes it was good enough.

0
source
  • Clone the repo.
  • Filter out all but one file.

Cloning can usually be done using git clone . This will work in a directory like git clone /path/to/the/repo . Then delete the deleted pointer back to the clone.

 git clone /path/to/the/repo git remote rm origin 

Then use git filter-branch to filter out all but one file. This is easiest to do with an index filter that deletes all files and then restores only one.

 git rm --cached -qr -- . && git reset -q $GIT_COMMIT -- YOURFILENAME 

The index filter works by checking every single commit with all changes made. You execute this command and then confirm it. First, it removes all changes from the stage, then restores this single file in its state in this commit. $GIT_COMMIT is a rewrite of a commit. YOURFILENAME is the file you want to save.

If you do all branches and tags using --all , add a tag filter that ensures that the tags are overwritten. It is as simple as --tag-name-filter cat . It will not change the content of tags, but it will ensure that they are moved to overwritten commits.

Finally, you will want --prune-empty delete all empty entries that are not associated with this file. There will be many of them.

All together here.

 git filter-branch \ --index-filter 'git rm --cached -qr -- . && git reset -q $GIT_COMMIT -- YOURFILENAME' \ --tag-name-filter cat --prune-empty \ -- --all 
0
source

All Articles