git-trim 0.1.2 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 92db4c11447a62f7967f2beb14992824322cdc245c6cc9caba0289c5c7e19874
4
- data.tar.gz: 5a87497a2f3dd09195ae8991336eec680d78e06c26af9fd5bc3ea0ff32a949d1
3
+ metadata.gz: 14a8db7d9bf6cca92301a221f4e096d633882d103f9f7ea4b68e4ce5a6187ce5
4
+ data.tar.gz: 26a4e8614638c39d3692815c34aee4d4358088e62aa13ebb3d6ff0372d1ee3f7
5
5
  SHA512:
6
- metadata.gz: f6059a21f04dad9126aef59197ae5ad37f9b2574df92028272aa982b36255295eea1ab82e819a63a64fba09df14c4ef2531e7c7e57a90cc748ec099a9d30b006
7
- data.tar.gz: eb23ae147a5d2c5ce5eb5648d7c7cfd71050b5227d1732bb7ee53d0fce5b38f551c8254d374930d5fda429fc00b912530079a194ac758059193b8db4b8dc56e2
6
+ metadata.gz: a3915fb4d49379edebb0928cde8f4c7f2774c429f437ee67381edfd263b567c32b3d6f7ae5c922b7c1d963079859ea844b3916d62f7a3a5712a899f2e0a6d75e
7
+ data.tar.gz: 4e604a55e748caa6af8537b929d6bdde5d50b352c6e5a73cb38950133e9f796f0df855e620b45173928c5ef535b311f8dd28ae8a40d3b5e94c26239815cdbe44
@@ -0,0 +1,18 @@
1
+ name: build
2
+ on: pull_request
3
+ jobs:
4
+ build:
5
+ runs-on: ubuntu-latest
6
+ steps:
7
+ - uses: actions/checkout@v6
8
+ - uses: ruby/setup-ruby@v1
9
+ with:
10
+ ruby-version: ruby
11
+ bundler-cache: true
12
+
13
+ - name: Run specs
14
+ run: |
15
+ git config --global user.email "ci@example.com"
16
+ git config --global user.name "CI"
17
+ git config --global init.defaultBranch main
18
+ bundle exec rake spec
@@ -0,0 +1,65 @@
1
+ name: Release
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ version:
7
+ description: "Version to release (e.g. 0.2.0)"
8
+ required: true
9
+ type: string
10
+
11
+ jobs:
12
+ release:
13
+ runs-on: ubuntu-latest
14
+ permissions:
15
+ contents: write
16
+ id-token: write
17
+ steps:
18
+ - uses: actions/checkout@v6
19
+
20
+ - uses: ruby/setup-ruby@v1
21
+ with:
22
+ ruby-version: "3.3"
23
+ bundler-cache: true
24
+
25
+ - name: Run specs
26
+ run: bundle exec rake spec
27
+
28
+ - name: Update version
29
+ run: |
30
+ VERSION="${{ inputs.version }}"
31
+ sed -i "s/VERSION = \".*\"/VERSION = \"$VERSION\"/" lib/git-trim/version.rb
32
+ echo "Updated version to $VERSION"
33
+ cat lib/git-trim/version.rb
34
+
35
+ # bundler-cache sets frozen/deployment mode, which rejects the now
36
+ # out-of-date lockfile entry for git-trim itself. Re-lock so the
37
+ # release commit keeps the gemspec and lockfile in sync.
38
+ - name: Update Gemfile.lock
39
+ run: |
40
+ bundle config unset deployment
41
+ bundle config unset frozen
42
+ BUNDLE_FROZEN=false BUNDLE_DEPLOYMENT=false bundle lock
43
+
44
+ - name: Commit version bump
45
+ run: |
46
+ VERSION="${{ inputs.version }}"
47
+ git config user.name "github-actions[bot]"
48
+ git config user.email "github-actions[bot]@users.noreply.github.com"
49
+ git add lib/git-trim/version.rb Gemfile.lock
50
+ git commit -m "Release v$VERSION"
51
+
52
+ # Builds the gem into pkg/, tags v$VERSION, pushes the commit and
53
+ # tag, and publishes to RubyGems via OIDC trusted publishing.
54
+ - name: Release to RubyGems
55
+ uses: rubygems/release-gem@v1
56
+
57
+ - name: Create GitHub Release
58
+ env:
59
+ GH_TOKEN: ${{ github.token }}
60
+ run: |
61
+ VERSION="${{ inputs.version }}"
62
+ gh release create "v$VERSION" \
63
+ --title "v$VERSION" \
64
+ --generate-notes \
65
+ pkg/git-trim-*.gem
data/.gitignore CHANGED
@@ -9,3 +9,4 @@
9
9
 
