git-scripts 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. data/COPYING +21 -0
  2. data/README.md +124 -0
  3. data/Rakefile +35 -0
  4. data/bash_completion.sh +33 -0
  5. data/bin/feature +191 -0
  6. data/bin/hotfix +142 -0
  7. data/lib/git.rb +170 -0
  8. data/lib/github.rb +190 -0
  9. data/lib/helpers.rb +137 -0
  10. data/man/feature-clean.1 +28 -0
  11. data/man/feature-clean.1.html +115 -0
  12. data/man/feature-clean.1.markdown +53 -0
  13. data/man/feature-clean.1.ronn +26 -0
  14. data/man/feature-finish.1 +19 -0
  15. data/man/feature-finish.1.html +107 -0
  16. data/man/feature-finish.1.markdown +47 -0
  17. data/man/feature-finish.1.ronn +21 -0
  18. data/man/feature-github-test.1 +19 -0
  19. data/man/feature-github-test.1.html +105 -0
  20. data/man/feature-github-test.1.markdown +45 -0
  21. data/man/feature-github-test.1.ronn +19 -0
  22. data/man/feature-list.1 +19 -0
  23. data/man/feature-list.1.html +106 -0
  24. data/man/feature-list.1.markdown +46 -0
  25. data/man/feature-list.1.ronn +20 -0
  26. data/man/feature-merge.1 +22 -0
  27. data/man/feature-merge.1.html +110 -0
  28. data/man/feature-merge.1.markdown +50 -0
  29. data/man/feature-merge.1.ronn +24 -0
  30. data/man/feature-start.1 +19 -0
  31. data/man/feature-start.1.html +105 -0
  32. data/man/feature-start.1.markdown +45 -0
  33. data/man/feature-start.1.ronn +19 -0
  34. data/man/feature-stashes.1 +28 -0
  35. data/man/feature-stashes.1.html +117 -0
  36. data/man/feature-stashes.1.markdown +55 -0
  37. data/man/feature-stashes.1.ronn +28 -0
  38. data/man/feature-status.1 +22 -0
  39. data/man/feature-status.1.html +108 -0
  40. data/man/feature-status.1.markdown +48 -0
  41. data/man/feature-status.1.ronn +22 -0
  42. data/man/feature-switch.1 +25 -0
  43. data/man/feature-switch.1.html +113 -0
  44. data/man/feature-switch.1.markdown +51 -0
  45. data/man/feature-switch.1.ronn +24 -0
  46. data/man/feature.1 +61 -0
  47. data/man/feature.1.html +123 -0
  48. data/man/feature.1.markdown +70 -0
  49. data/man/feature.1.ronn +43 -0
  50. data/man/feature.html +140 -0
  51. data/man/hotfix-finish.1 +19 -0
  52. data/man/hotfix-finish.1.html +107 -0
  53. data/man/hotfix-finish.1.markdown +47 -0
  54. data/man/hotfix-finish.1.ronn +21 -0
  55. data/man/hotfix-list.1 +19 -0
  56. data/man/hotfix-list.1.html +106 -0
  57. data/man/hotfix-list.1.markdown +46 -0
  58. data/man/hotfix-list.1.ronn +20 -0
  59. data/man/hotfix-merge.1 +22 -0
  60. data/man/hotfix-merge.1.html +110 -0
  61. data/man/hotfix-merge.1.markdown +50 -0
  62. data/man/hotfix-merge.1.ronn +24 -0
  63. data/man/hotfix-start.1 +19 -0
  64. data/man/hotfix-start.1.html +105 -0
  65. data/man/hotfix-start.1.markdown +45 -0
  66. data/man/hotfix-start.1.ronn +19 -0
  67. data/man/hotfix-switch.1 +19 -0
  68. data/man/hotfix-switch.1.html +105 -0
  69. data/man/hotfix-switch.1.markdown +45 -0
  70. data/man/hotfix-switch.1.ronn +19 -0
  71. data/man/hotfix.1 +41 -0
  72. data/man/hotfix.1.html +118 -0
  73. data/man/hotfix.1.markdown +60 -0
  74. data/man/hotfix.1.ronn +33 -0
  75. data/man/index.html +7 -0
  76. data/man/index.txt +21 -0
  77. metadata +177 -0
