Git 格式-补丁是否与 svn 兼容?

有没有什么方法可以使用 git 格式创建的补丁与 svn 兼容,这样我就可以将它提交给 svn 回购?

我正在处理 github 上的一个 svn 回购,并希望将我的更改提交回主回购。我需要创建一个补丁来做到这一点,但是补丁不能应用,因为 git 格式的补丁不同于 svn。有什么秘密我还没发现吗?

更新: 虽然目前还没有脚本或者本地 git 方法来实现这个功能,但是我在今年早些时候找到了一篇关于如何手动完成这个功能的文章。我已经按照说明进行了操作,并成功地让我的 git 补丁与 svn 一起工作。

如果有人能够尝试编写一个脚本来完成这个任务,并且为 Git 项目做出贡献,我会非常感激的。

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

35652 次浏览

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)

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.

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.

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.*/===================================================================/"

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

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

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.

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

git show --pretty >> myChangesFile.patch

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.