Code

Merge branch 'maint' to sync with 1.5.2.5
authorJunio C Hamano <gitster@pobox.com>
Thu, 16 Aug 2007 04:38:38 +0000 (21:38 -0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 16 Aug 2007 04:38:38 +0000 (21:38 -0700)
* maint:
  GIT 1.5.2.5
  git-add -u paths... now works from subdirectory
  Fix "git add -u" data corruption.

1  2 
builtin-add.c
t/t2200-add-update.sh

diff --combined builtin-add.c
index 82c806acf003e04f2435477eb4624eb72fe4fb32,07e3ddfd0a49fd42206cf421924db17620fb690a..3dd4ded937e20d326737d17cceeebb1f3f744f07
@@@ -40,29 -40,42 +40,29 @@@ static void prune_directory(struct dir_
        dir->nr = dst - dir->entries;
  
        for (i = 0; i < specs; i++) {
 -              struct stat st;
 -              const char *match;
 -              if (seen[i])
 -                      continue;
 -
 -              match = pathspec[i];
 -              if (!match[0])
 -                      continue;
 -
 -              /* Existing file? We must have ignored it */
 -              if (!lstat(match, &st)) {
 -                      struct dir_entry *ent;
 -
 -                      ent = dir_add_name(dir, match, strlen(match));
 -                      ent->ignored = 1;
 -                      if (S_ISDIR(st.st_mode))
 -                              ent->ignored_dir = 1;
 -                      continue;
 -              }
 -              die("pathspec '%s' did not match any files", match);
 +              if (!seen[i] && !file_exists(pathspec[i]))
 +                      die("pathspec '%s' did not match any files",
 +                                      pathspec[i]);
        }
  }
  
 -static void fill_directory(struct dir_struct *dir, const char **pathspec)
 +static void fill_directory(struct dir_struct *dir, const char **pathspec,
 +              int ignored_too)
  {
        const char *path, *base;
        int baselen;
  
        /* Set up the default git porcelain excludes */
        memset(dir, 0, sizeof(*dir));
 -      dir->exclude_per_dir = ".gitignore";
 -      path = git_path("info/exclude");
 -      if (!access(path, R_OK))
 -              add_excludes_from_file(dir, path);
 -      if (!access(excludes_file, R_OK))
 -              add_excludes_from_file(dir, excludes_file);
 +      if (!ignored_too) {
 +              dir->collect_ignored = 1;
 +              dir->exclude_per_dir = ".gitignore";
 +              path = git_path("info/exclude");
 +              if (!access(path, R_OK))
 +                      add_excludes_from_file(dir, path);
 +              if (excludes_file != NULL && !access(excludes_file, R_OK))
 +                      add_excludes_from_file(dir, excludes_file);
 +      }
  
        /*
         * Calculate common prefix for the pathspec, and
@@@ -102,6 -115,7 +102,7 @@@ static void update_callback(struct diff
                        break;
                case DIFF_STATUS_DELETED:
                        remove_file_from_cache(path);
+                       cache_tree_invalidate_path(active_cache_tree, path);
                        if (verbose)
                                printf("remove '%s'\n", path);
                        break;
        }
  }
  
- static void update(int verbose, const char **files)
+ static void update(int verbose, const char *prefix, const char **files)
  {
        struct rev_info rev;
-       init_revisions(&rev, "");
+       init_revisions(&rev, prefix);
        setup_revisions(0, NULL, &rev, NULL);
-       rev.prune_data = get_pathspec(rev.prefix, files);
+       rev.prune_data = get_pathspec(prefix, files);
        rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
        rev.diffopt.format_callback = update_callback;
        rev.diffopt.format_callback_data = &verbose;
        run_diff_files(&rev, 0);
  }
  
 +static void refresh(int verbose, const char **pathspec)
 +{
 +      char *seen;
 +      int i, specs;
 +
 +      for (specs = 0; pathspec[specs];  specs++)
 +              /* nothing */;
 +      seen = xcalloc(specs, 1);
 +      if (read_cache() < 0)
 +              die("index file corrupt");
 +      refresh_index(&the_index, verbose ? 0 : REFRESH_QUIET, pathspec, seen);
 +      for (i = 0; i < specs; i++) {
 +              if (!seen[i])
 +                      die("pathspec '%s' did not match any files", pathspec[i]);
 +      }
 +}
 +
  static int git_add_config(const char *var, const char *value)
  {
        if (!strcmp(var, "core.excludesfile")) {
@@@ -160,7 -157,7 +161,7 @@@ static const char ignore_warning[] 
  int cmd_add(int argc, const char **argv, const char *prefix)
  {
        int i, newfd;
 -      int verbose = 0, show_only = 0, ignored_too = 0;
 +      int verbose = 0, show_only = 0, ignored_too = 0, refresh_only = 0;
        const char **pathspec;
        struct dir_struct dir;
        int add_interactive = 0;
                        take_worktree_changes = 1;
                        continue;
                }
 +              if (!strcmp(arg, "--refresh")) {
 +                      refresh_only = 1;
 +                      continue;
 +              }
                usage(builtin_add_usage);
        }
  
        if (take_worktree_changes) {
-               update(verbose, argv + i);
+               update(verbose, prefix, argv + i);
                goto finish;
        }
  
        }
        pathspec = get_pathspec(prefix, argv + i);
  
 -      fill_directory(&dir, pathspec);
 +      if (refresh_only) {
 +              refresh(verbose, pathspec);
 +              goto finish;
 +      }
 +
 +      fill_directory(&dir, pathspec, ignored_too);
  
        if (show_only) {
                const char *sep = "", *eof = "";
                for (i = 0; i < dir.nr; i++) {
 -                      if (!ignored_too && dir.entries[i]->ignored)
 -                              continue;
                        printf("%s%s", sep, dir.entries[i]->name);
                        sep = " ";
                        eof = "\n";
        if (read_cache() < 0)
                die("index file corrupt");
  
 -      if (!ignored_too) {
 -              int has_ignored = 0;
 -              for (i = 0; i < dir.nr; i++)
 -                      if (dir.entries[i]->ignored)
 -                              has_ignored = 1;
 -              if (has_ignored) {
 -                      fprintf(stderr, ignore_warning);
 -                      for (i = 0; i < dir.nr; i++) {
 -                              if (!dir.entries[i]->ignored)
 -                                      continue;
 -                              fprintf(stderr, "%s", dir.entries[i]->name);
 -                              if (dir.entries[i]->ignored_dir)
 -                                      fprintf(stderr, " (directory)");
 -                              fputc('\n', stderr);
 -                      }
 -                      fprintf(stderr,
 -                              "Use -f if you really want to add them.\n");
 -                      exit(1);
 +      if (dir.ignored_nr) {
 +              fprintf(stderr, ignore_warning);
 +              for (i = 0; i < dir.ignored_nr; i++) {
 +                      fprintf(stderr, "%s\n", dir.ignored[i]->name);
                }
 +              fprintf(stderr, "Use -f if you really want to add them.\n");
 +              exit(1);
        }
  
        for (i = 0; i < dir.nr; i++)
diff --combined t/t2200-add-update.sh
index 0a703af14976d7e546e1b5fde6affbde22b724c2,58cd7f31bed90fd24d1f5cd43ff0e26c922ea4ab..61d08bb431ca18d6223e944cd4ca43fba6c1d332
@@@ -1,6 -1,6 +1,6 @@@
  #!/bin/sh
  
 -test_description='git-add -u with path limiting
 +test_description='git add -u with path limiting
  
  This test creates a working tree state with three files:
  
@@@ -8,31 -8,72 +8,72 @@@
    dir/sub (previously committed, modified)
    dir/other (untracked)
  
 -and issues a git-add -u with path limiting on "dir" to add
 +and issues a git add -u with path limiting on "dir" to add
  only the updates to dir/sub.'
  
  . ./test-lib.sh
  
- test_expect_success 'setup' '
- echo initial >top &&
- mkdir dir &&
- echo initial >dir/sub &&
- git add dir/sub top &&
- git-commit -m initial &&
- echo changed >top &&
- echo changed >dir/sub &&
- echo other >dir/other
+ test_expect_success setup '
+       echo initial >check &&
+       echo initial >top &&
+       mkdir dir1 dir2 &&
+       echo initial >dir1/sub1 &&
+       echo initial >dir1/sub2 &&
+       echo initial >dir2/sub3 &&
+       git add check dir1 dir2 top &&
+       test_tick
+       git-commit -m initial &&
+       echo changed >check &&
+       echo changed >top &&
+       echo changed >dir2/sub3 &&
+       rm -f dir1/sub1 &&
+       echo other >dir2/other
  '
  
- test_expect_success 'update' 'git add -u dir'
+ test_expect_success update '
+       git add -u dir1 dir2
+ '
  
- test_expect_success 'update touched correct path' \
-   'test "`git diff-files --name-status dir/sub`" = ""'
+ test_expect_success 'update noticed a removal' '
+       test "$(git-ls-files dir1/sub1)" = ""
+ '
+ test_expect_success 'update touched correct path' '
+       test "$(git-diff-files --name-status dir2/sub3)" = ""
+ '
+ test_expect_success 'update did not touch other tracked files' '
+       test "$(git-diff-files --name-status check)" = "M       check" &&
+       test "$(git-diff-files --name-status top)" = "M top"
+ '
+ test_expect_success 'update did not touch untracked files' '
+       test "$(git-ls-files dir2/other)" = ""
+ '
  
- test_expect_success 'update did not touch other tracked files' \
-   'test "`git diff-files --name-status top`" = "M     top"'
+ test_expect_success 'cache tree has not been corrupted' '
  
- test_expect_success 'update did not touch untracked files' \
-   'test "`git diff-files --name-status dir/other`" = ""'
+       git ls-files -s |
+       sed -e "s/ 0    /       /" >expect &&
+       git ls-tree -r $(git write-tree) |
+       sed -e "s/ blob / /" >current &&
+       diff -u expect current
+ '
+ test_expect_success 'update from a subdirectory' '
+       (
+               cd dir1 &&
+               echo more >sub2 &&
+               git add -u sub2
+       )
+ '
+ test_expect_success 'change gets noticed' '
+       test "$(git diff-files --name-status dir1)" = ""
+ '
  
  test_done