How can a patchfile created with `git-log -p <filename>` be applied to create all the commits included?
Background: this question. git apply <patchfile>
just recreates the file but without committ开发者_StackOverflow中文版ing 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")
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
self
else
result = ''
scan(/('+)|[^']+/) {
if $1
result << %q{\'} * $1.length
else
result << "'#{$&}'"
end
}
result
end
end
end
dir1, dir2, *files = ARGV
patchlog = Dir.chdir(dir1){`git log -p #{files.map(&:shell_escape).join(" ")}`}
patches = []
patchlog.each_line{|line|
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
else
(patches[-1][:diff] ||= "") << line
end
}
patch_level = 2
skip = 0
dry_run = false
patches.reverse[skip..-1].each{|patch|
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(" ")
next
end
Dir.chdir(dir2){
IO.popen("patch -p#{patch_level}", "w"){|fh|
fh.puts diff
}
system "git", "add", *files
system "git", "commit", "-m", msg, "--date", date
}
}
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.
精彩评论