10
10
  # rspec failure tracking
11
11
  .rspec_status
12
+ .ruby-version
data/Gemfile.lock CHANGED
@@ -1,35 +1,36 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- git-trim (0.1.2)
4
+ git-trim (0.2.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
- diff-lcs (1.3)
10
- rake (13.0.1)
11
- rspec (3.7.0)
12
- rspec-core (~> 3.7.0)
13
- rspec-expectations (~> 3.7.0)
14
- rspec-mocks (~> 3.7.0)
15
- rspec-core (3.7.1)
16
- rspec-support (~> 3.7.0)
17
- rspec-expectations (3.7.0)
9
+ diff-lcs (1.6.2)
10
+ rake (13.4.2)
11
+ rspec (3.13.2)
12
+ rspec-core (~> 3.13.0)
13
+ rspec-expectations (~> 3.13.0)
14
+ rspec-mocks (~> 3.13.0)
15
+ rspec-core (3.13.6)
16
+ rspec-support (~> 3.13.0)
17
+ rspec-expectations (3.13.5)
18
18
  diff-lcs (>= 1.2.0, < 2.0)
19
- rspec-support (~> 3.7.0)
20
- rspec-mocks (3.7.0)
19
+ rspec-support (~> 3.13.0)
20
+ rspec-mocks (3.13.8)
21
21
  diff-lcs (>= 1.2.0, < 2.0)
22
- rspec-support (~> 3.7.0)
23
- rspec-support (3.7.1)
22
+ rspec-support (~> 3.13.0)
23
+ rspec-support (3.13.7)
24
24
 
25
25
  PLATFORMS
26
+ arm64-darwin-25
26
27
  ruby
27
28
 
28
29
  DEPENDENCIES
29
- bundler (~> 1.16)
30
+ bundler (>= 1.16)
30
31
  git-trim!
31
32
  rake (~> 13.0)
32
33
  rspec (~> 3.0)
33
34
 
34
35
  BUNDLED WITH
35
- 1.17.3
36
+ 2.5.3
data/README.md CHANGED
@@ -1,8 +1,6 @@
1
1
  # git trim
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/git/trim`. To experiment with that code, run `bin/console` for an interactive prompt.
4
-
5
- TODO: Delete this and the text above, and describe your gem
3
+ Deletes local branches and the [linked worktrees](https://git-scm.com/docs/git-worktree) that hold them once they are fully merged into `main`. Run it after a round of PRs merge and it cleans up everything that's done, while refusing to touch anything that still has work in it.
6
4
 
7
5
  ## Installation
8
6
 
@@ -22,7 +20,28 @@ Or install it yourself as:
22
20
 
23
21
  ## Usage
24
22
 
25
- You can call `git trim` and it will remove any branch that isn't currently merged into the current branch that isn't also in the `.git-protected-branches` file. It will not remove the main branch.
23
+ Run `git trim` from anywhere inside a repository. It fetches (with prune), then removes every local branch that is fully merged into `main`, unless the branch is:
24
+
25
+ - `main` itself,
26
+ - the branch you currently have checked out, or
27
+ - listed in a `.git-protected-branches` file.
28
+
29
+ If no local `main` exists (common in bare-repo + worktrees layouts), it compares against `origin/main` instead.
30
+
31
+ ### Worktrees
32
+
33
+ If a merged branch is checked out in a linked worktree, `git trim` removes the worktree first and then deletes the branch. Worktrees with uncommitted changes or untracked files are left alone, along with their branch:
34
+
35
+ ```
36
+ $ git trim
37
+ Removed worktree /Users/you/src/project/feature-a
38
+ Deleted branch feature-a (was fa68cf94).
39
+ Skipping branch 'feature-b': worktree at /Users/you/src/project/feature-b has local changes
40
+ ```
41
+
42
+ Commit or stash the local changes and run `git trim` again to clean up the rest.
43
+
44
+ ### Protected branches
26
45
 
27
46
  The `.git-protected-branches` file can reside in the current directory or any parent directory. Branch names are each listed on a line in the file. For example:
28
47
 
@@ -32,9 +51,13 @@ staging
32
51
  production
33
52
  ```
34
53
 
54
+ ## Releasing
55
+
56
+ Releases are cut from the GitHub Actions **Release** workflow (Actions → Release → Run workflow → enter a version like `0.2.0`). The workflow runs the specs, bumps `lib/git-trim/version.rb`, tags `v<version>`, publishes to RubyGems via [trusted publishing](https://guides.rubygems.org/trusted-publishing/) (no API key), and creates a GitHub release.
57
+
35
58
  ## Contributing
36
59
 
37
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/git-trim. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
60
+ Bug reports and pull requests are welcome on GitHub at https://github.com/cpetersen/git-trim. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
38
61
 
39
62
  ## License
40
63
 
@@ -42,4 +65,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
42
65
 
43
66
  ## Code of Conduct
44
67
 
45
- Everyone interacting in the Git::Trim project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/git-trim/blob/main/CODE_OF_CONDUCT.md).
68
+ Everyone interacting in the Git::Trim project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/cpetersen/git-trim/blob/main/CODE_OF_CONDUCT.md).
data/bin/git-trim CHANGED
@@ -2,4 +2,4 @@
2
2
 
