Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
# SugarJar Changelog

## 2.0.2 (2026-01-08)

* Fix `branchclean` logic to properly compare with the target branch
(might have refused to clean branches that could be cleaned)
* Add new commands to handle remote branch cleanup as well as rename
`bclean` (keeping backwards compatible aliases):
* `localbranchclean` / `lbclean` - local branch clean. aliased as
`bclean` for back-comat
* `localbranchcleanall` / `lbcleanall` - local all branch clean aliased
as `bcleanall` for back-compat
* `remotebranchclean` / `rbclean` - remote branch clean
* `remotebranchcleanall` / `rbcleanall` - remote all branch clean
* `globalbranchclean` / `gbclean` - local+remote branch clean
* `globalbranchcleanall` / `gbcleanall` - local+remote all branch clean
* Added new `sync` command to aid syncing branches across multiple workstations,
see help for details.
* Fix meta-ref handling which fixes crashes when using `smartlog` during rebases
* Handle worktress gracefully when doing branch cleans
* Make unittests work properly outside of git repos

## 2.0.1 (2025-05-12)

* Fix gemspec to include new library files
Expand Down
60 changes: 30 additions & 30 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
sugarjar (2.0.1)
sugarjar (2.0.2)
deep_merge
mixlib-log
mixlib-shellout
Expand All @@ -11,27 +11,27 @@ GEM
remote: https://rubygems.org/
specs:
ast (2.4.3)
chef-utils (18.7.6)
chef-utils (18.8.54)
concurrent-ruby
concurrent-ruby (1.3.5)
concurrent-ruby (1.3.6)
deep_merge (1.2.2)
diff-lcs (1.6.1)
ffi (1.17.2)
ffi (1.17.2-arm64-darwin)
ffi (1.17.2-x86_64-darwin)
ffi (1.17.2-x86_64-linux-gnu)
json (2.11.3)
diff-lcs (1.6.2)
ffi (1.17.3)
ffi (1.17.3-arm64-darwin)
ffi (1.17.3-x86_64-darwin)
ffi (1.17.3-x86_64-linux-gnu)
json (2.18.0)
kramdown (2.5.1)
rexml (>= 3.3.9)
kramdown-parser-gfm (1.1.0)
kramdown (~> 2.0)
language_server-protocol (3.17.0.4)
language_server-protocol (3.17.0.5)
lint_roller (1.1.0)
mdl (0.13.0)
mdl (0.15.0)
kramdown (~> 2.3)
kramdown-parser-gfm (~> 1.1)
mixlib-cli (~> 2.1, >= 2.1.1)
mixlib-config (>= 2.2.1, < 4)
mixlib-cli
mixlib-config
mixlib-shellout
mixlib-cli (2.1.8)
mixlib-config (3.0.27)
Expand All @@ -41,49 +41,49 @@ GEM
mixlib-shellout (3.3.9)
chef-utils
parallel (1.27.0)
parser (3.3.8.0)
parser (3.3.10.0)
ast (~> 2.4.1)
racc
pastel (0.8.0)
tty-color (~> 0.5)
prism (1.4.0)
prism (1.7.0)
racc (1.8.1)
rainbow (3.1.1)
regexp_parser (2.10.0)
rexml (3.4.2)
rspec (3.13.0)
regexp_parser (2.11.3)
rexml (3.4.4)
rspec (3.13.2)
rspec-core (~> 3.13.0)
rspec-expectations (~> 3.13.0)
rspec-mocks (~> 3.13.0)
rspec-core (3.13.3)
rspec-core (3.13.6)
rspec-support (~> 3.13.0)
rspec-expectations (3.13.4)
rspec-expectations (3.13.5)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-mocks (3.13.4)
rspec-mocks (3.13.7)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-support (3.13.3)
rubocop (1.75.5)
rspec-support (3.13.6)
rubocop (1.82.1)
json (~> 2.3)
language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.1.0)
parallel (~> 1.10)
parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 2.9.3, < 3.0)
rubocop-ast (>= 1.44.0, < 2.0)
rubocop-ast (>= 1.48.0, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 4.0)
rubocop-ast (1.44.1)
rubocop-ast (1.49.0)
parser (>= 3.3.7.2)
prism (~> 1.4)
prism (~> 1.7)
ruby-progressbar (1.13.0)
tomlrb (2.0.3)
tomlrb (2.0.4)
tty-color (0.6.0)
unicode-display_width (3.1.4)
unicode-emoji (~> 4.0, >= 4.0.4)
unicode-emoji (4.0.4)
unicode-display_width (3.2.0)
unicode-emoji (~> 4.1)
unicode-emoji (4.2.0)

