sugarjar 2.0.1 → 2.0.2
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 +4 -4
- data/CHANGELOG.md +20 -0
- data/README.md +35 -6
- data/bin/sj +62 -9
- data/lib/sugarjar/commands/bclean.rb +130 -15
- data/lib/sugarjar/commands/checks.rb +2 -0
- data/lib/sugarjar/commands/pullsuggestions.rb +2 -15
- data/lib/sugarjar/commands/push.rb +3 -14
- data/lib/sugarjar/commands/smartpullrequest.rb +1 -0
- data/lib/sugarjar/commands/up.rb +24 -3
- data/lib/sugarjar/commands.rb +55 -4
- data/lib/sugarjar/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d0f9fa156720c59e1fc95f289273950176cad61ab82a67018d836a0ee878d81e
|
|
4
|
+
data.tar.gz: 6bec27c224878e6faee0e5801dec631e39db36170b759b6bf335a045cdda75a0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e4a5e2900d551ce1bb4bc8f9899e37dff28d6faaa7c9a46e96c140febb3e8b240465499e491054525aed0c470e8892af2f8d3d546f8c19925c070d283df45478
|
|
7
|
+
data.tar.gz: 979dce6e20a27fb94a11432fa5a39912693539de948f0a6278eb6662f68a6f62846e2d94667506094588592e99d5aba7fe57843e41771a55b128699a09595dce
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# SugarJar Changelog
|
|
2
2
|
|
|
3
|
+
## 2.0.2 (2026-01-08)
|
|
4
|
+
|
|
5
|
+
* Fix `branchclean` logic to properly compare with the target branch
|
|
6
|
+
(might have refused to clean branches that could be cleaned)
|
|
7
|
+
* Add new commands to handle remote branch cleanup as well as rename
|
|
8
|
+
`bclean` (keeping backwards compatible aliases):
|
|
9
|
+
* `localbranchclean` / `lbclean` - local branch clean. aliased as
|
|
10
|
+
`bclean` for back-comat
|
|
11
|
+
* `localbranchcleanall` / `lbcleanall` - local all branch clean aliased
|
|
12
|
+
as `bcleanall` for back-compat
|
|
13
|
+
* `remotebranchclean` / `rbclean` - remote branch clean
|
|
14
|
+
* `remotebranchcleanall` / `rbcleanall` - remote all branch clean
|
|
15
|
+
* `globalbranchclean` / `gbclean` - local+remote branch clean
|
|
16
|
+
* `globalbranchcleanall` / `gbcleanall` - local+remote all branch clean
|
|
17
|
+
* Added new `sync` command to aid syncing branches across multiple workstations,
|
|
18
|
+
see help for details.
|
|
19
|
+
* Fix meta-ref handling which fixes crashes when using `smartlog` during rebases
|
|
20
|
+
* Handle worktress gracefully when doing branch cleans
|
|
21
|
+
* Make unittests work properly outside of git repos
|
|
22
|
+
|
|
3
23
|
## 2.0.1 (2025-05-12)
|
|
4
24
|
|
|
5
25
|
* Fix gemspec to include new library files
|
data/README.md
CHANGED
|
@@ -30,6 +30,7 @@ Jump to what you're most interested in:
|
|
|
30
30
|
* [Cleaning up your own history](#cleaning-up-your-own-history)
|
|
31
31
|
* [Better feature branches](#better-feature-branches)
|
|
32
32
|
* [Smartlog](#smartlog)
|
|
33
|
+
* [Sync work across workstations](#sync-work-across-workstations)
|
|
33
34
|
* [Pulling in suggestions from the web](#pulling-in-suggestions-from-the-web)
|
|
34
35
|
* [And more!](#and-more)
|
|
35
36
|
* [Installation](#installation)
|
|
@@ -50,8 +51,10 @@ doesn't work. Git will tell you the branch isn't fully merged. You can, of
|
|
|
50
51
|
course `git branch -D <branch>`, but that does no safety checks at all, it
|
|
51
52
|
forces the deletion.
|
|
52
53
|
|
|
53
|
-
Enter `sj
|
|
54
|
-
and safely deletes if so.
|
|
54
|
+
Enter `sj lbclean` - it determines if the contents of your branch has been merge
|
|
55
|
+
and safely deletes if so. (Note: `lbclean` stands for "local branch clean", and
|
|
56
|
+
is aliased to `bclean` for both backwards-compatibility and also since it's the
|
|
57
|
+
most common branch-cleanup command).
|
|
55
58
|
|
|
56
59
|

|
|
57
60
|
|
|
@@ -65,6 +68,17 @@ been merged:
|
|
|
65
68
|
|
|
66
69
|

|
|
67
70
|
|
|
71
|
+
There is also `sj rbclean` ("remote branch clean") (and `sj rbcleanall`) for
|
|
72
|
+
cleanup of remote branches. *Note*: This cannot differentiate between
|
|
73
|
+
PR/feature branches which have been merged and long-lived release branches that
|
|
74
|
+
have been merged (e.g. if '2.0-release' is a branch and has no commits not in
|
|
75
|
+
main, it will be deleted).
|
|
76
|
+
|
|
77
|
+
There is even `sj gbclean` ("global branch clean") (and `sj gbcleanall`) which will
|
|
78
|
+
do both the local and remote cleaning.
|
|
79
|
+
|
|
80
|
+
*NOTE*: Remote branch cleaning is still experimental, use with caution!
|
|
81
|
+
|
|
68
82
|
### Smarter clones and remotes
|
|
69
83
|
|
|
70
84
|
There's a pattern to every new repo we want to contribute to. First we fork,
|
|
@@ -275,6 +289,21 @@ smartlog` or `sj sl` for short.
|
|
|
275
289
|
|
|
276
290
|

|
|
277
291
|
|
|
292
|
+
### Sync work across workstations
|
|
293
|
+
|
|
294
|
+
If you work on multiple workstations, keeping your branches in-sync can be a
|
|
295
|
+
pain. SugarJar provides `sync` to help with this.
|
|
296
|
+
|
|
297
|
+
For example, if you do some work on feature `foo` on machine1 and push to
|
|
298
|
+
`origin/foo` (intending to eventually merge to `upstream/main`), then on
|
|
299
|
+
machine2, you pull that branch, do more work, which you also push to
|
|
300
|
+
`origin/foo`, then on machine1, you can do `sj sync` to pull down the changes
|
|
301
|
+
from `origin/foo`. If you have local changes, that are not already on
|
|
302
|
+
`origin/foo`, those will be rebased on top of the changes from `origin/foo`.
|
|
303
|
+
|
|
304
|
+
It's very similar to `sj up`, but instead of rebasing on top of the tracking
|
|
305
|
+
branch, it rebases on top of the push target branch.
|
|
306
|
+
|
|
278
307
|
### Pulling in suggestions from the web
|
|
279
308
|
|
|
280
309
|
When someone 'suggests' a change in the GitHub WebUI, once you choose to commit
|
|
@@ -314,7 +343,7 @@ directly from there.
|
|
|
314
343
|
|
|
315
344
|
Sugarjar will read in both a system-level config file
|
|
316
345
|
(`/etc/sugarjar/config.yaml`) and a user-level config file
|
|
317
|
-
`~/.config/sugarjar/config.yaml
|
|
346
|
+
(`~/.config/sugarjar/config.yaml`), if they exist. Anything in the user config
|
|
318
347
|
will override the system config, and command-line options override both. The
|
|
319
348
|
yaml file is a straight key-value pair of options without their '--'.
|
|
320
349
|
|
|
@@ -397,9 +426,9 @@ it on Windows, but I'll happily accept patches for Windows compatibility.
|
|
|
397
426
|
|
|
398
427
|
**How do I get tab-completion?**
|
|
399
428
|
|
|
400
|
-
If the package for your OS/distro didn't set it up
|
|
401
|
-
that `sugarjar_completion.bash` is included in the package, and you can
|
|
402
|
-
source that in your dotfiles, assuming you are using bash.
|
|
429
|
+
If the package for your OS/distro didn't set it up automatically, you should
|
|
430
|
+
find that `sugarjar_completion.bash` is included in the package, and you can
|
|
431
|
+
simply source that in your dotfiles, assuming you are using bash.
|
|
403
432
|
|
|
404
433
|
**What happens now that Sapling is released?**
|
|
405
434
|
|
data/bin/sj
CHANGED
|
@@ -118,15 +118,6 @@ COMMANDS:
|
|
|
118
118
|
Same as "amend" but without changing the message. Alias for
|
|
119
119
|
"git commit --amend --no-edit".
|
|
120
120
|
|
|
121
|
-
bclean [<branch>]
|
|
122
|
-
If safe, delete the current branch (or the specified branch).
|
|
123
|
-
Unlike "git branch -d", bclean can handle squash-merged branches.
|
|
124
|
-
Think of it as a smarter "git branch -d".
|
|
125
|
-
|
|
126
|
-
bcleanall
|
|
127
|
-
Walk all branches, and try to delete them if it's safe. See
|
|
128
|
-
"bclean" for details.
|
|
129
|
-
|
|
130
121
|
binfo
|
|
131
122
|
Verbose information about the current branch.
|
|
132
123
|
|
|
@@ -157,14 +148,62 @@ COMMANDS:
|
|
|
157
148
|
branches. Very convenient for keeping the branch behind a pull-
|
|
158
149
|
request clean.
|
|
159
150
|
|
|
151
|
+
globalbranchclean, gbclean [<branch>] [<remote>]
|
|
152
|
+
WARNING: EXPERIMENTAL COMMAND.
|
|
153
|
+
|
|
154
|
+
Combination of "lbclean" and "rbclean". Cleans up
|
|
155
|
+
both local and remote branches safely. See those commands for
|
|
156
|
+
details.
|
|
157
|
+
|
|
158
|
+
globalbranchcleanall, gbcleanall [<remote>]
|
|
159
|
+
WARNING: EXPERIMENTAL COMMAND.
|
|
160
|
+
|
|
161
|
+
Safely clean all branches, both local and remote. See "gbclean"
|
|
162
|
+
for details.
|
|
163
|
+
|
|
160
164
|
lint
|
|
161
165
|
Run any linters configured in .sugarjar.yaml.
|
|
162
166
|
|
|
167
|
+
localbranchclean, lbclean [<branch>]
|
|
168
|
+
If safe, delete the current branch (or the specified branch).
|
|
169
|
+
Unlike "git branch -d", lbclean can handle squash-merged branches.
|
|
170
|
+
Think of it as a smarter "git branch -d".
|
|
171
|
+
|
|
172
|
+
Aliased to 'bclean' for backwards compatibility.
|
|
173
|
+
|
|
174
|
+
localbranchcleanall, lbcleanall
|
|
175
|
+
Walk all branches, and try to delete them if it's safe. See
|
|
176
|
+
"lbclean" for details.
|
|
177
|
+
|
|
178
|
+
Aliased to 'bcleanall' for backwards compatibility.
|
|
179
|
+
|
|
163
180
|
pullsuggestions, ps
|
|
164
181
|
Pull any suggestions *that have been committed* in the GitHub UI.
|
|
165
182
|
This will show the diff and prompt for confirmation before
|
|
166
183
|
merging. Note that a fast-forward merge will be used.
|
|
167
184
|
|
|
185
|
+
remotebranchclean, rbclean [<branch>] [<remote>]
|
|
186
|
+
WARNING: EXPERIMENTAL COMMAND.
|
|
187
|
+
|
|
188
|
+
Similar to lbclean, except safely cleans up remote branches.
|
|
189
|
+
Unlike many git commands, <remote> comes after <branch> so
|
|
190
|
+
that you can specify a branch and the remote defaults to 'origin'.
|
|
191
|
+
This means you can do "sj rclean" to clean the remote branch with
|
|
192
|
+
the same name as the local one. Note that you probably want
|
|
193
|
+
"sclean", which will do both local and remote cleaning in one
|
|
194
|
+
command.
|
|
195
|
+
|
|
196
|
+
WARNING: This command cannot differentiate release branches
|
|
197
|
+
that are fully merged but still need to be kept around for future
|
|
198
|
+
work. So if main contains everything that 2.0-devel and 3.0-devel
|
|
199
|
+
has, then those branches will be deleted. Use with caution.
|
|
200
|
+
|
|
201
|
+
remotebranchcleanall, rbcleanall [<remote>]
|
|
202
|
+
WARNING: EXPERIMENTAL COMMAND.
|
|
203
|
+
|
|
204
|
+
Walk all remote branches, and try to delete them if it's safe. See
|
|
205
|
+
"rbclean" for details.
|
|
206
|
+
|
|
168
207
|
smartclone, sclone
|
|
169
208
|
A smart wrapper to "git clone" that handles forking and managing
|
|
170
209
|
remotes for you.
|
|
@@ -190,6 +229,20 @@ COMMANDS:
|
|
|
190
229
|
subfeature, sf <feature>
|
|
191
230
|
An alias for 'sj feature <feature> <current_branch>'
|
|
192
231
|
|
|
232
|
+
sync
|
|
233
|
+
Similar to `up`, except instead of rebasing on a tracked branch
|
|
234
|
+
(usually `upstream` remote), rebases to wherever our remote push
|
|
235
|
+
target is (usually `origin` remote). Useful for syncing work
|
|
236
|
+
across different machines.
|
|
237
|
+
|
|
238
|
+
For example, if you do some work on feature `foo` on machine1 and
|
|
239
|
+
push to `origin/foo` (intending to eventually merge to
|
|
240
|
+
`upstream/main`), then on machine2, you pull that branch, do more
|
|
241
|
+
work, which you also push to `origin/foo`, then on machine1, you
|
|
242
|
+
can do `sj sync` to pull down the changes from `origin/foo`. If
|
|
243
|
+
you have local changes, that are not already on `origin/foo`,
|
|
244
|
+
those will be rebased on top of the changes from `origin/foo`.
|
|
245
|
+
|
|
193
246
|
unit
|
|
194
247
|
Run any unitests configured in .sugarjar.yaml.
|
|
195
248
|
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
class SugarJar
|
|
2
2
|
class Commands
|
|
3
|
-
def
|
|
3
|
+
def lbclean(name = nil)
|
|
4
4
|
assert_in_repo!
|
|
5
5
|
name ||= current_branch
|
|
6
6
|
name = fprefix(name)
|
|
7
|
+
|
|
8
|
+
wt_branches = worktree_branches
|
|
9
|
+
|
|
10
|
+
if wt_branches.include?(name)
|
|
11
|
+
SugarJar::Log.warn("#{name}: #{color('skipped', :yellow)} (worktree)")
|
|
12
|
+
return
|
|
13
|
+
end
|
|
14
|
+
|
|
7
15
|
if clean_branch(name)
|
|
8
16
|
SugarJar::Log.info("#{name}: #{color('reaped', :green)}")
|
|
9
17
|
else
|
|
@@ -13,15 +21,58 @@ class SugarJar
|
|
|
13
21
|
)
|
|
14
22
|
end
|
|
15
23
|
end
|
|
24
|
+
alias localbranchclean lbclean
|
|
25
|
+
# backcompat
|
|
26
|
+
alias bclean lbclean
|
|
16
27
|
|
|
17
|
-
def
|
|
28
|
+
def rbclean(name = nil, remote = nil)
|
|
29
|
+
assert_in_repo!
|
|
30
|
+
name ||= current_branch
|
|
31
|
+
name = fprefix(name)
|
|
32
|
+
remote ||= 'origin'
|
|
33
|
+
|
|
34
|
+
ref = "refs/remotes/#{remote}/#{name}"
|
|
35
|
+
if git_nofail('show-ref', '--quiet', ref).error?
|
|
36
|
+
SugarJar::Log.warn("Remote branch #{name} on #{remote} does not exist.")
|
|
37
|
+
return
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
if clean_branch(ref, :remote)
|
|
41
|
+
SugarJar::Log.info("#{ref}: #{color('reaped', :green)}")
|
|
42
|
+
else
|
|
43
|
+
die(
|
|
44
|
+
"#{color("Cannot clean #{ref}", :red)}! there are unmerged " +
|
|
45
|
+
"commits; use 'git push #{remote} -d #{name}' to forcefully delete " +
|
|
46
|
+
' it.',
|
|
47
|
+
)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
alias remotebranchclean rbclean
|
|
51
|
+
|
|
52
|
+
def gbclean(name = nil, remote = nil)
|
|
53
|
+
assert_in_repo!
|
|
54
|
+
name ||= current_branch
|
|
55
|
+
remote ||= 'origin'
|
|
56
|
+
lbclean(name)
|
|
57
|
+
rbclean(name, remote)
|
|
58
|
+
end
|
|
59
|
+
alias globalbranchclean gbclean
|
|
60
|
+
|
|
61
|
+
def lbcleanall
|
|
18
62
|
assert_in_repo!
|
|
19
63
|
curr = current_branch
|
|
64
|
+
wt_branches = worktree_branches
|
|
20
65
|
all_local_branches.each do |branch|
|
|
21
66
|
if MAIN_BRANCHES.include?(branch)
|
|
22
67
|
SugarJar::Log.debug("Skipping #{branch}")
|
|
23
68
|
next
|
|
24
69
|
end
|
|
70
|
+
if wt_branches.include?(branch)
|
|
71
|
+
SugarJar::Log.info(
|
|
72
|
+
"#{branch}: #{color('skipped', :yellow)} (worktree)",
|
|
73
|
+
)
|
|
74
|
+
next
|
|
75
|
+
end
|
|
25
76
|
|
|
26
77
|
if clean_branch(branch)
|
|
27
78
|
SugarJar::Log.info("#{branch}: #{color('reaped', :green)}")
|
|
@@ -41,28 +92,87 @@ class SugarJar
|
|
|
41
92
|
checkout_main_branch
|
|
42
93
|
end
|
|
43
94
|
end
|
|
95
|
+
alias localbranchcleanall lbcleanall
|
|
96
|
+
# backcomat
|
|
97
|
+
alias bcleanall lbcleanall
|
|
98
|
+
|
|
99
|
+
def rbcleanall(remote = nil)
|
|
100
|
+
assert_in_repo!
|
|
101
|
+
curr = current_branch
|
|
102
|
+
remote ||= 'origin'
|
|
103
|
+
all_remote_branches(remote).each do |branch|
|
|
104
|
+
if (MAIN_BRANCHES + ['HEAD']).include?(branch)
|
|
105
|
+
SugarJar::Log.debug("Skipping #{branch}")
|
|
106
|
+
next
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
ref = "refs/remotes/#{remote}/#{branch}"
|
|
110
|
+
if clean_branch(ref, :remote)
|
|
111
|
+
SugarJar::Log.info("#{ref}: #{color('reaped', :green)}")
|
|
112
|
+
else
|
|
113
|
+
SugarJar::Log.info("#{ref}: skipped")
|
|
114
|
+
SugarJar::Log.debug(
|
|
115
|
+
"There are unmerged commits; use 'git branch -D #{branch}' to " +
|
|
116
|
+
'forcefully delete it)',
|
|
117
|
+
)
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Return to the branch we were on, or main
|
|
122
|
+
if all_local_branches.include?(curr)
|
|
123
|
+
git('checkout', curr)
|
|
124
|
+
else
|
|
125
|
+
checkout_main_branch
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
alias remotebranchcleanall rbcleanall
|
|
129
|
+
|
|
130
|
+
def gbcleanall(remote = nil)
|
|
131
|
+
assert_in_repo!
|
|
132
|
+
bcleanall
|
|
133
|
+
rcleanall(remote)
|
|
134
|
+
end
|
|
135
|
+
alias globalbranchcleanall gbcleanall
|
|
44
136
|
|
|
45
137
|
private
|
|
46
138
|
|
|
47
|
-
|
|
48
|
-
|
|
139
|
+
# rubocop:disable Naming/PredicateMethod
|
|
140
|
+
def clean_branch(name, type = :local)
|
|
141
|
+
undeleteable = MAIN_BRANCHES.dup
|
|
142
|
+
undeleteable << 'HEAD' if type == :remote
|
|
143
|
+
die("Cannot remove #{name} branch") if undeleteable.include?(name)
|
|
49
144
|
SugarJar::Log.debug('Fetch relevant remote...')
|
|
50
145
|
fetch_upstream
|
|
51
|
-
|
|
146
|
+
fetch(remote_from_ref(name)) if type == :remote
|
|
147
|
+
return false unless safe_to_clean?(name)
|
|
52
148
|
|
|
53
149
|
SugarJar::Log.debug('branch deemed safe to delete...')
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
150
|
+
if type == :remote
|
|
151
|
+
remote = remote_from_ref(name)
|
|
152
|
+
branch = branch_from_ref(name, :remote)
|
|
153
|
+
git('push', remote, '--delete', branch)
|
|
154
|
+
else
|
|
155
|
+
checkout_main_branch
|
|
156
|
+
git('branch', '-D', name)
|
|
157
|
+
rebase
|
|
158
|
+
end
|
|
57
159
|
true
|
|
58
160
|
end
|
|
161
|
+
# rubocop:enable Naming/PredicateMethod
|
|
59
162
|
|
|
60
|
-
def safe_to_clean(branch)
|
|
163
|
+
def safe_to_clean?(branch)
|
|
61
164
|
# cherry -v will output 1 line per commit on the target branch
|
|
62
165
|
# prefixed by a - or + - anything with a - can be dropped, anything
|
|
63
166
|
# else cannot.
|
|
167
|
+
SugarJar::Log.debug("Checking if branch #{branch} is safe to delete...")
|
|
168
|
+
if branch.start_with?('refs/remotes/')
|
|
169
|
+
remote = remote_from_ref(branch)
|
|
170
|
+
tracked = main_remote_branch(remote)
|
|
171
|
+
else
|
|
172
|
+
tracked = tracked_branch(branch)
|
|
173
|
+
end
|
|
64
174
|
out = git(
|
|
65
|
-
'cherry', '-v',
|
|
175
|
+
'cherry', '-v', tracked, branch
|
|
66
176
|
).stdout.lines.reject do |line|
|
|
67
177
|
line.start_with?('-')
|
|
68
178
|
end
|
|
@@ -80,10 +190,10 @@ class SugarJar
|
|
|
80
190
|
# First we need a temp branch to work on
|
|
81
191
|
tmpbranch = "_sugar_jar.#{Process.pid}"
|
|
82
192
|
|
|
83
|
-
git('checkout', '-b', tmpbranch,
|
|
193
|
+
git('checkout', '-b', tmpbranch, tracked)
|
|
84
194
|
s = git_nofail('merge', '--squash', branch)
|
|
85
195
|
if s.error?
|
|
86
|
-
cleanup_tmp_branch(tmpbranch, branch)
|
|
196
|
+
cleanup_tmp_branch(tmpbranch, branch, tracked)
|
|
87
197
|
SugarJar::Log.debug(
|
|
88
198
|
'Failed to merge changes into current main. This means we could ' +
|
|
89
199
|
'not figure out if this is merged or not. Check manually and use ' +
|
|
@@ -95,7 +205,7 @@ class SugarJar
|
|
|
95
205
|
s = git('diff', '--staged')
|
|
96
206
|
out = s.stdout
|
|
97
207
|
SugarJar::Log.debug("Squash-merged diff: #{out}")
|
|
98
|
-
cleanup_tmp_branch(tmpbranch, branch)
|
|
208
|
+
cleanup_tmp_branch(tmpbranch, branch, tracked)
|
|
99
209
|
if out.empty?
|
|
100
210
|
SugarJar::Log.debug(
|
|
101
211
|
'After squash-merging, this branch appears safe to delete',
|
|
@@ -109,9 +219,14 @@ class SugarJar
|
|
|
109
219
|
end
|
|
110
220
|
end
|
|
111
221
|
|
|
112
|
-
def cleanup_tmp_branch(tmp, backto)
|
|
113
|
-
|
|
222
|
+
def cleanup_tmp_branch(tmp, backto, tracked = nil)
|
|
223
|
+
tracked ||= tracked_branch
|
|
224
|
+
# Reset any changes on our temp branch from various merge attempts
|
|
225
|
+
# so we're in a state we know we can 'checkout' away from.
|
|
226
|
+
git('reset', '--hard', tracked)
|
|
227
|
+
# checkout whatever branch we were on before
|
|
114
228
|
git('checkout', backto)
|
|
229
|
+
# delete our temp branch
|
|
115
230
|
git('branch', '-D', tmp)
|
|
116
231
|
end
|
|
117
232
|
end
|
|
@@ -4,24 +4,11 @@ class SugarJar
|
|
|
4
4
|
class Commands
|
|
5
5
|
def pullsuggestions
|
|
6
6
|
assert_in_repo!
|
|
7
|
-
|
|
8
|
-
if dirty?
|
|
9
|
-
if @ignore_dirty
|
|
10
|
-
SugarJar::Log.warn(
|
|
11
|
-
'Your repo is dirty, but --ignore-dirty was specified, so ' +
|
|
12
|
-
'carrying on anyway.',
|
|
13
|
-
)
|
|
14
|
-
else
|
|
15
|
-
SugarJar::Log.error(
|
|
16
|
-
'Your repo is dirty, so I am not going to push. Please commit ' +
|
|
17
|
-
'or amend first.',
|
|
18
|
-
)
|
|
19
|
-
exit(1)
|
|
20
|
-
end
|
|
21
|
-
end
|
|
7
|
+
dirty_check!
|
|
22
8
|
|
|
23
9
|
src = "origin/#{current_branch}"
|
|
24
10
|
fetch('origin')
|
|
11
|
+
|
|
25
12
|
diff = git('diff', "..#{src}").stdout
|
|
26
13
|
return unless diff && !diff.empty?
|
|
27
14
|
|
|
@@ -20,20 +20,7 @@ class SugarJar
|
|
|
20
20
|
branch ||= current_branch
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
if @ignore_dirty
|
|
25
|
-
SugarJar::Log.warn(
|
|
26
|
-
'Your repo is dirty, but --ignore-dirty was specified, so ' +
|
|
27
|
-
'carrying on anyway.',
|
|
28
|
-
)
|
|
29
|
-
else
|
|
30
|
-
SugarJar::Log.error(
|
|
31
|
-
'Your repo is dirty, so I am not going to push. Please commit ' +
|
|
32
|
-
'or amend first.',
|
|
33
|
-
)
|
|
34
|
-
exit(1)
|
|
35
|
-
end
|
|
36
|
-
end
|
|
23
|
+
dirty_check!
|
|
37
24
|
|
|
38
25
|
unless run_prepush
|
|
39
26
|
if @ignore_prerun_failure
|
|
@@ -52,6 +39,7 @@ class SugarJar
|
|
|
52
39
|
puts git(*args).stderr
|
|
53
40
|
end
|
|
54
41
|
|
|
42
|
+
# rubocop:disable Naming/PredicateMethod
|
|
55
43
|
def run_prepush
|
|
56
44
|
@repo_config['on_push']&.each do |item|
|
|
57
45
|
SugarJar::Log.debug("Running on_push check type #{item}")
|
|
@@ -62,5 +50,6 @@ class SugarJar
|
|
|
62
50
|
end
|
|
63
51
|
true
|
|
64
52
|
end
|
|
53
|
+
# rubocop:enable Naming/PredicateMethod
|
|
65
54
|
end
|
|
66
55
|
end
|
data/lib/sugarjar/commands/up.rb
CHANGED
|
@@ -53,15 +53,35 @@ class SugarJar
|
|
|
53
53
|
end
|
|
54
54
|
end
|
|
55
55
|
|
|
56
|
+
def sync
|
|
57
|
+
assert_in_repo!
|
|
58
|
+
dirty_check!
|
|
59
|
+
|
|
60
|
+
src = "origin/#{current_branch}"
|
|
61
|
+
fetch('origin')
|
|
62
|
+
s = git_nofail('merge-base', '--is-ancestor', 'HEAD', src)
|
|
63
|
+
if s.error?
|
|
64
|
+
SugarJar::Log.debug(
|
|
65
|
+
"Choosing rebase sync since this isn't a direct ancestor",
|
|
66
|
+
)
|
|
67
|
+
rebase(src)
|
|
68
|
+
else
|
|
69
|
+
SugarJar::Log.debug('Choosing reset sync since this is an ancestor')
|
|
70
|
+
git('reset', '--hard', src)
|
|
71
|
+
end
|
|
72
|
+
SugarJar::Log.info("Synced to #{src}.")
|
|
73
|
+
end
|
|
74
|
+
|
|
56
75
|
private
|
|
57
76
|
|
|
58
|
-
def rebase
|
|
77
|
+
def rebase(base = nil)
|
|
78
|
+
skip_base_warning = !base.nil?
|
|
59
79
|
SugarJar::Log.debug('Fetching upstream')
|
|
60
80
|
fetch_upstream
|
|
61
81
|
curr = current_branch
|
|
62
82
|
# this isn't a hash, it's a named param, silly rubocop
|
|
63
83
|
# rubocop:disable Style/HashSyntax
|
|
64
|
-
base
|
|
84
|
+
base ||= tracked_branch(fallback: false)
|
|
65
85
|
# rubocop:enable Style/HashSyntax
|
|
66
86
|
unless base
|
|
67
87
|
SugarJar::Log.info(
|
|
@@ -74,7 +94,8 @@ class SugarJar
|
|
|
74
94
|
# If this is a subfeature based on a local branch which has since
|
|
75
95
|
# been deleted, 'tracked branch' will automatically return <most_main>
|
|
76
96
|
# so we don't need any special handling for that
|
|
77
|
-
if !MAIN_BRANCHES.include?(curr) && base == "origin/#{curr}"
|
|
97
|
+
if !MAIN_BRANCHES.include?(curr) && base == "origin/#{curr}" &&
|
|
98
|
+
!skip_base_warning
|
|
78
99
|
SugarJar::Log.warn(
|
|
79
100
|
"This branch is tracking origin/#{curr}, which is probably your " +
|
|
80
101
|
'downstream (where you push _to_) as opposed to your upstream ' +
|
data/lib/sugarjar/commands.rb
CHANGED
|
@@ -119,6 +119,23 @@ class SugarJar
|
|
|
119
119
|
die('sugarjar must be run from inside a git repo')
|
|
120
120
|
end
|
|
121
121
|
|
|
122
|
+
def dirty_check!
|
|
123
|
+
return unless dirty?
|
|
124
|
+
|
|
125
|
+
if @ignore_dirty
|
|
126
|
+
SugarJar::Log.warn(
|
|
127
|
+
'Your repo is dirty, but --ignore-dirty was specified, so ' +
|
|
128
|
+
'carrying on anyway.',
|
|
129
|
+
)
|
|
130
|
+
else
|
|
131
|
+
SugarJar::Log.error(
|
|
132
|
+
'Your repo is dirty, so I am refusing to continue. Please commit ' +
|
|
133
|
+
'or amend first (or use --ignore-dirty to override).',
|
|
134
|
+
)
|
|
135
|
+
exit(1)
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
122
139
|
def determine_main_branch(branches)
|
|
123
140
|
branches.include?('main') ? 'main' : 'master'
|
|
124
141
|
end
|
|
@@ -150,8 +167,10 @@ class SugarJar
|
|
|
150
167
|
git(
|
|
151
168
|
'branch', '--format', '%(refname)'
|
|
152
169
|
).stdout.lines.map do |line|
|
|
153
|
-
|
|
154
|
-
|
|
170
|
+
if line.start_with?('(')
|
|
171
|
+
SugarJar::Log.debug("Skipping meta-branch: #{line.strip}")
|
|
172
|
+
next
|
|
173
|
+
end
|
|
155
174
|
branch_from_ref(line.strip)
|
|
156
175
|
end
|
|
157
176
|
end
|
|
@@ -188,11 +207,13 @@ class SugarJar
|
|
|
188
207
|
all_local_branches.reject { |x| x == most_main }.include?(base)
|
|
189
208
|
end
|
|
190
209
|
|
|
191
|
-
def tracked_branch(fallback: true)
|
|
192
|
-
|
|
210
|
+
def tracked_branch(branch = nil, fallback: true)
|
|
211
|
+
curr = current_branch
|
|
212
|
+
git('checkout', branch) if branch && branch != curr
|
|
193
213
|
s = git_nofail(
|
|
194
214
|
'rev-parse', '--abbrev-ref', '--symbolic-full-name', '@{u}'
|
|
195
215
|
)
|
|
216
|
+
git('checkout', curr) if branch && branch != curr
|
|
196
217
|
if s.error?
|
|
197
218
|
branch = fallback ? most_main : nil
|
|
198
219
|
SugarJar::Log.debug("No specific tracked branch, using #{branch}")
|
|
@@ -307,6 +328,30 @@ class SugarJar
|
|
|
307
328
|
exit(1)
|
|
308
329
|
end
|
|
309
330
|
|
|
331
|
+
def worktree_branches
|
|
332
|
+
worktrees.values.map do |wt|
|
|
333
|
+
branch_from_ref(wt['branch'])
|
|
334
|
+
end
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
def worktrees
|
|
338
|
+
root = SugarJar::Util.repo_root
|
|
339
|
+
s = git('worktree', 'list', '--porcelain')
|
|
340
|
+
s.error!
|
|
341
|
+
worktrees = {}
|
|
342
|
+
# each entry is separated by a double newline
|
|
343
|
+
s.stdout.split("\n\n").each do |entry|
|
|
344
|
+
# then each key/val is split by a new line with the key and
|
|
345
|
+
# the value themselves split by a whitespace
|
|
346
|
+
tree = entry.split("\n").to_h(&:split)
|
|
347
|
+
# Skip the one
|
|
348
|
+
next if tree['worktree'] == root
|
|
349
|
+
|
|
350
|
+
worktrees[tree['worktree']] = tree
|
|
351
|
+
end
|
|
352
|
+
worktrees
|
|
353
|
+
end
|
|
354
|
+
|
|
310
355
|
def branch_from_ref(ref, type = :local)
|
|
311
356
|
# local branches are refs/head/XXXX
|
|
312
357
|
# remote branches are refs/remotes/<remote>/XXXX
|
|
@@ -314,6 +359,12 @@ class SugarJar
|
|
|
314
359
|
ref.split('/')[base..].join('/')
|
|
315
360
|
end
|
|
316
361
|
|
|
362
|
+
def remote_from_ref(ref)
|
|
363
|
+
return nil unless ref.start_with?('refs/remotes/')
|
|
364
|
+
|
|
365
|
+
ref.split('/')[2]
|
|
366
|
+
end
|
|
367
|
+
|
|
317
368
|
def git(*)
|
|
318
369
|
SugarJar::Util.git(*, :color => @color)
|
|
319
370
|
end
|
data/lib/sugarjar/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sugarjar
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.0.
|
|
4
|
+
version: 2.0.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Phil Dibowitz
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-01-08 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: deep_merge
|