Merge branches 'jc/clone' and 'jc/name'
authorJunio C Hamano <junkio@cox.net>
Sun, 26 Mar 2006 08:22:53 +0000 (00:22 -0800)
committerJunio C Hamano <junkio@cox.net>
Sun, 26 Mar 2006 08:22:53 +0000 (00:22 -0800)
* jc/clone:
git-clone: typofix.
clone: record the remote primary branch with remotes/$origin/HEAD
revamp git-clone (take #2).
revamp git-clone.
fetch,parse-remote,fmt-merge-msg: refs/remotes/* support

* jc/name:
sha1_name: make core.warnambiguousrefs the default.
sha1_name: warning ambiguous refs.
get_sha1_basic(): try refs/... and finally refs/remotes/$foo/HEAD
core.warnambiguousrefs: warns when "name" is used and both "name" branch and tag exists.

1  2  3 
blame.c
git-fetch.sh
diff --combined blame.c
index 7e88833a37f9a2b7380b96510a331cf376c99264,90338af31cf1f532891d8e34ede6c5cf9f72681f,270ca52c3abf4b8d51aba4c57693f6c72800bb14..396defccc728db836732aa140e54620775509760
+++ b/blame.c
   #include "tree.h"
   #include "blob.h"
   #include "diff.h"
 + #include "diffcore.h"
   #include "revision.h"
   
   #define DEBUG 0
@@@@ -35,9 -34,7 -35,9 +35,9 @@@@ struct util_info 
        char *buf;
        unsigned long size;
        int num_lines;
 - //    const char* path;
 +      const char* pathname;
 + 
 +      void* topo_data;
   };
   
   struct chunk {
@@@@ -180,13 -177,11 -180,13 +180,13 @@@@ static int get_blob_sha1_internal(unsig
                                  unsigned mode, int stage);
   
   static unsigned char blob_sha1[20];
 + static const char* blame_file;
   static int get_blob_sha1(struct tree *t, const char *pathname,
                         unsigned char *sha1)
   {
        int i;
        const char *pathspec[2];
 +      blame_file = pathname;
        pathspec[0] = pathname;
        pathspec[1] = NULL;
        memset(blob_sha1, 0, sizeof(blob_sha1));
@@@@ -211,10 -206,6 -211,10 +211,10 @@@@ static int get_blob_sha1_internal(unsig
        if (S_ISDIR(mode))
                return READ_TREE_RECURSIVE;
   
 +      if (strncmp(blame_file, base, baselen) ||
 +          strcmp(blame_file + baselen, pathname))
 +              return -1;
 + 
        memcpy(blob_sha1, sha1, 20);
        return -1;
   }
@@@@ -351,34 -342,25 -351,34 +351,34 @@@@ static int map_line(struct commit *comm
        return info->line_map[line];
   }
   
 - static int fill_util_info(struct commit *commit, const char *path)
 + static struct util_info* get_util(struct commit *commit)
   {
 -      struct util_info *util;
 -      if (commit->object.util)
 -              return 0;
 +      struct util_info *util = commit->object.util;
 + 
 +      if (util)
 +              return util;
   
        util = xmalloc(sizeof(struct util_info));
 +      util->buf = NULL;
 +      util->size = 0;
 +      util->line_map = NULL;
 +      util->num_lines = -1;
 +      util->pathname = NULL;
 +      commit->object.util = util;
 +      return util;
 + }
 + 
 + static int fill_util_info(struct commit *commit)
 + {
 +      struct util_info *util = commit->object.util;
 + 
 +      assert(util);
 +      assert(util->pathname);
   
 -      if (get_blob_sha1(commit->tree, path, util->sha1)) {
 -              free(util);
 +      if (get_blob_sha1(commit->tree, util->pathname, util->sha1))
                return 1;
 -      } else {
 -              util->buf = NULL;
 -              util->size = 0;
 -              util->line_map = NULL;
 -              util->num_lines = -1;
 -              commit->object.util = util;
 +      else
                return 0;
 -      }
   }
   
   static void alloc_line_map(struct commit *commit)
   
   static void init_first_commit(struct commit* commit, const char* filename)
   {
 -      struct util_info* util;
 +      struct util_info* util = commit->object.util;
        int i;
   
 -      if (fill_util_info(commit, filename))
 +      util->pathname = filename;
 +      if (fill_util_info(commit))
                die("fill_util_info failed");
   
        alloc_line_map(commit);
@@@@ -472,7 -453,7 -472,7 +472,7 @@@@ static void process_commits(struct rev_
                if(num_parents == 0)
                        *initial = commit;
   
 -              if(fill_util_info(commit, path))
 +              if (fill_util_info(commit))
                        continue;
   
                alloc_line_map(commit);
                                printf("parent: %s\n",
                                       sha1_to_hex(parent->object.sha1));
   
 -                      if(fill_util_info(parent, path)) {
 +                      if (fill_util_info(parent)) {
                                num_parents--;
                                continue;
                        }
        } while ((commit = get_revision(rev)) != NULL);
   }
   
 + 
 + static int compare_tree_path(struct rev_info* revs,
 +                           struct commit* c1, struct commit* c2)
 + {
 +      const char* paths[2];
 +      struct util_info* util = c2->object.util;
 +      paths[0] = util->pathname;
 +      paths[1] = NULL;
 + 
 +      diff_tree_setup_paths(get_pathspec(revs->prefix, paths));
 +      return rev_compare_tree(c1->tree, c2->tree);
 + }
 + 
 + 
 + static int same_tree_as_empty_path(struct rev_info *revs, struct tree* t1,
 +                                 const char* path)
 + {
 +      const char* paths[2];
 +      paths[0] = path;
 +      paths[1] = NULL;
 + 
 +      diff_tree_setup_paths(get_pathspec(revs->prefix, paths));
 +      return rev_same_tree_as_empty(t1);
 + }
 + 
 + static const char* find_rename(struct commit* commit, struct commit* parent)
 + {
 +      struct util_info* cutil = commit->object.util;
 +      struct diff_options diff_opts;
 +      const char *paths[1];
 +      int i;
 + 
 +      if (DEBUG) {
 +              printf("find_rename commit: %s ",
 +                     sha1_to_hex(commit->object.sha1));
 +              puts(sha1_to_hex(parent->object.sha1));
 +      }
 + 
 +      diff_setup(&diff_opts);
 +      diff_opts.recursive = 1;
 +      diff_opts.detect_rename = DIFF_DETECT_RENAME;
 +      paths[0] = NULL;
 +      diff_tree_setup_paths(paths);
 +      if (diff_setup_done(&diff_opts) < 0)
 +              die("diff_setup_done failed");
 + 
 +      diff_tree_sha1(commit->tree->object.sha1, parent->tree->object.sha1,
 +                     "", &diff_opts);
 +      diffcore_std(&diff_opts);
 + 
 +      for (i = 0; i < diff_queued_diff.nr; i++) {
 +              struct diff_filepair *p = diff_queued_diff.queue[i];
 + 
 +              if (p->status == 'R' && !strcmp(p->one->path, cutil->pathname)) {
 +                      if (DEBUG)
 +                              printf("rename %s -> %s\n", p->one->path, p->two->path);
 +                      return p->two->path;
 +              }
 +      }
 + 
 +      return 0;
 + }
 + 
 + static void simplify_commit(struct rev_info *revs, struct commit *commit)
 + {
 +      struct commit_list **pp, *parent;
 + 
 +      if (!commit->tree)
 +              return;
 + 
 +      if (!commit->parents) {
 +              struct util_info* util = commit->object.util;
 +              if (!same_tree_as_empty_path(revs, commit->tree,
 +                                           util->pathname))
 +                      commit->object.flags |= TREECHANGE;
 +              return;
 +      }
 + 
 +      pp = &commit->parents;
 +      while ((parent = *pp) != NULL) {
 +              struct commit *p = parent->item;
 + 
 +              if (p->object.flags & UNINTERESTING) {
 +                      pp = &parent->next;
 +                      continue;
 +              }
 + 
 +              parse_commit(p);
 +              switch (compare_tree_path(revs, p, commit)) {
 +              case REV_TREE_SAME:
 +                      parent->next = NULL;
 +                      commit->parents = parent;
 +                      get_util(p)->pathname = get_util(commit)->pathname;
 +                      return;
 + 
 +              case REV_TREE_NEW:
 +              {
 + 
 +                      struct util_info* util = commit->object.util;
 +                      if (revs->remove_empty_trees &&
 +                          same_tree_as_empty_path(revs, p->tree,
 +                                                  util->pathname)) {
 +                              const char* new_name = find_rename(commit, p);
 +                              if (new_name) {
 +                                      struct util_info* putil = get_util(p);
 +                                      if (!putil->pathname)
 +                                              putil->pathname = strdup(new_name);
 +                              } else {
 +                                      *pp = parent->next;
 +                                      continue;
 +                              }
 +                      }
 +              }
 + 
 +              /* fallthrough */
 +              case REV_TREE_DIFFERENT:
 +                      pp = &parent->next;
 +                      if (!get_util(p)->pathname)
 +                              get_util(p)->pathname =
 +                                      get_util(commit)->pathname;
 +                      continue;
 +              }
 +              die("bad tree compare for commit %s",
 +                  sha1_to_hex(commit->object.sha1));
 +      }
 +      commit->object.flags |= TREECHANGE;
 + }
 + 
 + 
   struct commit_info
   {
        char* author;
@@@@ -717,18 -569,6 -717,18 +717,18 @@@@ static const char* format_time(unsigne
        return time_buf;
   }
   
 + static void topo_setter(struct commit* c, void* data)
 + {
 +      struct util_info* util = c->object.util;
 +      util->topo_data = data;
 + }
 + 
 + static void* topo_getter(struct commit* c)
 + {
 +      struct util_info* util = c->object.util;
 +      return util->topo_data;
 + }
 + 
   int main(int argc, const char **argv)
   {
        int i;
        int sha1_len = 8;
        int compability = 0;
        int options = 1;
 +      struct commit* start_commit;
   
 -      int num_args;
        const char* args[10];
        struct rev_info rev;
   
        struct commit_info ci;
        const char *buf;
        int max_digits;
  -     size_t longest_file, longest_author;
 ++     int longest_file, longest_author;
 +      int found_rename;
   
        const char* prefix = setup_git_directory();
++      git_config(git_default_config);
   
        for(i = 1; i < argc; i++) {
                if(options) {
                strcpy(filename_buf, filename);
        filename = filename_buf;
   
 -      {
 -              struct commit* c;
 -              if (get_sha1(commit, sha1))
 -                      die("get_sha1 failed, commit '%s' not found", commit);
 -              c = lookup_commit_reference(sha1);
 - 
 -              if (fill_util_info(c, filename)) {
 -                      printf("%s not found in %s\n", filename, commit);
 -                      return 1;
 -              }
 +      if (get_sha1(commit, sha1))
 +              die("get_sha1 failed, commit '%s' not found", commit);
 +      start_commit = lookup_commit_reference(sha1);
 +      get_util(start_commit)->pathname = filename;
 +      if (fill_util_info(start_commit)) {
 +              printf("%s not found in %s\n", filename, commit);
 +              return 1;
        }
   
 -      num_args = 0;
 -      args[num_args++] = NULL;
 -      args[num_args++] = "--topo-order";
 -      args[num_args++] = "--remove-empty";
 -      args[num_args++] = commit;
 -      args[num_args++] = "--";
 -      args[num_args++] = filename;
 -      args[num_args] = NULL;
   
 -      setup_revisions(num_args, args, &rev, "HEAD");
 +      init_revisions(&rev);
 +      rev.remove_empty_trees = 1;
 +      rev.topo_order = 1;
 +      rev.prune_fn = simplify_commit;
 +      rev.topo_setter = topo_setter;
 +      rev.topo_getter = topo_getter;
 +      rev.limited = 1;
 + 
 +      commit_list_insert(start_commit, &rev.commits);
 + 
 +      args[0] = filename;
 +      args[1] = NULL;
 +      diff_tree_setup_paths(args);
        prepare_revision_walk(&rev);
        process_commits(&rev, filename, &initial);
   
        for (max_digits = 1, i = 10; i <= num_blame_lines + 1; max_digits++)
                i *= 10;
   
 +      longest_file = 0;
 +      longest_author = 0;
 +      found_rename = 0;
        for (i = 0; i < num_blame_lines; i++) {
                struct commit *c = blame_lines[i];
 +              struct util_info* u;
                if (!c)
                        c = initial;
 +              u = c->object.util;
   
 +              if (!found_rename && strcmp(filename, u->pathname))
 +                      found_rename = 1;
 +              if (longest_file < strlen(u->pathname))
 +                      longest_file = strlen(u->pathname);
 +              get_commit_info(c, &ci);
 +              if (longest_author < strlen(ci.author))
 +                      longest_author = strlen(ci.author);
 +      }
 + 
 +      for (i = 0; i < num_blame_lines; i++) {
 +              struct commit *c = blame_lines[i];
 +              struct util_info* u;
 + 
 +              if (!c)
 +                      c = initial;
 + 
 +              u = c->object.util;
                get_commit_info(c, &ci);
                fwrite(sha1_to_hex(c->object.sha1), sha1_len, 1, stdout);
 -              if(compability)
 +              if(compability) {
                        printf("\t(%10s\t%10s\t%d)", ci.author,
                               format_time(ci.author_time, ci.author_tz), i+1);
 -              else
 -                      printf(" (%-15.15s %10s %*d) ", ci.author,
 +              } else {
 +                      if (found_rename)
 +                              printf(" %-*.*s", longest_file, longest_file,
 +                                     u->pathname);
 +                      printf(" (%-*.*s %10s %*d) ",
 +                             longest_author, longest_author, ci.author,
                               format_time(ci.author_time, ci.author_tz),
                               max_digits, i+1);
 +              }
   
                if(i == num_blame_lines - 1) {
                        fwrite(buf, blame_len - (buf - blame_contents),
diff --combined git-fetch.sh
index 68356343a63b8c07def2edcbed4d3b8c06776921,c0eb96752e1574b48b973acd4ebfdb81406c7bac,0346d4a45ca6a67bc0f6521dea799bf37cbb7cf1..954901ddce9404eeadb616c4b65b466c62d4b63f
@@@@ -94,6 -94,9 -94,6 +94,9 @@@@ append_fetch_head () 
       # remote-nick is the URL given on the command line (or a shorthand)
       # remote-name is the $GIT_DIR relative refs/ path we computed
       # for this refspec.
+ +
+ +    # the $note_ variable will be fed to git-fmt-merge-msg for further
+ +    # processing.
       case "$remote_name_" in
       HEAD)
        note_= ;;
       refs/tags/*)
        note_="$(expr "$remote_name_" : 'refs/tags/\(.*\)')"
        note_="tag '$note_' of " ;;
+ +    refs/remotes/*)
+ +     note_="$(expr "$remote_name_" : 'refs/remotes/\(.*\)')"
+ +     note_="remote branch '$note_' of " ;;
       *)
        note_="$remote_name of " ;;
       esac
@@@@ -147,10 -153,10 -147,10 +153,10 @@@@ fast_forward_local () 
        else
                echo >&2 "* $1: storing $3"
        fi
- -     git-update-ref "$1" "$2" 
+ +     git-update-ref "$1" "$2"
        ;;
   
- -    refs/heads/*)
+ +    refs/heads/* | refs/remotes/*)
        # $1 is the ref being updated.
        # $2 is the new value for the ref.
        local=$(git-rev-parse --verify "$1^0" 2>/dev/null)
                        ;;
                *)
                        echo >&2 "  not updating."
 ++                     exit 1
                        ;;
                esac
            }