data/COPYING ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+ Copyright (c) 2012-2013 iFixit
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
5
+ this software and associated documentation files (the "Software"), to deal in
6
+ the Software without restriction, including without limitation the rights to
7
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
8
+ of the Software, and to permit persons to whom the Software is furnished to do
9
+ so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ SOFTWARE.
21
+
data/README.md ADDED
@@ -0,0 +1,124 @@
1
+ # Git Scripts
2
+
3
+ User scripts for easily managing feature branches and hotfixes.
4
+
5
+ ## Installation
6
+ ```bash
7
+ gem install git-scripts
8
+ ```
9
+
10
+ or
11
+
12
+ ```bash
13
+ git clone git://github.com/iFixit/git-scripts.git
14
+ cd git-scripts
15
+ bundle install
16
+ ln -s ${PWD}/bin/feature /path/to/bin/dir/
17
+ ln -s ${PWD}/bin/hotfix /path/to/bin/dir/
18
+ ```
19
+
20
+ ## Branching Model
21
+
22
+ This is loosely based on the [Git Flow][gitflow] branching model, with a couple
23
+ of noteable changes. Essentially Git Flow's `develop` is our `master`, Git
24
+ Flow's `master` is our `stable`, and there are no `release` branches and our
25
+ `hotfix` branch names all have a prefix.
26
+
27
+ **master** is the active development branch, and what our development server
28
+ has checked out. This is configurable using: `git config
29
+ feature.development_branch branch-name`
30
+
31
+ **stable** is the branch which is deployed on the production machines. You
32
+ should always be able to check out this branch and get "bug-free" production
33
+ code. This branch is always ready-to-go and should always be deployed as soon
34
+ as it's changed
35
+
36
+ **feature branches** are named after the feature you're developing and branched
37
+ from `master`. When finished, the feature branch is merged back into master
38
+ with `--no-ff` (so we preserve the merge commit) and deleted.
39
+
40
+ **hotfix branches** are named `hotfix-name` and branched from `stable`. When
41
+ finished, the hotfix branch is merged back into `stable` with `--no-ff` so we
42
+ preserve the merge commit. We attempt to merge it back into `master` as well,
43
+ but if it's going to get messy just bail.
44
+
45
+ ## Deployment
46
+
47
+ The production machines always run off the `stable` branch. When deploying,
48
+ you need to:
49
+
50
+ * Merge `stable` into `master` (and vice-versa). This ensures that the two code
51
+ paths come together relatively frequently. This also guarantees that we'll
52
+ pick up any stray hotfixes that didn't get merged back.
53
+
54
+ * Create a tag on `stable` for keeping track of deploys
55
+
56
+ ## feature script
57
+
58
+ feature <command> [branch name]
59
+
60
+ Automates some of the git commands for dealing with feature branches. Any
61
+ command that is run with missing arguments will just print the help and exit.
62
+ Any command that modifies the working dir should warn the user and exit(1) if
63
+ the working tree is dirty; automatically managing the stash is frought with
64
+ danger.
65
+
66
+ feature start my-awesome-thing
67
+
68
+ If the branch `my-awesome-thing` does not exist, a new feature branch
69
+ from `master` will be created after a confirmation, and runs a
70
+ `git checkout my-awesome-thing` to drop you on the new branch.
71
+
72
+ feature switch your-neato-thing
73
+
74
+ Assuming the branch `your-neato-thing` exists, it checks out that branch and
75
+ informs you about any stashes saved on that branch.
76
+
77
+ feature finish [your-neato-thing]
78
+
79
+ Creates a pull-request on Github for the current or specified feature branch.
80
+
81
+ feature merge [your-neato-thing]
82
+
83
+ Merges the feature branch back in to `master`, using `--no-ff` to ensure it's a
84
+ non-fast-forward merge. This attempts to get a pull request description from
85
+ the github API.
86
+
87
+ feature status
88
+
89
+ Shows a graphical commit log of the history between the current branch and the
90
+ remote version of the current branch (the upstream).
91
+
92
+ feature stashes
93
+
94
+ Lists the stashes saved on the current branch if any. -v shows all stashes on
95
+ all branches.
96
+
97
+ ## hotfix script
98
+
99
+ hotfix <command> [branch name]
100
+
101
+ Automates the process of fixing a bug on the live site, similar to the
102
+ `feature` script with a few differences. Any command that is run with missing
103
+ arguments will just print the help and exit
104
+
105
+ hotfix start my-sweet-fix
106
+
107
+ Makes a new branch from `stable` named `hotfix_my-sweet-fix`. Prepending the
108
+ name with `hotfix_` allows easy filtering.
109
+
110
+ hotfix switch my-other-fix
111
+
112
+ Switches hotfix branches. Assuming the branch `hotfix_my-other-fix` exists, it
113
+ checks out that branch and informs you about any stashes saved on that branch.
114
+
115
+ hotfix finish [my-other-fix]
116
+
117
+ Creates a pull-request on Github for the current or specified hotfix branch.
118
+
119
+ hotfix merge [my-other-fix]
120
+
121
+ Merges the hotfix branch back into `stable` with `--no-ff`. Also does a
122
+ merge back into `master`.
123
+
124
+ [gitflow]: http://nvie.com/posts/a-successful-git-branching-model/
data/Rakefile ADDED
@@ -0,0 +1,35 @@
1
+ require 'mg'
2
+ MG.new 'git-scripts.gemspec'
3
+
4
+ desc 'Build the manual'
5
+ task :man do
6
+ require 'ronn'
7
+ ENV['RONN_ORGANIZATION'] = 'iFixit'
8
+ sh "ronn -w -s toc -r5 --markdown man/*.ronn"
9
+ end
10
+
11
+ desc 'Publish to github pages'
12
+ task :pages => :man do
13
+ puts '----------------------------------------------'
14
+ puts 'Rebuilding pages ...'
15
+ verbose(false) {
16
+ rm_rf 'pages'
17
+ push_url = `git remote show origin`.each_line.grep(/Push.*URL/).first[/git@.*/]
18
+ sh "
19
+ set -ex
20
+ git fetch -q origin
21
+ rev=$(git rev-parse origin/gh-pages)
22
+ git clone -q -b gh-pages . pages
23
+ cd pages
24
+ git reset --hard $rev
25
+ rm -f *
26
+ cp -rp ../man/*.html ../man/index.txt ./
27
+ git add -A .
28
+ git commit -m 'Rebuild manual.'
29
+ git push #{push_url} gh-pages
30
+ cd ..
31
+ rm -rf pages
32
+ ", :verbose => false
33
+ }
34
+ end
35
+
@@ -0,0 +1,33 @@
1
+ #!/bin/sh
2
+
3
+ _git-scripts()
4
+ {
5
+ local cmd="${1##*/}"
6
+ local cur=${COMP_WORDS[COMP_CWORD]}
7
+ local line=${COMP_LINE}
8
+
9
+ # Check to see what command is being executed.
10
+ case "$cmd" in
11
+ feature)
12
+ if [ "$line" = "$cmd $cur" ]; then
13
+ words="switch start finish stashes list merge pull status clean"
14
+ else
15
+ # get branch names minus hotfixes
16
+ words="$(git branch -a | tr -d ' *' | grep -v 'hotfix-' | sed 's|remotes/origin/||')"
17
+ fi
18
+ ;;
19
+ hotfix)
20
+ if [ "$line" = "$cmd $cur" ]; then
21
+ words="switch start finish merge list clean"
22
+ else
23
+ # get hotfix branch names
24
+ words="$(git branch -a | tr -d ' *' | grep 'hotfix-' | sed -e 's|remotes/origin/||' -e 's|hotfix-||')"
25
+ fi
26
+ ;;
27
+ esac
28
+
29
+ COMPREPLY=($(compgen -W "${words}" -- ${cur}))
30
+ return 0
31
+ }
32
+
33
+ complete -F _git-scripts feature hotfix
data/bin/feature ADDED
@@ -0,0 +1,191 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative '../lib/github.rb'
3
+ require_relative '../lib/git.rb'
4
+ require_relative '../lib/helpers.rb'
5
+
6
+ command=ARGV.first
7
+
8
+ case command
9
+ when 'github-test'
10
+ octokit = Github::api
11
+ # Should succeed if authentication is setup.
12
+ octokit.pulls(Github::get_github_repo)
13
+ puts "[Successfully Authenticated]"
14
+
15
+ when 'start'
16
+ require_argument(:feature, :start)
17
+ feature = ARGV[1]
18
+
19
+ exit if !confirm("Create feature branch named: '#{feature}' ?")
20
+
21
+ Git::run_safe("git checkout #{Git::development_branch}")
22
+ Git::run_safe("git pull --rebase")
23
+ Git::run_safe("git branch \"#{feature}\" #{Git::development_branch}")
24
+ Git::run_safe("git checkout \"#{feature}\"")
25
+
26
+ Git::submodules_update
27
+
28
+ # Automatically setup remote tracking branch
29
+ Git::run_safe("git config branch.#{feature}.remote origin")
30
+ Git::run_safe("git config branch.#{feature}.merge refs/heads/#{feature}")
31
+ Git::run_safe("git config branch.#{feature}.rebase true")
32
+
33
+ puts "Successfully created a new feature-branch: #{feature}"
34
+
35
+ when 'status'
36
+ current = Git::current_branch
37
+ Git::run_safe("git fetch")
38
+
39
+ upstream = `git rev-parse --verify --quiet #{current}@{upstream} 2>/dev/null`.strip
40
+ if upstream == ''
41
+ die "Your branch #{current} hasn't been pushed"
42
+ end
43
+
44
+ git_command = 'git log --graph --boundary --color=always --decorate --date-order'
45
+ incoming = `#{git_command} #{current}..#{upstream}`.strip
46
+ outgoing = `#{git_command} #{upstream}..#{current}`.strip
47
+ incoming = nil if incoming == ''
48
+ outgoing = nil if outgoing == ''
49
+
50
+ if (incoming && outgoing)
51
+ # Show the whole history graph (... == through common ancestor)
52
+ puts `#{git_command} #{upstream}...#{current}`.strip
53
+ puts HIGHLIGHT
54
+ puts "Your branch has diverged from the remote branch"
55
+ elsif incoming
56
+ puts incoming
57
+ puts HIGHLIGHT
58
+ puts "Your branch is behind the remote branch"
59
+ elsif outgoing
60
+ puts outgoing
61
+ puts HIGHLIGHT
62
+ puts "Your branch is ahead of the remote branch"
63
+ else
64
+ puts HIGHLIGHT
65
+ puts "Your branch is up to date"
66
+ end
67
+ print HIGHLIGHT_OFF
68
+
69
+
70
+ when 'finish'
71
+ feature = ARGV[1] || Git::current_branch
72
+ # Push commits to origin
73
+ Git::run_safe("git push origin #{feature}:#{feature}")
74
+
75
+ exit 1 if !confirm("Create a pull-request for feature branch named: '#{feature}' ?")
76
+ octokit = Github::api
77
+
78
+ description = Github::get_pull_request_description(feature)
79
+ puts "Pull-request description:"
80
+ puts description[:title]
81
+ puts "#"
82
+ puts description[:body]
83
+
84
+ response = octokit.create_pull_request(
85
+ Github::get_github_repo,
86
+ Git::development_branch,
87
+ feature,
88
+ description[:title],
89
+ description[:body]
90
+ )
91
+
92
+ puts "Successfully created pull-request ##{response[:number]}"
93
+ puts " " + response[:html_url]
94
+
95
+ when 'merge'
96
+ dev_branch = Git::development_branch
97
+ fail_on_local_changes
98
+ Git::run_safe("git fetch")
99
+
100
+ feature = ARGV[1] || Git::current_branch
101
+
102
+ exit 1 if !confirm("Merge feature branch named: '#{feature}' ?")
103
+
104
+ description = Github::get_pull_request_description_from_api(feature, dev_branch)
105
+
106
+ # Checkout the branch first to make sure we have it locally.
107
+ Git::run_safe("git fetch")
108
+ Git::run_safe("git checkout \"#{feature}\"")
109
+
110
+ Git::run_safe("git rebase --preserve-merges origin/#{feature}")
111
+
112
+ # pull the latest changes from master
113
+ Git::run_safe("git checkout #{dev_branch}")
114
+
115
+ # rebase the unpushed master commits if any.
116
+ Git::run_safe("git rebase --preserve-merges origin/#{dev_branch}")
117
+
118
+ # merge the feature branch into master
119
+ Git::run_safe("git merge --no-ff --edit -m #{description.shellescape} \"#{feature}\"")
120
+
121
+ # init any submodules in the master branch
122
+ Git::submodules_update
123
+
124
+ # delete the local feature-branch
125
+ Git::run_safe("git branch -d \"#{feature}\"")
126
+
127
+ # delete the remote branch we'll leave this off for now
128
+ # Git::run_safe("git push origin :\"#{feature}\"")
129
+ # push the the merge to our origin
130
+ # Git::run_safe("git push origin")
131
+
132
+ puts
133
+ puts "Successfully merged feature-branch: #{feature} into #{dev_branch}"
134
+
135
+ when 'switch'
136
+ require_argument(:feature, :switch, min=2, max=3)
137
+ feature = ARGV[1]
138
+
139
+ Git::switch_branch(feature)
140
+
141
+ when 'clean'
142
+ args = ''
143
+
144
+ # Remove all untracked .gitignored files as well
145
+ args += 'x' if ARGV.include?('--all')
146
+
147
+ # -fd alone will NOT remove submodule directories, -ffd is required for this
148
+ Git::run_safe("git clean -ffd#{args}")
149
+
150
+ when 'pull'
151
+ Git::run_safe("git fetch")
152
+
153
+ current = Git::current_branch
154
+ upstream = "#{current}@{upstream}"
155
+ upstream_hash = Git::branch_hash(upstream)
156
+
157
+ if upstream_hash == ''
158
+ die "Your branch #{current} hasn't been pushed, nothing to pull from"
159
+ end
160
+
161
+ old_branch_hash = Git::branch_hash(current)
162
+ Git::run_safe("git rebase --preserve-merges origin/#{current}")
163
+
164
+ Git::submodules_update
165
+
166
+ if Git::branch_hash(current) == old_branch_hash
167
+ die "No changes in the remote branch. Your branch is up to date."
168
+ end
169
+
170
+ when 'list'
171
+ options = {
172
+ :feature => Git::feature_branches(:unmerged)
173
+ }
174
+ if ARGV.include?('-v')
175
+ options[:merged] = Git::feature_branches(:merged)
176
+ end
177
+ Git.show_branch_list(options)
178
+
179
+ when 'stashes'
180
+ current_branch = nil
181
+
182
+ if !ARGV.include?('-v')
183
+ current_branch = Git::current_branch
184
+ end
185
+
186
+ Git::show_stashes_saved_on(current_branch)
187
+
188
+ else
189
+ display_feature_help
190
+ end
191
+
data/bin/hotfix ADDED
@@ -0,0 +1,142 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative '../lib/github.rb'
3
+ require_relative '../lib/git.rb'
4
+ require_relative '../lib/helpers.rb'
5
+
6
+ command=ARGV.first
7
+ BRANCH_PREFIX = "hotfix-"
8
+ case command
9
+ when 'start'
10
+ require_argument(:hotfix, :start)
11
+ hotfix = BRANCH_PREFIX + ARGV[1]
12
+
13
+ exit if !confirm("Create hotfix branch named: '#{hotfix}' ?")
14
+
15
+ Git::run_safe("git checkout stable")
16
+ Git::run_safe("git pull --rebase")
17
+ Git::run_safe("git branch \"#{hotfix}\" stable")
18
+ Git::run_safe("git checkout \"#{hotfix}\"")
19
+
20
+ Git::submodules_update
21
+
22
+ # Automatically setup remote tracking branch
23
+ Git::run_safe("git config branch.#{hotfix}.remote origin")
24
+ Git::run_safe("git config branch.#{hotfix}.merge refs/heads/#{hotfix}")
25
+ Git::run_safe("git config branch.#{hotfix}.rebase true")
26
+
27
+ when 'switch'
28
+ require_argument(:hotfix, :switch, min=2, max=3)
29
+ hotfix = BRANCH_PREFIX + ARGV[1]
30
+
31
+ Git::switch_branch(hotfix)
32
+
33
+ when 'finish'
34
+ hotfix = ARGV[1] || Git::current_branch
35
+
36
+ # ensure the hotfix name is the real branch name
37
+ if (!hotfix.start_with?("hotfix-"))
38
+ hotfix = "hotfix-" + hotfix
39
+ end
40
+
41
+ # Push commits to origin
42
+ Git::run_safe("git push origin #{hotfix}:#{hotfix}")
43
+
44
+ exit 1 if !confirm("Create a pull-request for hotfix branch named: '#{hotfix}' ?")
45
+ octokit = Github::api
46
+
47
+ description = Github::get_pull_request_description(hotfix)
48
+ puts "Pull-request description:"
49
+ puts description[:title]
50
+ puts "#"
51
+ puts description[:body]
52
+
53
+ response = octokit.create_pull_request(
54
+ Github::get_github_repo,
55
+ 'stable',
56
+ hotfix,
57
+ description[:title],
58
+ description[:body]
59
+ )
60
+
61
+ puts "Successfully created pull-request ##{response[:number]}"
62
+ puts " " + response[:html_url]
63
+
64
+ when 'merge'
65
+ fail_on_local_changes
66
+ dev_branch = Git::development_branch
67
+
68
+ Git::run_safe("git fetch")
69
+
70
+ if ARGV[1]
71
+ hotfix = BRANCH_PREFIX + ARGV[1]
72
+ else
73
+ hotfix = Git::current_branch
74
+ end
75
+
76
+ exit 1 if !confirm("Merge hotfix named: '#{hotfix}' ?")
77
+
78
+ description = Github::get_pull_request_description_from_api(hotfix, 'stable')
79
+
80
+ # Checkout the branch to make sure we have it locally.
81
+ Git::run_safe("git checkout \"#{hotfix}\"")
82
+ Git::run_safe("git rebase --preserve-merges origin/#{hotfix}")
83
+
84
+ # Merge into stable
85
+ Git::run_safe("git checkout stable")
86
+
87
+ # pull the latest changes and rebase the unpushed commits if any.
88
+ Git::run_safe("git rebase --preserve-merges origin/stable")
89
+
90
+ # merge the hotfix branch into stable
91
+ Git::run_safe("git merge --no-ff --edit -m #{description.shellescape} \"#{hotfix}\"")
92
+
93
+ # init any submodules in the stable branch
94
+ Git::submodules_update
95
+ # push the the merge to our origin
96
+ # Git::run_safe("git push origin")
97
+
98
+ description = Github::get_pull_request_description_from_api(hotfix, dev_branch)
99
+
100
+ # Merge into master
101
+ Git::run_safe("git checkout #{dev_branch}")
102
+
103
+ # pull the latest changes and rebase the unpushed master commits if any.
104
+ Git::run_safe("git rebase origin/#{dev_branch}")
105
+
106
+ # merge the hotfix branch into master
107
+ Git::run_safe("git merge --no-ff --edit -m #{description.shellescape} \"#{hotfix}\"")
108
+
109
+ # init any submodules in the master branch. Note: no need to change
110
+ # directories before calling git submodule since we are already in the
111
+ # projects top-level directory
112
+ Git::submodules_update
113
+
114
+ # push the the merge to our origin
115
+ # Git::run_safe("git push origin")
116
+
117
+ # delete the local hotfix branch
118
+ Git::run_safe("git branch -d \"#{hotfix}\"")
119
+ # delete the remote hotfix branch -- we'll leave this off for now
120
+ # Git::run_safe("git push origin :\"#{hotfix}\"")
121
+
122
+ # checkout stable branch
123
+ Git::run_safe("git checkout stable")
124
+
125
+ puts "Successfully merged hotfix branch: #{hotfix} into stable and #{dev_branch}"
126
+ puts "If you are satisfied with the result, do this:\n" + <<CMDS
127
+ git push
128
+ git checkout #{dev_branch}
129
+ git push
130
+ CMDS
131
+
132
+ when 'list'
133
+ options = {
134
+ :hotfix => Git::hotfix_branches(:unmerged)
135
+ }
136
+ if ARGV.include?('-v')
137
+ options[:merged] = Git::hotfix_branches(:merged)
138
+ end
139
+ Git.show_branch_list(options)
140
+ else
141
+ display_hotfix_help
142
+ end