git_reflow 0.2
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/.gitignore +0 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +91 -0
- data/README.rdoc +39 -0
- data/Rakefile +13 -0
- data/bin/git-reflow +125 -0
- data/bin/gitreflow-common +314 -0
- data/features/step_definitions/debug_steps.rb +4 -0
- data/features/step_definitions/gem_steps.rb +3 -0
- data/features/step_definitions/git_steps.rb +138 -0
- data/features/support/env.rb +27 -0
- data/features/support/gem.rb +85 -0
- data/features/support/github_helpers.rb +3 -0
- data/features/user_delivers_flow.feature +22 -0
- data/features/user_installs_gem.feature +18 -0
- data/features/user_starts_flow.feature +19 -0
- data/git_reflow.gemspec +32 -0
- data/lib/git_reflow/base.rb +0 -0
- data/lib/git_reflow/version.rb +3 -0
- data/lib/git_reflow.rb +233 -0
- data/spec/fixtures/git/git_config +7 -0
- data/spec/fixtures/pull_requests/pull_request.json +123 -0
- data/spec/fixtures/pull_requests/pull_request_exists_error.json +32 -0
- data/spec/fixtures/pull_requests/pull_requests.json +117 -0
- data/spec/git_reflow_spec.rb +139 -0
- data/spec/spec_helper.rb +28 -0
- data/spec/support/fixtures.rb +8 -0
- data/spec/support/github_helpers.rb +45 -0
- data/spec/support/web_mocks.rb +39 -0
- metadata +287 -0
data/.gitignore
ADDED
File without changes
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
git_reflow (0.2)
|
5
|
+
github_api (= 0.6.5)
|
6
|
+
gli (= 2.0.0)
|
7
|
+
highline
|
8
|
+
httpclient
|
9
|
+
json_pure (= 1.7.5)
|
10
|
+
|
11
|
+
GEM
|
12
|
+
remote: http://rubygems.org/
|
13
|
+
specs:
|
14
|
+
addressable (2.3.2)
|
15
|
+
aruba (0.4.11)
|
16
|
+
childprocess (>= 0.2.3)
|
17
|
+
cucumber (>= 1.1.1)
|
18
|
+
ffi (>= 1.0.11)
|
19
|
+
rspec (>= 2.7.0)
|
20
|
+
builder (3.0.0)
|
21
|
+
childprocess (0.3.5)
|
22
|
+
ffi (~> 1.0, >= 1.0.6)
|
23
|
+
crack (0.3.1)
|
24
|
+
cucumber (1.2.1)
|
25
|
+
builder (>= 2.1.2)
|
26
|
+
diff-lcs (>= 1.1.3)
|
27
|
+
gherkin (~> 2.11.0)
|
28
|
+
json (>= 1.4.6)
|
29
|
+
diff-lcs (1.1.3)
|
30
|
+
faraday (0.8.4)
|
31
|
+
multipart-post (~> 1.1)
|
32
|
+
ffi (1.1.5)
|
33
|
+
gherkin (2.11.2)
|
34
|
+
json (>= 1.4.6)
|
35
|
+
git (1.2.5)
|
36
|
+
github_api (0.6.5)
|
37
|
+
faraday (~> 0.8.1)
|
38
|
+
hashie (~> 1.2.0)
|
39
|
+
multi_json (~> 1.3)
|
40
|
+
nokogiri (~> 1.5.2)
|
41
|
+
oauth2
|
42
|
+
gli (2.0.0)
|
43
|
+
hashie (1.2.0)
|
44
|
+
highline (1.6.14)
|
45
|
+
httpauth (0.1)
|
46
|
+
httpclient (2.2.7)
|
47
|
+
jeweler (1.8.4)
|
48
|
+
bundler (~> 1.0)
|
49
|
+
git (>= 1.2.5)
|
50
|
+
rake
|
51
|
+
rdoc
|
52
|
+
json (1.7.5)
|
53
|
+
json_pure (1.7.5)
|
54
|
+
jwt (0.1.5)
|
55
|
+
multi_json (>= 1.0)
|
56
|
+
multi_json (1.3.6)
|
57
|
+
multipart-post (1.1.5)
|
58
|
+
nokogiri (1.5.5)
|
59
|
+
oauth2 (0.8.0)
|
60
|
+
faraday (~> 0.8)
|
61
|
+
httpauth (~> 0.1)
|
62
|
+
jwt (~> 0.1.4)
|
63
|
+
multi_json (~> 1.0)
|
64
|
+
rack (~> 1.2)
|
65
|
+
rack (1.4.1)
|
66
|
+
rake (0.9.2.2)
|
67
|
+
rdoc (3.12)
|
68
|
+
json (~> 1.4)
|
69
|
+
rspec (2.11.0)
|
70
|
+
rspec-core (~> 2.11.0)
|
71
|
+
rspec-expectations (~> 2.11.0)
|
72
|
+
rspec-mocks (~> 2.11.0)
|
73
|
+
rspec-core (2.11.1)
|
74
|
+
rspec-expectations (2.11.2)
|
75
|
+
diff-lcs (~> 1.1.3)
|
76
|
+
rspec-mocks (2.11.2)
|
77
|
+
webmock (1.8.9)
|
78
|
+
addressable (>= 2.2.7)
|
79
|
+
crack (>= 0.1.7)
|
80
|
+
|
81
|
+
PLATFORMS
|
82
|
+
ruby
|
83
|
+
|
84
|
+
DEPENDENCIES
|
85
|
+
aruba (~> 0.4.6)
|
86
|
+
git_reflow!
|
87
|
+
jeweler
|
88
|
+
rake
|
89
|
+
rdoc
|
90
|
+
rspec
|
91
|
+
webmock
|
data/README.rdoc
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
git-reflow
|
2
|
+
==========
|
3
|
+
Tools to help build software that just works.
|
4
|
+
|
5
|
+
How it works
|
6
|
+
-------------
|
7
|
+
`$ git reflow setup`
|
8
|
+
Sets up your Github credentials
|
9
|
+
|
10
|
+
`$ git reflow start branch-name`
|
11
|
+
Creates new branch
|
12
|
+
Prompts for PT ticket numbers? (Keep the PT stuff as a plugin?)
|
13
|
+
|
14
|
+
`$ git reflow review [branch]`
|
15
|
+
Assumes remote 'origin'
|
16
|
+
Performs the following against [branch] or master if branch is not specified:
|
17
|
+
`git fetch origin`
|
18
|
+
- Are we up-to-date with changes from the destination?
|
19
|
+
- Fail with "origin/[branch] has newer changes" if no
|
20
|
+
- Run the test suite
|
21
|
+
- If fails, do not continue
|
22
|
+
- If not configured, fail with "Run test suite then use flag --green"
|
23
|
+
`git push origin current-branch` # Updates remote branch
|
24
|
+
- Do we have pull request?
|
25
|
+
- if no, create it and print "Pull request created at http://pull-url/"
|
26
|
+
|
27
|
+
`$ git reflow deliver [branch]`
|
28
|
+
- Do we have lgtm after last commit?
|
29
|
+
- If no, print "Still waiting for review" (Maybe provide a way to skip this with `--lgtm`?)
|
30
|
+
- Prompt "Accepted by:" and get name/email/github username of person who does acceptance
|
31
|
+
- Checkout destination branch
|
32
|
+
- Update destination from origin (`git pull origin [branch]`)
|
33
|
+
- Merge squashed (`git merge --squash branch-name`)
|
34
|
+
- Prepare commit message (Adds Closes #pull-request-number)
|
35
|
+
- Perform the commit
|
36
|
+
- Push to branch
|
37
|
+
- Delete the remote branch
|
38
|
+
- Delete the local branch
|
39
|
+
- Deploy (Maybe with flag `--deploy`)
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'bundler/gem_tasks'
|
3
|
+
require 'cucumber'
|
4
|
+
require 'cucumber/rake/task'
|
5
|
+
|
6
|
+
Dir[File.join(File.dirname(__FILE__),'lib/tasks/*.rake')].each { |f| load f }
|
7
|
+
|
8
|
+
Cucumber::Rake::Task.new(:features) do |t|
|
9
|
+
t.cucumber_opts = "features --format pretty -x"
|
10
|
+
t.fork = false
|
11
|
+
end
|
12
|
+
|
13
|
+
task :default => [:spec, :cucumber]
|
data/bin/git-reflow
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# 1.9 adds realpath to resolve symlinks; 1.8 doesn't
|
3
|
+
# have this method, so we add it so we get resolved symlinks
|
4
|
+
# and compatibility
|
5
|
+
unless File.respond_to? :realpath
|
6
|
+
class File #:nodoc:
|
7
|
+
def self.realpath path
|
8
|
+
return realpath(File.readlink(path)) if symlink?(path)
|
9
|
+
path
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
$: << File.expand_path(File.dirname(File.realpath(__FILE__)) + '/../lib')
|
14
|
+
require 'rubygems'
|
15
|
+
require 'gli'
|
16
|
+
require 'git_reflow'
|
17
|
+
require 'git_reflow/version'
|
18
|
+
|
19
|
+
include GLI::App
|
20
|
+
|
21
|
+
program_desc 'Git Reflow manages your git workflow.'
|
22
|
+
|
23
|
+
version GitReflow::VERSION
|
24
|
+
|
25
|
+
desc 'Describe some switch here'
|
26
|
+
switch [:s,:switch]
|
27
|
+
|
28
|
+
desc 'Describe some flag here'
|
29
|
+
default_value 'the default'
|
30
|
+
arg_name 'The name of the argument'
|
31
|
+
flag [:f,:flagname]
|
32
|
+
|
33
|
+
desc 'Setup your GitHub account'
|
34
|
+
command :setup do |c|
|
35
|
+
c.action do |global_options,options,args|
|
36
|
+
GitReflow.setup
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
desc 'Start will create a new feature branch and setup remote tracking'
|
41
|
+
arg_name 'Describe arguments to start here'
|
42
|
+
command :start do |c|
|
43
|
+
c.desc 'Describe a switch to start'
|
44
|
+
c.switch :s
|
45
|
+
|
46
|
+
c.desc 'Describe a flag to start'
|
47
|
+
c.default_value 'default'
|
48
|
+
c.flag :f
|
49
|
+
c.action do |global_options,options,args|
|
50
|
+
|
51
|
+
# Your command logic here
|
52
|
+
if args.empty?
|
53
|
+
raise "usage: git-reflow start [new-branch-name]"
|
54
|
+
else
|
55
|
+
`git push origin master:refs/heads/#{args[0]}`
|
56
|
+
`git fetch origin`
|
57
|
+
`git checkout --track -b #{args[0]} origin/#{args[0]}`
|
58
|
+
end
|
59
|
+
# If you have any errors, just raise them
|
60
|
+
# raise "that command made no sense"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
desc 'Describe review here'
|
65
|
+
arg_name 'Describe arguments to review here'
|
66
|
+
command :review do |c|
|
67
|
+
c.action do |global_options,options,args|
|
68
|
+
review_options = {'base' => nil, 'title' => nil, 'body' => nil}
|
69
|
+
case args.length
|
70
|
+
when 3
|
71
|
+
review_options['base'] = args[0]
|
72
|
+
review_options['title'] = args[1]
|
73
|
+
review_options['body'] = args[2]
|
74
|
+
when 2
|
75
|
+
review_options['base'] = args[0]
|
76
|
+
review_options['title'] = args[1]
|
77
|
+
review_options['body'] = review_options['title']
|
78
|
+
when 1
|
79
|
+
review_options['base'] = args[0]
|
80
|
+
review_options['title'] = review_options['body'] = GitReflow.get_first_commit_message
|
81
|
+
else
|
82
|
+
review_options['title'] = review_options['body'] = GitReflow.get_first_commit_message
|
83
|
+
end
|
84
|
+
GitReflow.review review_options
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
desc 'deliver will merge your feature branch down to your base branch'
|
89
|
+
arg_name 'base_branch - the branch you want to merge into'
|
90
|
+
command :deliver do |c|
|
91
|
+
c.action do |global_options,options,args|
|
92
|
+
deliver_options = {'base' => nil, 'head' => nil}
|
93
|
+
case args.length
|
94
|
+
when 2
|
95
|
+
deliver_options['base'] = args[0]
|
96
|
+
deliver_options['head'] = args[1]
|
97
|
+
when 1
|
98
|
+
deliver_options['base'] = args[0]
|
99
|
+
end
|
100
|
+
GitReflow.deliver deliver_options
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
pre do |global,command,options,args|
|
105
|
+
# Pre logic here
|
106
|
+
# Return true to proceed; false to abourt and not call the
|
107
|
+
# chosen command
|
108
|
+
# Use skips_pre before a command to skip this block
|
109
|
+
# on that command only
|
110
|
+
true
|
111
|
+
end
|
112
|
+
|
113
|
+
post do |global,command,options,args|
|
114
|
+
# Post logic here
|
115
|
+
# Use skips_post before a command to skip this
|
116
|
+
# block on that command only
|
117
|
+
end
|
118
|
+
|
119
|
+
on_error do |exception|
|
120
|
+
# Error logic here
|
121
|
+
# return false to skip default error handling
|
122
|
+
true
|
123
|
+
end
|
124
|
+
|
125
|
+
exit run(ARGV)
|
@@ -0,0 +1,314 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
# git-flow -- A collection of Git extensions to provide high-level
|
3
|
+
# repository operations for Vincent Driessen's branching model.
|
4
|
+
#
|
5
|
+
# Original blog post presenting this model is found at:
|
6
|
+
# http://nvie.com/git-model
|
7
|
+
#
|
8
|
+
# Feel free to contribute to this project at:
|
9
|
+
# http://github.com/nvie/gitreflow
|
10
|
+
#
|
11
|
+
# Copyright 2010 Vincent Driessen. All rights reserved.
|
12
|
+
#
|
13
|
+
# Redistribution and use in source and binary forms, with or without
|
14
|
+
# modification, are permitted provided that the following conditions are met:
|
15
|
+
#
|
16
|
+
# 1. Redistributions of source code must retain the above copyright notice,
|
17
|
+
# this list of conditions and the following disclaimer.
|
18
|
+
#
|
19
|
+
# 2. Redistributions in binary form must reproduce the above copyright
|
20
|
+
# notice, this list of conditions and the following disclaimer in the
|
21
|
+
# documentation and/or other materials provided with the distribution.
|
22
|
+
#
|
23
|
+
# THIS SOFTWARE IS PROVIDED BY VINCENT DRIESSEN ``AS IS'' AND ANY EXPRESS OR
|
24
|
+
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
25
|
+
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
26
|
+
# EVENT SHALL VINCENT DRIESSEN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
27
|
+
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
28
|
+
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
29
|
+
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
30
|
+
# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
31
|
+
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
32
|
+
# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
33
|
+
#
|
34
|
+
# The views and conclusions contained in the software and documentation are
|
35
|
+
# those of the authors and should not be interpreted as representing official
|
36
|
+
# policies, either expressed or implied, of Vincent Driessen.
|
37
|
+
#
|
38
|
+
|
39
|
+
#
|
40
|
+
# Common functionality
|
41
|
+
#
|
42
|
+
|
43
|
+
# shell output
|
44
|
+
warn() { echo "$@" >&2; }
|
45
|
+
die() { warn "$@"; exit 1; }
|
46
|
+
|
47
|
+
escape() {
|
48
|
+
echo "$1" | sed 's/\([\.\+\$\*]\)/\\\1/g'
|
49
|
+
}
|
50
|
+
|
51
|
+
# set logic
|
52
|
+
has() {
|
53
|
+
local item=$1; shift
|
54
|
+
echo " $@ " | grep -q " $(escape $item) "
|
55
|
+
}
|
56
|
+
|
57
|
+
# basic math
|
58
|
+
min() { [ "$1" -le "$2" ] && echo "$1" || echo "$2"; }
|
59
|
+
max() { [ "$1" -ge "$2" ] && echo "$1" || echo "$2"; }
|
60
|
+
|
61
|
+
# basic string matching
|
62
|
+
startswith() { [ "$1" != "${1#$2}" ]; }
|
63
|
+
endswith() { [ "$1" != "${1%$2}" ]; }
|
64
|
+
|
65
|
+
#
|
66
|
+
# Git specific common functionality
|
67
|
+
#
|
68
|
+
|
69
|
+
git_local_branches() { git branch --no-color | sed 's/^[* ] //'; }
|
70
|
+
git_remote_branches() { git branch -r --no-color | sed 's/^[* ] //'; }
|
71
|
+
git_all_branches() { ( git branch --no-color; git branch -r --no-color) | sed 's/^[* ] //'; }
|
72
|
+
git_all_tags() { git tag; }
|
73
|
+
|
74
|
+
git_current_branch() {
|
75
|
+
git branch --no-color | grep '^\* ' | grep -v 'no branch' | sed 's/^* //g'
|
76
|
+
}
|
77
|
+
|
78
|
+
git_is_clean_working_tree() {
|
79
|
+
if ! git diff --no-ext-diff --ignore-submodules --quiet --exit-code; then
|
80
|
+
return 1
|
81
|
+
elif ! git diff-index --cached --quiet --ignore-submodules HEAD --; then
|
82
|
+
return 2
|
83
|
+
else
|
84
|
+
return 0
|
85
|
+
fi
|
86
|
+
}
|
87
|
+
|
88
|
+
git_repo_is_headless() {
|
89
|
+
! git rev-parse --quiet --verify HEAD >/dev/null 2>&1
|
90
|
+
}
|
91
|
+
|
92
|
+
git_local_branch_exists() {
|
93
|
+
has $1 $(git_local_branches)
|
94
|
+
}
|
95
|
+
|
96
|
+
git_remote_branch_exists() {
|
97
|
+
has $1 $(git_remote_branches)
|
98
|
+
}
|
99
|
+
|
100
|
+
git_branch_exists() {
|
101
|
+
has $1 $(git_all_branches)
|
102
|
+
}
|
103
|
+
|
104
|
+
git_tag_exists() {
|
105
|
+
has $1 $(git_all_tags)
|
106
|
+
}
|
107
|
+
|
108
|
+
#
|
109
|
+
# git_compare_branches()
|
110
|
+
#
|
111
|
+
# Tests whether branches and their "origin" counterparts have diverged and need
|
112
|
+
# merging first. It returns error codes to provide more detail, like so:
|
113
|
+
#
|
114
|
+
# 0 Branch heads point to the same commit
|
115
|
+
# 1 First given branch needs fast-forwarding
|
116
|
+
# 2 Second given branch needs fast-forwarding
|
117
|
+
# 3 Branch needs a real merge
|
118
|
+
# 4 There is no merge base, i.e. the branches have no common ancestors
|
119
|
+
#
|
120
|
+
git_compare_branches() {
|
121
|
+
local commit1=$(git rev-parse "$1")
|
122
|
+
local commit2=$(git rev-parse "$2")
|
123
|
+
if [ "$commit1" != "$commit2" ]; then
|
124
|
+
local base=$(git merge-base "$commit1" "$commit2")
|
125
|
+
if [ $? -ne 0 ]; then
|
126
|
+
return 4
|
127
|
+
elif [ "$commit1" = "$base" ]; then
|
128
|
+
return 1
|
129
|
+
elif [ "$commit2" = "$base" ]; then
|
130
|
+
return 2
|
131
|
+
else
|
132
|
+
return 3
|
133
|
+
fi
|
134
|
+
else
|
135
|
+
return 0
|
136
|
+
fi
|
137
|
+
}
|
138
|
+
|
139
|
+
#
|
140
|
+
# git_is_branch_merged_into()
|
141
|
+
#
|
142
|
+
# Checks whether branch $1 is succesfully merged into $2
|
143
|
+
#
|
144
|
+
git_is_branch_merged_into() {
|
145
|
+
local subject=$1
|
146
|
+
local base=$2
|
147
|
+
local all_merges="$(git branch --no-color --contains $subject | sed 's/^[* ] //')"
|
148
|
+
has $base $all_merges
|
149
|
+
}
|
150
|
+
|
151
|
+
#
|
152
|
+
# gitreflow specific common functionality
|
153
|
+
#
|
154
|
+
|
155
|
+
# check if this repo has been inited for gitreflow
|
156
|
+
gitreflow_has_master_configured() {
|
157
|
+
local master=$(git config --get gitreflow.branch.master)
|
158
|
+
[ "$master" != "" ] && git_local_branch_exists "$master"
|
159
|
+
}
|
160
|
+
|
161
|
+
gitreflow_has_develop_configured() {
|
162
|
+
local develop=$(git config --get gitreflow.branch.develop)
|
163
|
+
[ "$develop" != "" ] && git_local_branch_exists "$develop"
|
164
|
+
}
|
165
|
+
|
166
|
+
gitreflow_has_prefixes_configured() {
|
167
|
+
git config --get gitreflow.prefix.feature >/dev/null 2>&1 && \
|
168
|
+
git config --get gitreflow.prefix.release >/dev/null 2>&1 && \
|
169
|
+
git config --get gitreflow.prefix.hotfix >/dev/null 2>&1 && \
|
170
|
+
git config --get gitreflow.prefix.support >/dev/null 2>&1 && \
|
171
|
+
git config --get gitreflow.prefix.versiontag >/dev/null 2>&1
|
172
|
+
}
|
173
|
+
|
174
|
+
gitreflow_is_initialized() {
|
175
|
+
gitreflow_has_master_configured && \
|
176
|
+
gitreflow_has_develop_configured && \
|
177
|
+
[ "$(git config --get gitreflow.branch.master)" != \
|
178
|
+
"$(git config --get gitreflow.branch.develop)" ] && \
|
179
|
+
gitreflow_has_prefixes_configured
|
180
|
+
}
|
181
|
+
|
182
|
+
# loading settings that can be overridden using git config
|
183
|
+
gitreflow_load_settings() {
|
184
|
+
export DOT_GIT_DIR=$(git rev-parse --git-dir 2>/dev/null)
|
185
|
+
export MASTER_BRANCH=$(git config --get gitreflow.branch.master)
|
186
|
+
export DEVELOP_BRANCH=$(git config --get gitreflow.branch.develop)
|
187
|
+
export ORIGIN=$(git config --get gitreflow.origin || echo origin)
|
188
|
+
}
|
189
|
+
|
190
|
+
#
|
191
|
+
# gitreflow_resolve_nameprefix
|
192
|
+
#
|
193
|
+
# Inputs:
|
194
|
+
# $1 = name prefix to resolve
|
195
|
+
# $2 = branch prefix to use
|
196
|
+
#
|
197
|
+
# Searches branch names from git_local_branches() to look for a unique
|
198
|
+
# branch name whose name starts with the given name prefix.
|
199
|
+
#
|
200
|
+
# There are multiple exit codes possible:
|
201
|
+
# 0: The unambiguous full name of the branch is written to stdout
|
202
|
+
# (success)
|
203
|
+
# 1: No match is found.
|
204
|
+
# 2: Multiple matches found. These matches are written to stderr
|
205
|
+
#
|
206
|
+
gitreflow_resolve_nameprefix() {
|
207
|
+
local name=$1
|
208
|
+
local prefix=$2
|
209
|
+
local matches
|
210
|
+
local num_matches
|
211
|
+
|
212
|
+
# first, check if there is a perfect match
|
213
|
+
if git_local_branch_exists "$prefix$name"; then
|
214
|
+
echo "$name"
|
215
|
+
return 0
|
216
|
+
fi
|
217
|
+
|
218
|
+
matches=$(echo "$(git_local_branches)" | grep "^$(escape "$prefix$name")")
|
219
|
+
num_matches=$(echo "$matches" | wc -l)
|
220
|
+
if [ -z "$matches" ]; then
|
221
|
+
# no prefix match, so take it literally
|
222
|
+
warn "No branch matches prefix '$name'"
|
223
|
+
return 1
|
224
|
+
else
|
225
|
+
if [ $num_matches -eq 1 ]; then
|
226
|
+
echo "${matches#$prefix}"
|
227
|
+
return 0
|
228
|
+
else
|
229
|
+
# multiple matches, cannot decide
|
230
|
+
warn "Multiple branches match prefix '$name':"
|
231
|
+
for match in $matches; do
|
232
|
+
warn "- $match"
|
233
|
+
done
|
234
|
+
return 2
|
235
|
+
fi
|
236
|
+
fi
|
237
|
+
}
|
238
|
+
|
239
|
+
#
|
240
|
+
# Assertions for use in git-flow subcommands
|
241
|
+
#
|
242
|
+
|
243
|
+
require_git_repo() {
|
244
|
+
if ! git rev-parse --git-dir >/dev/null 2>&1; then
|
245
|
+
die "fatal: Not a git repository"
|
246
|
+
fi
|
247
|
+
}
|
248
|
+
|
249
|
+
require_gitreflow_initialized() {
|
250
|
+
if ! gitreflow_is_initialized; then
|
251
|
+
die "fatal: Not a gitreflow-enabled repo yet. Please run \"git flow init\" first."
|
252
|
+
fi
|
253
|
+
}
|
254
|
+
|
255
|
+
require_clean_working_tree() {
|
256
|
+
git_is_clean_working_tree
|
257
|
+
local result=$?
|
258
|
+
if [ $result -eq 1 ]; then
|
259
|
+
die "fatal: Working tree contains unstaged changes. Aborting."
|
260
|
+
fi
|
261
|
+
if [ $result -eq 2 ]; then
|
262
|
+
die "fatal: Index contains uncommited changes. Aborting."
|
263
|
+
fi
|
264
|
+
}
|
265
|
+
|
266
|
+
require_local_branch() {
|
267
|
+
if ! git_local_branch_exists $1; then
|
268
|
+
die "fatal: Local branch '$1' does not exist and is required."
|
269
|
+
fi
|
270
|
+
}
|
271
|
+
|
272
|
+
require_remote_branch() {
|
273
|
+
if ! has $1 $(git_remote_branches); then
|
274
|
+
die "Remote branch '$1' does not exist and is required."
|
275
|
+
fi
|
276
|
+
}
|
277
|
+
|
278
|
+
require_branch() {
|
279
|
+
if ! has $1 $(git_all_branches); then
|
280
|
+
die "Branch '$1' does not exist and is required."
|
281
|
+
fi
|
282
|
+
}
|
283
|
+
|
284
|
+
require_branch_absent() {
|
285
|
+
if has $1 $(git_all_branches); then
|
286
|
+
die "Branch '$1' already exists. Pick another name."
|
287
|
+
fi
|
288
|
+
}
|
289
|
+
|
290
|
+
require_tag_absent() {
|
291
|
+
for tag in $(git_all_tags); do
|
292
|
+
if [ "$1" = "$tag" ]; then
|
293
|
+
die "Tag '$1' already exists. Pick another name."
|
294
|
+
fi
|
295
|
+
done
|
296
|
+
}
|
297
|
+
|
298
|
+
require_branches_equal() {
|
299
|
+
require_local_branch "$1"
|
300
|
+
require_remote_branch "$2"
|
301
|
+
git_compare_branches "$1" "$2"
|
302
|
+
local status=$?
|
303
|
+
if [ $status -gt 0 ]; then
|
304
|
+
warn "Branches '$1' and '$2' have diverged."
|
305
|
+
if [ $status -eq 1 ]; then
|
306
|
+
die "And branch '$1' may be fast-forwarded."
|
307
|
+
elif [ $status -eq 2 ]; then
|
308
|
+
# Warn here, since there is no harm in being ahead
|
309
|
+
warn "And local branch '$1' is ahead of '$2'."
|
310
|
+
else
|
311
|
+
die "Branches need merging first."
|
312
|
+
fi
|
313
|
+
fi
|
314
|
+
}
|