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 +7 -0
- data/.gitignore +9 -0
- data/.pryrc +2 -0
- data/.rubocop.yml +16 -0
- data/.ruby-version +1 -0
- data/.travis.yml +7 -0
- data/Gemfile +6 -0
- data/README.md +83 -0
- data/Rakefile +33 -0
- data/bin/console +7 -0
- data/bin/setup +13 -0
- data/exe/git-branch--delete--stray +21 -0
- data/exe/git-branch--list--stray +15 -0
- data/git-branch--stray.gemspec +30 -0
- data/lib/git/branch/stray/version.rb +7 -0
- data/lib/git/branch/stray.rb +86 -0
- metadata +130 -0
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
data/.pryrc
ADDED
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
data/Gemfile
ADDED
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
data/bin/setup
ADDED
@@ -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,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: []
|