5

I try to move a directory and all its history from repository to another repository.

Extracting the complete history of the directory is easy with git subtree split.

This creates a new branch, which can easily be fetched to the other repository.

Now I used git subtree add to paste the directory back into the second repository.

If I look at gitk or git log --decorate --graph everything looks fine. All commits are present as expected. Also all the files are present as expected.

But when I try to see the history of a transplanted file using git log -- transplanted_dir/somefile, I only see the one "merge" commit, resulting from the git subtree add.

Why do I see the commits in gitk above, but not in the log of a single file?

If I do a simple git merge, I can see the history of each file, but the files will, of course not live in a subfolder.

What is the right way to integrate the moved commits into the other repository?

Detailed example commands to reproduce situation:

#create two repositories:
git init a
git init b

# create directory dir with some history
cd a
mkdir dir
echo 1 > dir/file
git add .
git commit -am 1
echo 2 > dir/file
git commit -am 2
echo 3 > dir/file
echo 3 > otherfile
git add .
git commit -am 3

#split subtree
git subtree split --prefix dir -b split

#create a commit on repo b
cd ../b
mkdir otherdir
touch otherdir/file
git add .
git commit -am init

#fetch split branch of repo a
git fetch ../a split
git co -b split FETCH_HEAD
git log --decorate --graph --name-status 
git co master

# add commits to repo b
git subtree add --prefix somedir split

# this looks fine:
git log --decorate --graph --name-status

# no history here - Why?
git log --decorate --graph --name-status somedir/file
git log --decorate --graph --name-status --follow somedir/file
michas
  • 25,361
  • 15
  • 76
  • 121
  • When you move a file, you rename it. I am pretty sure that `git log` with no parameters just stops at the point of the rename; further back in time, that file does not exist. – matt May 06 '13 at 17:08
  • No, there is no rename. The "merge" commit just adds new files. – michas May 06 '13 at 18:09
  • @michas Moving `foo/bar/baz` to `bar/baz` counts as a rename. What is the output of `git log --follow`? – gcbenison May 06 '13 at 18:25
  • No, --follow does not work, either. Please set up the situation as given above, and try by yourself. – michas May 07 '13 at 04:58

1 Answers1

3

Alright, reading the source cleared things up.

git subtree add is pretty ugly: It first uses git read-tree to add the current version without any history into the given directory. Afterwards it uses git commit-tree to create a fake merge commit to attach the old history containing the unprefixed files.

On the other hand, now the prefixed file at HEAD and the unprefixed one in HEAD^2 should be exactly the same and should be recognized as a move by --follow.

Unfortuately it is not recognized as such. No idea why.

The best solution is probably to add an explicit commit moving the files to the new directory and do a normal merge. - An alternative is to rewrite the history of the transplanted directory as described in How can I rewrite history so that all files, except the ones I already moved, are in a subdirectory?.

For my situation git subtree add is bad, a normal git merge with a correctly prepared subtree seems to be exactly the right thing.

Community
  • 1
  • 1
michas
  • 25,361
  • 15
  • 76
  • 121
  • There is a very similar issue here: http://stackoverflow.com/questions/10918244/git-subtree-without-squash-view-log – Maic López Sáenz May 07 '13 at 17:54
  • If I have a repository that was created via `git subtree add`, is there a way to restore the history so that `git log` works properly? – oconnor0 May 16 '13 at 22:14
  • What do you mean by "correctly prepared subtree"? Could you please add the commands/changes to the commands in your question to the answer? – Aaron Digulla Jul 01 '14 at 08:56