@@ -572,6 +572,40 @@ static int interactive_checkout(const char *revision, const char **pathspec,
572
572
return run_add_interactive (revision , "--patch=checkout" , pathspec );
573
573
}
574
574
575
+ struct tracking_name_data {
576
+ const char * name ;
577
+ char * remote ;
578
+ int unique ;
579
+ };
580
+
581
+ static int check_tracking_name (const char * refname , const unsigned char * sha1 ,
582
+ int flags , void * cb_data )
583
+ {
584
+ struct tracking_name_data * cb = cb_data ;
585
+ const char * slash ;
586
+
587
+ if (prefixcmp (refname , "refs/remotes/" ))
588
+ return 0 ;
589
+ slash = strchr (refname + 13 , '/' );
590
+ if (!slash || strcmp (slash + 1 , cb -> name ))
591
+ return 0 ;
592
+ if (cb -> remote ) {
593
+ cb -> unique = 0 ;
594
+ return 0 ;
595
+ }
596
+ cb -> remote = xstrdup (refname );
597
+ return 0 ;
598
+ }
599
+
600
+ static const char * unique_tracking_name (const char * name )
601
+ {
602
+ struct tracking_name_data cb_data = { name , NULL , 1 };
603
+ for_each_ref (check_tracking_name , & cb_data );
604
+ if (cb_data .unique )
605
+ return cb_data .remote ;
606
+ free (cb_data .remote );
607
+ return NULL ;
608
+ }
575
609
576
610
int cmd_checkout (int argc , const char * * argv , const char * prefix )
577
611
{
@@ -630,8 +664,6 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
630
664
opts .new_branch = argv0 + 1 ;
631
665
}
632
666
633
- if (opts .track == BRANCH_TRACK_UNSPECIFIED )
634
- opts .track = git_branch_track ;
635
667
if (conflict_style ) {
636
668
opts .merge = 1 ; /* implied */
637
669
git_xmerge_config ("merge.conflictstyle" , conflict_style , NULL );
@@ -655,6 +687,11 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
655
687
* With no paths, if <something> is a commit, that is to
656
688
* switch to the branch or detach HEAD at it.
657
689
*
690
+ * With no paths, if <something> is _not_ a commit, no -t nor -b
691
+ * was given, and there is a tracking branch whose name is
692
+ * <something> in one and only one remote, then this is a short-hand
693
+ * to fork local <something> from that remote tracking branch.
694
+ *
658
695
* Otherwise <something> shall not be ambiguous.
659
696
* - If it's *only* a reference, treat it like case (1).
660
697
* - If it's only a path, treat it like case (2).
@@ -677,7 +714,20 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
677
714
if (get_sha1 (arg , rev )) {
678
715
if (has_dash_dash ) /* case (1) */
679
716
die ("invalid reference: %s" , arg );
680
- goto no_reference ; /* case (3 -> 2) */
717
+ if (!patch_mode &&
718
+ opts .track == BRANCH_TRACK_UNSPECIFIED &&
719
+ !opts .new_branch &&
720
+ !check_filename (NULL , arg ) &&
721
+ argc == 1 ) {
722
+ const char * remote = unique_tracking_name (arg );
723
+ if (!remote || get_sha1 (remote , rev ))
724
+ goto no_reference ;
725
+ opts .new_branch = arg ;
726
+ arg = remote ;
727
+ /* DWIMmed to create local branch */
728
+ }
729
+ else
730
+ goto no_reference ;
681
731
}
682
732
683
733
/* we can't end up being in (2) anymore, eat the argument */
@@ -715,6 +765,10 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
715
765
}
716
766
717
767
no_reference :
768
+
769
+ if (opts .track == BRANCH_TRACK_UNSPECIFIED )
770
+ opts .track = git_branch_track ;
771
+
718
772
if (argc ) {
719
773
const char * * pathspec = get_pathspec (prefix , argv );
720
774
0 commit comments