1313#include "revision.h"
1414#include "rerere.h"
1515#include "merge-recursive.h"
16+ #include "refs.h"
1617
1718/*
1819 * This implements the builtins revert and cherry-pick.
@@ -35,7 +36,7 @@ static const char * const cherry_pick_usage[] = {
3536 NULL
3637};
3738
38- static int edit , no_replay , no_commit , mainline , signoff ;
39+ static int edit , no_replay , no_commit , mainline , signoff , allow_ff ;
3940static enum { REVERT , CHERRY_PICK } action ;
4041static struct commit * commit ;
4142static const char * commit_name ;
@@ -60,8 +61,19 @@ static void parse_args(int argc, const char **argv)
6061 OPT_INTEGER ('m' , "mainline" , & mainline , "parent number" ),
6162 OPT_RERERE_AUTOUPDATE (& allow_rerere_auto ),
6263 OPT_END (),
64+ OPT_END (),
65+ OPT_END (),
6366 };
6467
68+ if (action == CHERRY_PICK ) {
69+ struct option cp_extra [] = {
70+ OPT_BOOLEAN (0 , "ff" , & allow_ff , "allow fast-forward" ),
71+ OPT_END (),
72+ };
73+ if (parse_options_concat (options , ARRAY_SIZE (options ), cp_extra ))
74+ die ("program error" );
75+ }
76+
6577 if (parse_options (argc , argv , NULL , options , usage_str , 0 ) != 1 )
6678 usage_with_options (usage_str , options );
6779
@@ -244,14 +256,25 @@ static NORETURN void die_dirty_index(const char *me)
244256 }
245257}
246258
259+ static int fast_forward_to (const unsigned char * to , const unsigned char * from )
260+ {
261+ struct ref_lock * ref_lock ;
262+
263+ read_cache ();
264+ if (checkout_fast_forward (from , to ))
265+ exit (1 ); /* the callee should have complained already */
266+ ref_lock = lock_any_ref_for_update ("HEAD" , from , 0 );
267+ return write_ref_sha1 (ref_lock , to , "cherry-pick" );
268+ }
269+
247270static int revert_or_cherry_pick (int argc , const char * * argv )
248271{
249272 unsigned char head [20 ];
250273 struct commit * base , * next , * parent ;
251274 int i , index_fd , clean ;
252275 char * oneline , * reencoded_message = NULL ;
253276 const char * message , * encoding ;
254- char * defmsg = git_pathdup ( "MERGE_MSG" ) ;
277+ char * defmsg = NULL ;
255278 struct merge_options o ;
256279 struct tree * result , * next_tree , * base_tree , * head_tree ;
257280 static struct lock_file index_lock ;
@@ -265,6 +288,17 @@ static int revert_or_cherry_pick(int argc, const char **argv)
265288 if (action == REVERT && !no_replay )
266289 die ("revert is incompatible with replay" );
267290
291+ if (allow_ff ) {
292+ if (signoff )
293+ die ("cherry-pick --ff cannot be used with --signoff" );
294+ if (no_commit )
295+ die ("cherry-pick --ff cannot be used with --no-commit" );
296+ if (no_replay )
297+ die ("cherry-pick --ff cannot be used with -x" );
298+ if (edit )
299+ die ("cherry-pick --ff cannot be used with --edit" );
300+ }
301+
268302 if (read_cache () < 0 )
269303 die ("git %s: failed to read the index" , me );
270304 if (no_commit ) {
@@ -284,8 +318,6 @@ static int revert_or_cherry_pick(int argc, const char **argv)
284318 }
285319 discard_cache ();
286320
287- index_fd = hold_locked_index (& index_lock , 1 );
288-
289321 if (!commit -> parents ) {
290322 if (action == REVERT )
291323 die ("Cannot revert a root commit" );
@@ -314,6 +346,9 @@ static int revert_or_cherry_pick(int argc, const char **argv)
314346 else
315347 parent = commit -> parents -> item ;
316348
349+ if (allow_ff && !hashcmp (parent -> object .sha1 , head ))
350+ return fast_forward_to (commit -> object .sha1 , head );
351+
317352 if (!(message = commit -> buffer ))
318353 die ("Cannot get commit message for %s" ,
319354 sha1_to_hex (commit -> object .sha1 ));
@@ -329,6 +364,7 @@ static int revert_or_cherry_pick(int argc, const char **argv)
329364 * reverse of it if we are revert.
330365 */
331366
367+ defmsg = git_pathdup ("MERGE_MSG" );
332368 msg_fd = hold_lock_file_for_update (& msg_file , defmsg ,
333369 LOCK_DIE_ON_ERROR );
334370
@@ -343,6 +379,8 @@ static int revert_or_cherry_pick(int argc, const char **argv)
343379
344380 oneline = get_oneline (message );
345381
382+ index_fd = hold_locked_index (& index_lock , 1 );
383+
346384 if (action == REVERT ) {
347385 char * oneline_body = strchr (oneline , ' ' );
348386
0 commit comments