git-branch--stray 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 4c4dd87337d21115aebe331f57a12fdddff6cef940956e63adadda37e465c5ec
4
+ data.tar.gz: e160bdbfa27758e704935d27df66c03bd2077d633afc1d95b780337d320138e2
5
+ SHA512:
6
+ metadata.gz: 1c81e946ca83b3c3cb388c611d644e8e9536beca3ff658788f75b0036c45ea068864485f6cf1cc30e874ecc42f0b83fc950a73bb1cd111ef6a4367ebb967ff3c
7
+ data.tar.gz: deff72901ca564f32cfc0bd3f4b7aec878ae38ff33d9d6c1792ae5ea8c8b2960df60041de061e393ebaea69c91c24390ed86d7a7c946d406dd59fdc1bfe49052
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.pryrc ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler/setup'
2
+ require 'git/branch/stray'
data/.rubocop.yml ADDED
@@ -0,0 +1,16 @@
1
+ Layout/EmptyLinesAroundModuleBody:
2
+ Enabled: false
3
+ Layout/MultilineOperationIndentation:
4
+ Enabled: false
5
+
6
+ Metrics/AbcSize:
7
+ Enabled: false
8
+ Metrics/MethodLength:
9
+ Enabled: false
10
+
11
+ Style/BlockDelimiters:
12
+ Enabled: false
13
+ Style/Documentation:
14
+ Enabled: false
15
+ Style/FrozenStringLiteralComment:
16
+ Enabled: false
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.5.1
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.5.1
7
+ before_install: gem install bundler -v 1.16.6
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in git-branch--stray.gemspec
6
+ gemspec
data/README.md ADDED
@@ -0,0 +1,83 @@
1
+ # Delete "stray" git branches
2
+
3
+ ## tl;dr
4
+
5
+ Run `git branch--delete--stray` to delete local "remote-tracking" branches for which the branch being tracked has been deleted on the remote.
6
+
7
+ ## Background
8
+
9
+ Git has a default disposition of keeping data unless it's explicitly thrown away; this extends to _(unnecessarily)_ holding onto references to so-called local "remote-tracking" branches where the branch being tracked has long since been deleted on the remote itself.
10
+
11
+ This utility refers to these local branches as "stray" branches, and includes two git extensions: one for listing all "stray" branches, and a second one for _(selectively)_ deleting them.
12
+
13
+ In case of the [GitHub Flow](https://guides.github.com/introduction/flow/) for instance, a local branch would become "stray" after a pull request gets merged and the underlying remote branch gets deleted... after the next `git fetch` it would be possible to identify the "stray" branch with something akin to `git branch --list --merged`.
14
+
15
+ But that's not the only scenario that results in "stray" branches, which is why the various "solutions" you find on Stack Overflow don't typically cover all edge cases, whereas this utility does; it also prefers git plumbing over git porcelain, and it implements most of its logic in a library, making it very easy indeed to implement even more git extensions for dealing with "stray" branches.
16
+
17
+ ## What's in a name?
18
+
19
+ In the context of this utility, a branch is considered "stray" if it is what git calls a "remote-tracking" branch but one where the remote branch it was tracking no longer exists _(ie. where the branch it was tracking has been deleted on the remote, e.g. on GitHub or on Bitbucket)_.
20
+
21
+ The term "stray" was chosen to avoid confusion with existing git terminology like ''merged", "tracked" and even "orpaned".
22
+
23
+ Also, the names of the two git extensions implemented by this utility:
24
+
25
+ * `git-branch--list--stray`
26
+ * `git-branch--delete--stray`
27
+
28
+ ... were chosen two mimic some existing `git branch` commands:
29
+
30
+ * `git branch --list --merged`
31
+ * `git branch --delete`
32
+
33
+ respectively.
34
+
35
+ ## Installation
36
+
37
+ Add this line to your application's Gemfile:
38
+
39
+ ```ruby
40
+ gem 'git-branch--stray'
41
+ ```
42
+
43
+ And then execute:
44
+
45
+ $ bundle
46
+
47
+ Or install it yourself as:
48
+
49
+ $ gem install git-branch--stray
50
+
51
+ ## Usage
52
+
53
+ After installing the gem, you will have two new git extensions in your environment: `git-branch--list--stray` will list all stray branches, whereas `git-branch--delete--stray` will iterate over the list and - after prompting for confirmation - delete any stray branches in your git workarea.
54
+
55
+ Because they will be in your local `$PATH` you can run them as so-called git subcommands as follows:
56
+
57
+ ```
58
+ git branch--list--stray
59
+ git branch--delete-stray
60
+ ```
61
+
62
+ Most likely, though, you will want to create some [git aliases](https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases) to make it easier to work with the two utility scripts:
63
+
64
+ ```
65
+ git config --global alias.bls branch--list--stray
66
+ git config --global alias.bds branch--delete--stray
67
+ ```
68
+
69
+ Alternatively, a similar approach can be used to add either of the scripts to your existing git aliases and/or git utility scripts.
70
+
71
+ ## Pruning
72
+
73
+ The two git extensions work best if your git workflow includes regular pruning of remote-tracking references that no longer exist on the remote, either by running `git fetch --prune` when syncing with the remote in question, or else configuring [git's pruning behaviour](https://git-scm.com/docs/git-fetch#_pruning) for your environment.
74
+
75
+ ## Development
76
+
77
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
78
+
79
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
80
+
81
+ ## Contributing
82
+
83
+ Bug reports and pull requests are welcome on GitHub at https://github.com/pvdb/git-branch--stray.
data/Rakefile ADDED
@@ -0,0 +1,33 @@
1
+ # rubocop:disable Style/SymbolArray
2
+ # rubocop:disable Style/HashSyntax
3
+
4
+ require 'bundler/gem_tasks'
5
+
6
+ task :validate_gemspec do
7
+ Bundler.load_gemspec('git-branch--stray.gemspec').validate
8
+ end
9
+
10
+ task :version => :validate_gemspec do
11
+ puts Git::Branch::Stray::VERSION
12
+ end
13
+
14
+ require 'rubocop/rake_task'
15
+
16
+ RuboCop::RakeTask.new(:rubocop)
17
+
18
+ require 'rake/testtask'
19
+
20
+ Rake::TestTask.new(:test) do |t|
21
+ t.libs << 'test'
22
+ t.libs << 'lib'
23
+ t.test_files = FileList['test/**/*_test.rb']
24
+ end
25
+
26
+ task :default => [:rubocop, :test]
27
+
28
+ task :documentation
29
+
30
+ Rake::Task['build'].enhance([:default, :documentation])
31
+
32
+ # rubocop:enable Style/HashSyntax
33
+ # rubocop:enable Style/SymbolArray
data/bin/console ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'git/branch/stray'
5
+
6
+ require 'pry'
7
+ Pry.start
data/bin/setup ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ rbenv install -s
7
+ gem install --conservative bundler
8
+ bundle install
9
+
10
+ set +vxeu
11
+ echo
12
+
13
+ # That's all Folks!
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib = File.expand_path('../../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'git/branch/stray'
6
+
7
+ %w[TERM INT].each do |signal|
8
+ Signal.trap(signal) do
9
+ exit(0)
10
+ end
11
+ end
12
+
13
+ if git('rev-parse --show-toplevel').first
14
+ Git.delete_stray_branches
15
+ exit(0)
16
+ else
17
+ puts "Please run #{File.basename(__FILE__)} from inside a git repo!"
18
+ exit(-1)
19
+ end
20
+
21
+ # That's all Folks!
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib = File.expand_path('../../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'git/branch/stray'
6
+
7
+ if git('rev-parse --show-toplevel').first
8
+ Git.list_stray_branches
9
+ exit(0)
10
+ else
11
+ puts "Please run #{File.basename(__FILE__)} from inside a git repo!"
12
+ exit(-1)
13
+ end
14
+
15
+ # That's all Folks!
@@ -0,0 +1,30 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'git/branch/stray/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'git-branch--stray'
7
+ spec.version = Git::Branch::Stray::VERSION
8
+ spec.authors = ['Peter Vandenberk']
9
+ spec.email = ['pvandenberk@mac.com']
10
+
11
+ spec.summary = 'Delete local tracking branches that have been strayed'
12
+ spec.description = 'Delete local tracking branches that have been strayed'
13
+ spec.homepage = 'https://github.com/pvdb/git-branch--stray'
14
+
15
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
16
+ `git ls-files -z`
17
+ .split("\x0")
18
+ .reject { |f| f.match(%r{^(test|spec|features)/}) }
19
+ end
20
+ spec.bindir = 'exe'
21
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.require_paths = ['lib']
23
+
24
+ spec.add_dependency 'consenter', '~> 1.0'
25
+
26
+ spec.add_development_dependency 'bundler', '~> 1.16'
27
+ spec.add_development_dependency 'minitest', '~> 5.0'
28
+ spec.add_development_dependency 'pry', '~> 0.11'
29
+ spec.add_development_dependency 'rake', '~> 10.0'
30
+ end
@@ -0,0 +1,7 @@
1
+ module Git
2
+ module Branch
3
+ module Stray
4
+ VERSION = '1.0.0'.freeze
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,86 @@
1
+ require 'git/branch/stray/version'
2
+
3
+ require 'English'
4
+ require 'consenter'
5
+
6
+ module Kernel
7
+ def git(command)
8
+ `git #{command}`.split($RS).each(&:strip!)
9
+ end
10
+ end
11
+
12
+ module Git
13
+
14
+ module_function
15
+
16
+ def local_head_refs
17
+ git("for-each-ref --format='%(refname)' refs/heads")
18
+ end
19
+
20
+ def head_refs_for(remote)
21
+ # alternative implementation that requires
22
+ # access to the remote tracking repository
23
+ #
24
+ # git("ls-remote --quiet --refs --heads #{remote}")
25
+ # .map { |sha_and_ref| sha_and_ref.split(/\s+/).last }
26
+ #
27
+ # but we assume that this utility will mainly be
28
+ # used as part of a "git workflow" that includes
29
+ # regular pruning of remote tracking references,
30
+ # which means we don't have to go over the wire!
31
+ git("for-each-ref --format='%(refname)' refs/remotes/#{remote}")
32
+ end
33
+
34
+ def upstream_reference_for(branch)
35
+ git("rev-parse --verify --abbrev-ref #{branch}@{upstream}").first
36
+ end
37
+
38
+ def remote_for(branch)
39
+ git("config --local --get branch.#{branch}.remote").first
40
+ end
41
+
42
+ def merge_ref_for(branch)
43
+ git("config --local --get branch.#{branch}.merge").first
44
+ end
45
+
46
+ def branch_name_from(symbolic_ref)
47
+ # extract the branch name from a given symbolic ref
48
+ # local: e.g. "refs/heads/master"
49
+ # remote: e.g. "refs/remotes/origin/master"
50
+ symbolic_ref.sub(%r{\Arefs/(heads|remotes/[^/]+)/}, '')
51
+ end
52
+
53
+ def stray_branches
54
+ to_branch_name = method(:branch_name_from)
55
+
56
+ local_branch_names = local_head_refs.map(&to_branch_name)
57
+
58
+ remote_branch_names = Hash.new { |branch_names, remote|
59
+ branch_names[remote] = head_refs_for(remote).map(&to_branch_name)
60
+ }
61
+
62
+ local_branch_names.find_all { |local_branch|
63
+ (remote = remote_for(local_branch)) &&
64
+ (merge_ref = merge_ref_for(local_branch)) &&
65
+ (upstream_branch = to_branch_name[merge_ref]) &&
66
+ !remote_branch_names[remote].include?(upstream_branch)
67
+ }
68
+ end
69
+
70
+ def delete_stray_branches
71
+ stray_branches.each_consented('Delete stray branch "%s"') do |stray|
72
+ system("git branch -d #{stray}")
73
+ next if $CHILD_STATUS.success?
74
+ Array(stray).each_consented('Delete unmerged branch "%s"') do |unmerged|
75
+ system("git branch -D #{unmerged}")
76
+ end
77
+ end
78
+ end
79
+
80
+ def list_stray_branches
81
+ stray_branches.each do |stray|
82
+ system("git --no-pager branch -vv --list #{stray}")
83
+ end
84
+ end
85
+
86
+ end
metadata ADDED
@@ -0,0 +1,130 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: git-branch--stray
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Peter Vandenberk
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-10-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: consenter
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.16'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.16'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.11'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.11'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '10.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '10.0'
83
+ description: Delete local tracking branches that have been strayed
84
+ email:
85
+ - pvandenberk@mac.com
86
+ executables:
87
+ - git-branch--delete--stray
88
+ - git-branch--list--stray
89
+ extensions: []
90
+ extra_rdoc_files: []
91
+ files:
92
+ - ".gitignore"
93
+ - ".pryrc"
94
+ - ".rubocop.yml"
95
+ - ".ruby-version"
96
+ - ".travis.yml"
97
+ - Gemfile
98
+ - README.md
99
+ - Rakefile
100
+ - bin/console
101
+ - bin/setup
102
+ - exe/git-branch--delete--stray
103
+ - exe/git-branch--list--stray
104
+ - git-branch--stray.gemspec
105
+ - lib/git/branch/stray.rb
106
+ - lib/git/branch/stray/version.rb
107
+ homepage: https://github.com/pvdb/git-branch--stray
108
+ licenses: []
109
+ metadata: {}
110
+ post_install_message:
111
+ rdoc_options: []
112
+ require_paths:
113
+ - lib
114
+ required_ruby_version: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ required_rubygems_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ requirements: []
125
+ rubyforge_project:
126
+ rubygems_version: 2.7.6
127
+ signing_key:
128
+ specification_version: 4
129
+ summary: Delete local tracking branches that have been strayed
130
+ test_files: []