git-utils 0.1.0

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2faeb0fba87e36f531addf4afed6971f1edf3aca
4
+ data.tar.gz: c74f6c8870f6f05b34976ebf29ce7803afebf1f4
5
+ SHA512:
6
+ metadata.gz: 2bb21163ca18e41b1695b00da352c8d259cd1f3b0e2db93feed285021ef44607c2b63f25063643cd601708356dbd140f651a92cbe9c4ad26da807c6acfe2541b
7
+ data.tar.gz: c0efe25871d671007427bf3cb2d28427f16a03d59b7086d768b046b2d513e1f7b0358a7be08d9847f8135b2927bcf22872f48f4a7597088701260e615fd18cb9
@@ -0,0 +1,21 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .rvmrc
19
+ .DS_Store
20
+ .api_token
21
+ .project_id
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1 @@
1
+ pivotal-github
@@ -0,0 +1 @@
1
+ ruby-2.0.0
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+ ruby '2.0.0'
3
+
4
+ gem 'rspec', '~> 2.13.0'
5
+
6
+ gemspec
@@ -0,0 +1,23 @@
1
+ Copyright (c) 2013 Michael Hartl
2
+ Copyright (c) 2013 Aleksandar Simic
3
+
4
+ MIT License
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining
7
+ a copy of this software and associated documentation files (the
8
+ "Software"), to deal in the Software without restriction, including
9
+ without limitation the rights to use, copy, modify, merge, publish,
10
+ distribute, sublicense, and/or sell copies of the Software, and to
11
+ permit persons to whom the Software is furnished to do so, subject to
12
+ the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be
15
+ included in all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,85 @@
1
+ # Git utilities
2
+
3
+ This repo contains some Git utility scripts. The highlights are `git open`, `git pull-request`, `git push-branch`, and `git undo`, which you'll never understand how you did without.
4
+
5
+ The commands are especially useful when combined with [`pivotal-github`](https://github.com/mhartl/git-utils) gem (which, despite its name, also works with Bitbucket).
6
+
7
+ The `git-utils` used to be pure Bash scripts, but they are now available as a Ruby gem, both because Ruby is more powerful than bash and because now `git-utils` can be included more easily as a dependency for the [`pivotal-github`](https://github.com/mhartl/pivotal-github/) gem. As a result, installation is easy if you have RubyGems installed:
8
+
9
+ gem install git-utils
10
+
11
+ ## Commands
12
+
13
+ * `git amend`: alias for `git commit --amend`
14
+ * `git anal` (use with caution): makes a commit with the message "Make anal changes"
15
+ * `git cleanup`: deletes every branch already merged into current branch (apart from `master`, `staging`, and `development`)
16
+ * `git merge-branch [branch]`: merges current branch into given branch (defaults to `master`)
17
+ * `git open`: opens the remote page for the repo (OS X only)
18
+ * `git polish`: makes a commit with the message "Polish"
19
+ * `git pull-request`: opens the remote page for issuing a new a pull request (OS X only)
20
+ * `git push-branch`: pushes the current branch up to origin
21
+ * `git delete-remote-branch <branch>`: deletes the remote branch if it is safe to do so
22
+ * `git switch <pattern>`: switches to the first branch matching the given pattern
23
+ * `git sync`: syncs the local master with remote
24
+ * `git undo`: undoes the last commit
25
+
26
+ ## Aliases
27
+
28
+ Here are some suggested aliases:
29
+
30
+ git config --global alias.mb merge-branch
31
+ git config --global alias.pr pull-request
32
+ git config --global alias.pb push-branch
33
+
34
+ ## Further details
35
+
36
+ Some of these commands deserve further explanation.
37
+
38
+ ### git merge-branch
39
+
40
+ `git merge-branch [target]` merges the current branch into the target branch (defaults to `master`). On a branch called `add-markdown-support`, `git merge-branch` is equivalent to the following:
41
+
42
+ $ git checkout master
43
+ $ git merge --no-ff --log add-markdown-support
44
+
45
+ Note that this effectively changes the default merge behavior from fast-forward to no-fast-forward, which makes it possible to use `git log` to see which of the commit objects together have implemented a feature on a particular branch. As noted in [A successful Git branching model](http://nvie.com/posts/a-successful-git-branching-model/),
46
+
47
+ > The `--no-ff` flag causes the merge to always create a new commit object, even if the merge could be performed with a fast-forward. This avoids losing information about the historical existence of a feature branch and groups together all commits that together added the feature… Yes, it will create a few more (empty) commit objects, but the gain is much bigger than that cost.
48
+
49
+ In addition, the `--log` option puts the commit messages from the individual commits in the merge message, which is especially useful for viewing the full diff represented by the commit.
50
+
51
+ These options can be overriden (and thus restored to their defaults) by passing the options `-ff` or `--no-log`. `git merge-branch` accepts any options valid for `git merge`.
52
+
53
+ ### git push-branch
54
+
55
+ `git push-branch` creates a remote branch at `origin` with the name of the current branch:
56
+
57
+ $ git branch-push
58
+ * [new branch] add-markdown-support -> add-markdown-support
59
+
60
+ `git push-branch` accepts any options valid for `git push`.
61
+
62
+
63
+ ### git sync
64
+
65
+ `git sync` syncs the local `master` with the remote `master`. On a branch called `add-markdown-support`, `git sync` is equivalent to the following:
66
+
67
+ $ git checkout master
68
+ $ git pull
69
+ $ git checkout add-markdown-support
70
+
71
+ The purpose of `git sync` is to prepare the current branch for rebasing against `master`:
72
+
73
+ $ git sync
74
+ $ git rebase master
75
+
76
+ (This is essentially equivalent to
77
+
78
+ $ git fetch
79
+ $ git rebase origin/master
80
+
81
+ but I don't like having `master` and `origin/master` be different since that means you have to remember to run `git pull` on `master` some time down the line.)
82
+
83
+ ## Installation
84
+
85
+ gem install git-utils
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Opens the last commit message for editing.
4
+ system 'git commit --amend'
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Makes anal changes.
4
+ system 'git commit -am "Make anal changes"'
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Deletes (almost) every branch already merged into current branch.
4
+ # Exceptions are `master`, `staging`, and `development`, and the current
5
+ # branch, which are preserved.
6
+ preserved = "(master|staging|development)"
7
+ cmd = %(git branch --merged | grep -v "\*" | egrep -v "#{preserved}" | )
8
+ cmd += 'xargs -n 1 git branch -d'
9
+ system cmd
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
3
+ require 'git-utils/delete_remote_branch'
4
+
5
+ # Deletes the remote branch on origin if it is safe to do so.
6
+ exit Command.run!(DeleteRemoteBranch, ARGV.dup)
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
3
+ require 'git-utils/merge_branch'
4
+
5
+ # Merges the current branch into the given branch (defaults to master).
6
+ # E.g., 'git merge-branch foobar' merges the current branch into foobar.
7
+ # 'git merge-branch', merges the current branch into master.
8
+ # git merge-branch uses the --no-ff --log options to ensure that the
9
+ # merge creates a new commit object and that the individual commits appear
10
+ # in the log file.
11
+ exit Command.run!(MergeBranch, ARGV.dup)
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
3
+ require 'git-utils/open'
4
+
5
+ # Opens the remote page for the repo (OS X only).
6
+ exit Command.run!(Open, ARGV.dup)
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Makes a commit with the message 'Polish'
4
+ system 'git commit -am "Polish"'
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
3
+ require 'git-utils/pull_request'
4
+
5
+ # Opens the remote page for issuing a new pull request.
6
+ exit Command.run!(PullRequest, ARGV.dup)
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
3
+ require 'git-utils/push_branch'
4
+
5
+ # Pushes the current branch to origin.
6
+ exit Command.run!(PushBranch, ARGV.dup)
7
+
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
3
+ require 'git-utils/switch'
4
+
5
+ # Switches to the first branch matching the given pattern.
6
+ # E.g., 'git switch foobar' switches to 'the-foobar-branch'.
7
+ exit Command.run!(Switch, ARGV.dup)
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
3
+ require 'git-utils/sync'
4
+
5
+ # Syncs the local master branch with remote.
6
+ exit Command.run!(Sync, ARGV.dup)
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Undoes the last commit and places the changes back in the staging area.
4
+ system 'git reset --soft HEAD^''
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'git-utils/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "git-utils"
8
+ gem.version = Git::Utils::VERSION
9
+ gem.authors = ["Michael Hartl"]
10
+ gem.email = ["michael@michaelhartl.com"]
11
+ gem.description = %q{Add some Git utilities}
12
+ gem.summary = %q{See the README for full documentation}
13
+ gem.homepage = "https://github.com/mhartl/git-utils"
14
+ gem.license = "MIT"
15
+
16
+ gem.files = `git ls-files`.split($/)
17
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
18
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
+ gem.require_paths = ["lib"]
20
+ end
@@ -0,0 +1,10 @@
1
+ require "git-utils/version"
2
+ require "git-utils/options"
3
+ require "git-utils/command"
4
+ require "git-utils/merge_branch"
5
+ require "git-utils/open"
6
+ require "git-utils/delete_remote_branch"
7
+ require "git-utils/push_branch"
8
+ require "git-utils/switch"
9
+ require "git-utils/sync"
10
+ require "git-utils/pull_request"
@@ -0,0 +1,100 @@
1
+ require 'optparse'
2
+ require 'ostruct'
3
+ require 'git-utils/options'
4
+
5
+ class Command
6
+ attr_accessor :args, :cmd, :options, :known_options, :unknown_options
7
+
8
+ def initialize(args = [])
9
+ self.args = args
10
+ self.options = OpenStruct.new
11
+ parse
12
+ end
13
+
14
+ def parse
15
+ self.known_options = Options::known_options(parser, args)
16
+ self.unknown_options = Options::unknown_options(parser, args)
17
+ parser.parse!(known_options)
18
+ end
19
+
20
+ def parser
21
+ OptionParser.new
22
+ end
23
+
24
+ # Returns the current Git branch.
25
+ def current_branch
26
+ @current_branch ||= `git rev-parse --abbrev-ref HEAD`.strip
27
+ end
28
+
29
+ # Returns the URL for the remote origin.
30
+ def origin_url
31
+ @origin_url ||= `git config --get remote.origin.url`.strip
32
+ end
33
+
34
+
35
+
36
+ # Returns the name of the repository service.
37
+ # It's currently GitHub, Bitbucket, or Stash.
38
+ # We return blank for an unknown service; the command will still
39
+ # often work in that case.
40
+ def service
41
+ if origin_url =~ /github/i
42
+ 'github'
43
+ elsif origin_url =~ /bitbucket/i
44
+ 'bitbucket'
45
+ elsif origin_url =~ /stash/i
46
+ 'stash'
47
+ else
48
+ ''
49
+ end
50
+ end
51
+
52
+ # Returns the protocol of the origin URL (defaults to ssh).
53
+ def protocol
54
+ if origin_url =~ /https?:\/\//
55
+ 'http'
56
+ else
57
+ 'ssh'
58
+ end
59
+ end
60
+
61
+ # Runs a command.
62
+ # If the argument array contains '--debug', returns the command that would
63
+ # have been run.
64
+ def self.run!(command_class, args)
65
+ debug = args.delete('--debug')
66
+ command = command_class.new(args)
67
+ if debug
68
+ puts command.cmd
69
+ return 1
70
+ else
71
+ command.run!
72
+ return 0
73
+ end
74
+ end
75
+
76
+ def run!
77
+ system cmd
78
+ end
79
+
80
+ private
81
+
82
+ # Returns an argument string based on given arguments.
83
+ # The main trick is to add in quotes for option
84
+ # arguments when necessary.
85
+ # For example, ['-a', '-m', 'foo bar'] becomes
86
+ # '-a -m "foo bar"'
87
+ def argument_string(args)
88
+ args.inject([]) do |opts, opt|
89
+ opts << (opt =~ /^-/ ? opt : opt.inspect)
90
+ end.join(' ')
91
+ end
92
+
93
+ def finish?
94
+ options.finish
95
+ end
96
+
97
+ def deliver?
98
+ options.deliver
99
+ end
100
+ end
@@ -0,0 +1,41 @@
1
+ require 'git-utils/command'
2
+
3
+ class DeleteRemoteBranch < Command
4
+
5
+ def parser
6
+ OptionParser.new do |opts|
7
+ opts.banner = "Usage: git delete-remote-branch <branch>"
8
+ opts.on("-o", "--override", "override unsafe delete") do |opt|
9
+ self.options.override = opt
10
+ end
11
+ opts.on_tail("-h", "--help", "this usage guide") do
12
+ puts opts.to_s; exit 0
13
+ end
14
+ end
15
+ end
16
+
17
+ def delete_safely?
18
+ command = "git log ..origin/#{target_branch} 2> /dev/null"
19
+ system(command) && !`#{command}`.strip.empty?
20
+ end
21
+
22
+ # Returns a command appropriate for executing at the command line
23
+ def cmd
24
+ if delete_safely? || options.override
25
+ c = ["git push origin :#{target_branch}"]
26
+ c << argument_string(unknown_options) unless unknown_options.empty?
27
+ c.join("\n")
28
+ else
29
+ $stderr.puts "Target branch contains unmerged commits."
30
+ $stderr.puts "Please cherry-pick the commits or merge the branch again."
31
+ $stderr.puts "Use -o or --override to override."
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ # Returns the name of the branch to be deleted.
38
+ def target_branch
39
+ self.known_options.first
40
+ end
41
+ end
@@ -0,0 +1,35 @@
1
+ require 'git-utils/command'
2
+
3
+ class MergeBranch < Command
4
+
5
+ def parser
6
+ OptionParser.new do |opts|
7
+ opts.banner = "Usage: git merge-branch [branch] [options]"
8
+ opts.on_tail("-h", "--help", "this usage guide") do
9
+ puts opts.to_s; exit 0
10
+ end
11
+ end
12
+ end
13
+
14
+ # Returns a command appropriate for executing at the command line
15
+ # For example:
16
+ # git checkout master
17
+ # git merge --no-ff --log <branch>
18
+ def cmd
19
+ lines = ["git checkout #{target_branch}"]
20
+ c = ["git merge --no-ff --log"]
21
+ c << argument_string(unknown_options) unless unknown_options.empty?
22
+ c << current_branch
23
+ lines << c.join(' ')
24
+ lines.join("\n")
25
+ end
26
+
27
+ private
28
+
29
+ # Returns the name of the branch to be merged into.
30
+ # If there is anything left in the known options after parsing,
31
+ # that's the merge branch. Otherwise, it's master.
32
+ def target_branch
33
+ self.known_options.first || 'master'
34
+ end
35
+ end
@@ -0,0 +1,40 @@
1
+ require 'git-utils/command'
2
+
3
+ class Open < Command
4
+
5
+ def parser
6
+ OptionParser.new do |opts|
7
+ opts.banner = "Usage: git open"
8
+ opts.on_tail("-h", "--help", "this usage guide") do
9
+ puts opts.to_s; exit 0
10
+ end
11
+ end
12
+ end
13
+
14
+ # Returns the URL for the repository page.
15
+ def page_url
16
+ if service == 'stash' && protocol == 'ssh'
17
+ pattern = /(.*)@([^:]*):?([^\/]*)\/([^\/]*)\/(.*)\.git/
18
+ replacement = 'https://\2/projects/\4/repos/\5/browse?at=' +
19
+ current_branch
20
+ elsif service == 'stash' && protocol == 'http'
21
+ pattern = /(.*)@([^:\/]*)(:?[^\/]*)\/(.*)scm\/([^\/]*)\/(.*)\.git/
22
+ replacement = 'https://\2\3/\4projects/\5/repos/\6/browse?at=' +
23
+ current_branch
24
+ elsif protocol == 'ssh'
25
+ pattern = /(.*)@(.*):(.*)\.git/
26
+ replacement = 'https://\2/\3/'
27
+ elsif protocol == 'http'
28
+ pattern = /https?\:\/\/(([^@]*)@)?(.*)\.git/
29
+ replacement = 'https://\3/'
30
+ end
31
+ origin_url.sub(pattern, replacement)
32
+ end
33
+
34
+ # Returns a command appropriate for executing at the command line
35
+ def cmd
36
+ c = ["open #{page_url}"]
37
+ c << argument_string(unknown_options) unless unknown_options.empty?
38
+ c.join("\n")
39
+ end
40
+ end
@@ -0,0 +1,39 @@
1
+ require 'optparse'
2
+
3
+ module Options
4
+
5
+ # Returns a list of options unknown to a particular options parser
6
+ # For example, if '-a' is a known option but '-b' and '-c' are not,
7
+ # unknown_options(parser, ['-a', '-b', '-c']) returns ['-b', '-c'].
8
+ # It also preserves arguments, so
9
+ # unknown_options(parser, ['-a', '-b', '-c', 'foo bar']) returns
10
+ # ['-b', '-c', 'foo bar'].
11
+ def self.unknown_options(parser, args)
12
+ unknown = []
13
+ recursive_parse = Proc.new do |arg_list|
14
+ begin
15
+ # Hack to handle an unknown '-ff' argument
16
+ # The issue here is that OptParse interprets '-ff' as a '-f' option
17
+ # applied twice. This is sort-of a feature, as it allows, e.g., '-am'
18
+ # to set both the '-a' and '-m' options, but it interacts badly
19
+ # with '-ff' (as used by 'git merge') when '-f' is one of the options.
20
+ unknown << arg_list.delete('-ff') if arg_list.include?('-ff')
21
+ parser.parse!(arg_list)
22
+ rescue OptionParser::InvalidOption => e
23
+ unknown.concat(e.args)
24
+ while !arg_list.empty? && arg_list.first[0] != "-"
25
+ unknown << arg_list.shift
26
+ end
27
+ recursive_parse.call(arg_list)
28
+ end
29
+ end
30
+ recursive_parse.call(args.dup)
31
+ unknown
32
+ end
33
+
34
+ # Returns a list of options with unknown options removed
35
+ def self.known_options(parser, args)
36
+ unknown = unknown_options(parser, args)
37
+ args.reject { |arg| unknown.include?(arg) }
38
+ end
39
+ end
@@ -0,0 +1,46 @@
1
+ require 'git-utils/command'
2
+
3
+ class PullRequest < Command
4
+
5
+ def parser
6
+ OptionParser.new do |opts|
7
+ opts.banner = "Usage: git pull-request"
8
+ opts.on_tail("-h", "--help", "this usage guide") do
9
+ puts opts.to_s; exit 0
10
+ end
11
+ end
12
+ end
13
+
14
+ # Returns the URL for a new pull request.
15
+ def new_pr_url
16
+ if service == 'stash' && protocol == 'ssh'
17
+ pattern = /(.*)@([^:]*):?([^\/]*)\/([^\/]*)\/(.*)\.git/
18
+ replacement = 'https://\2/projects/\4/repos/\5/pull-requests?create&sourceBranch=' +
19
+ current_branch
20
+ elsif service == 'stash' && protocol == 'http'
21
+ pattern = /(.*)@([^:\/]*)(:?[^\/]*)\/(.*)scm\/([^\/]*)\/(.*)\.git/
22
+ replacement = 'https://\2\3/\4projects/\5/repos/\6/pull-requests?create&sourceBranch=' +
23
+ current_branch
24
+ elsif service == 'github' && protocol == 'ssh'
25
+ pattern = /(.*)@(.*):(.*)\.git/
26
+ replacement = 'https://\2/\3/pull/new/' + current_branch
27
+ elsif service == 'github' && protocol == 'http'
28
+ pattern = /https?\:\/\/(([^@]*)@)?(.*)\.git/
29
+ replacement = 'https://\3/pull/new/' + current_branch
30
+ elsif service == 'bitbucket' && protocol == 'ssh'
31
+ pattern = /(.*)@(.*):(.*)\.git/
32
+ replacement = 'https://\2/\3/pull-request/new/'
33
+ elsif service == 'bitbucket' && protocol == 'http'
34
+ pattern = /https?\:\/\/(([^@]*)@)?(.*)\.git/
35
+ replacement = 'https://\3/pull-request/new/'
36
+ end
37
+ origin_url.sub(pattern, replacement)
38
+ end
39
+
40
+ # Returns a command appropriate for executing at the command line
41
+ def cmd
42
+ c = ["open #{new_pr_url}"]
43
+ c << argument_string(unknown_options) unless unknown_options.empty?
44
+ c.join("\n")
45
+ end
46
+ end
@@ -0,0 +1,20 @@
1
+ require 'git-utils/command'
2
+
3
+ class PushBranch < Command
4
+
5
+ def parser
6
+ OptionParser.new do |opts|
7
+ opts.banner = "Usage: git push-branch"
8
+ opts.on_tail("-h", "--help", "this usage guide") do
9
+ puts opts.to_s; exit 0
10
+ end
11
+ end
12
+ end
13
+
14
+ # Returns a command appropriate for executing at the command line
15
+ def cmd
16
+ c = ["git push origin #{current_branch}"]
17
+ c << argument_string(unknown_options) unless unknown_options.empty?
18
+ c.join("\n")
19
+ end
20
+ end
@@ -0,0 +1,33 @@
1
+ require 'git-utils/command'
2
+
3
+ class Switch < Command
4
+
5
+ def parser
6
+ OptionParser.new do |opts|
7
+ opts.banner = "Usage: git switch <pattern>"
8
+ opts.on_tail("-h", "--help", "this usage guide") do
9
+ puts opts.to_s; exit 0
10
+ end
11
+ end
12
+ end
13
+
14
+ # Returns the branch to switch to.
15
+ def other_branch
16
+ @other_branch ||= `git branch | grep #{pattern}`.strip
17
+ end
18
+
19
+ # Returns a command appropriate for executing at the command line
20
+ def cmd
21
+ c = ["git checkout #{other_branch}"]
22
+ c << argument_string(unknown_options) unless unknown_options.empty?
23
+ c.join("\n")
24
+ end
25
+
26
+ private
27
+
28
+ # Returns the pattern of the branch to switch to.
29
+ def pattern
30
+ self.known_options.first
31
+ end
32
+
33
+ end
@@ -0,0 +1,22 @@
1
+ require 'git-utils/command'
2
+
3
+ class Sync < Command
4
+
5
+ def parser
6
+ OptionParser.new do |opts|
7
+ opts.banner = "Usage: git sync"
8
+ opts.on_tail("-h", "--help", "this usage guide") do
9
+ puts opts.to_s; exit 0
10
+ end
11
+ end
12
+ end
13
+
14
+ # Returns a command appropriate for executing at the command line
15
+ def cmd
16
+ c = ["git checkout master"]
17
+ c << "git pull"
18
+ c << "git checkout #{current_branch}"
19
+ c << argument_string(unknown_options) unless unknown_options.empty?
20
+ c.join("\n")
21
+ end
22
+ end
@@ -0,0 +1,5 @@
1
+ module Git
2
+ module Utils
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe Command do
4
+ let(:command) { Command.new }
5
+ subject { command }
6
+
7
+ it { should respond_to(:cmd) }
8
+ it { should respond_to(:args) }
9
+ it { should respond_to(:options) }
10
+ it { should respond_to(:parse) }
11
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe DeleteRemoteBranch do
4
+
5
+ let(:command) { DeleteRemoteBranch.new(['remote_branch']) }
6
+ before do
7
+ command.stub(:current_branch).and_return('test-br')
8
+ command.stub(:delete_safely?).and_return(true)
9
+ end
10
+ subject { command }
11
+
12
+ its(:cmd) { should match /git push origin :remote_branch/ }
13
+
14
+ describe "command-line command" do
15
+ subject { `bin/git-delete-remote-branch foobar -o --debug` }
16
+ it { should match /git push origin/ }
17
+ end
18
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ describe MergeBranch do
4
+
5
+ let(:command) { MergeBranch.new }
6
+ before { command.stub(:current_branch).and_return('tau-manifesto') }
7
+ subject { command }
8
+
9
+ its(:cmd) { should match /git merge/ }
10
+
11
+ shared_examples "merge-branch with known options" do
12
+ subject { command }
13
+ it "should not raise an error" do
14
+ expect { command.parse }.not_to raise_error(OptionParser::InvalidOption)
15
+ end
16
+ end
17
+
18
+ describe "with no options" do
19
+ its(:cmd) { should match /git checkout master/ }
20
+ end
21
+
22
+ describe "with a custom development branch" do
23
+ let(:command) { MergeBranch.new(['development']) }
24
+ its(:cmd) { should match /git checkout development/ }
25
+ end
26
+
27
+ describe "with some unknown options" do
28
+ let(:command) { MergeBranch.new(['dev', '-o', '-a', '-z', '--foo']) }
29
+ it_should_behave_like "merge-branch with known options"
30
+ its(:cmd) { should match /-a -z --foo/ }
31
+ end
32
+
33
+ describe "command-line command" do
34
+ subject { `bin/git-merge-branch --debug development` }
35
+ it { should match /git checkout development/ }
36
+ it { should match /git merge --no-ff --log/ }
37
+ end
38
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ describe Open do
4
+
5
+ let(:command) { Open.new }
6
+ before do
7
+ command.stub(:current_branch).and_return('test-br')
8
+ end
9
+ subject { command }
10
+
11
+ its(:cmd) { should match /open #{command.page_url}/ }
12
+
13
+ it "should have the right page URLs" do
14
+ urls = %w[
15
+ https://mwatson@bitbucket.org/atlassian/amps.git https://bitbucket.org/atlassian/amps
16
+ git@bitbucket.org:atlassian/amps.git https://bitbucket.org/atlassian/amps
17
+ git@github.com:mhartl/git-utils.git https://github.com/mhartl/git-utils
18
+ https://github.com/mhartl/git-utils.git https://github.com/mhartl/git-utils
19
+ ssh://git@stash.atlassian.com:7999/stash/stash.git https://stash.atlassian.com/projects/stash/repos/stash/browse?at=test-br
20
+ https://mwatson@stash.atlassian.com:7990/scm/stash/stash.git https://stash.atlassian.com:7990/projects/stash/repos/stash/browse?at=test-br
21
+ ssh://git@stash.atlassian.com/stash/stash.git https://stash.atlassian.com/projects/stash/repos/stash/browse?at=test-br
22
+ https://mwatson@stash.atlassian.com/scm/stash/stash.git https://stash.atlassian.com/projects/stash/repos/stash/browse?at=test-br
23
+ https://mwatson@stash.atlassian.com/stash/scm/stash/stash.git https://stash.atlassian.com/stash/projects/stash/repos/stash/browse?at=test-br
24
+ https://mwatson@stash.atlassian.com:7990/stash/scm/stash/stash.git https://stash.atlassian.com:7990/stash/projects/stash/repos/stash/browse?at=test-br
25
+ https://example.com/repos/foobar.git https://example.com/repos/foobar
26
+ ]
27
+ urls.each_slice(2) do |origin_url, page_url|
28
+ command.stub(:origin_url).and_return(origin_url)
29
+ expect(command.page_url).to include page_url
30
+ end
31
+ end
32
+
33
+ describe "command-line command" do
34
+ subject { `bin/git-open --debug` }
35
+ it { should match /open/ }
36
+ end
37
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ describe PullRequest do
4
+
5
+ let(:command) { PullRequest.new }
6
+ before do
7
+ command.stub(:current_branch).and_return('test-br')
8
+ end
9
+ subject { command }
10
+
11
+ its(:cmd) { should match /open #{command.new_pr_url}/ }
12
+
13
+ it "should have the right pull request URLs" do
14
+ urls = %w[
15
+ https://mwatson@bitbucket.org/atlassian/amps.git https://bitbucket.org/atlassian/amps/pull-request/new
16
+ git@bitbucket.org:atlassian/amps.git https://bitbucket.org/atlassian/amps/pull-request/new
17
+ git@github.com:mhartl/git-utils.git https://github.com/mhartl/git-utils/pull/new/test-br
18
+ https://github.com/mhartl/git-utils.git https://github.com/mhartl/git-utils/pull/new/test-br
19
+ ssh://git@stash.atlassian.com:7999/stash/stash.git https://stash.atlassian.com/projects/stash/repos/stash/pull-requests?create&sourceBranch=test-br
20
+ https://mwatson@stash.atlassian.com:7990/scm/stash/stash.git https://stash.atlassian.com:7990/projects/stash/repos/stash/pull-requests?create&sourceBranch=test-br
21
+ ssh://git@stash.atlassian.com/stash/stash.git https://stash.atlassian.com/projects/stash/repos/stash/pull-requests?create&sourceBranch=test-br
22
+ https://mwatson@stash.atlassian.com/scm/stash/stash.git https://stash.atlassian.com/projects/stash/repos/stash/pull-requests?create&sourceBranch=test-br
23
+ https://mwatson@stash.atlassian.com/stash/scm/stash/stash.git https://stash.atlassian.com/stash/projects/stash/repos/stash/pull-requests?create&sourceBranch=test-br
24
+ https://mwatson@stash.atlassian.com:7990/stash/scm/stash/stash.git https://stash.atlassian.com:7990/stash/projects/stash/repos/stash/pull-requests?create&sourceBranch=test-br
25
+ ]
26
+
27
+ urls.each_slice(2) do |origin_url, new_pr_url|
28
+ command.stub(:origin_url).and_return(origin_url)
29
+ expect(command.new_pr_url).to include new_pr_url
30
+ end
31
+ end
32
+
33
+
34
+ describe "command-line command" do
35
+ subject { `bin/git-pull-request --debug` }
36
+ it { should match /open/ }
37
+ end
38
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe PushBranch do
4
+
5
+ let(:command) { PushBranch.new(['remote_branch']) }
6
+ before do
7
+ command.stub(:current_branch).and_return('test-br')
8
+ end
9
+ subject { command }
10
+
11
+ its(:cmd) { should match /git push origin #{command.current_branch}/ }
12
+
13
+ describe "command-line command" do
14
+ subject { `bin/git-push-branch --debug` }
15
+ it { should match /git push origin/ }
16
+ end
17
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe Switch do
4
+
5
+ let(:command) { Switch.new(['other-branch']) }
6
+ before do
7
+ command.stub(:current_branch).and_return('test-br')
8
+ command.stub(:other_branch).and_return('other-branch')
9
+ end
10
+ subject { command }
11
+
12
+ its(:cmd) { should match /git checkout #{command.other_branch}/ }
13
+
14
+ describe "command-line command" do
15
+ subject { `bin/git-push-branch --debug` }
16
+ it { should match /git push origin/ }
17
+ end
18
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe Sync do
4
+
5
+ let(:command) { Sync.new }
6
+ before do
7
+ command.stub(:current_branch).and_return('test-br')
8
+ end
9
+ subject { command }
10
+
11
+ its(:cmd) { should match /git checkout master/ }
12
+ its(:cmd) { should match /git pull/ }
13
+ its(:cmd) { should match /git checkout #{command.current_branch}/ }
14
+
15
+ describe "command-line command" do
16
+ subject { `bin/git-sync --debug` }
17
+ it { should match /git checkout master/ }
18
+ end
19
+ end
@@ -0,0 +1,12 @@
1
+ require 'git-utils'
2
+
3
+ RSpec.configure do |config|
4
+ config.treat_symbols_as_metadata_keys_with_true_values = true
5
+ config.run_all_when_everything_filtered = true
6
+ config.filter_run :focus
7
+
8
+ # Disallow the old-style 'object.should' syntax.
9
+ config.expect_with :rspec do |c|
10
+ c.syntax = :expect
11
+ end
12
+ end
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ git init test-repo >/dev/null
4
+ cd test-repo
5
+ git checkout -b test-br 2>/dev/null
6
+ touch foo
7
+ git add foo
8
+ git commit -m "foo" >/dev/null
9
+ cat > open <<EOF
10
+ #!/usr/bin/env ruby
11
+
12
+ echo \$*
13
+ EOF
14
+ chmod +x open
15
+ cat > git-push-branch <<EOF
16
+ #!/usr/bin/env ruby
17
+ EOF
18
+ chmod +x git-push-branch
19
+ export PATH=`pwd`:$PATH
20
+ git remote add origin foo
21
+
22
+ test_open () {
23
+ REMOTE=$1
24
+ EXPECTED=$2
25
+ git remote set-url origin $REMOTE
26
+ RESULT=`../git-open`
27
+ if [ "$RESULT" = "$EXPECTED" ]
28
+ then
29
+ echo "passed: open $REMOTE"
30
+ else
31
+ echo "FAILED: open: Expected $EXPECTED (for origin $REMOTE) but got $RESULT"
32
+ fi
33
+ }
34
+
35
+ test_open https://mwatson@bitbucket.org/atlassian/amps.git https://bitbucket.org/atlassian/amps
36
+ test_open git@bitbucket.org:atlassian/amps.git https://bitbucket.org/atlassian/amps
37
+ test_open git@github.com:mhartl/git-utils.git https://github.com/mhartl/git-utils
38
+ test_open https://github.com/mhartl/git-utils.git https://github.com/mhartl/git-utils
39
+ test_open ssh://git@stash.atlassian.com:7999/stash/stash.git https://stash.atlassian.com/projects/stash/repos/stash/browse?at=test-br
40
+ test_open https://mwatson@stash.atlassian.com:7990/scm/stash/stash.git https://stash.atlassian.com:7990/projects/stash/repos/stash/browse?at=test-br
41
+ test_open ssh://git@stash.atlassian.com/stash/stash.git https://stash.atlassian.com/projects/stash/repos/stash/browse?at=test-br
42
+ test_open https://mwatson@stash.atlassian.com/scm/stash/stash.git https://stash.atlassian.com/projects/stash/repos/stash/browse?at=test-br
43
+ test_open https://mwatson@stash.atlassian.com/stash/scm/stash/stash.git https://stash.atlassian.com/stash/projects/stash/repos/stash/browse?at=test-br
44
+ test_open https://mwatson@stash.atlassian.com:7990/stash/scm/stash/stash.git https://stash.atlassian.com:7990/stash/projects/stash/repos/stash/browse?at=test-br
45
+
46
+ test_pr () {
47
+ REMOTE=$1
48
+ EXPECTED=$2
49
+ git remote set-url origin $REMOTE
50
+ RESULT=`../git-pull-request`
51
+ if [ "$RESULT" = "$EXPECTED" ]
52
+ then
53
+ echo "passed: pull-request $REMOTE"
54
+ else
55
+ echo "FAILED: pull-request: Expected $EXPECTED (for origin $REMOTE) but got $RESULT"
56
+ fi
57
+ }
58
+
59
+ test_pr https://mwatson@bitbucket.org/atlassian/amps.git https://bitbucket.org/atlassian/amps/pull-request/new
60
+ test_pr git@bitbucket.org:atlassian/amps.git https://bitbucket.org/atlassian/amps/pull-request/new
61
+ test_pr git@github.com:mhartl/git-utils.git https://github.com/mhartl/git-utils/pull/new/test-br
62
+ test_pr https://github.com/mhartl/git-utils.git https://github.com/mhartl/git-utils/pull/new/test-br
63
+ test_pr ssh://git@stash.atlassian.com:7999/stash/stash.git https://stash.atlassian.com/projects/stash/repos/stash/pull-requests?create\&sourceBranch=test-br
64
+ test_pr https://mwatson@stash.atlassian.com:7990/scm/stash/stash.git https://stash.atlassian.com:7990/projects/stash/repos/stash/pull-requests?create\&sourceBranch=test-br
65
+ test_pr ssh://git@stash.atlassian.com/stash/stash.git https://stash.atlassian.com/projects/stash/repos/stash/pull-requests?create\&sourceBranch=test-br
66
+ test_pr https://mwatson@stash.atlassian.com/scm/stash/stash.git https://stash.atlassian.com/projects/stash/repos/stash/pull-requests?create\&sourceBranch=test-br
67
+ test_pr https://mwatson@stash.atlassian.com/stash/scm/stash/stash.git https://stash.atlassian.com/stash/projects/stash/repos/stash/pull-requests?create\&sourceBranch=test-br
68
+ test_pr https://mwatson@stash.atlassian.com:7990/stash/scm/stash/stash.git https://stash.atlassian.com:7990/stash/projects/stash/repos/stash/pull-requests?create\&sourceBranch=test-br
69
+
70
+ cd ..
71
+ rm -rf test-repo
metadata ADDED
@@ -0,0 +1,114 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: git-utils
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Michael Hartl
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-06-19 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Add some Git utilities
14
+ email:
15
+ - michael@michaelhartl.com
16
+ executables:
17
+ - git-amend
18
+ - git-anal
19
+ - git-cleanup
20
+ - git-delete-remote-branch
21
+ - git-merge-branch
22
+ - git-open
23
+ - git-polish
24
+ - git-pull-request
25
+ - git-push-branch
26
+ - git-switch
27
+ - git-sync
28
+ - git-undo
29
+ extensions: []
30
+ extra_rdoc_files: []
31
+ files:
32
+ - .DS_Store
33
+ - .gitignore
34
+ - .project_id
35
+ - .rspec
36
+ - .ruby-gemset
37
+ - .ruby-version
38
+ - Gemfile
39
+ - Gemfile.lock
40
+ - LICENSE.txt
41
+ - README.md
42
+ - Rakefile
43
+ - bin/git-amend
44
+ - bin/git-anal
45
+ - bin/git-cleanup
46
+ - bin/git-delete-remote-branch
47
+ - bin/git-merge-branch
48
+ - bin/git-open
49
+ - bin/git-polish
50
+ - bin/git-pull-request
51
+ - bin/git-push-branch
52
+ - bin/git-switch
53
+ - bin/git-sync
54
+ - bin/git-undo
55
+ - git-utils.gemspec
56
+ - lib/git-utils.rb
57
+ - lib/git-utils/command.rb
58
+ - lib/git-utils/delete_remote_branch.rb
59
+ - lib/git-utils/merge_branch.rb
60
+ - lib/git-utils/open.rb
61
+ - lib/git-utils/options.rb
62
+ - lib/git-utils/pull_request.rb
63
+ - lib/git-utils/push_branch.rb
64
+ - lib/git-utils/switch.rb
65
+ - lib/git-utils/sync.rb
66
+ - lib/git-utils/version.rb
67
+ - spec/.DS_Store
68
+ - spec/commands/.DS_Store
69
+ - spec/commands/command_spec.rb
70
+ - spec/commands/delete_remote_branch_spec.rb
71
+ - spec/commands/merge_branch_spec.rb
72
+ - spec/commands/open_spec.rb
73
+ - spec/commands/pull_request_spec.rb
74
+ - spec/commands/push_branch_spec.rb
75
+ - spec/commands/switch_spec.rb
76
+ - spec/commands/sync_spec.rb
77
+ - spec/spec_helper.rb
78
+ - test-open-pr.sh
79
+ homepage: https://github.com/mhartl/git-utils
80
+ licenses:
81
+ - MIT
82
+ metadata: {}
83
+ post_install_message:
84
+ rdoc_options: []
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - '>='
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ requirements: []
98
+ rubyforge_project:
99
+ rubygems_version: 2.0.3
100
+ signing_key:
101
+ specification_version: 4
102
+ summary: See the README for full documentation
103
+ test_files:
104
+ - spec/.DS_Store
105
+ - spec/commands/.DS_Store
106
+ - spec/commands/command_spec.rb
107
+ - spec/commands/delete_remote_branch_spec.rb
108
+ - spec/commands/merge_branch_spec.rb
109
+ - spec/commands/open_spec.rb
110
+ - spec/commands/pull_request_spec.rb
111
+ - spec/commands/push_branch_spec.rb
112
+ - spec/commands/switch_spec.rb
113
+ - spec/commands/sync_spec.rb
114
+ - spec/spec_helper.rb