tags:

views:

47

answers:

2

I'm working on a Git repo that's been pulled from an SVN repo using git svn. Many moons ago, the SVN repo was created from a source tarball of the original (upstream) project. The original project had a file structure like the following:

/
  COPYING
  README
  src/
      ...many source files...

However, when the SVN repo was created, the README files, etc., were stripped out, and the app was created with src/ as the root, so the repo now just looks like:

/
  ...many source files

I recently converted this SVN repo into a Git repo. The original project is also in a Git repo, and I'd like to start tracking upstream changes so I can easily see what custom changes have been made (and submit patches back to the original project, if applicable). I've found the commit in the upstream repo that our SVN repo was created from, so now I'd like to apply our changes to that commit (in a branch). I can easily create a set of patches using git format-patch and apply them to the cloned upstream repo...except that the file structures are different, so the patches don't point to the correct files anymore. Is there a way to apply the patches from git format-patch to the src/ directory in the cloned repo? (Note that the Git patches also have the necessary info like the original author name, email, and date, which I'd also like to apply and not have to do by hand, i.e., by messing around with GIT_AUTHOR_EMAIL, etc.)

A: 

I had to do something very similar once, wasn't pretty but it was manageable. What I ended up doing was:

git format-patch <commitish> --stdout > patches-for-upstream.mbox
$EDITOR patches-for-upstream.mbox

Inside the editor, I looked at which bits were common and needed changed to make "git am" do what I wanted. That turned out to be three lines, per file committed in each commit:

  • the line starting with diff --git a/path/to/file b/path/to/file
  • the line starting with --- a/path/to/file
  • the line starting with +++ b/path/to/file

What the editor needs to do at this point is to go through these kind of lines and make the changes that you know are necessary to have all the patches apply to the other Git repository.

I did that in Vim, using three quickly typed macroes, YMMV. Something along the lines of:

  • go to next line starting with diff --git a/
  • go forward to that slash after the a
  • change the path as you need it to be
  • go forward to the slash after the b/ (forward to next space from the a file, then /)
  • change the path in the same way as a
  • next line (the ---)
  • go forward to a/
  • change the path
  • next line (the +++)
  • go forward to b/
  • change the path

Repeat until the file's done. In Vim it was a matter of getting it in a macro once (qq<long string of commands>q), trying it out once (@q) and then doing it for the whole file (999@q).

Save the file, go in the other Git repo, and try to git am it.

mfontani
+1  A: 

Seems to me that you should be able to use git filter-branch to change the paths in the previously-cloned-from-SVN repo. Then, after all the file paths have been updated, you can now just use git format-patch to create patches that will apply to the newly-cloned-from-upstream repo.

Try:

git filter-branch --tree-filter 'mkdir src; git ls-tree --name-only $GIT_COMMIT | xargs -I files mv files src'

Dan Moulding
Almost works, but the files under `src/` are organized into subdirectories -- this solution moves them all directly under `src/`. Any way to move the entire subdirectory tree?
mipadi
@mipadi: Right you are. My mistake for not actually *testing* what I write :O. I've corrected that error in my answer. Thanks for pointing out the problem :)
Dan Moulding
No biggie -- your original answer works fine if `src/` doesn't contain any subdirectories (and I forgot to mention that in my question).
mipadi