git-prepare-merge 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|