Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Moving part of a git repository’s history into another repository

There are lots of posts on here about moving a folder out of one repository into a new repository using git filter-branch; what I need to do is move a single file into a new repository.

I’ve already created the new repository, and added the old one from the filesystem as a ‘remote,’ and created a new “root commit” (just adding a README for the new single-file project.) Now I need to transplant the commits pertaining to this particular file onto that new root-commit.

(I should mention that at no point was this file modified in the same commit as any other files; I suspect that may make this task slightly easier.)

like image 965
ELLIOTTCABLE Avatar asked Feb 21 '11 01:02

ELLIOTTCABLE


1 Answers

This is based on an example in the filter-branch manpage:

git filter-branch --index-filter 'git ls-files -s | grep $'\t'<file-to-keep>$ | \
    GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info && \
    mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE' --prune-empty -- --all

The index filter prints the current contents of the index using git ls-files -s, greps out only the file to keep (that grep is fairly obsessive - the fields are tab-delimited, with the filename being the last one), then creates a new index using that information, and moves it on top of the old one.

The --prune-empty option causes filter-branch to remove any commits which now do nothing (i.e. they only touched other files), and the -- --all tells it to rewrite all refs.

As always with filter-branch, it's best to do this in a fresh clone, so if you screw anything up really badly you're safe, even though filter-branch does keep backups in refs/originals. You might also want to read the checklist for shrinking a repository in the manpage; the upshot is that once you're done, the best way to actually get rid of all the stuff you no longer need is to simply clone the filtered repository.

This will actually work even if the file was modified in the same commits as other files, though I suppose you could try to be sneaky and take advantage of that fact by simply generating patches for all commits which did touch that file, then going and constructing a new repository by applying those patches... but why bother?

(Side note: it's way easier to remove a single file than to keep a single file. All you have to do in that case is use git rm --cached --ignore-unmatch <filename> for an index filter.)

like image 97
Cascabel Avatar answered Oct 17 '22 15:10

Cascabel