-
Notifications
You must be signed in to change notification settings - Fork 8
/
git-export-diff.rb
executable file
·149 lines (115 loc) · 3.36 KB
/
git-export-diff.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#!/usr/bin/env ruby
#
#= Export diff files on specific revisions
#
# Export diff files on specific revisions.
#
#= Usage
#
# git-export-diff.rb {hash}
#
# If you want to use with SourceTree, set custom action with argument $SHA
#
require "yaml"
require "optparse"
require 'shellwords'
root_path = Dir::pwd # get repository fill path without $REPO.
root_dir = File.basename(root_path)
unless File.exists?(File.join(root_path, ".git"))
puts "Oops! Current directory is not a git repository."
exit 1
end
# default options
options = {
:archive => nil,
:output => File.join(root_path, "..")
}
# load config if exist
path_yml = File.join(root_path, "git-export-config.yml")
global_config = File.exists?(path_yml) ? YAML.load_file(path_yml) : {}
config = global_config['diff'] # FIXME: be more flexible
# overwrite options by values from yaml
if config
[:archive, :output, :format].each do |k|
options[k] = config[k.to_s] if config[k.to_s]
end
end
# overwrite options by argument options
OptionParser.new do |opt|
opt.on('-a VALUE', 'ARCHIVE FORMAT (zip, tar ,tgz, tar.gz)') do |v|
options[:archive] = v if /(zip|tar|tgz|tar\.gz)/ === v
end
opt.on('-o VALUE', 'OUTPUT PATH') do |v|
options[:output] = v
end
opt.on('-f VALUE', 'OUTPUT NAME FORMAT (ex. OUTPUT-%y%m%d)') do |v|
options[:format] = v
end
opt.parse!(ARGV)
end
sha = ARGV.first # get last selected rev. newer commit
sha_old = ARGV.last # get last selected rev. older commit
unless /[a-z0-9]{4,40}/ === sha and /[a-z0-9]{4,40}/ === sha_old
puts "Give me valid SHA hash!"
exit 1
end
# set previous hash to "from" if not selected multiple revision
sha_old = sha + "^" if sha_old === sha
if options[:format]
dir = Time.now.strftime(options[:format])
else
# get tag name or branch name
desc = %x[git describe --contains --all #{sha}]
name = case desc
when /^tags/
desc[/tags\/([\w\/]+)\^0/, 1].strip
when /^remotes/
desc[/remotes\/(\w+\/\w+)/, 1].gsub("/", "-").strip + "-#{sha[0,7]}"
else
desc.sub(/~\d/, "").strip + "-#{sha[0,7]}"
end
dir = "#{root_dir}-#{name}"
end
output = File.join(options[:output], dir)
puts "sha\t: " + "#{sha}"
puts "sha_old\t: " + "#{sha}"
puts "root\t: " + "#{root_path}"
puts "name\t: " + "#{name}"
puts "dir\t: " + "#{dir}"
puts "output\t: " + "#{output}"
puts "---- options ---- "
options.keys.each do |k|
puts "#{k.to_s}\t: #{options[k]}"
end
diff_cmd = "git diff --stat --diff-filter=ACRM --name-only #{sha_old}..#{sha}"
diff_files = %x[#{diff_cmd}]
puts "\n"
puts "---- export candidate files ----"
puts diff_files
puts "--------------------------------"
puts "\n"
if diff_files.empty?
puts "There are no export files."
exit 0
end
# suffix number if already exist file or directory
suffix_no = 0
suffix_format = "-%03d"
suffix = ""
ext = options[:archive] ? options[:archive] : ""
while File.exists?(output + suffix + ext)
suffix_no = suffix_no + 1
suffix = suffix_format % [suffix_no]
end
output = (output + suffix).shellescape
# for arguments
diff_files = diff_files.split("\n").join(" ")
cmd = case options[:archive]
when /(zip|tar|tar\.gz|tgz)/
%[git archive #{sha} --format=#{options[:archive]} --prefix=#{dir}/ -o #{output}.#{options[:archive]} -- #{diff_files}]
else
%[mkdir -p #{output}; git archive #{sha} -- #{diff_files} | tar -xC #{output}]
end
puts "cmd\t: " + cmd
%x[#{cmd}]
exit 0