3
3
  require 'git-trim'
4
4
 
5
- GitTrim.new.run(ARGV)
5
+ exit GitTrim.new.run(ARGV)
data/git-trim.gemspec CHANGED
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
11
11
 
12
12
  spec.summary = %q{A script to remove all merged branches that aren't protected.}
13
13
  spec.description = %q{A script to remove all merged branches that aren't specified in the .git-protected-branches file.}
14
- spec.homepage = "https://github.com/assaydepot/git-trim"
14
+ spec.homepage = "https://github.com/cpetersen/git-trim"
15
15
  spec.license = "MIT"
16
16
 
17
17
  # Specify which files should be added to the gem when it is released.
@@ -23,7 +23,7 @@ Gem::Specification.new do |spec|
23
23
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
24
24
  spec.require_paths = ["lib", "bin"]
25
25
 
26
- spec.add_development_dependency "bundler", "~> 1.16"
26
+ spec.add_development_dependency "bundler", ">= 1.16"
27
27
  spec.add_development_dependency "rake", "~> 13.0"
28
28
  spec.add_development_dependency "rspec", "~> 3.0"
29
29
  end
@@ -1,3 +1,3 @@
1
1
  class GitTrim
2
- VERSION = "0.1.2"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/git-trim.rb CHANGED
@@ -1,26 +1,75 @@
1
1
  require "git-trim/version"
2
+ require "shellwords"
2
3
 
3
4
  class GitTrim
4
5
  def run(argv=nil)
5
6
  %x{git fetch -ap}
6
7
 
7
- if File.exists?(".git-protected-branches")
8
+ if File.exist?(".git-protected-branches")
8
9
  protected_branches = File.read(".git-protected-branches").split("\n")
9
10
  end
10
11
  protected_branches ||= []
11
12
  protected_branches << "main"
12
13
 
13
- branches = %x{git branch --merged main}.split("\n").collect {|b| b.gsub('*', '').strip}
14
+ base = base_ref
15
+ unless base
16
+ warn "git-trim: neither 'main' nor 'origin/main' exists; nothing to trim against"
17
+ return 1
18
+ end
19
+
20
+ branches = %x{git branch --merged #{Shellwords.escape(base)} --format='%(refname:short)'}.split("\n").collect(&:strip)
14
21
  branches -= protected_branches
22
+ branches -= [current_branch]
23
+
24
+ worktrees = linked_worktrees
15
25
 
16
26
  branches.each do |branch|
17
- puts %x{git branch -d #{branch}}
27
+ if (path = worktrees[branch])
28
+ output = %x{git worktree remove #{Shellwords.escape(path)} 2>&1}
29
+ unless $?.success?
30
+ if output.include?("contains modified or untracked files")
31
+ puts "Skipping branch '#{branch}': worktree at #{path} has local changes"
32
+ else
33
+ puts "Skipping branch '#{branch}': could not remove worktree at #{path}"
34
+ puts output
35
+ end
36
+ next
37
+ end
38
+ puts "Removed worktree #{path}"
39
+ end
40
+ puts %x{git branch -d #{Shellwords.escape(branch)}}
41
+ end
42
+
43
+ 0
44
+ end
45
+
46
+ def current_branch
47
+ %x{git branch --show-current}.strip
48
+ end
49
+
50
+ # Local main when it exists; otherwise origin/main (e.g. bare-repo +
51
+ # worktrees layouts where no local main is checked out). Nil if neither.
52
+ def base_ref
53
+ ["main", "origin/main"].find do |ref|
54
+ %x{git rev-parse --verify --quiet #{Shellwords.escape(ref)}}
55
+ $?.success?
56
+ end
57
+ end
58
+
59
+ # Maps branch name => worktree path for linked worktrees. The first entry
60
+ # in `git worktree list` is the main worktree, which is never removable.
61
+ def linked_worktrees
62
+ entries = %x{git worktree list --porcelain}.split("\n\n")
63
+ entries.drop(1).each_with_object({}) do |entry, map|
64
+ path = entry[/^worktree (.+)$/, 1]
65
+ branch = entry[/^branch refs\/heads\/(.+)$/, 1]
66
+ map[branch] = path if path && branch
18
67
  end
19
68
  end
20
69
 
21
70
  def find_file(filename, directory=Dir.pwd)
22
71
  local_filename = File.expand_path(filename, directory)
23
- if File.exists?(local_filename)
72
+ if File.exist?(local_filename)
24
73
  return local_filename
25
74
  elsif directory == "/"
26
75
  return nil
metadata CHANGED
@@ -1,27 +1,27 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: git-trim
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Christopher Petersen
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-11-09 00:00:00.000000000 Z
11
+ date: 2026-06-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '1.16'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.16'
27
27
  - !ruby/object:Gem::Dependency
@@ -61,6 +61,8 @@ executables:
61
61
  extensions: []
62
62
  extra_rdoc_files: []
63
63
  files:
64
+ - ".github/workflows/ci.yml"
65
+ - ".github/workflows/release.yml"
64
66
  - ".gitignore"
65
67
  - ".rspec"
66
68
  - ".travis.yml"
@@ -74,11 +76,11 @@ files:
74
76
  - git-trim.gemspec
75
77
  - lib/git-trim.rb
76
78
  - lib/git-trim/version.rb
77
- homepage: https://github.com/assaydepot/git-trim
79
+ homepage: https://github.com/cpetersen/git-trim
78
80
  licenses:
79
81
  - MIT
80
82
  metadata: {}
81
- post_install_message:
83
+ post_install_message:
82
84
  rdoc_options: []
83
85
  require_paths:
84
86
  - lib
@@ -94,9 +96,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
94
96
  - !ruby/object:Gem::Version
95
97
  version: '0'
96
98
  requirements: []
97
- rubyforge_project:
98
- rubygems_version: 2.7.6.2
99
- signing_key:
99
+ rubygems_version: 3.5.22
100
+ signing_key:
100
101
  specification_version: 4
101
102
  summary: A script to remove all merged branches that aren't protected.
102
103
  test_files: []