git-prepare-merge 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +4 -0
- data/README.md +63 -0
- data/Rakefile +18 -0
- data/bin/git-compare-branches +132 -0
- data/bin/git-prepare-merge +485 -0
- data/lib/prepare_merge.rb +60 -0
- data/spec/prepare_merge_spec.rb +6 -0
- data/spec/spec_helper.rb +15 -0
- data/test/test_prepare_merge.rb +0 -0
- data/version.txt +1 -0
- metadata +108 -0
data/History.txt
ADDED
data/README.md
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
prepare_merge
|
2
|
+
===========
|
3
|
+
|
4
|
+
Git Scripts to ease the merging of review branches into develop.
|
5
|
+
|
6
|
+
Features
|
7
|
+
--------
|
8
|
+
|
9
|
+
|
10
|
+
|
11
|
+
Examples
|
12
|
+
--------
|
13
|
+
|
14
|
+
Requirements
|
15
|
+
------------
|
16
|
+
|
17
|
+
Ruby 1.9.1
|
18
|
+
git 1.7.6
|
19
|
+
|
20
|
+
Install
|
21
|
+
-------
|
22
|
+
|
23
|
+
the gem file is located in the pkg subfolder
|
24
|
+
|
25
|
+
just run
|
26
|
+
|
27
|
+
gem install Rebase_review_flow_git_scripts-0.0.1.gem
|
28
|
+
|
29
|
+
|
30
|
+
Author
|
31
|
+
------
|
32
|
+
|
33
|
+
Original author: Simone Vicentini
|
34
|
+
|
35
|
+
Contributors:
|
36
|
+
|
37
|
+
|
38
|
+
|
39
|
+
License
|
40
|
+
-------
|
41
|
+
|
42
|
+
(The MIT License)
|
43
|
+
|
44
|
+
Copyright (c) 2011 - HuzuTech
|
45
|
+
|
46
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
47
|
+
a copy of this software and associated documentation files (the
|
48
|
+
'Software'), to deal in the Software without restriction, including
|
49
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
50
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
51
|
+
permit persons to whom the Software is furnished to do so, subject to
|
52
|
+
the following conditions:
|
53
|
+
|
54
|
+
The above copyright notice and this permission notice shall be
|
55
|
+
included in all copies or substantial portions of the Software.
|
56
|
+
|
57
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
58
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
59
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
60
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
61
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
62
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
63
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
|
2
|
+
begin
|
3
|
+
require 'bones'
|
4
|
+
rescue LoadError
|
5
|
+
abort '### Please install the "bones" gem ###'
|
6
|
+
end
|
7
|
+
|
8
|
+
|
9
|
+
Bones {
|
10
|
+
name 'git-prepare-merge'
|
11
|
+
authors 'Simone Vicentini - HuzuTech ltd'
|
12
|
+
email 'simone.vicentini@huzutech.com'
|
13
|
+
url 'http://www.huzutech.com'
|
14
|
+
depend_on 'git'
|
15
|
+
depend_on 'highline'
|
16
|
+
depend_on 'OptionParser'
|
17
|
+
}
|
18
|
+
|
@@ -0,0 +1,132 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require "highline/import"
|
3
|
+
require 'git'
|
4
|
+
include Git
|
5
|
+
|
6
|
+
#
|
7
|
+
# Git Compare Branches
|
8
|
+
#
|
9
|
+
# Script to find out what is in a branch that is not in a second branch.
|
10
|
+
# The two branches need to have a common ancestor.
|
11
|
+
# git command:
|
12
|
+
# git log --cherry-pick --format="%h %s" --no-merges --right-only branch1...branch2
|
13
|
+
#
|
14
|
+
#
|
15
|
+
# The script can also find out the latest Release Candidate branch to then compare it
|
16
|
+
# with the current branch.
|
17
|
+
# Release Candidate branches should following this naming convention:
|
18
|
+
# RC-YYYYMMDD-name
|
19
|
+
#
|
20
|
+
# e.g.
|
21
|
+
# RC-20110112-AntoninePlague
|
22
|
+
# RC-20111129-MoscowPlagueAndRiot
|
23
|
+
#
|
24
|
+
|
25
|
+
def checkIfCommandRunInGITrootFolder
|
26
|
+
begin
|
27
|
+
repo = Base.new :working_directory => "."
|
28
|
+
return repo
|
29
|
+
rescue ArgumentError
|
30
|
+
puts 'You should run this script from the root folder of your git repo'
|
31
|
+
puts 'Aborting...'
|
32
|
+
exit 1
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
numberOfArgs = ARGV.length
|
37
|
+
|
38
|
+
compareWithLastRC = false
|
39
|
+
|
40
|
+
branch1 = ""
|
41
|
+
branch2 = ""
|
42
|
+
|
43
|
+
optparse = OptionParser.new do|opts|
|
44
|
+
# Set a banner, displayed at the top
|
45
|
+
# of the help screen.
|
46
|
+
opts.banner = "Usage: git compare-branches -b <branchName> [-c <branchName>] | -l"
|
47
|
+
|
48
|
+
opts.on( '-l', '--lastRC', 'Will try to find out the latest Release Candidate and compare the current branch with it' ) do|b|
|
49
|
+
compareWithLastRC = true
|
50
|
+
end
|
51
|
+
|
52
|
+
opts.on( '-b','--base BRANCH', 'Find out what is in the current branch which is not already in BRANCH') do|b|
|
53
|
+
branch1 = b
|
54
|
+
end
|
55
|
+
|
56
|
+
opts.on( '-c','--current BRANCH', 'Use BRANCH instead of the current branch.' ) do|b|
|
57
|
+
branch2 = b
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
# This displays the help screen, all programs are
|
62
|
+
# assumed to have this option.
|
63
|
+
opts.on( '-h', 'Display this screen' ) do
|
64
|
+
puts opts
|
65
|
+
exit
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
optparse.parse!
|
70
|
+
|
71
|
+
if (branch1.empty? && branch2.empty? || branch1.empty? && !branch2.empty?)&& !compareWithLastRC then
|
72
|
+
puts optparse.help
|
73
|
+
exit 0
|
74
|
+
end
|
75
|
+
|
76
|
+
repo = checkIfCommandRunInGITrootFolder
|
77
|
+
|
78
|
+
|
79
|
+
#Fetch latest stuff from the remote repo
|
80
|
+
puts "Fetching latest stuff..."
|
81
|
+
repo.fetch()
|
82
|
+
puts "Fetching finished."
|
83
|
+
|
84
|
+
#saving current branch
|
85
|
+
currentBranch = repo.current_branch()
|
86
|
+
|
87
|
+
if branch2.empty? then
|
88
|
+
branch2 = currentBranch
|
89
|
+
end
|
90
|
+
|
91
|
+
if compareWithLastRC then
|
92
|
+
|
93
|
+
remoteBranches = `git branch -r | grep -E "RC-20[0-9][0-9](0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01])"`
|
94
|
+
remoteBranches.strip!
|
95
|
+
if remoteBranches.length == 0 then
|
96
|
+
puts "No Release Candidate branches found!"
|
97
|
+
exit 0
|
98
|
+
end
|
99
|
+
|
100
|
+
remoteBranches = remoteBranches.split($/)
|
101
|
+
|
102
|
+
remoteBranches.each { |w| w.strip! }
|
103
|
+
remoteBranches.sort!
|
104
|
+
rc = remoteBranches.last
|
105
|
+
puts "Looks like \n#{rc}\nis the most recent Release Candidate"
|
106
|
+
correctRC = agree "Is this correct?\n(Y = continue, N = show me all the other available Release Candidate branches)"
|
107
|
+
if correctRC then
|
108
|
+
branch1 = rc
|
109
|
+
else
|
110
|
+
puts "Then select a RC from the available ones:"
|
111
|
+
CHOICES = remoteBranches
|
112
|
+
branch1 = choose(*CHOICES)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
puts "going to find out what is in #{branch2} which is not already in #{branch1}"
|
117
|
+
diffs = `git log --cherry-pick --format="%h %s" --no-merges --right-only #{branch1}...#{branch2}`
|
118
|
+
result = $?.success?
|
119
|
+
puts "...done!"
|
120
|
+
|
121
|
+
if ! result then
|
122
|
+
puts "Something went wrong while comparing the branches"
|
123
|
+
exit 1
|
124
|
+
end
|
125
|
+
if diffs.empty? then
|
126
|
+
puts "No differences between #{branch1} and #{branch2}"
|
127
|
+
exit 0
|
128
|
+
end
|
129
|
+
puts " "
|
130
|
+
puts "Here is what is in #{branch2} but not in #{branch1}:"
|
131
|
+
puts " "
|
132
|
+
puts diffs
|
@@ -0,0 +1,485 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'git'
|
3
|
+
require 'fileutils'
|
4
|
+
include FileUtils
|
5
|
+
include Git
|
6
|
+
require "highline/import"
|
7
|
+
|
8
|
+
######################################################################
|
9
|
+
#
|
10
|
+
# Git Prepare Merge
|
11
|
+
#
|
12
|
+
# Script to automatically squash and rebase a branch with a standard commit message.
|
13
|
+
#
|
14
|
+
# N.B. The reason why we are not using the rebase command with the --autosquash option
|
15
|
+
# is that the autosquash is not completely automatic and it can be only used with the -i (interactive)
|
16
|
+
# option which defeats the point of this script. Why? because the interactive option will show
|
17
|
+
# a list of the commits which are about to be rebased and then is up to the user editing that
|
18
|
+
# list before rebasing, while the prepare merge script will automate this process.
|
19
|
+
#
|
20
|
+
#
|
21
|
+
# Steps executed by the script:
|
22
|
+
# 1 - find out the fork-point commit between the current branch and the destination branch.
|
23
|
+
# 2 - soft reset current branch to the fork point commit.
|
24
|
+
# 3 - stage all the changes
|
25
|
+
# 4 - ask for commit message details
|
26
|
+
# 5 - commit
|
27
|
+
#
|
28
|
+
# ====================================================================
|
29
|
+
# o = commit
|
30
|
+
#
|
31
|
+
# find fork point
|
32
|
+
#
|
33
|
+
# destination branch
|
34
|
+
# /
|
35
|
+
# o---o---o---o---o---o
|
36
|
+
# |\
|
37
|
+
# | o---o---o---o---o---o---o
|
38
|
+
# | \
|
39
|
+
# | your branch
|
40
|
+
# |
|
41
|
+
# fork-point
|
42
|
+
#
|
43
|
+
# ====================================================================
|
44
|
+
# reset and create only one commit (simulating rebasing)
|
45
|
+
#
|
46
|
+
#
|
47
|
+
# destination branch
|
48
|
+
# /
|
49
|
+
# o---o---o---o---o---o
|
50
|
+
# |\
|
51
|
+
# | o
|
52
|
+
# | \
|
53
|
+
# | your branch
|
54
|
+
# |
|
55
|
+
# fork-point
|
56
|
+
#
|
57
|
+
# ====================================================================
|
58
|
+
# rebase on top of the destination branch
|
59
|
+
#
|
60
|
+
# destination branch
|
61
|
+
# /
|
62
|
+
# o---o---o---o---o---o---o
|
63
|
+
# \
|
64
|
+
# your branch
|
65
|
+
#
|
66
|
+
#
|
67
|
+
######################################################################
|
68
|
+
|
69
|
+
|
70
|
+
#constants
|
71
|
+
TEMP_DIR = ".git#{File::SEPARATOR}prepare_merge"
|
72
|
+
HEAD_SHA_FILE = "HEAD"
|
73
|
+
TODO_FILE = "TODO"
|
74
|
+
|
75
|
+
|
76
|
+
destination_branch = "develop"
|
77
|
+
|
78
|
+
is_windows = (RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/)
|
79
|
+
|
80
|
+
# Windows terminals don't support pretty colours
|
81
|
+
if is_windows
|
82
|
+
HighLine.use_color=false
|
83
|
+
end
|
84
|
+
|
85
|
+
# Abort if ctrl-c on input
|
86
|
+
if is_windows
|
87
|
+
trap('INT') { say("\n\n\nAborting...\n\n\n"); exit }
|
88
|
+
else
|
89
|
+
stty_save = `stty -g`.chomp
|
90
|
+
trap('INT') { say("\n\n\n<%=color('Aborting...'.ljust(76), WHITE, ON_RED, BOLD)%>\n\n\n"); system('stty', stty_save); exit }
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
#class override
|
95
|
+
def commit(title, message, ref, opts = {})
|
96
|
+
arr_opts = Array.new
|
97
|
+
arr_opts.push 'commit'
|
98
|
+
|
99
|
+
arr_opts.push '-m'
|
100
|
+
arr_opts.push title
|
101
|
+
|
102
|
+
if !message.empty? then
|
103
|
+
arr_opts.push '-m'
|
104
|
+
arr_opts.push message
|
105
|
+
end
|
106
|
+
|
107
|
+
if !ref.empty? then
|
108
|
+
arr_opts.push '-m'
|
109
|
+
arr_opts.push ref
|
110
|
+
end
|
111
|
+
|
112
|
+
arr_opts.push '-a' if opts[:add_all]
|
113
|
+
|
114
|
+
arr_opts.push '--amend' if opts[:amend]
|
115
|
+
|
116
|
+
commitParams = "#{arr_opts.join(" ")}"
|
117
|
+
puts "commit message:"
|
118
|
+
puts "@"*60
|
119
|
+
system("git", *arr_opts); result = $?.success?
|
120
|
+
puts "@"*60
|
121
|
+
return result
|
122
|
+
end
|
123
|
+
|
124
|
+
#methods
|
125
|
+
|
126
|
+
ft = HighLine::ColorScheme.new do |cs|
|
127
|
+
cs[:headline] = [ :bold, :yellow, :on_black ]
|
128
|
+
cs[:message] = [:yellow, :on_black ]
|
129
|
+
cs[:even_row] = [ :green ]
|
130
|
+
cs[:error] = [ :bold, :black, :on_red ]
|
131
|
+
cs[:command] = [:black, :on_white ]
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
HighLine.color_scheme = ft
|
136
|
+
|
137
|
+
def drawHeadline
|
138
|
+
say("<%= color('*'*60, :headline)%>\n")
|
139
|
+
end
|
140
|
+
|
141
|
+
def drawErrorLine
|
142
|
+
say("<%= color('-'*60, :error)%>\n")
|
143
|
+
end
|
144
|
+
|
145
|
+
def sayMessage(msg)
|
146
|
+
msg = msg.gsub(34.chr, '\"')
|
147
|
+
msg = msg.center(60)
|
148
|
+
say("<%= color(\"#{msg}\", :message)%>\n")
|
149
|
+
end
|
150
|
+
|
151
|
+
def sayError(error)
|
152
|
+
error = error.gsub(34.chr, '\"')
|
153
|
+
error = error.center(60)
|
154
|
+
say("<%= color(\"#{error}\", :error)%>\n")
|
155
|
+
end
|
156
|
+
|
157
|
+
def sayCommand(cmd)
|
158
|
+
cmd = cmd.gsub(34.chr, '\"')
|
159
|
+
cmd = cmd.center(60)
|
160
|
+
say("<%= color(\"#{cmd}\", :command)%>\n")
|
161
|
+
end
|
162
|
+
|
163
|
+
def checkIfCommandRunInGITrootFolder
|
164
|
+
begin
|
165
|
+
repo = Base.new :working_directory => "."
|
166
|
+
return repo
|
167
|
+
rescue ArgumentError
|
168
|
+
drawErrorLine
|
169
|
+
sayError('You should run this script from the root folder of your git repo')
|
170
|
+
sayError('Aborting...')
|
171
|
+
drawErrorLine
|
172
|
+
exit 1
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def rebaseOn(repo, target)
|
177
|
+
drawHeadline
|
178
|
+
sayMessage("Now rebasing on top of #{target}")
|
179
|
+
sayMessage("Fetching latest stuff from origin\n")
|
180
|
+
repo.fetch()
|
181
|
+
output = `git rebase #{target}`; result = $?.success?
|
182
|
+
drawHeadline
|
183
|
+
return result
|
184
|
+
end
|
185
|
+
|
186
|
+
def getSavedHEADsha
|
187
|
+
#read saved SHA for the current branch
|
188
|
+
if ! File.exist?(TEMP_DIR+File::SEPARATOR+HEAD_SHA_FILE) then
|
189
|
+
sayMessage "The saved HEAD file does not exists!"
|
190
|
+
return ""
|
191
|
+
end
|
192
|
+
headShaFile = File.new(TEMP_DIR+File::SEPARATOR+HEAD_SHA_FILE , "r")
|
193
|
+
sha = headShaFile.gets.chomp
|
194
|
+
headShaFile.close
|
195
|
+
return sha
|
196
|
+
end
|
197
|
+
|
198
|
+
def removeTempFiles
|
199
|
+
FileUtils.rm_rf TEMP_DIR
|
200
|
+
end
|
201
|
+
|
202
|
+
|
203
|
+
doClean = false
|
204
|
+
doContinue = false
|
205
|
+
doAbort = false
|
206
|
+
|
207
|
+
optparse = OptionParser.new do|opts|
|
208
|
+
# Set a banner, displayed at the top
|
209
|
+
# of the help screen.
|
210
|
+
opts.banner = "Usage: git prepare-merge [options]"
|
211
|
+
|
212
|
+
|
213
|
+
opts.on( '-b', '--branch BRANCH', "Specify the destination BRANCH.",
|
214
|
+
"The actual branch comparison is done against the relative remote branch.",
|
215
|
+
"If nothing is passed the default branch used is develop." ) do|b|
|
216
|
+
destination_branch = b
|
217
|
+
end
|
218
|
+
|
219
|
+
|
220
|
+
opts.on( '--clean', "To stop the execution of prepare-merge without",
|
221
|
+
"trying to set the repo back as it was before." ) do
|
222
|
+
doClean = true
|
223
|
+
end
|
224
|
+
|
225
|
+
|
226
|
+
opts.on( '--continue', "If, for any reason, the script was interrupted",
|
227
|
+
"you can use this to try to resume it." ) do
|
228
|
+
doContinue = true
|
229
|
+
end
|
230
|
+
|
231
|
+
|
232
|
+
opts.on( '--abort', 'Abort the current prepare merge and reset branch to original HEAD' ) do
|
233
|
+
doAbort = true
|
234
|
+
end
|
235
|
+
|
236
|
+
|
237
|
+
|
238
|
+
# This displays the help screen, all programs are
|
239
|
+
# assumed to have this option.
|
240
|
+
opts.on( '-h', 'Display this screen' ) do
|
241
|
+
puts opts
|
242
|
+
exit
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
optparse.parse!
|
247
|
+
|
248
|
+
|
249
|
+
repo = checkIfCommandRunInGITrootFolder
|
250
|
+
|
251
|
+
|
252
|
+
|
253
|
+
currentBranch = repo.current_branch()
|
254
|
+
if ["#{destination_branch}", "master", "origin/#{destination_branch}", "origin/master"].include?(currentBranch) then
|
255
|
+
drawErrorLine
|
256
|
+
sayError "You cannot run this command on this branch. It\'s too risky."
|
257
|
+
drawErrorLine
|
258
|
+
exit 1
|
259
|
+
end
|
260
|
+
|
261
|
+
|
262
|
+
|
263
|
+
if doContinue || doClean then
|
264
|
+
if ! File.exist?(TEMP_DIR) then
|
265
|
+
sayError "Not currently in the middle of a prepare-merge"
|
266
|
+
sayError "Nothing to do."
|
267
|
+
exit 0
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
|
272
|
+
if doClean then
|
273
|
+
sayMessage "prepare-merge stopped and temp files removed."
|
274
|
+
sayMessage "Check that this branch is set to the commit expected before doing anything else."
|
275
|
+
continueClean = agree "Are you sure you want to continue?"
|
276
|
+
if continueClean then
|
277
|
+
removeTempFiles
|
278
|
+
end
|
279
|
+
exit 0
|
280
|
+
end
|
281
|
+
|
282
|
+
if doAbort then
|
283
|
+
#the temp directory doesn't exist
|
284
|
+
if ! File.exist?(TEMP_DIR) then
|
285
|
+
sayMessage "nothing to abort"
|
286
|
+
exit 0
|
287
|
+
end
|
288
|
+
sha = getSavedHEADsha
|
289
|
+
if ! sha.empty? then
|
290
|
+
commit = Git::Object::Commit.new(repo, sha)
|
291
|
+
sayMessage "THIS OPERATION WILL RESET YOUR BRANCH TO THE FOLLOWING REVIEW:"
|
292
|
+
sayMessage "SHA: #{sha}"
|
293
|
+
sayMessage "Commit Message: "+commit.message.to_s
|
294
|
+
sayMessage "Commit Date: "+commit.committer_date.to_s
|
295
|
+
sayMessage "Commit Author: "+commit.committer.to_s
|
296
|
+
|
297
|
+
continueAborting = agree "ARE YOU REALLY SURE YOU WANT TO CONTINUE? (Y/N)"
|
298
|
+
if continueAborting then
|
299
|
+
#reset current branch to saved SHA
|
300
|
+
repo.reset_hard(sha)
|
301
|
+
removeTempFiles
|
302
|
+
sayMessage "prepare merge aborted successfully"
|
303
|
+
else
|
304
|
+
sayMessage "Abort operation cancelled. Check your repo carefully and if you want to end the prepare-merge process"
|
305
|
+
sayMessage "without any alteration to the current repo , use it with the --clean parameter."
|
306
|
+
end
|
307
|
+
end
|
308
|
+
exit 0
|
309
|
+
end
|
310
|
+
|
311
|
+
|
312
|
+
############################################################################
|
313
|
+
#ok we are not aborting or cleaning so we need to check if
|
314
|
+
#the repo is ready.
|
315
|
+
statusMessage = `git status --porcelain`
|
316
|
+
|
317
|
+
if ! statusMessage.empty? then
|
318
|
+
drawErrorLine
|
319
|
+
sayError "There are either untracked files or changes that have not been committed yet on this branch. Please solve those problems so to have a clean working directory before running the prepare merge script."
|
320
|
+
drawErrorLine
|
321
|
+
puts "This is what GIT has to say:"
|
322
|
+
puts statusMessage
|
323
|
+
exit 1
|
324
|
+
end
|
325
|
+
############################################################################
|
326
|
+
|
327
|
+
if !doContinue then
|
328
|
+
|
329
|
+
begin
|
330
|
+
Dir.mkdir(TEMP_DIR)
|
331
|
+
rescue
|
332
|
+
sayError "Looks like you are in the middle of preparing a merge"
|
333
|
+
sayError "To abort the current submission run the script with the --abort option"
|
334
|
+
sayError "To try to continue the submission run the script with the --continue option"
|
335
|
+
sayError "To stop the execution of prepare-merge without trying to set the repo back as it was before running the command run the script with --clean"
|
336
|
+
exit 1
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
drawHeadline
|
341
|
+
|
342
|
+
puts "Is this a feature or a bugfix ?"
|
343
|
+
CHOICES = ["FEATURE", "BUG FIX"]
|
344
|
+
choice = choose(*CHOICES)
|
345
|
+
choice = CHOICES.index(choice)
|
346
|
+
|
347
|
+
type = "[BUG FIX]"
|
348
|
+
if choice == 0 then
|
349
|
+
feature = ask "Input a label for the feature"
|
350
|
+
while feature.empty? do
|
351
|
+
puts "you need to bloody specify a feature"
|
352
|
+
feature = gets.chomp
|
353
|
+
end
|
354
|
+
type = "[#{feature}]"
|
355
|
+
end
|
356
|
+
|
357
|
+
title = ""
|
358
|
+
while title.empty? do
|
359
|
+
title = ask "Input a title for the commit"
|
360
|
+
end
|
361
|
+
|
362
|
+
details = ask "Input some details"
|
363
|
+
|
364
|
+
|
365
|
+
|
366
|
+
drawHeadline
|
367
|
+
sayMessage "You are on branch: " + currentBranch
|
368
|
+
|
369
|
+
sayMessage "Fetching latest stuff from origin"
|
370
|
+
repo.fetch()
|
371
|
+
|
372
|
+
#save current branch HEAD to be able to reset it back if needed
|
373
|
+
currentBranchHEAD = repo.revparse("HEAD")
|
374
|
+
sayMessage "The current HEAD for "+currentBranch+ " is :"
|
375
|
+
sayMessage currentBranchHEAD
|
376
|
+
|
377
|
+
|
378
|
+
Dir.new(TEMP_DIR)
|
379
|
+
headSHAfilePath = TEMP_DIR+File::SEPARATOR+HEAD_SHA_FILE
|
380
|
+
headSHAfile = File.new(headSHAfilePath, "w+")
|
381
|
+
headSHAfile.write(currentBranchHEAD)
|
382
|
+
headSHAfile.close
|
383
|
+
|
384
|
+
|
385
|
+
if !doContinue then
|
386
|
+
#get differences between current branch and origin/#{destination_branch}
|
387
|
+
diffs = `git log --cherry-pick --format="%H" --no-merges --right-only origin/#{destination_branch}...`
|
388
|
+
result = $?.success?
|
389
|
+
if ! result then
|
390
|
+
drawErrorLine
|
391
|
+
sayError "Something went wrong while comparing the branches."
|
392
|
+
drawErrorLine
|
393
|
+
exit 1
|
394
|
+
end
|
395
|
+
if diffs.empty? then
|
396
|
+
sayMessage "No differences between #{currentBranch} and origin/#{destination_branch}"
|
397
|
+
sayMessage "Maybe your branch has already been merged to #{destination_branch}."
|
398
|
+
exit 0
|
399
|
+
end
|
400
|
+
diffs = diffs.split($/)
|
401
|
+
#reversing the array so that the oldest commit is at the start
|
402
|
+
diffs.reverse!
|
403
|
+
sayMessage "Resetting to first commit"
|
404
|
+
sha = diffs.shift
|
405
|
+
sayMessage "SHA: #{sha}"
|
406
|
+
repo.reset_hard(sha)
|
407
|
+
#save the rest of the commits that we need to apply in a file
|
408
|
+
todofilePath = TEMP_DIR+File::SEPARATOR+TODO_FILE
|
409
|
+
todofile = File.new(todofilePath, "w+")
|
410
|
+
todofile.write(diffs.join($/))
|
411
|
+
todofile.close
|
412
|
+
end
|
413
|
+
|
414
|
+
|
415
|
+
diffs = IO.readlines(TEMP_DIR+File::SEPARATOR+TODO_FILE, $/)
|
416
|
+
|
417
|
+
while (diffs.length > 0)
|
418
|
+
sha = diffs.shift.chomp
|
419
|
+
commit = Git::Object::Commit.new(repo, sha)
|
420
|
+
sayMessage "Applying commit ..."
|
421
|
+
sayMessage "SHA: "+sha
|
422
|
+
sayMessage "Message: #{commit.message}"
|
423
|
+
system("git cherry-pick --no-commit "+sha); result = $?.success?
|
424
|
+
|
425
|
+
if ! result then
|
426
|
+
todofilePath = TEMP_DIR+File::SEPARATOR+TODO_FILE
|
427
|
+
todofile = File.new(todofilePath, "w")
|
428
|
+
diffs.each {|sha| todofile.puts(sha)}
|
429
|
+
todofile.close
|
430
|
+
sayError "Crap! You've got some conflicts! You need to solve them and then run the command with --continue"
|
431
|
+
exit 1
|
432
|
+
end
|
433
|
+
end
|
434
|
+
|
435
|
+
#ok now we commit everything
|
436
|
+
system("git add --all")
|
437
|
+
|
438
|
+
savedHEADSha = getSavedHEADsha
|
439
|
+
|
440
|
+
result = commit(type+" "+title, details, "Original branch HEAD: #{savedHEADSha}", :amend => 0)
|
441
|
+
if ! result then
|
442
|
+
drawErrorLine
|
443
|
+
sayError "something went wrong while trying to squash your commits."
|
444
|
+
sayError "check the status of your branch adn if needed abort or clean the prepare merge."
|
445
|
+
drawErrorLine
|
446
|
+
exit 1
|
447
|
+
end
|
448
|
+
|
449
|
+
removeTempFiles
|
450
|
+
sayMessage "\nYEAH! all done!\n"
|
451
|
+
|
452
|
+
rebaseNow = agree "Do you want to rebase on top of origin/#{destination_branch}?"
|
453
|
+
|
454
|
+
if rebaseNow then
|
455
|
+
result = rebaseOn(repo, "origin/#{destination_branch}")
|
456
|
+
if !result then
|
457
|
+
sayError "Rebasing has raised some conflicts and you are now in the middle of a rebase. You need to solve them manually. Unfortunately this script cannot continue automatically, so once you've solved your conflicts you need to manually run these commands:\n "
|
458
|
+
puts "git checkout #{destination_branch} && git pull origin #{destination_branch} && git merge --ff-only #{currentBranch}\n"
|
459
|
+
exit 1
|
460
|
+
end
|
461
|
+
sayMessage "Rebased successfully!\n"
|
462
|
+
drawHeadline
|
463
|
+
puts "now switch to #{destination_branch} and merge (Fast Forward) this review and then push\n\n"
|
464
|
+
puts "copy and paste the following command"
|
465
|
+
puts " "
|
466
|
+
puts "git checkout #{destination_branch} && git pull origin #{destination_branch} && git merge --ff-only #{currentBranch}"
|
467
|
+
puts " "
|
468
|
+
puts "if the commands above are run successfully you should push your #{destination_branch} to origin\n\n"
|
469
|
+
puts "git push origin #{destination_branch}"
|
470
|
+
else
|
471
|
+
drawHeadline
|
472
|
+
puts "You now need to rebase on top of origin #{destination_branch} manually."
|
473
|
+
puts " "
|
474
|
+
puts "use: git rebase origin/#{destination_branch}"
|
475
|
+
puts " "
|
476
|
+
puts "After that switch to #{destination_branch} and merge (Fast Forward) this review and then push"
|
477
|
+
puts "copy and paste the following command"
|
478
|
+
puts " "
|
479
|
+
puts "git checkout #{destination_branch} && git pull origin #{destination_branch} && git merge --ff-only #{currentBranch}"
|
480
|
+
puts " "
|
481
|
+
puts "if the commands above are run successfully you should push your #{destination_branch} to origin"
|
482
|
+
puts " "
|
483
|
+
puts "git push origin #{destination_branch}"
|
484
|
+
end
|
485
|
+
drawHeadline
|
@@ -0,0 +1,60 @@
|
|
1
|
+
|
2
|
+
module PrepareMerge
|
3
|
+
|
4
|
+
# :stopdoc:
|
5
|
+
LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
|
6
|
+
PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
|
7
|
+
VERSION = ::File.read(PATH + 'version.txt').strip
|
8
|
+
# :startdoc:
|
9
|
+
|
10
|
+
# Returns the library path for the module. If any arguments are given,
|
11
|
+
# they will be joined to the end of the libray path using
|
12
|
+
# <tt>File.join</tt>.
|
13
|
+
#
|
14
|
+
def self.libpath( *args )
|
15
|
+
rv = args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
|
16
|
+
if block_given?
|
17
|
+
begin
|
18
|
+
$LOAD_PATH.unshift LIBPATH
|
19
|
+
rv = yield
|
20
|
+
ensure
|
21
|
+
$LOAD_PATH.shift
|
22
|
+
end
|
23
|
+
end
|
24
|
+
return rv
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns the lpath for the module. If any arguments are given,
|
28
|
+
# they will be joined to the end of the path using
|
29
|
+
# <tt>File.join</tt>.
|
30
|
+
#
|
31
|
+
def self.path( *args )
|
32
|
+
rv = args.empty? ? PATH : ::File.join(PATH, args.flatten)
|
33
|
+
if block_given?
|
34
|
+
begin
|
35
|
+
$LOAD_PATH.unshift PATH
|
36
|
+
rv = yield
|
37
|
+
ensure
|
38
|
+
$LOAD_PATH.shift
|
39
|
+
end
|
40
|
+
end
|
41
|
+
return rv
|
42
|
+
end
|
43
|
+
|
44
|
+
# Utility method used to require all files ending in .rb that lie in the
|
45
|
+
# directory below this file that has the same name as the filename passed
|
46
|
+
# in. Optionally, a specific _directory_ name can be passed in such that
|
47
|
+
# the _filename_ does not have to be equivalent to the directory.
|
48
|
+
#
|
49
|
+
def self.require_all_libs_relative_to( fname, dir = nil )
|
50
|
+
dir ||= ::File.basename(fname, '.*')
|
51
|
+
search_me = ::File.expand_path(
|
52
|
+
::File.join(::File.dirname(fname), dir, '**', '*.rb'))
|
53
|
+
|
54
|
+
Dir.glob(search_me).sort.each {|rb| require rb}
|
55
|
+
end
|
56
|
+
|
57
|
+
end # module PrepareMerge
|
58
|
+
|
59
|
+
PrepareMerge.require_all_libs_relative_to(__FILE__)
|
60
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
|
2
|
+
require File.expand_path(
|
3
|
+
File.join(File.dirname(__FILE__), %w[.. lib prepare_merge]))
|
4
|
+
|
5
|
+
Spec::Runner.configure do |config|
|
6
|
+
# == Mock Framework
|
7
|
+
#
|
8
|
+
# RSpec uses it's own mocking framework by default. If you prefer to
|
9
|
+
# use mocha, flexmock or RR, uncomment the appropriate line:
|
10
|
+
#
|
11
|
+
# config.mock_with :mocha
|
12
|
+
# config.mock_with :flexmock
|
13
|
+
# config.mock_with :rr
|
14
|
+
end
|
15
|
+
|
File without changes
|
data/version.txt
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.1
|
metadata
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: git-prepare-merge
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Simone Vicentini - HuzuTech ltd
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-01-18 00:00:00.000000000 +00:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: git
|
17
|
+
requirement: &27820392 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 1.2.5
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *27820392
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: highline
|
28
|
+
requirement: &27820020 !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.6.2
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: *27820020
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: OptionParser
|
39
|
+
requirement: &27819660 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ! '>='
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: 0.5.1
|
45
|
+
type: :runtime
|
46
|
+
prerelease: false
|
47
|
+
version_requirements: *27819660
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: bones
|
50
|
+
requirement: &27819240 !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ! '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: 3.7.0
|
56
|
+
type: :development
|
57
|
+
prerelease: false
|
58
|
+
version_requirements: *27819240
|
59
|
+
description: Git Scripts to ease the merging of review branches into develop.
|
60
|
+
email: simone.vicentini@huzutech.com
|
61
|
+
executables:
|
62
|
+
- git-compare-branches
|
63
|
+
- git-prepare-merge
|
64
|
+
extensions: []
|
65
|
+
extra_rdoc_files:
|
66
|
+
- History.txt
|
67
|
+
- bin/git-compare-branches
|
68
|
+
- bin/git-prepare-merge
|
69
|
+
files:
|
70
|
+
- History.txt
|
71
|
+
- README.md
|
72
|
+
- Rakefile
|
73
|
+
- bin/git-compare-branches
|
74
|
+
- bin/git-prepare-merge
|
75
|
+
- lib/prepare_merge.rb
|
76
|
+
- spec/prepare_merge_spec.rb
|
77
|
+
- spec/spec_helper.rb
|
78
|
+
- test/test_prepare_merge.rb
|
79
|
+
- version.txt
|
80
|
+
has_rdoc: true
|
81
|
+
homepage: http://www.huzutech.com
|
82
|
+
licenses: []
|
83
|
+
post_install_message:
|
84
|
+
rdoc_options:
|
85
|
+
- --main
|
86
|
+
- README.md
|
87
|
+
require_paths:
|
88
|
+
- lib
|
89
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ! '>='
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
|
+
none: false
|
97
|
+
requirements:
|
98
|
+
- - ! '>='
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '0'
|
101
|
+
requirements: []
|
102
|
+
rubyforge_project: git-prepare-merge
|
103
|
+
rubygems_version: 1.5.2
|
104
|
+
signing_key:
|
105
|
+
specification_version: 3
|
106
|
+
summary: Git Scripts to ease the merging of review branches into develop.
|
107
|
+
test_files:
|
108
|
+
- test/test_prepare_merge.rb
|