PLATFORMS
arm64-darwin
Expand Down
33 changes: 31 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ Jump to what you're most interested in:
* [Cleaning up your own history](#cleaning-up-your-own-history)
* [Better feature branches](#better-feature-branches)
* [Smartlog](#smartlog)
* [Sync work across workstations](#sync-work-across-workstations)
* [Pulling in suggestions from the web](#pulling-in-suggestions-from-the-web)
* [And more!](#and-more)
* [Installation](#installation)
Expand All @@ -50,8 +51,10 @@ doesn't work. Git will tell you the branch isn't fully merged. You can, of
course `git branch -D <branch>`, but that does no safety checks at all, it
forces the deletion.

Enter `sj bclean` - it determines if the contents of your branch has been merge
and safely deletes if so.
Enter `sj lbclean` - it determines if the contents of your branch has been merge
and safely deletes if so. (Note: `lbclean` stands for "local branch clean", and
is aliased to `bclean` for both backwards-compatibility and also since it's the
most common branch-cleanup command).

![bclean screenshot](https://github.com/jaymzh/sugarjar/blob/main/images/bclean.png)

Expand All @@ -65,6 +68,17 @@ been merged:

![bcleanall screenshot](https://github.com/jaymzh/sugarjar/blob/main/images/bcleanall.png)

There is also `sj rbclean` ("remote branch clean") (and `sj rbcleanall`) for
cleanup of remote branches. *Note*: This cannot differentiate between
PR/feature branches which have been merged and long-lived release branches that
have been merged (e.g. if '2.0-release' is a branch and has no commits not in
main, it will be deleted).

There is even `sj gbclean` ("global branch clean") (and `sj gbcleanall`) which will
do both the local and remote cleaning.

*NOTE*: Remote branch cleaning is still experimental, use with caution!

### Smarter clones and remotes

There's a pattern to every new repo we want to contribute to. First we fork,
Expand Down Expand Up @@ -275,6 +289,21 @@ smartlog` or `sj sl` for short.

![smartlog screenshot](https://github.com/jaymzh/sugarjar/blob/main/images/smartlog.png)

### Sync work across workstations

If you work on multiple workstations, keeping your branches in-sync can be a
pain. SugarJar provides `sync` to help with this.

For example, if you do some work on feature `foo` on machine1 and push to
`origin/foo` (intending to eventually merge to `upstream/main`), then on
machine2, you pull that branch, do more work, which you also push to
`origin/foo`, then on machine1, you can do `sj sync` to pull down the changes
from `origin/foo`. If you have local changes, that are not already on
`origin/foo`, those will be rebased on top of the changes from `origin/foo`.

It's very similar to `sj up`, but instead of rebasing on top of the tracking
branch, it rebases on top of the push target branch.

### Pulling in suggestions from the web

When someone 'suggests' a change in the GitHub WebUI, once you choose to commit
Expand Down
2 changes: 1 addition & 1 deletion bin/sj
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ COMMANDS:

For example, if you do some work on feature `foo` on machine1 and
push to `origin/foo` (intending to eventually merge to
`upstream/foo`), then on machine2, you pull that branch, do more
`upstream/main`), then on machine2, you pull that branch, do more
work, which you also push to `origin/foo`, then on machine1, you
can do `sj sync` to pull down the changes from `origin/foo`. If
you have local changes, that are not already on `origin/foo`,
Expand Down
6 changes: 4 additions & 2 deletions lib/sugarjar/commands/bclean.rb
Original file line number Diff line number Diff line change
Expand Up @@ -136,14 +136,15 @@ def gbcleanall(remote = nil)

private

# rubocop:disable Naming/PredicateMethod
def clean_branch(name, type = :local)
undeleteable = MAIN_BRANCHES.dup
undeleteable << 'HEAD' if type == :remote
die("Cannot remove #{name} branch") if undeleteable.include?(name)
SugarJar::Log.debug('Fetch relevant remote...')
fetch_upstream
fetch(remote_from_ref(name)) if type == :remote
return false unless safe_to_clean(name)
return false unless safe_to_clean?(name)

SugarJar::Log.debug('branch deemed safe to delete...')
if type == :remote
Expand All @@ -157,8 +158,9 @@ def clean_branch(name, type = :local)
end
true
end
# rubocop:enable Naming/PredicateMethod

def safe_to_clean(branch)
def safe_to_clean?(branch)
# cherry -v will output 1 line per commit on the target branch
# prefixed by a - or + - anything with a - can be dropped, anything
# else cannot.
Expand Down
2 changes: 2 additions & 0 deletions lib/sugarjar/commands/push.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ def _smartpush(remote, branch, force)
puts git(*args).stderr
end

# rubocop:disable Naming/PredicateMethod
def run_prepush
@repo_config['on_push']&.each do |item|
SugarJar::Log.debug("Running on_push check type #{item}")
Expand All @@ -49,5 +50,6 @@ def run_prepush
end
true
end
# rubocop:enable Naming/PredicateMethod
end
end
2 changes: 1 addition & 1 deletion lib/sugarjar/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
class SugarJar
VERSION = '2.0.1'.freeze
VERSION = '2.0.2'.freeze
end
14 changes: 7 additions & 7 deletions spec/commands/bclean_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
SugarJar::Commands.new({ 'no_change' => true })
end

context '#safe_to_clean' do
context '#safe_to_clean?' do
it 'Allows cleanup when cherry -v shows no delta' do
expect(sj).to receive(:tracked_branch).with('foo').
and_return('origin/main')
so = double({ 'stdout' => '' })
expect(sj).to receive(:git).with('cherry', '-v', 'origin/main', 'foo').
and_return(so)
expect(sj.send(:safe_to_clean, 'foo')).to eq(true)
expect(sj.send(:safe_to_clean?, 'foo')).to eq(true)
end

it 'Allows cleanup when cherry -v shows no important delta' do
Expand All @@ -21,7 +21,7 @@
so = double({ 'stdout' => "- aabbcc0 something\n-bbccdd1 another\n" })
expect(sj).to receive(:git).with('cherry', '-v', 'origin/main', 'foo').
and_return(so)
expect(sj.send(:safe_to_clean, 'foo')).to eq(true)
expect(sj.send(:safe_to_clean?, 'foo')).to eq(true)
end

it 'Does not allow cleanup when we fail to build our merge test branch' do
Expand All @@ -42,7 +42,7 @@
and_return(so2)
expect(sj).to receive(:cleanup_tmp_branch).
with(tmp_branch, branch, tracked_branch)
expect(sj.send(:safe_to_clean, branch)).to eq(false)
expect(sj.send(:safe_to_clean?, branch)).to eq(false)
end

it 'Does not allow cleanup when merge test branch shows delta' do
Expand All @@ -65,7 +65,7 @@
expect(sj).to receive(:git).with('diff', '--staged').and_return(so3)
expect(sj).to receive(:cleanup_tmp_branch).
with(tmp_branch, branch, tracked_branch)
expect(sj.send(:safe_to_clean, branch)).to eq(false)
expect(sj.send(:safe_to_clean?, branch)).to eq(false)
end

it 'Does allows cleanup when merge test branch shows no delta' do
Expand All @@ -89,7 +89,7 @@
expect(sj).to receive(:git).with('diff', '--staged').and_return(so3)
expect(sj).to receive(:cleanup_tmp_branch).
with(tmp_branch, branch, tracked_branch)
expect(sj.send(:safe_to_clean, branch)).to eq(true)
expect(sj.send(:safe_to_clean?, branch)).to eq(true)
end

it 'Uses the correct base for detecting delta' do
Expand All @@ -99,7 +99,7 @@
expect(sj).to receive(:git).
with('cherry', '-v', 'origin/develop', 'feature/foo').
and_return(so)
expect(sj.send(:safe_to_clean, 'feature/foo')).to eq(true)
expect(sj.send(:safe_to_clean?, 'feature/foo')).to eq(true)
end
end
end
Loading