Merge branch 'jc/reupdate' into next
authorJunio C Hamano <junkio@cox.net>
Sat, 6 May 2006 07:20:54 +0000 (00:20 -0700)
committerJunio C Hamano <junkio@cox.net>
Sat, 6 May 2006 07:20:54 +0000 (00:20 -0700)
* jc/reupdate:
update-index --again: take optional pathspecs
update-index --again
update-index: plug memory leak from prefix_path()
checkout-index: plug memory leak from prefix_path()
update-index --unresolve: work from a subdirectory.

1  2 
checkout-index.c
update-index.c
diff --combined checkout-index.c
index e56c354f8c44e9fc06acea7c4b2673b46f2a3a0b,0b9cabc61cafa06501064c0b2cccbc3d434904c2..64bdc3bd132288f9c130488446214b125d2cfb14
@@@ -39,7 -39,6 +39,7 @@@
  #include "cache.h"
  #include "strbuf.h"
  #include "quote.h"
 +#include "cache-tree.h"
  
  #define CHECKOUT_ALL 4
  static const char *prefix;
@@@ -270,12 -269,16 +270,16 @@@ int main(int argc, char **argv
        /* Check out named files first */
        for ( ; i < argc; i++) {
                const char *arg = argv[i];
+               const char *p;
  
                if (all)
                        die("git-checkout-index: don't mix '--all' and explicit filenames");
                if (read_from_stdin)
                        die("git-checkout-index: don't mix '--stdin' and explicit filenames");
-               checkout_file(prefix_path(prefix, prefix_length, arg));
+               p = prefix_path(prefix, prefix_length, arg);
+               checkout_file(p);
+               if (p != arg)
+                       free((char*)p);
        }
  
        if (read_from_stdin) {
                strbuf_init(&buf);
                while (1) {
                        char *path_name;
+                       const char *p;
                        read_line(&buf, stdin, line_termination);
                        if (buf.eof)
                                break;
                                path_name = unquote_c_style(buf.buf, NULL);
                        else
                                path_name = buf.buf;
-                       checkout_file(prefix_path(prefix, prefix_length, path_name));
+                       p = prefix_path(prefix, prefix_length, path_name);
+                       checkout_file(p);
+                       if (p != path_name)
+                               free((char *)p);
                        if (path_name != buf.buf)
                                free(path_name);
                }
diff --combined update-index.c
index 061b18c1a568539cbaf2dae3e80c479fe06df2d8,184b2526da58b56b8e808faceb1efc6949d3c831..7db67aacfedaa542b6f64175580ad5e4e4c15e8d
@@@ -6,7 -6,6 +6,7 @@@
  #include "cache.h"
  #include "strbuf.h"
  #include "quote.h"
 +#include "cache-tree.h"
  #include "tree-walk.h"
  
  /*
@@@ -72,7 -71,6 +72,7 @@@ static int mark_valid(const char *path
                        active_cache[pos]->ce_flags &= ~htons(CE_VALID);
                        break;
                }
 +              cache_tree_invalidate_path(active_cache_tree, path);
                active_cache_changed = 1;
                return 0;
        }
@@@ -86,12 -84,6 +86,12 @@@ static int add_file_to_cache(const cha
        struct stat st;
  
        status = lstat(path, &st);
 +
 +      /* We probably want to do this in remove_file_from_cache() and
 +       * add_cache_entry() instead...
 +       */
 +      cache_tree_invalidate_path(active_cache_tree, path);
 +
        if (status < 0 || S_ISDIR(st.st_mode)) {
                /* When we used to have "path" and now we want to add
                 * "path/file", we need a way to remove "path" before
@@@ -334,7 -326,6 +334,7 @@@ static int add_cacheinfo(unsigned int m
                return error("%s: cannot add to the index - missing --add option?",
                             path);
        report("add '%s'", path);
 +      cache_tree_invalidate_path(active_cache_tree, path);
        return 0;
  }
  
@@@ -359,7 -350,6 +359,7 @@@ static void chmod_path(int flip, const 
        default:
                goto fail;
        }
 +      cache_tree_invalidate_path(active_cache_tree, path);
        active_cache_changed = 1;
        report("chmod %cx '%s'", flip, path);
        return;
@@@ -374,24 -364,26 +374,27 @@@ static void update_one(const char *path
        const char *p = prefix_path(prefix, prefix_length, path);
        if (!verify_path(p)) {
                fprintf(stderr, "Ignoring path %s\n", path);
-               return;
+               goto free_return;
        }
        if (mark_valid_only) {
                if (mark_valid(p))
                        die("Unable to mark file %s", path);
-               return;
+               goto free_return;
        }
 +      cache_tree_invalidate_path(active_cache_tree, path);
  
        if (force_remove) {
                if (remove_file_from_cache(p))
                        die("git-update-index: unable to remove %s", path);
                report("remove '%s'", path);
-               return;
+               goto free_return;
        }
        if (add_file_to_cache(p))
                die("Unable to process file %s", path);
        report("add '%s'", path);
+  free_return:
+       if (p != path)
+               free((char*)p);
  }
  
  static void read_index_info(int line_termination)
                                free(path_name);
                        continue;
                }
 +              cache_tree_invalidate_path(active_cache_tree, path_name);
  
                if (!mode) {
                        /* mode == 0 means there is no such path -- remove */
  }
  
  static const char update_index_usage[] =
- "git-update-index [-q] [--add] [--replace] [--remove] [--unmerged] [--refresh] [--really-refresh] [--cacheinfo] [--chmod=(+|-)x] [--assume-unchanged] [--info-only] [--force-remove] [--stdin] [--index-info] [--unresolve] [--ignore-missing] [-z] [--verbose] [--] <file>...";
+ "git-update-index [-q] [--add] [--replace] [--remove] [--unmerged] [--refresh] [--really-refresh] [--cacheinfo] [--chmod=(+|-)x] [--assume-unchanged] [--info-only] [--force-remove] [--stdin] [--index-info] [--unresolve] [--again] [--ignore-missing] [-z] [--verbose] [--] <file>...";
  
  static unsigned char head_sha1[20];
  static unsigned char merge_head_sha1[20];
@@@ -500,11 -491,13 +503,13 @@@ static struct cache_entry *read_one_ent
        struct cache_entry *ce;
  
        if (get_tree_entry(ent, path, sha1, &mode)) {
-               error("%s: not in %s branch.", path, which);
+               if (which)
+                       error("%s: not in %s branch.", path, which);
                return NULL;
        }
        if (mode == S_IFDIR) {
-               error("%s: not a blob in %s branch.", path, which);
+               if (which)
+                       error("%s: not a blob in %s branch.", path, which);
                return NULL;
        }
        size = cache_entry_size(namelen);
@@@ -562,7 -555,6 +567,7 @@@ static int unresolve_one(const char *pa
                goto free_return;
        }
  
 +      cache_tree_invalidate_path(active_cache_tree, path);
        remove_file_from_cache(path);
        if (add_cache_entry(ce_2, ADD_CACHE_OK_TO_ADD)) {
                error("%s: cannot add our version to the index.", path);
@@@ -589,7 -581,8 +594,8 @@@ static void read_head_pointers(void
        }
  }
  
- static int do_unresolve(int ac, const char **av)
+ static int do_unresolve(int ac, const char **av,
+                       const char *prefix, int prefix_length)
  {
        int i;
        int err = 0;
  
        for (i = 1; i < ac; i++) {
                const char *arg = av[i];
-               err |= unresolve_one(arg);
+               const char *p = prefix_path(prefix, prefix_length, arg);
+               err |= unresolve_one(p);
+               if (p != arg)
+                       free((char*)p);
        }
        return err;
  }
  
+ static int do_reupdate(int ac, const char **av,
+                      const char *prefix, int prefix_length)
+ {
+       /* Read HEAD and run update-index on paths that are
+        * merged and already different between index and HEAD.
+        */
+       int pos;
+       int has_head = 1;
+       char **pathspec = get_pathspec(prefix, av + 1);
+       if (read_ref(git_path("HEAD"), head_sha1))
+               /* If there is no HEAD, that means it is an initial
+                * commit.  Update everything in the index.
+                */
+               has_head = 0;
+  redo:
+       for (pos = 0; pos < active_nr; pos++) {
+               struct cache_entry *ce = active_cache[pos];
+               struct cache_entry *old = NULL;
+               int save_nr;
+               if (ce_stage(ce) || !ce_path_match(ce, pathspec))
+                       continue;
+               if (has_head)
+                       old = read_one_ent(NULL, head_sha1,
+                                          ce->name, ce_namelen(ce), 0);
+               if (old && ce->ce_mode == old->ce_mode &&
+                   !memcmp(ce->sha1, old->sha1, 20)) {
+                       free(old);
+                       continue; /* unchanged */
+               }
+               /* Be careful.  The working tree may not have the
+                * path anymore, in which case, under 'allow_remove',
+                * or worse yet 'allow_replace', active_nr may decrease.
+                */
+               save_nr = active_nr;
+               update_one(ce->name + prefix_length, prefix, prefix_length);
+               if (save_nr != active_nr)
+                       goto redo;
+       }
+       return 0;
+ }
  int main(int argc, const char **argv)
  {
        int i, newfd, entries, has_errors = 0, line_termination = '\n';
                                break;
                        }
                        if (!strcmp(path, "--unresolve")) {
-                               has_errors = do_unresolve(argc - i, argv + i);
+                               has_errors = do_unresolve(argc - i, argv + i,
+                                                         prefix, prefix_length);
+                               if (has_errors)
+                                       active_cache_changed = 0;
+                               goto finish;
+                       }
+                       if (!strcmp(path, "--again")) {
+                               has_errors = do_reupdate(argc - i, argv + i,
+                                                        prefix, prefix_length);
                                if (has_errors)
                                        active_cache_changed = 0;
                                goto finish;
                strbuf_init(&buf);
                while (1) {
                        char *path_name;
+                       const char *p;
                        read_line(&buf, stdin, line_termination);
                        if (buf.eof)
                                break;
                                path_name = unquote_c_style(buf.buf, NULL);
                        else
                                path_name = buf.buf;
-                       update_one(path_name, prefix, prefix_length);
-                       if (set_executable_bit) {
-                               const char *p = prefix_path(prefix, prefix_length, path_name);
+                       p = prefix_path(prefix, prefix_length, path_name);
+                       update_one(p, NULL, 0);
+                       if (set_executable_bit)
                                chmod_path(set_executable_bit, p);
-                       }
+                       if (p != path_name)
+                               free((char*) p);
                        if (path_name != buf.buf)
                                free(path_name);
                }