For importing the old snapshots, you find some of the tools in Git's contrib/fast-import directory useful. Or, if you already have each old snapshot in a directory, you might do something like this:
# Assumes the v* glob will sort in the right order
# (i.e. zero padded, fixed width numeric fields)
# For v1, v2, v10, v11, ... you might try:
# v{1..23} (1 through 23)
# v?{,?} (v+one character, then v+two characters)
# v?{,?{,?}} (v+{one,two,three} characters)
# $(ls -v v*) (GNU ls has "version sorting")
# Or, just list them directly: ``for d in foo bar baz quux; do''
(git init import)
for d in v*; do
if mv import/.git "$d/"; then
(cd "$d" && git add --all && git commit -m"pre-Git snapshot $d")
mv "$d/.git" import/
fi
done
(cd import && git checkout HEAD -- .)
Then fetch the old history into your working repository:
cd work && git fetch ../import master:old-history
Once you have both the old history and your Git-based history in the same repository, you have a couple of options for the prepend operation: grafts and replacements.
Grafts are a per-repository mechanism to (possibly temporarily) edit the parentage of various existing commits. Grafts are controlled by the $GIT_DIR/info/grafts
file (described under “info/grafts” of the gitrepository-layout manpage).
INITIAL_SHA1=$(git rev-list --reverse master | head -1)
TIP_OF_OLD_HISTORY_SHA1=$(git rev-parse old-history)
echo $INITIAL_SHA1 $TIP_OF_OLD_HISTORY_SHA1 >> .git/info/grafts
With the graft in place (the original initial commit did not have any parents, the graft gave it one parent), you can use all the normal Git tools to search through and view the extended history (e.g. git log
should now show you the old history after your commits).
The main problem with grafts is that they are limited to your repository. But, if you decide that they should be a permanent part of the history, you can use git filter-branch to make them so (make a tar/zip backup of your .git
dir first; git filter-branch will save original refs, but sometime it is just easier to use a plain backup).
git filter-branch --tag-name-filter cat -- --all
rm .git/info/grafts
The replacement mechanism is newer (Git 1.6.5+), but they can be disabled on a per-command basis (git --no-replace-objects …
) and they can pushed for easier sharing. Replacement works on individual objects (blobs, trees, commits, or annotated tags), so the mechanism is also more general. The replace mechanism is documented in the git replace manpage. Due to the generality, the “prepending” setup is a little more involved (we have to create a new commit instead of just naming the new parent):
INITIAL_SHA1=$(git rev-list --reverse master | head -1)
# detach HEAD at the end of the old history
git checkout old-history~0
# make a new commit that looks like the old initial commit
git rm -r -- .
git checkout $INITIAL_SHA1 -- .
git commit -C $INITIAL_SHA1
# replace the old initial commit with the newly created commit
git replace $INITIAL_SHA1 HEAD
# return to the previous branch (reattach HEAD)
git checkout -
Sharing this replacement is not automatic. You have to push part of (or all of) refs/replace
to share the replacement.
git push some-remote 'refs/replace/*'
If you decide to make the replacement permanent, use git filter-branch (same as with grafts; make a tar/zip backup of your .git
directory first):
git filter-branch --tag-name-filter cat -- --all
git replace -d $INITIAL_SHA1