Merge branch 'sz/submodule-force-update'
authorJunio C Hamano <gitster@pobox.com>
Mon, 3 Sep 2012 22:54:17 +0000 (15:54 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 3 Sep 2012 22:54:18 +0000 (15:54 -0700)
"git submodule update --force" used to leave the working tree of the
submodule intact when there were local changes. It is more intiutive
to make "--force" a sign to run "checkout -f" to overwrite them.

* sz/submodule-force-update:
Make 'git submodule update --force' always check out submodules.

1  2 
git-submodule.sh
t/t7406-submodule-update.sh
diff --combined git-submodule.sh
index 08405249edfedba744a36e9e653320b0948b2746,812a60fe4c4184d57ab22a43e0a471753f2a577a..3e2045e52daf43cc351af23af0fd770fb1a5044f
@@@ -30,22 -30,7 +30,22 @@@ nofetch
  update=
  prefix=
  
 -# Resolve relative url by appending to parent's url
 +# The function takes at most 2 arguments. The first argument is the
 +# URL that navigates to the submodule origin repo. When relative, this URL
 +# is relative to the superproject origin URL repo. The second up_path
 +# argument, if specified, is the relative path that navigates
 +# from the submodule working tree to the superproject working tree.
 +#
 +# The output of the function is the origin URL of the submodule.
 +#
 +# The output will either be an absolute URL or filesystem path (if the
 +# superproject origin URL is an absolute URL or filesystem path,
 +# respectively) or a relative file system path (if the superproject
 +# origin URL is a relative file system path).
 +#
 +# When the output is a relative file system path, the path is either
 +# relative to the submodule working tree, if up_path is specified, or to
 +# the superproject working tree otherwise.
  resolve_relative_url ()
  {
        remote=$(get_default_remote)
        url="$1"
        remoteurl=${remoteurl%/}
        sep=/
 +      up_path="$2"
 +
 +      case "$remoteurl" in
 +      *:*|/*)
 +              is_relative=
 +              ;;
 +      ./*|../*)
 +              is_relative=t
 +              ;;
 +      *)
 +              is_relative=t
 +              remoteurl="./$remoteurl"
 +              ;;
 +      esac
 +
        while test -n "$url"
        do
                case "$url" in
                                sep=:
                                ;;
                        *)
 -                              die "$(eval_gettext "cannot strip one component off url '\$remoteurl'")"
 +                              if test -z "$is_relative" || test "." = "$remoteurl"
 +                              then
 +                                      die "$(eval_gettext "cannot strip one component off url '\$remoteurl'")"
 +                              else
 +                                      remoteurl=.
 +                              fi
                                ;;
                        esac
                        ;;
@@@ -99,8 -64,7 +99,8 @@@
                        break;;
                esac
        done
 -      echo "$remoteurl$sep${url%/}"
 +      remoteurl="$remoteurl$sep${url%/}"
 +      echo "${is_relative:+${up_path}}${remoteurl#./}"
  }
  
  #
  #
  module_list()
  {
 -      git ls-files --error-unmatch --stage -- "$@" |
 +      (
 +              git ls-files --error-unmatch --stage -- "$@" ||
 +              echo "unmatched pathspec exists"
 +      ) |
        perl -e '
        my %unmerged = ();
        my ($null_sha1) = ("0" x 40);
 +      my @out = ();
 +      my $unmatched = 0;
        while (<STDIN>) {
 +              if (/^unmatched pathspec/) {
 +                      $unmatched = 1;
 +                      next;
 +              }
                chomp;
                my ($mode, $sha1, $stage, $path) =
                        /^([0-7]+) ([0-9a-f]{40}) ([0-3])\t(.*)$/;
                next unless $mode eq "160000";
                if ($stage ne "0") {
                        if (!$unmerged{$path}++) {
 -                              print "$mode $null_sha1 U\t$path\n";
 +                              push @out, "$mode $null_sha1 U\t$path\n";
                        }
                        next;
                }
 -              print "$_\n";
 +              push @out, "$_\n";
 +      }
 +      if ($unmatched) {
 +              print "#unmatched\n";
 +      } else {
 +              print for (@out);
        }
        '
  }
  
 +die_if_unmatched ()
 +{
 +      if test "$1" = "#unmatched"
 +      then
 +              exit 1
 +      fi
 +}
 +
  #
  # Map submodule path to submodule name
  #
@@@ -203,18 -145,13 +203,18 @@@ module_clone(
                rm -f "$gitdir/index"
        else
                mkdir -p "$gitdir_base"
 -              git clone $quiet -n ${reference:+"$reference"} \
 -                      --separate-git-dir "$gitdir" "$url" "$sm_path" ||
 +              (
 +                      clear_local_git_env
 +                      git clone $quiet -n ${reference:+"$reference"} \
 +                              --separate-git-dir "$gitdir" "$url" "$sm_path"
 +              ) ||
                die "$(eval_gettext "Clone of '\$url' into submodule path '\$sm_path' failed")"
        fi
  
 -      a=$(cd "$gitdir" && pwd)/
 -      b=$(cd "$sm_path" && pwd)/
 +      # We already are at the root of the work tree but cd_to_toplevel will
 +      # resolve any symlinks that might be present in $PWD
 +      a=$(cd_to_toplevel && cd "$gitdir" && pwd)/
 +      b=$(cd_to_toplevel && cd "$sm_path" && pwd)/
        # normalize Windows-style absolute paths to POSIX-style absolute paths
        case $a in [a-zA-Z]:/*) a=/${a%%:*}${a#*:} ;; esac
        case $b in [a-zA-Z]:/*) b=/${b%%:*}${b#*:} ;; esac
@@@ -407,7 -344,6 +407,7 @@@ cmd_foreach(
        module_list |
        while read mode sha1 stage sm_path
        do
 +              die_if_unmatched "$mode"
                if test -e "$sm_path"/.git
                then
                        say "$(eval_gettext "Entering '\$prefix\$sm_path'")"
@@@ -460,7 -396,6 +460,7 @@@ cmd_init(
        module_list "$@" |
        while read mode sha1 stage sm_path
        do
 +              die_if_unmatched "$mode"
                name=$(module_name "$sm_path") || exit
  
                # Copy url setting when it is not set yet
@@@ -561,7 -496,6 +561,7 @@@ cmd_update(
        err=
        while read mode sha1 stage sm_path
        do
 +              die_if_unmatched "$mode"
                if test "$stage" = U
                then
                        echo >&2 "Skipping unmerged submodule $sm_path"
@@@ -603,7 -537,7 +603,7 @@@ Maybe you want to use 'update --init'?"
                        die "$(eval_gettext "Unable to find current revision in submodule path '\$sm_path'")"
                fi
  
-               if test "$subsha1" != "$sha1"
+               if test "$subsha1" != "$sha1" -o -n "$force"
                then
                        subforce=$force
                        # If we don't already have a -f flag and the submodule has never been checked out
@@@ -776,7 -710,7 +776,7 @@@ cmd_summary() 
        if [ -n "$files" ]
        then
                test -n "$cached" &&
 -              die "$(gettext -- "--cached cannot be used with --files")"
 +              die "$(gettext "The --cached option cannot be used with the --files option")"
                diff_cmd=diff-files
                head=
        fi
@@@ -957,7 -891,6 +957,7 @@@ cmd_status(
        module_list "$@" |
        while read mode sha1 stage sm_path
        do
 +              die_if_unmatched "$mode"
                name=$(module_name "$sm_path") || exit
                url=$(git config submodule."$name".url)
                displaypath="$prefix$sm_path"
@@@ -1026,33 -959,20 +1026,33 @@@ cmd_sync(
        module_list "$@" |
        while read mode sha1 stage sm_path
        do
 +              die_if_unmatched "$mode"
                name=$(module_name "$sm_path")
                url=$(git config -f .gitmodules --get submodule."$name".url)
  
                # Possibly a url relative to parent
                case "$url" in
                ./*|../*)
 -                      url=$(resolve_relative_url "$url") || exit
 +                      # rewrite foo/bar as ../.. to find path from
 +                      # submodule work tree to superproject work tree
 +                      up_path="$(echo "$sm_path" | sed "s/[^/][^/]*/../g")" &&
 +                      # guarantee a trailing /
 +                      up_path=${up_path%/}/ &&
 +                      # path from submodule work tree to submodule origin repo
 +                      sub_origin_url=$(resolve_relative_url "$url" "$up_path") &&
 +                      # path from superproject work tree to submodule origin repo
 +                      super_config_url=$(resolve_relative_url "$url") || exit
 +                      ;;
 +              *)
 +                      sub_origin_url="$url"
 +                      super_config_url="$url"
                        ;;
                esac
  
                if git config "submodule.$name.url" >/dev/null 2>/dev/null
                then
                        say "$(eval_gettext "Synchronizing submodule url for '\$name'")"
 -                      git config submodule."$name".url "$url"
 +                      git config submodule."$name".url "$super_config_url"
  
                        if test -e "$sm_path"/.git
                        then
                                clear_local_git_env
                                cd "$sm_path"
                                remote=$(get_default_remote)
 -                              git config remote."$remote".url "$url"
 +                              git config remote."$remote".url "$sub_origin_url"
                        )
                        fi
                fi
