@@ -51,6 +51,10 @@ struct Args {
51
51
/// The maximum number of commits to show when looking for your merge point
52
52
#[ structopt( short = "m" , long = "max-commits" , default_value = "15" ) ]
53
53
max_commits : usize ,
54
+
55
+ /// Specify a commit to ammend by the subject line of the commit
56
+ #[ structopt( short = "P" , long) ]
57
+ commit_message_pattern : Option < String > ,
54
58
}
55
59
56
60
#[ derive( Eq , PartialEq , Debug ) ]
@@ -64,7 +68,7 @@ fn main() {
64
68
if env:: args ( ) . next ( ) . unwrap ( ) . ends_with ( "squash" ) {
65
69
args. squash = true
66
70
}
67
- if let Err ( e) = run ( args. squash , args. max_commits ) {
71
+ if let Err ( e) = run ( args. squash , args. max_commits , args . commit_message_pattern ) {
68
72
// An empty message means don't display any error message
69
73
let msg = e. to_string ( ) ;
70
74
if !msg. is_empty ( ) {
@@ -73,7 +77,11 @@ fn main() {
73
77
}
74
78
}
75
79
76
- fn run ( squash : bool , max_commits : usize ) -> Result < ( ) , Box < dyn Error > > {
80
+ fn run (
81
+ squash : bool ,
82
+ max_commits : usize ,
83
+ message_pattern : Option < String > ,
84
+ ) -> Result < ( ) , Box < dyn Error > > {
77
85
let repo = Repository :: open ( "." ) ?;
78
86
let head = repo
79
87
. head ( )
@@ -82,8 +90,15 @@ fn run(squash: bool, max_commits: usize) -> Result<(), Box<dyn Error>> {
82
90
let head_branch = Branch :: wrap ( head) ;
83
91
let diff = repo. diff_tree_to_index ( Some ( & head_tree) , None , None ) ?;
84
92
let upstream = get_upstream ( & repo, & head_branch) ?;
85
- let commit_to_amend =
86
- create_fixup_commit ( & repo, & head_branch, upstream, & diff, squash, max_commits) ?;
93
+ let commit_to_amend = create_fixup_commit (
94
+ & repo,
95
+ & head_branch,
96
+ upstream,
97
+ & diff,
98
+ squash,
99
+ max_commits,
100
+ & message_pattern,
101
+ ) ?;
87
102
println ! (
88
103
"selected: {} {}" ,
89
104
& commit_to_amend. id( ) . to_string( ) [ 0 ..10 ] ,
@@ -143,6 +158,7 @@ fn create_fixup_commit<'a>(
143
158
diff : & ' a Diff ,
144
159
squash : bool ,
145
160
max_commits : usize ,
161
+ message_pattern : & Option < String > ,
146
162
) -> Result < Commit < ' a > , Box < dyn Error > > {
147
163
let diffstat = diff. stats ( ) ?;
148
164
if diffstat. files_changed ( ) == 0 {
@@ -166,7 +182,7 @@ fn create_fixup_commit<'a>(
166
182
println ! ( "Staged changes:" ) ;
167
183
print_diff ( Changes :: Staged ) ?;
168
184
}
169
- let commit_to_amend = select_commit_to_amend ( & repo, upstream, max_commits) ?;
185
+ let commit_to_amend = select_commit_to_amend ( & repo, upstream, max_commits, message_pattern ) ?;
170
186
do_fixup_commit ( & repo, & head_branch, & commit_to_amend, squash) ?;
171
187
Ok ( commit_to_amend)
172
188
}
@@ -195,6 +211,7 @@ fn select_commit_to_amend<'a>(
195
211
repo : & ' a Repository ,
196
212
upstream : Option < Object < ' a > > ,
197
213
max_commits : usize ,
214
+ message_pattern : & Option < String > ,
198
215
) -> Result < Commit < ' a > , anyhow:: Error > {
199
216
let mut walker = repo. revwalk ( ) ?;
200
217
walker. push_head ( ) ?;
@@ -230,33 +247,49 @@ fn select_commit_to_amend<'a>(
230
247
} )
231
248
} )
232
249
. collect ( ) ;
233
- let rev_aliases = commits
234
- . iter ( )
235
- . enumerate ( )
236
- . map ( |( i, commit) | {
237
- let bname = if i > 0 {
238
- branches
239
- . get ( & commit. id ( ) )
240
- . map ( |n| format ! ( "({}) " , n) )
241
- . unwrap_or_else ( String :: new)
242
- } else {
243
- String :: new ( )
244
- } ;
245
- format ! (
246
- "{} {}{}" ,
247
- & style( & commit. id( ) . to_string( ) [ 0 ..10 ] ) . blue( ) ,
248
- style( bname) . green( ) ,
249
- commit. summary( ) . unwrap_or( "no commit summary" )
250
- )
251
- } )
252
- . collect :: < Vec < _ > > ( ) ;
253
- if upstream. is_none ( ) {
254
- eprintln ! ( "Select a commit to amend (no upstream for HEAD):" ) ;
250
+ if let Some ( message_pattern) = message_pattern. as_ref ( ) {
251
+ eprintln ! (
252
+ "trying to find message_pattern in {} commits" ,
253
+ commits. len( )
254
+ ) ;
255
+ commits
256
+ . into_iter ( )
257
+ . find ( |commit| {
258
+ commit
259
+ . summary ( )
260
+ . map ( |s| s. contains ( message_pattern) )
261
+ . unwrap_or ( false )
262
+ } )
263
+ . ok_or_else ( || anyhow:: anyhow!( "No commit contains the pattern in its summary" ) )
255
264
} else {
256
- eprintln ! ( "Select a commit to amend:" ) ;
265
+ let rev_aliases = commits
266
+ . iter ( )
267
+ . enumerate ( )
268
+ . map ( |( i, commit) | {
269
+ let bname = if i > 0 {
270
+ branches
271
+ . get ( & commit. id ( ) )
272
+ . map ( |n| format ! ( "({}) " , n) )
273
+ . unwrap_or_else ( String :: new)
274
+ } else {
275
+ String :: new ( )
276
+ } ;
277
+ format ! (
278
+ "{} {}{}" ,
279
+ & style( & commit. id( ) . to_string( ) [ 0 ..10 ] ) . blue( ) ,
280
+ style( bname) . green( ) ,
281
+ commit. summary( ) . unwrap_or( "no commit summary" )
282
+ )
283
+ } )
284
+ . collect :: < Vec < _ > > ( ) ;
285
+ if upstream. is_none ( ) {
286
+ eprintln ! ( "Select a commit to amend (no upstream for HEAD):" ) ;
287
+ } else {
288
+ eprintln ! ( "Select a commit to amend:" ) ;
289
+ }
290
+ let selected = Select :: new ( ) . items ( & rev_aliases) . default ( 0 ) . interact ( ) ;
291
+ Ok ( repo. find_commit ( commits[ selected?] . id ( ) ) ?)
257
292
}
258
- let selected = Select :: new ( ) . items ( & rev_aliases) . default ( 0 ) . interact ( ) ;
259
- Ok ( repo. find_commit ( commits[ selected?] . id ( ) ) ?)
260
293
}
261
294
262
295
fn format_ref ( rf : & git2:: Reference < ' _ > ) -> Result < String , anyhow:: Error > {
0 commit comments