15
15
#include "dir.h"
16
16
#include "refs.h"
17
17
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
+
18
65
static const char * const pull_usage [] = {
19
66
N_ ("git pull [options] [<repository> [<refspec>...]]" ),
20
67
NULL
@@ -24,7 +71,8 @@ static const char * const pull_usage[] = {
24
71
static int opt_verbosity ;
25
72
static char * opt_progress ;
26
73
27
- /* Options passed to git-merge */
74
+ /* Options passed to git-merge or git-rebase */
75
+ static enum rebase_type opt_rebase ;
28
76
static char * opt_diffstat ;
29
77
static char * opt_log ;
30
78
static char * opt_squash ;
@@ -58,8 +106,12 @@ static struct option pull_options[] = {
58
106
N_ ("force progress reporting" ),
59
107
PARSE_OPT_NOARG ),
60
108
61
- /* Options passed to git-merge */
109
+ /* Options passed to git-merge or git-rebase */
62
110
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 },
63
115
OPT_PASSTHRU ('n' , NULL , & opt_diffstat , NULL ,
64
116
N_ ("do not show a diffstat at the end of the merge" ),
65
117
PARSE_OPT_NOARG | PARSE_OPT_NONEG ),
@@ -449,11 +501,194 @@ static int run_merge(void)
449
501
return ret ;
450
502
}
451
503
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
+
452
686
int cmd_pull (int argc , const char * * argv , const char * prefix )
453
687
{
454
688
const char * repo , * * refspecs ;
455
689
struct sha1_array merge_heads = SHA1_ARRAY_INIT ;
456
690
unsigned char orig_head [GIT_SHA1_RAWSZ ], curr_head [GIT_SHA1_RAWSZ ];
691
+ unsigned char rebase_fork_point [GIT_SHA1_RAWSZ ];
457
692
458
693
if (!getenv ("_GIT_USE_BUILTIN_PULL" )) {
459
694
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)
483
718
if (get_sha1 ("HEAD" , orig_head ))
484
719
hashclr (orig_head );
485
720
721
+ if (opt_rebase )
722
+ if (get_rebase_fork_point (rebase_fork_point , repo , * refspecs ))
723
+ hashclr (rebase_fork_point );
724
+
486
725
if (run_fetch (repo , refspecs ))
487
726
return 1 ;
488
727
@@ -524,6 +763,10 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
524
763
if (merge_heads .nr > 1 )
525
764
die (_ ("Cannot merge multiple branches into empty head." ));
526
765
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 );
527
770
} else
528
771
return run_merge ();
529
772
}
0 commit comments