{"thread":{"id":"2988","subject":"[PATCH] git-fetch: auto-following tags.","startedAt":"2006-01-07T10:34:56Z","lastAt":"2006-01-07T10:34:56Z","messageCount":1,"participants":["Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"14243","messageId":"7v3bk0l41b.fsf@assigned-by-dhcp.cox.net","threadId":"2988","inReplyTo":null,"subject":"[PATCH] git-fetch: auto-following tags.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-01-07T10:34:56Z","receivedAt":"2006-01-07T10:34:56Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"I added things to ls-remote so that Cogito can auto-follow tags\neasily and correctly a while ago, but git-fetch did not use the\nfacility.  Recently added git-describe command relies on\nrepository keeping up-to-date set of tags, which made it much\nmore attractive to automatically follow tags, so we do that as\nwell.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n\n---\n\n * This is not 1.0.X material rather for 1.1.0\n\n Documentation/fetch-options.txt |   18 ++\n git-fetch.sh                    |  283 ++++++++++++++++++++++-----------------\n 2 files changed, 173 insertions(+), 128 deletions(-)\n\n6f3ccd3bdb2e2b2187c93bfa0c6f957b44a2e206\ndiff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt\nindex 200c9b2..1fe8423 100644\n--- a/Documentation/fetch-options.txt\n+++ b/Documentation/fetch-options.txt\n@@ -10,15 +10,23 @@\n \tfetches is a descendant of `<lbranch>`.  This option\n \toverrides that check.\n \n+\\--no-tags::\n+\tBy default, `git-fetch` fetches tags that point at\n+\tobjects that are downloaded from the remote repository\n+\tand stores them locally.  This option disables this\n+\tautomatic tag following.\n+\n -t, \\--tags::\n-\tBy default, the git core utilities will not fetch and store\n-\ttags under the same name as the remote repository;  ask it\n-\tto do so using `--tags`.  Using this option will bound the\n-\tlist of objects pulled to the remote tags.  Commits in branches\n-\tbeyond the tags will be ignored.\n+\tMost of the tags are fetched automatically as branch\n+\theads are downloaded, but tags that do not point at\n+\tobjects reachable from the branch heads that are being\n+\ttracked will not be fetched by this mechanism.  This\n+\tflag lets all tags and their associated objects be\n+\tdownloaded.\n \n -u, \\--update-head-ok::\n \tBy default `git-fetch` refuses to update the head which\n \tcorresponds to the current branch.  This flag disables the\n \tcheck.  Note that fetching into the current branch will not\n \tupdate the index and working directory, so use it with care.\n+\ndiff --git a/git-fetch.sh b/git-fetch.sh\nindex b46b3e5..73e57bd 100755\n--- a/git-fetch.sh\n+++ b/git-fetch.sh\n@@ -11,6 +11,7 @@ LF='\n '\n IFS=\"$LF\"\n \n+no_tags=\n tags=\n append=\n force=\n@@ -28,6 +29,9 @@ do\n \t-t|--t|--ta|--tag|--tags)\n \t\ttags=t\n \t\t;;\n+\t-n|--n|--no|--no-|--no-t|--no-ta|--no-tag|--no-tags)\n+\t\tno_tags=t\n+\t\t;;\n \t-u|--u|--up|--upd|--upda|--updat|--update|--update-|--update-h|\\\n \t--update-he|--update-hea|--update-head|--update-head-|\\\n \t--update-head-o|--update-head-ok)\n@@ -212,133 +216,166 @@ then\n \tfi\n fi\n \n-for ref in $reflist\n-do\n-    refs=\"$refs$LF$ref\"\n-\n-    # These are relative path from $GIT_DIR, typically starting at refs/\n-    # but may be HEAD\n-    if expr \"$ref\" : '\\.' >/dev/null\n-    then\n-\tnot_for_merge=t\n-\tref=$(expr \"$ref\" : '\\.\\(.*\\)')\n-    else\n-\tnot_for_merge=\n-    fi\n-    if expr \"$ref\" : '\\+' >/dev/null\n-    then\n-\tsingle_force=t\n-\tref=$(expr \"$ref\" : '\\+\\(.*\\)')\n-    else\n-\tsingle_force=\n-    fi\n-    remote_name=$(expr \"$ref\" : '\\([^:]*\\):')\n-    local_name=$(expr \"$ref\" : '[^:]*:\\(.*\\)')\n-\n-    rref=\"$rref$LF$remote_name\"\n-\n-    # There are transports that can fetch only one head at a time...\n-    case \"$remote\" in\n-    http://* | https://*)\n-\tif [ -n \"$GIT_SSL_NO_VERIFY\" ]; then\n-\t    curl_extra_args=\"-k\"\n-\tfi\n-\tremote_name_quoted=$(perl -e '\n-\t    my $u = $ARGV[0];\n-\t    $u =~ s{([^-a-zA-Z0-9/.])}{sprintf\"%%%02x\",ord($1)}eg;\n-\t    print \"$u\";\n-\t' \"$remote_name\")\n-\thead=$(curl -nsfL $curl_extra_args \"$remote/$remote_name_quoted\") &&\n-\texpr \"$head\" : \"$_x40\\$\" >/dev/null ||\n-\t\tdie \"Failed to fetch $remote_name from $remote\"\n-\techo >&2 Fetching \"$remote_name from $remote\" using http\n-\tgit-http-fetch -v -a \"$head\" \"$remote/\" || exit\n-\t;;\n-    rsync://*)\n-\tTMP_HEAD=\"$GIT_DIR/TMP_HEAD\"\n-\trsync -L -q \"$remote/$remote_name\" \"$TMP_HEAD\" || exit 1\n-\thead=$(git-rev-parse --verify TMP_HEAD)\n-\trm -f \"$TMP_HEAD\"\n-\ttest \"$rsync_slurped_objects\" || {\n-\t    rsync -av --ignore-existing --exclude info \\\n-\t\t\"$remote/objects/\" \"$GIT_OBJECT_DIRECTORY/\" || exit\n-\n-\t    # Look at objects/info/alternates for rsync -- http will\n-\t    # support it natively and git native ones will do it on the remote\n-\t    # end.  Not having that file is not a crime.\n-\t    rsync -q \"$remote/objects/info/alternates\" \\\n-\t\t\"$GIT_DIR/TMP_ALT\" 2>/dev/null ||\n-\t\trm -f \"$GIT_DIR/TMP_ALT\"\n-\t    if test -f \"$GIT_DIR/TMP_ALT\"\n-\t    then\n-\t\tresolve_alternates \"$remote\" <\"$GIT_DIR/TMP_ALT\" |\n-\t\twhile read alt\n-\t\tdo\n-\t\t    case \"$alt\" in 'bad alternate: '*) die \"$alt\";; esac\n-\t\t    echo >&2 \"Getting alternate: $alt\"\n-\t\t    rsync -av --ignore-existing --exclude info \\\n-\t\t    \"$alt\" \"$GIT_OBJECT_DIRECTORY/\" || exit\n-\t\tdone\n-\t\trm -f \"$GIT_DIR/TMP_ALT\"\n-\t    fi\n-\t    rsync_slurped_objects=t\n-\t}\n-\t;;\n-    *)\n-\t# We will do git native transport with just one call later.\n-\tcontinue ;;\n-    esac\n+fetch_main () {\n+  reflist=\"$1\"\n+  refs=\n+\n+  for ref in $reflist\n+  do\n+      refs=\"$refs$LF$ref\"\n+\n+      # These are relative path from $GIT_DIR, typically starting at refs/\n+      # but may be HEAD\n+      if expr \"$ref\" : '\\.' >/dev/null\n+      then\n+\t  not_for_merge=t\n+\t  ref=$(expr \"$ref\" : '\\.\\(.*\\)')\n+      else\n+\t  not_for_merge=\n+      fi\n+      if expr \"$ref\" : '\\+' >/dev/null\n+      then\n+\t  single_force=t\n+\t  ref=$(expr \"$ref\" : '\\+\\(.*\\)')\n+      else\n+\t  single_force=\n+      fi\n+      remote_name=$(expr \"$ref\" : '\\([^:]*\\):')\n+      local_name=$(expr \"$ref\" : '[^:]*:\\(.*\\)')\n+\n+      rref=\"$rref$LF$remote_name\"\n+\n+      # There are transports that can fetch only one head at a time...\n+      case \"$remote\" in\n+      http://* | https://*)\n+\t  if [ -n \"$GIT_SSL_NO_VERIFY\" ]; then\n+\t      curl_extra_args=\"-k\"\n+\t  fi\n+\t  remote_name_quoted=$(perl -e '\n+\t      my $u = $ARGV[0];\n+\t      $u =~ s{([^-a-zA-Z0-9/.])}{sprintf\"%%%02x\",ord($1)}eg;\n+\t      print \"$u\";\n+\t  ' \"$remote_name\")\n+\t  head=$(curl -nsfL $curl_extra_args \"$remote/$remote_name_quoted\") &&\n+\t  expr \"$head\" : \"$_x40\\$\" >/dev/null ||\n+\t\t  die \"Failed to fetch $remote_name from $remote\"\n+\t  echo >&2 Fetching \"$remote_name from $remote\" using http\n+\t  git-http-fetch -v -a \"$head\" \"$remote/\" || exit\n+\t  ;;\n+      rsync://*)\n+\t  TMP_HEAD=\"$GIT_DIR/TMP_HEAD\"\n+\t  rsync -L -q \"$remote/$remote_name\" \"$TMP_HEAD\" || exit 1\n+\t  head=$(git-rev-parse --verify TMP_HEAD)\n+\t  rm -f \"$TMP_HEAD\"\n+\t  test \"$rsync_slurped_objects\" || {\n+\t      rsync -av --ignore-existing --exclude info \\\n+\t\t  \"$remote/objects/\" \"$GIT_OBJECT_DIRECTORY/\" || exit\n+\n+\t      # Look at objects/info/alternates for rsync -- http will\n+\t      # support it natively and git native ones will do it on\n+\t      # the remote end.  Not having that file is not a crime.\n+\t      rsync -q \"$remote/objects/info/alternates\" \\\n+\t\t  \"$GIT_DIR/TMP_ALT\" 2>/dev/null ||\n+\t\t  rm -f \"$GIT_DIR/TMP_ALT\"\n+\t      if test -f \"$GIT_DIR/TMP_ALT\"\n+\t      then\n+\t\t  resolve_alternates \"$remote\" <\"$GIT_DIR/TMP_ALT\" |\n+\t\t  while read alt\n+\t\t  do\n+\t\t      case \"$alt\" in 'bad alternate: '*) die \"$alt\";; esac\n+\t\t      echo >&2 \"Getting alternate: $alt\"\n+\t\t      rsync -av --ignore-existing --exclude info \\\n+\t\t      \"$alt\" \"$GIT_OBJECT_DIRECTORY/\" || exit\n+\t\t  done\n+\t\t  rm -f \"$GIT_DIR/TMP_ALT\"\n+\t      fi\n+\t      rsync_slurped_objects=t\n+\t  }\n+\t  ;;\n+      *)\n+\t  # We will do git native transport with just one call later.\n+\t  continue ;;\n+      esac\n+\n+      append_fetch_head \"$head\" \"$remote\" \\\n+\t  \"$remote_name\" \"$remote_nick\" \"$local_name\" \"$not_for_merge\"\n+\n+  done\n+\n+  case \"$remote\" in\n+  http://* | https://* | rsync://* )\n+      ;; # we are already done.\n+  *)\n+    ( : subshell because we muck with IFS\n+      IFS=\" \t$LF\"\n+      (\n+\t  git-fetch-pack \"$remote\" $rref || echo failed \"$remote\"\n+      ) |\n+      while read sha1 remote_name\n+      do\n+\t  case \"$sha1\" in\n+\t  failed)\n+\t\t  echo >&2 \"Fetch failure: $remote\"\n+\t\t  exit 1 ;;\n+\t  esac\n+\t  found=\n+\t  single_force=\n+\t  for ref in $refs\n+\t  do\n+\t      case \"$ref\" in\n+\t      +$remote_name:*)\n+\t\t  single_force=t\n+\t\t  not_for_merge=\n+\t\t  found=\"$ref\"\n+\t\t  break ;;\n+\t      .+$remote_name:*)\n+\t\t  single_force=t\n+\t\t  not_for_merge=t\n+\t\t  found=\"$ref\"\n+\t\t  break ;;\n+\t      .$remote_name:*)\n+\t\t  not_for_merge=t\n+\t\t  found=\"$ref\"\n+\t\t  break ;;\n+\t      $remote_name:*)\n+\t\t  not_for_merge=\n+\t\t  found=\"$ref\"\n+\t\t  break ;;\n+\t      esac\n+\t  done\n+\t  local_name=$(expr \"$found\" : '[^:]*:\\(.*\\)')\n+\t  append_fetch_head \"$sha1\" \"$remote\" \\\n+\t\t  \"$remote_name\" \"$remote_nick\" \"$local_name\" \"$not_for_merge\"\n+      done\n+    ) || exit ;;\n+  esac\n \n-    append_fetch_head \"$head\" \"$remote\" \\\n-    \t\"$remote_name\" \"$remote_nick\" \"$local_name\" \"$not_for_merge\"\n+}\n \n-done\n+fetch_main \"$reflist\"\n \n-case \"$remote\" in\n-http://* | https://* | rsync://* )\n-    ;; # we are already done.\n-*)\n-    IFS=\" \t$LF\"\n-    (\n-\tgit-fetch-pack \"$remote\" $rref || echo failed \"$remote\"\n-    ) |\n-    while read sha1 remote_name\n-    do\n-\tcase \"$sha1\" in\n-\tfailed)\n-\t\techo >&2 \"Fetch failure: $remote\"\n-\t\texit 1 ;;\n-\tesac\n-\tfound=\n-\tsingle_force=\n-\tfor ref in $refs\n+# automated tag following\n+case \"$no_tags$tags\" in\n+'')\n+\ttaglist=$(IFS=\" \" &&\n+    \tgit-ls-remote --tags \"$remote\" |\n+\tsed -ne 's|^\\([0-9a-f]*\\)[ \t]\\(refs/tags/.*\\)^{}$|\\1 \\2|p' |\n+\twhile read sha1 name\n \tdo\n-\t    case \"$ref\" in\n-\t    +$remote_name:*)\n-\t\tsingle_force=t\n-\t\tnot_for_merge=\n-\t\tfound=\"$ref\"\n-\t\tbreak ;;\n-\t    .+$remote_name:*)\n-\t\tsingle_force=t\n-\t\tnot_for_merge=t\n-\t\tfound=\"$ref\"\n-\t\tbreak ;;\n-\t    .$remote_name:*)\n-\t        not_for_merge=t\n-\t\tfound=\"$ref\"\n-\t\tbreak ;;\n-\t    $remote_name:*)\n-\t    \tnot_for_merge=\n-\t\tfound=\"$ref\"\n-\t\tbreak ;;\n-\t    esac\n-\tdone\n-\tlocal_name=$(expr \"$found\" : '[^:]*:\\(.*\\)')\n-\tappend_fetch_head \"$sha1\" \"$remote\" \\\n-\t\t\"$remote_name\" \"$remote_nick\" \"$local_name\" \"$not_for_merge\"\n-    done || exit\n-    ;;\n+\t\ttest -f \"$GIT_DIR/$name\" && continue\n+\t  \tgit-check-ref-format \"$name\" || {\n+\t\t\techo >&2 \"warning: tag ${name} ignored\"\n+\t\t\tcontinue\n+\t\t}\n+\t\tgit-cat-file -t \"$sha1\" >/dev/null 2>&1 || continue\n+\t\techo >&2 \"Auto-following $name\"\n+\t\techo \".${name}:${name}\"\n+\tdone)\n+\tcase \"$taglist\" in\n+\t'') ;;\n+\t?*)\n+\t\tfetch_main \"$taglist\" ;;\n+\tesac\n esac\n \n # If the original head was empty (i.e. no \"master\" yet), or\n-- \n1.0.7-g0263\n"}]}