Take the 2-minute tour ×

Background: this question. git apply <patchfile> just recreates the file but without committing the history, which in this case would be desireable. Is there any switch for git-apply to do so? Or is there a way to convert the patchfile into a git-am compatible file? (Currently, git-am complains "Patch format detection failed")

share|improve this question
If you've got a range of commits that you want to apply you're usually much better off creating a bundle, or simply fetching and rebasing than trying to re-create commits from a log -p output. –  Charles Bailey Jul 7 '10 at 11:39
@Charles is that also possible for a single file's history? That's what the mentioned question is about, so I simply tried git log -p <filename> > <patchfile> to get the patch... –  Tobias Kienzler Jul 7 '10 at 11:50
git apply is more of an opposite to git diff than log -p so without manually splitting the output I don't think it's possible (or not easy, anyway). If you can get a bundle between the two repositories then I think it would be much easier to manipulate the original branch to apply to a single file (e.g. using filter-branch) and then rebase it than to fiddle with text based patches. –  Charles Bailey Jul 7 '10 at 12:08
add comment

2 Answers

up vote 1 down vote accepted

You asked, so here it is.

I used this script, but it's all rather fragile. Treat it an as inspiration, not as a reasonable solution.

It extracts (date / author / commit message / patch) from output of git log -p, and then runs patch+git add+git apply for all, in reverse order.

There's probably some way of automatically figuring out correct patch_level, but I didn't bother. And pass author to git apply if it's not all you.

#!/usr/bin/env ruby

class String
  def shell_escape
    if empty?
    elsif %r{\A[0-9A-Za-z+,./:=@_-]+\z} =~ self
      result = ''
      scan(/('+)|[^']+/) {
        if $1
          result << %q{\'} * $1.length
          result << "'#{$&}'"

dir1, dir2, *files = ARGV

patchlog = Dir.chdir(dir1){`git log -p #{files.map(&:shell_escape).join(" ")}`}

patches = []
  if line =~ /\Acommit/
    patches << {}
  elsif line =~ /\A(Author|Date):\s*(.*)/
    patches[-1][$1] = $2
  elsif patches[-1][:diff].nil? and line !~ /\Adiff/
    (patches[-1][:msg] ||= "") << line
    (patches[-1][:diff] ||= "") << line

patch_level = 2
skip = 0
dry_run = false

  author = patch["Author"].strip
  date = patch["Date"].strip
  msg = patch[:msg].strip
  diff = patch[:diff]

  if dry_run
    puts ["git", "commit", "-m", msg, "--date", date].join(" ")

    IO.popen("patch -p#{patch_level}", "w"){|fh|
      fh.puts diff
    system "git", "add", *files
share|improve this answer
add comment

look into git quiltimport. You provide a directory where the command finds a file called "series". In this file you simply mention the names of the patchfiles, in order which it will apply them". The text prior to the actuall diff in the file is used as commit comment, the filename (minus the .patch) is used as headline, and it tries to find the author in each patch, if none are found you get asked for it.

share|improve this answer
I'll have a look into it, thanks HAL :p –  Tobias Kienzler Sep 6 '11 at 14:33
add comment

Your Answer


