101

Is there any way to get a patch created with git format-patch to be svn compatible so that I can submit it to an svn repo?

I'm working off an svn repo on github and want to submit my changes back to the main repo. I need to create a patch to do this, however the patch cannot be applied since git formats that patch differently then svn. Is there some secret I haven't discovered yet?

UPDATE: Although currently there exists no script or native git way to do this, I did managed to find a post from earlier this year about how to manually accomplish this. I have followed the instructions and had success getting my git patches to work with svn.

If someone could take a stab at writing a script to accomplish this and contribute to the git project, I'm everyone would be much appreciated.

http://kerneltrap.org/mailarchive/git/2008/1/15/570308/thread#mid-570308

Community
  • 1
  • 1
rip747
  • 9,375
  • 8
  • 36
  • 47

8 Answers8

99

I always have to Google this but the way I've found that works perfectly (for me) is:

  • Create the patch with git diff --no-prefix master..branch > somefile.diff, the master and branch part are optional, depends how you want to get your diffs.
  • Send it wherever and apply with patch -p0 < somefile.diff.

It always seems to work fine for me and seems to be the simplest method that I've come across.

Duncan Jones
  • 67,400
  • 29
  • 193
  • 254
Nicholas Smith
  • 11,642
  • 6
  • 37
  • 55
  • 1
    This is the canonical way to generate SVN-compatible patch with Git. It should be marked as the answer. – mloskot Apr 23 '14 at 18:22
  • `--no-pager` is no longer an option for `git diff`. – naught101 Sep 01 '14 at 07:29
  • It was originally posted without `--no-pager`, I'm not certain why it was added it in the edit. It's always worked fine for me without `--no-pager` anyway. – Nicholas Smith Sep 01 '14 at 09:06
  • 3
    For a particular commit only: `git diff --no-prefix 056a1ba5140 7d939289b80 >my.patch` worked for me (where `056a1ba5140` and `7d939289b80` are the sha-1 of the previous and particular commit in git). – Ed Randall Jul 29 '16 at 18:39
  • @Lilás this is a problem with SVN. Diffs/patches in SVN have never been able to handle removed files – Toofy Dec 26 '18 at 23:23
23

The short answer is patch -p1 -i {patch.file}.

Please refer to this blog for details: Creating Subversion patches with git.

Mateusz Piotrowski
  • 8,029
  • 10
  • 53
  • 79
Wallace Wong
  • 279
  • 2
  • 2
17

Here's a helper script for making a diff against the the latest svn changeset and the given commit: http://www.mail-archive.com/dev@trafficserver.apache.org/msg00864.html

#!/bin/sh
#
# git-svn-diff
# Generate an SVN-compatible diff against the tip of the tracking branch
TRACKING_BRANCH=`git config --get svn-remote.svn.fetch | sed -e 's/.*:refs\/remotes\///'`
REV=`git svn find-rev $(git rev-list --date-order --max-count=1 $TRACKING_BRANCH)`
git diff --no-prefix $(git rev-list --date-order --max-count=1 $TRACKING_BRANCH) $* |
sed -e "s/^+++ .*/&    (working copy)/" -e "s/^--- .*/&    (revision $REV)/" \
-e "s/^diff --git [^[:space:]]*/Index:/" \
-e "s/^index.*/===================================================================/"
Christoph
  • 171
  • 1
  • 2
  • 1
    I found that the REV value is incorrect if you're not working with the latest svn revision. I corrected it to use `git svn info` instead like this: `REV=\`git svn info | grep 'Last Changed Rev:' | sed -E 's/^.*: ([[:digit:]]*)/\1/'\`` – Sebastien Martin Apr 14 '11 at 11:14
  • 1
    This is AWESOME! Thank you so much. I had to make one change for it to work for importing my patches into Fisheye's crucible, and that was to replace the spaces before "(revision" with a tab instead. – Aaron Silverman Apr 12 '12 at 18:24
10

Subversion < 1.6 doesn't have patch support. It looks like Subversion 1.7 will allow applying patches and the git/hg extensions to unified diff are on our TODO list.

Bert Huijben
  • 19,525
  • 4
  • 57
  • 73
10

SVN probably cannot understand the output of git diff -p, but you can resort to brute force:

  1. Make two clones of your repo
  2. In one clone check out your latest stuff
  3. In the other clone checkout whatever is equivalent to the svn upstream. If you have planned ahead you have a copy of svn upstream on its own branch, or you have tagged the last svn version. If you have not planned ahead, use the date or gitk to find the git SHA1 hash that most closely approximates the svn state.
  4. Now compute a real patch by running diff -r over the two clones.
Norman Ramsey
  • 198,648
  • 61
  • 360
  • 533
  • 12
    Or just follow @Nicholas-smith's advise and run `git diff --no-prefix > somefile.diff` in your git repo and send that to any svn user for them to apply the patch with `patch -p0 < somefile.diff` in the root of the project. – DavidGamba Mar 06 '13 at 16:47
4

It is indeed a feature request early 2008

Linus Torvalds said at the time:

So I would argue that you need something stronger to say "don't do a git diff", and that should also disallow rename detection at a minimum.
Quite frankly, any program that is so stupid as to not accept current git patches (ie TortoiseSVN), then we damn well shouldn't just disable the most trivial part of it. We should make sure that we do not enable any of the rather important extensions:
even if ToirtoiseSVN would ignore them, if ignoring them means that it mis-understands the diff, it shouldn't be allowed at all.

That may be why

 git-format-patch: add --no-binary to omit binary changes in the patch.

has been introduced in Git1.5.6 in May/July 2008 (I have not tested it though)

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
0

Make sure your changes are committed and rebased on top of your local git branch, from git bash run:

git show --pretty >> myChangesFile.patch

Ismail Hawayel
  • 2,167
  • 18
  • 16
0

The accepted answer provided by Nicholas works fine, except when a) binary files exist in the diff or b) you are working in windows Git and have directories with spaces. To get that resolved I had to add a nested git diff command to ignore binaries and sed command to escape the spaces. It's a bit cumbersome to write, so I created an alias:

[alias]
svnpatch = "!f() { git diff --name-only --no-prefix master...$1 | grep -Ev \"\\.sdf|\\.Doc|\\.dll|\\.zip|\\.exe\" | sed 's_\\s_\\\\\\\\ _g'  | xargs git diff --no-prefix master...$1 > $1.patch; echo "Created $1.patch"; }; f"

If you then type:

git svnpatch Feature123

...a patch file Feature123.patch will be created with the differences between the merge base of branch master and branch Feature123.