index 646298b2125fbbb7379ffb041099dc0d4bafaa55,8e9c380c47f33fcdc0a99646050cb6c67f9fa2e5..15426530e49ef2e42cda2528f4a72a784eb40cd9
@@@ -123,6 -123,18 +123,18 @@@ test_expect_success 'submodule update s
        )
  '
  
+ test_expect_success 'submodule update --force forcibly checks out submodules' '
+       (cd super &&
+        (cd submodule &&
+         rm -f file
+        ) &&
+        git submodule update --force submodule &&
+        (cd submodule &&
+         test "$(git status -s file)" = ""
+        )
+       )
+ '
  test_expect_success 'submodule update --rebase staying on master' '
        (cd super/submodule &&
          git checkout master
@@@ -367,7 -379,7 +379,7 @@@ test_expect_success 'submodule update c
         git submodule init &&
         git commit -am "new_submodule" &&
         (cd submodule2 &&
 -        git rev-parse --max-count=1 HEAD > ../expect
 +        git rev-parse --verify HEAD >../expect
         ) &&
         (cd submodule &&
          test_commit "update_submodule" file
         git checkout HEAD^ &&
         test_must_fail git submodule update &&
         (cd submodule2 &&
 -        git rev-parse --max-count=1 HEAD > ../actual
 +        git rev-parse --verify HEAD >../actual
         ) &&
         test_cmp expect actual
        )
@@@ -413,7 -425,7 +425,7 @@@ test_expect_success 'submodule update c
          test_commit "update_submodule_again_again" file
         ) &&
         (cd submodule2 &&
 -        git rev-parse --max-count=1 HEAD > ../expect &&
 +        git rev-parse --verify HEAD >../expect &&
          test_commit "update_submodule2_again" file
         ) &&
         git add submodule &&
         ) &&
         test_must_fail git submodule update --recursive &&
         (cd submodule2 &&
 -        git rev-parse --max-count=1 HEAD > ../actual
 +        git rev-parse --verify HEAD >../actual
         ) &&
         test_cmp expect actual
        )
