Merge branch 'cb/maint-update-ref-fix' into maint
authorJunio C Hamano <gitster@pobox.com>
Sun, 9 Nov 2008 01:32:49 +0000 (17:32 -0800)
committerJunio C Hamano <gitster@pobox.com>
Sun, 9 Nov 2008 01:32:49 +0000 (17:32 -0800)
* cb/maint-update-ref-fix:
push: fix local refs update if already up-to-date
do not force write of packed refs

1  2 
builtin-send-pack.c
refs.c
diff --combined builtin-send-pack.c
index ed94f9a460336d84ef5c1edcc0c4b5a26163c74d,8fdeaa398933be3788c9d6a796d32ee5b2a61484..e428eace2b2213750d4dfa0fe4da9c07bd656892
@@@ -222,7 -222,7 +222,7 @@@ static void update_tracking_ref(struct 
  {
        struct refspec rs;
  
-       if (ref->status != REF_STATUS_OK)
+       if (ref->status != REF_STATUS_OK && ref->status != REF_STATUS_UPTODATE)
                return;
  
        rs.src = ref->name;
                if (args.verbose)
                        fprintf(stderr, "updating local tracking ref '%s'\n", rs.dst);
                if (ref->deletion) {
 -                      delete_ref(rs.dst, NULL);
 +                      delete_ref(rs.dst, NULL, 0);
                } else
                        update_ref("update by push", rs.dst,
                                        ref->new_sha1, NULL, 0, 0);
@@@ -424,24 -424,19 +424,19 @@@ static int do_send_pack(int in, int out
         */
        new_refs = 0;
        for (ref = remote_refs; ref; ref = ref->next) {
-               const unsigned char *new_sha1;
-               if (!ref->peer_ref) {
-                       if (!args.send_mirror)
-                               continue;
-                       new_sha1 = null_sha1;
-               }
-               else
-                       new_sha1 = ref->peer_ref->new_sha1;
  
+               if (ref->peer_ref)
+                       hashcpy(ref->new_sha1, ref->peer_ref->new_sha1);
+               else if (!args.send_mirror)
+                       continue;
  
-               ref->deletion = is_null_sha1(new_sha1);
+               ref->deletion = is_null_sha1(ref->new_sha1);
                if (ref->deletion && !allow_deleting_refs) {
                        ref->status = REF_STATUS_REJECT_NODELETE;
                        continue;
                }
                if (!ref->deletion &&
-                   !hashcmp(ref->old_sha1, new_sha1)) {
+                   !hashcmp(ref->old_sha1, ref->new_sha1)) {
                        ref->status = REF_STATUS_UPTODATE;
                        continue;
                }
                    !ref->deletion &&
                    !is_null_sha1(ref->old_sha1) &&
                    (!has_sha1_file(ref->old_sha1)
-                     || !ref_newer(new_sha1, ref->old_sha1));
+                     || !ref_newer(ref->new_sha1, ref->old_sha1));
  
                if (ref->nonfastforward && !ref->force && !args.force_update) {
                        ref->status = REF_STATUS_REJECT_NONFASTFORWARD;
                        continue;
                }
  
-               hashcpy(ref->new_sha1, new_sha1);
                if (!ref->deletion)
                        new_refs++;
  
diff --combined refs.c
index 48271a99ab0a7616ff0ae990a166c4a19811ffc9,7d91b670c5a923ed2e4e93a87ba40e9e93387f2b..293389e7641a8d4ec948f21407de3f69eacbdddd
--- 1/refs.c
--- 2/refs.c
+++ b/refs.c
@@@ -401,7 -401,7 +401,7 @@@ const char *resolve_ref(const char *ref
                *flag = 0;
  
        for (;;) {
 -              const char *path = git_path("%s", ref);
 +              char path[PATH_MAX];
                struct stat st;
                char *buf;
                int fd;
                if (--depth < 0)
                        return NULL;
  
 +              git_snpath(path, sizeof(path), "%s", ref);
                /* Special case: non-existing file.
                 * Not having the refs/heads/new-branch is OK
                 * if we are writing into it, so is .git/HEAD
@@@ -789,10 -788,10 +789,10 @@@ static struct ref_lock *lock_ref_sha1_b
        char *ref_file;
        const char *orig_ref = ref;
        struct ref_lock *lock;
-       struct stat st;
        int last_errno = 0;
        int type, lflags;
        int mustexist = (old_sha1 && !is_null_sha1(old_sha1));
+       int missing = 0;
  
        lock = xcalloc(1, sizeof(struct ref_lock));
        lock->lock_fd = -1;
                        orig_ref, strerror(errno));
                goto error_return;
        }
+       missing = is_null_sha1(lock->old_sha1);
        /* When the ref did not exist and we are creating it,
         * make sure there is no existing ref that is packed
         * whose name begins with our refname, nor a ref whose
         * name is a proper prefix of our refname.
         */
-       if (is_null_sha1(lock->old_sha1) &&
+       if (missing &&
              !is_refname_available(ref, NULL, get_packed_refs(), 0))
                goto error_return;
  
        lock->ref_name = xstrdup(ref);
        lock->orig_ref_name = xstrdup(orig_ref);
        ref_file = git_path("%s", ref);
-       if (lstat(ref_file, &st) && errno == ENOENT)
+       if (missing)
                lock->force_write = 1;
        if ((flags & REF_NODEREF) && (type & REF_ISSYMREF))
                lock->force_write = 1;
@@@ -916,33 -916,25 +917,33 @@@ static int repack_without_ref(const cha
        return commit_lock_file(&packlock);
  }
  
 -int delete_ref(const char *refname, const unsigned char *sha1)
 +int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
  {
        struct ref_lock *lock;
 -      int err, i, ret = 0, flag = 0;
 +      int err, i = 0, ret = 0, flag = 0;
  
        lock = lock_ref_sha1_basic(refname, sha1, 0, &flag);
        if (!lock)
                return 1;
 -      if (!(flag & REF_ISPACKED)) {
 +      if (!(flag & REF_ISPACKED) || flag & REF_ISSYMREF) {
                /* loose */
 -              i = strlen(lock->lk->filename) - 5; /* .lock */
 -              lock->lk->filename[i] = 0;
 -              err = unlink(lock->lk->filename);
 +              const char *path;
 +
 +              if (!(delopt & REF_NODEREF)) {
 +                      i = strlen(lock->lk->filename) - 5; /* .lock */
 +                      lock->lk->filename[i] = 0;
 +                      path = lock->lk->filename;
 +              } else {
 +                      path = git_path(refname);
 +              }
 +              err = unlink(path);
                if (err && errno != ENOENT) {
                        ret = 1;
                        error("unlink(%s) failed: %s",
 -                            lock->lk->filename, strerror(errno));
 +                            path, strerror(errno));
                }
 -              lock->lk->filename[i] = '.';
 +              if (!(delopt & REF_NODEREF))
 +                      lock->lk->filename[i] = '.';
        }
        /* removing the loose one could have resurrected an earlier
         * packed one.  Also, if it was not loose we need to repack
@@@ -967,16 -959,11 +968,16 @@@ int rename_ref(const char *oldref, cons
        struct ref_lock *lock;
        struct stat loginfo;
        int log = !lstat(git_path("logs/%s", oldref), &loginfo);
 +      const char *symref = NULL;
  
 -      if (S_ISLNK(loginfo.st_mode))
 +      if (log && S_ISLNK(loginfo.st_mode))
                return error("reflog for %s is a symlink", oldref);
  
 -      if (!resolve_ref(oldref, orig_sha1, 1, &flag))
 +      symref = resolve_ref(oldref, orig_sha1, 1, &flag);
 +      if (flag & REF_ISSYMREF)
 +              return error("refname %s is a symbolic ref, renaming it is not supported",
 +                      oldref);
 +      if (!symref)
                return error("refname %s not found", oldref);
  
        if (!is_refname_available(newref, oldref, get_packed_refs(), 0))
                return error("unable to move logfile logs/%s to tmp-renamed-log: %s",
                        oldref, strerror(errno));
  
 -      if (delete_ref(oldref, orig_sha1)) {
 +      if (delete_ref(oldref, orig_sha1, REF_NODEREF)) {
                error("unable to delete old %s", oldref);
                goto rollback;
        }
  
 -      if (resolve_ref(newref, sha1, 1, &flag) && delete_ref(newref, sha1)) {
 +      if (resolve_ref(newref, sha1, 1, &flag) && delete_ref(newref, sha1, REF_NODEREF)) {
                if (errno==EISDIR) {
                        if (remove_empty_directories(git_path("%s", newref))) {
                                error("Directory not empty: %s", newref);
                error("unable to lock %s for update", newref);
                goto rollback;
        }
 -
        lock->force_write = 1;
        hashcpy(lock->old_sha1, orig_sha1);
        if (write_ref_sha1(lock, orig_sha1, logmsg)) {
@@@ -1137,14 -1125,13 +1138,14 @@@ static int log_ref_write(const char *re
        int logfd, written, oflags = O_APPEND | O_WRONLY;
        unsigned maxlen, len;
        int msglen;
 -      char *log_file, *logrec;
 +      char log_file[PATH_MAX];
 +      char *logrec;
        const char *committer;
  
        if (log_all_ref_updates < 0)
                log_all_ref_updates = !is_bare_repository();
  
 -      log_file = git_path("logs/%s", ref_name);
 +      git_snpath(log_file, sizeof(log_file), "logs/%s", ref_name);
  
        if (log_all_ref_updates &&
            (!prefixcmp(ref_name, "refs/heads/") ||
@@@ -1273,7 -1260,7 +1274,7 @@@ int create_symref(const char *ref_targe
        const char *lockpath;
        char ref[1000];
        int fd, len, written;
 -      char *git_HEAD = xstrdup(git_path("%s", ref_target));
 +      char *git_HEAD = git_pathdup("%s", ref_target);
        unsigned char old_sha1[20], new_sha1[20];
  
        if (logmsg && read_ref(ref_target, old_sha1))