Applying SVN patch diff file to a GIT repository

  • Posted on: 7 September 2015
  • By: Michał Turecki

There are many FOSS projects using subversion for source control. I'm using GIT instead because or a unique mixture of features it has and a widespread use of GIT in FOSS community including legendary GitHub. Subversion is much less flexible and is worse performing regardless of popular opinions based mostly on better familiarity with it without "big picture" comparison. Major reason for my personal dislike of SVN is inability to browse the history of a repository without having an established network connection to the subversion repository server.

That's why I'm maintaining a refactored fork of Safe Exam Browser on GitHub (although recently SEB team switched to git so it's just a one time catch up). Before a move to git I needed to convert SVN commits to GIT and even with tools like TortoiseGIT and TortoiseSVN it seems not to be a trivial task.

TortoiseSVN on "Show Log" can generate a diff patch when we select 1 commit or a continuous range of commits, using context menu's "Show changes as united diff" option. This is roughly equivalent to running:

git diff --revision X:Y

NOTICE: In TortoiseSVN 1.8.11 when creating a diff for multiple commits I needed to select 1 commit before the first commit I wanted to include in diff. What's interestng is that list of changed files included this "before-first" commit's contents but diff did not.

But this file is not compatibile with git am patching as it is in different format, when running "Apply patch" feature in TortoiseGit we get the following error:

git.exe am --3way --ignore-space-change --keep-cr "path_to_diff_file"
Patch format detection failed.

Fail

There is an alternative git command git apply but it also fails if there is at least a single mismatch in the diff file against the codebase it is executed against.

It returned many errors like:

X:line: trailing whitespace.

error: file_name: does not exist in index. (git apply ignored first part of the diff file path on my windows machine)

error: file_name: patch does not apply (newlines + conflicting changes issue)

error: repository lacks the necessary blob to fall back on 3-way merge. (because I used -3 parameter to enable 3-way merge).

The solution is to use patch command with some possible options letting the user to fine tune the patching process. In my case I modified the original code extensively so setting +/- 100 lines with -F option when finding original code was a must. Also windows line endings were used in the project so --binary option allowed to prevent patching from changing all line endings in files being patched. Line endings should be also ignored when searching for patched code so -l option is used. Overall the patching for every contiguous set of SVN commits I chose to become a single GIT commit is done using the following command:

patch -F 100 -l --binary --no-backup-if-mismatch -p0 < c:/patches/1.diff

After running the command and (optionally) pointing the new locations of some files moved, there can be some reject files (*.rej) left in the source control which will contain patches which could not be applied. After manual applying I usually copy original commit texts, revisions and authors using "Copy to clipboard" feature of TortoiseSVN log and commit to Git. Job done.