@@@ -460,12 -472,12 +472,12 @@@ test_expect_success 'submodule update e
         ) &&
         git checkout HEAD^ &&
         (cd submodule2 &&
 -        git rev-parse --max-count=1 HEAD > ../expect
 +        git rev-parse --verify HEAD >../expect
         ) &&
         git config submodule.submodule.update merge &&
         test_must_fail git submodule update &&
         (cd submodule2 &&
 -        git rev-parse --max-count=1 HEAD > ../actual
 +        git rev-parse --verify HEAD >../actual
         ) &&
         test_cmp expect actual
        )
@@@ -495,12 -507,12 +507,12 @@@ test_expect_success 'submodule update e
         ) &&
         git checkout HEAD^ &&
         (cd submodule2 &&
 -        git rev-parse --max-count=1 HEAD > ../expect
 +        git rev-parse --verify HEAD >../expect
         ) &&
         git config submodule.submodule.update rebase &&
         test_must_fail git submodule update &&
         (cd submodule2 &&
 -        git rev-parse --max-count=1 HEAD > ../actual
 +        git rev-parse --verify HEAD >../actual
         ) &&
         test_cmp expect actual
        )
@@@ -636,17 -648,4 +648,17 @@@ test_expect_success 'submodule update p
        )
  '
  
 +test_expect_success SYMLINKS 'submodule update can handle symbolic links in pwd' '
 +      mkdir -p linked/dir &&
 +      ln -s linked/dir linkto &&
 +      (
 +              cd linkto &&
 +              git clone "$TRASH_DIRECTORY"/super_update_r2 super &&
 +              (
 +                      cd super &&
 +                      git submodule update --init --recursive
 +              )
 +      )
 +'
 +
  test_done