1515#include "dir.h"
1616#include "refs.h"
1717
18+ enum rebase_type {
19+ REBASE_INVALID = -1 ,
20+ REBASE_FALSE = 0 ,
21+ REBASE_TRUE ,
22+ REBASE_PRESERVE
23+ };
24+
25+ /**
26+ * Parses the value of --rebase. If value is a false value, returns
27+ * REBASE_FALSE. If value is a true value, returns REBASE_TRUE. If value is
28+ * "preserve", returns REBASE_PRESERVE. If value is a invalid value, dies with
29+ * a fatal error if fatal is true, otherwise returns REBASE_INVALID.
30+ */
31+ static enum rebase_type parse_config_rebase (const char * key , const char * value ,
32+ int fatal )
33+ {
34+ int v = git_config_maybe_bool ("pull.rebase" , value );
35+
36+ if (!v )
37+ return REBASE_FALSE ;
38+ else if (v > 0 )
39+ return REBASE_TRUE ;
40+ else if (!strcmp (value , "preserve" ))
41+ return REBASE_PRESERVE ;
42+
43+ if (fatal )
44+ die (_ ("Invalid value for %s: %s" ), key , value );
45+ else
46+ error (_ ("Invalid value for %s: %s" ), key , value );
47+
48+ return REBASE_INVALID ;
49+ }
50+
51+ /**
52+ * Callback for --rebase, which parses arg with parse_config_rebase().
53+ */
54+ static int parse_opt_rebase (const struct option * opt , const char * arg , int unset )
55+ {
56+ enum rebase_type * value = opt -> value ;
57+
58+ if (arg )
59+ * value = parse_config_rebase ("--rebase" , arg , 0 );
60+ else
61+ * value = unset ? REBASE_FALSE : REBASE_TRUE ;
62+ return * value == REBASE_INVALID ? -1 : 0 ;
63+ }
64+
1865static const char * const pull_usage [] = {
1966 N_ ("git pull [options] [<repository> [<refspec>...]]" ),
2067 NULL
@@ -24,7 +71,8 @@ static const char * const pull_usage[] = {
2471static int opt_verbosity ;
2572static char * opt_progress ;
2673
27- /* Options passed to git-merge */
74+ /* Options passed to git-merge or git-rebase */
75+ static enum rebase_type opt_rebase ;
2876static char * opt_diffstat ;
2977static char * opt_log ;
3078static char * opt_squash ;
@@ -58,8 +106,12 @@ static struct option pull_options[] = {
58106 N_ ("force progress reporting" ),
59107 PARSE_OPT_NOARG ),
60108
61- /* Options passed to git-merge */
109+ /* Options passed to git-merge or git-rebase */
62110 OPT_GROUP (N_ ("Options related to merging" )),
111+ { OPTION_CALLBACK , 'r' , "rebase" , & opt_rebase ,
112+ N_ ("false|true|preserve" ),
113+ N_ ("incorporate changes by rebasing rather than merging" ),
114+ PARSE_OPT_OPTARG , parse_opt_rebase },
63115 OPT_PASSTHRU ('n' , NULL , & opt_diffstat , NULL ,
64116 N_ ("do not show a diffstat at the end of the merge" ),
65117 PARSE_OPT_NOARG | PARSE_OPT_NONEG ),
@@ -449,11 +501,194 @@ static int run_merge(void)
449501 return ret ;
450502}
451503
504+ /**
505+ * Returns remote's upstream branch for the current branch. If remote is NULL,
506+ * the current branch's configured default remote is used. Returns NULL if
507+ * `remote` does not name a valid remote, HEAD does not point to a branch,
508+ * remote is not the branch's configured remote or the branch does not have any
509+ * configured upstream branch.
510+ */
511+ static const char * get_upstream_branch (const char * remote )
512+ {
513+ struct remote * rm ;
514+ struct branch * curr_branch ;
515+ const char * curr_branch_remote ;
516+
517+ rm = remote_get (remote );
518+ if (!rm )
519+ return NULL ;
520+
521+ curr_branch = branch_get ("HEAD" );
522+ if (!curr_branch )
523+ return NULL ;
524+
525+ curr_branch_remote = remote_for_branch (curr_branch , NULL );
526+ assert (curr_branch_remote );
527+
528+ if (strcmp (curr_branch_remote , rm -> name ))
529+ return NULL ;
530+
531+ return branch_get_upstream (curr_branch , NULL );
532+ }
533+
534+ /**
535+ * Derives the remote tracking branch from the remote and refspec.
536+ *
537+ * FIXME: The current implementation assumes the default mapping of
538+ * refs/heads/<branch_name> to refs/remotes/<remote_name>/<branch_name>.
539+ */
540+ static const char * get_tracking_branch (const char * remote , const char * refspec )
541+ {
542+ struct refspec * spec ;
543+ const char * spec_src ;
544+ const char * merge_branch ;
545+
546+ spec = parse_fetch_refspec (1 , & refspec );
547+ spec_src = spec -> src ;
548+ if (!* spec_src || !strcmp (spec_src , "HEAD" ))
549+ spec_src = "HEAD" ;
550+ else if (skip_prefix (spec_src , "heads/" , & spec_src ))
551+ ;
552+ else if (skip_prefix (spec_src , "refs/heads/" , & spec_src ))
553+ ;
554+ else if (starts_with (spec_src , "refs/" ) ||
555+ starts_with (spec_src , "tags/" ) ||
556+ starts_with (spec_src , "remotes/" ))
557+ spec_src = "" ;
558+
559+ if (* spec_src ) {
560+ if (!strcmp (remote , "." ))
561+ merge_branch = mkpath ("refs/heads/%s" , spec_src );
562+ else
563+ merge_branch = mkpath ("refs/remotes/%s/%s" , remote , spec_src );
564+ } else
565+ merge_branch = NULL ;
566+
567+ free_refspec (1 , spec );
568+ return merge_branch ;
569+ }
570+
571+ /**
572+ * Given the repo and refspecs, sets fork_point to the point at which the
573+ * current branch forked from its remote tracking branch. Returns 0 on success,
574+ * -1 on failure.
575+ */
576+ static int get_rebase_fork_point (unsigned char * fork_point , const char * repo ,
577+ const char * refspec )
578+ {
579+ int ret ;
580+ struct branch * curr_branch ;
581+ const char * remote_branch ;
582+ struct child_process cp = CHILD_PROCESS_INIT ;
583+ struct strbuf sb = STRBUF_INIT ;
584+
585+ curr_branch = branch_get ("HEAD" );
586+ if (!curr_branch )
587+ return -1 ;
588+
589+ if (refspec )
590+ remote_branch = get_tracking_branch (repo , refspec );
591+ else
592+ remote_branch = get_upstream_branch (repo );
593+
594+ if (!remote_branch )
595+ return -1 ;
596+
597+ argv_array_pushl (& cp .args , "merge-base" , "--fork-point" ,
598+ remote_branch , curr_branch -> name , NULL );
599+ cp .no_stdin = 1 ;
600+ cp .no_stderr = 1 ;
601+ cp .git_cmd = 1 ;
602+
603+ ret = capture_command (& cp , & sb , GIT_SHA1_HEXSZ );
604+ if (ret )
605+ goto cleanup ;
606+
607+ ret = get_sha1_hex (sb .buf , fork_point );
608+ if (ret )
609+ goto cleanup ;
610+
611+ cleanup :
612+ strbuf_release (& sb );
613+ return ret ? -1 : 0 ;
614+ }
615+
616+ /**
617+ * Sets merge_base to the octopus merge base of curr_head, merge_head and
618+ * fork_point. Returns 0 if a merge base is found, 1 otherwise.
619+ */
620+ static int get_octopus_merge_base (unsigned char * merge_base ,
621+ const unsigned char * curr_head ,
622+ const unsigned char * merge_head ,
623+ const unsigned char * fork_point )
624+ {
625+ struct commit_list * revs = NULL , * result ;
626+
627+ commit_list_insert (lookup_commit_reference (curr_head ), & revs );
628+ commit_list_insert (lookup_commit_reference (merge_head ), & revs );
629+ if (!is_null_sha1 (fork_point ))
630+ commit_list_insert (lookup_commit_reference (fork_point ), & revs );
631+
632+ result = reduce_heads (get_octopus_merge_bases (revs ));
633+ free_commit_list (revs );
634+ if (!result )
635+ return 1 ;
636+
637+ hashcpy (merge_base , result -> item -> object .sha1 );
638+ return 0 ;
639+ }
640+
641+ /**
642+ * Given the current HEAD SHA1, the merge head returned from git-fetch and the
643+ * fork point calculated by get_rebase_fork_point(), runs git-rebase with the
644+ * appropriate arguments and returns its exit status.
645+ */
646+ static int run_rebase (const unsigned char * curr_head ,
647+ const unsigned char * merge_head ,
648+ const unsigned char * fork_point )
649+ {
650+ int ret ;
651+ unsigned char oct_merge_base [GIT_SHA1_RAWSZ ];
652+ struct argv_array args = ARGV_ARRAY_INIT ;
653+
654+ if (!get_octopus_merge_base (oct_merge_base , curr_head , merge_head , fork_point ))
655+ if (!is_null_sha1 (fork_point ) && !hashcmp (oct_merge_base , fork_point ))
656+ fork_point = NULL ;
657+
658+ argv_array_push (& args , "rebase" );
659+
660+ /* Shared options */
661+ argv_push_verbosity (& args );
662+
663+ /* Options passed to git-rebase */
664+ if (opt_rebase == REBASE_PRESERVE )
665+ argv_array_push (& args , "--preserve-merges" );
666+ if (opt_diffstat )
667+ argv_array_push (& args , opt_diffstat );
668+ argv_array_pushv (& args , opt_strategies .argv );
669+ argv_array_pushv (& args , opt_strategy_opts .argv );
670+ if (opt_gpg_sign )
671+ argv_array_push (& args , opt_gpg_sign );
672+
673+ argv_array_push (& args , "--onto" );
674+ argv_array_push (& args , sha1_to_hex (merge_head ));
675+
676+ if (fork_point && !is_null_sha1 (fork_point ))
677+ argv_array_push (& args , sha1_to_hex (fork_point ));
678+ else
679+ argv_array_push (& args , sha1_to_hex (merge_head ));
680+
681+ ret = run_command_v_opt (args .argv , RUN_GIT_CMD );
682+ argv_array_clear (& args );
683+ return ret ;
684+ }
685+
452686int cmd_pull (int argc , const char * * argv , const char * prefix )
453687{
454688 const char * repo , * * refspecs ;
455689 struct sha1_array merge_heads = SHA1_ARRAY_INIT ;
456690 unsigned char orig_head [GIT_SHA1_RAWSZ ], curr_head [GIT_SHA1_RAWSZ ];
691+ unsigned char rebase_fork_point [GIT_SHA1_RAWSZ ];
457692
458693 if (!getenv ("_GIT_USE_BUILTIN_PULL" )) {
459694 const char * path = mkpath ("%s/git-pull" , git_exec_path ());
@@ -483,6 +718,10 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
483718 if (get_sha1 ("HEAD" , orig_head ))
484719 hashclr (orig_head );
485720
721+ if (opt_rebase )
722+ if (get_rebase_fork_point (rebase_fork_point , repo , * refspecs ))
723+ hashclr (rebase_fork_point );
724+
486725 if (run_fetch (repo , refspecs ))
487726 return 1 ;
488727
@@ -524,6 +763,10 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
524763 if (merge_heads .nr > 1 )
525764 die (_ ("Cannot merge multiple branches into empty head." ));
526765 return pull_into_void (* merge_heads .sha1 , curr_head );
766+ } else if (opt_rebase ) {
767+ if (merge_heads .nr > 1 )
768+ die (_ ("Cannot rebase onto multiple branches." ));
769+ return run_rebase (curr_head , * merge_heads .sha1 , rebase_fork_point );
527770 } else
528771 return run_merge ();
529772}
0 commit comments