Merge branch 'jc/apply' into next
authorJunio C Hamano <junkio@cox.net>
Tue, 16 May 2006 00:58:02 +0000 (17:58 -0700)
committerJunio C Hamano <junkio@cox.net>
Tue, 16 May 2006 00:58:02 +0000 (17:58 -0700)
* jc/apply:
git-am: use apply --cached
apply --cached: apply a patch without using working tree.

1  2 
apply.c
git-am.sh
diff --combined apply.c
index 8391daf91772899c7b768de6f1aab272f2d2e79e,b3b9b40596ef4af5c2187b0d1227e17cadecd342..5bd50733656eee24f59486553f5afaaac9a784bc
+++ b/apply.c
@@@ -8,7 -8,6 +8,7 @@@
   */
  #include <fnmatch.h>
  #include "cache.h"
 +#include "cache-tree.h"
  #include "quote.h"
  #include "blob.h"
  #include "delta.h"
@@@ -18,6 -17,8 +18,8 @@@
  //  --stat does just a diffstat, and doesn't actually apply
  //  --numstat does numeric diffstat, and doesn't actually apply
  //  --index-info shows the old and new index info for paths if available.
+ //  --index updates the cache as well.
+ //  --cached updates only the cache without ever touching the working tree.
  //
  static const char *prefix;
  static int prefix_length = -1;
@@@ -27,6 -28,7 +29,7 @@@ static int p_value = 1
  static int allow_binary_replacement = 0;
  static int check_index = 0;
  static int write_index = 0;
+ static int cached = 0;
  static int diffstat = 0;
  static int numstat = 0;
  static int summary = 0;
@@@ -37,7 -39,7 +40,7 @@@ static int show_index_info = 0
  static int line_termination = '\n';
  static unsigned long p_context = -1;
  static const char apply_usage[] =
- "git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [-z] [-pNUM] [-CNUM] [--whitespace=<nowarn|warn|error|error-all|strip>] <patch>...";
+ "git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--cached] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [-z] [-pNUM] [-CNUM] [--whitespace=<nowarn|warn|error|error-all|strip>] <patch>...";
  
  static enum whitespace_eol {
        nowarn_whitespace,
@@@ -1601,7 -1603,7 +1604,7 @@@ static int apply_fragments(struct buffe
        return 0;
  }
  
- static int apply_data(struct patch *patch, struct stat *st)
+ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)
  {
        char *buf;
        unsigned long size, alloc;
        size = 0;
        alloc = 0;
        buf = NULL;
-       if (patch->old_name) {
+       if (cached) {
+               if (ce) {
+                       char type[20];
+                       buf = read_sha1_file(ce->sha1, type, &size);
+                       if (!buf)
+                               return error("read of %s failed",
+                                            patch->old_name);
+                       alloc = size;
+               }
+       }
+       else if (patch->old_name) {
                size = st->st_size;
                alloc = size + 8192;
                buf = xmalloc(alloc);
@@@ -1638,16 -1650,21 +1651,21 @@@ static int check_patch(struct patch *pa
        const char *old_name = patch->old_name;
        const char *new_name = patch->new_name;
        const char *name = old_name ? old_name : new_name;
+       struct cache_entry *ce = NULL;
  
        if (old_name) {
-               int changed;
-               int stat_ret = lstat(old_name, &st);
+               int changed = 0;
+               int stat_ret = 0;
+               unsigned st_mode = 0;
  
+               if (!cached)
+                       stat_ret = lstat(old_name, &st);
                if (check_index) {
                        int pos = cache_name_pos(old_name, strlen(old_name));
                        if (pos < 0)
                                return error("%s: does not exist in index",
                                             old_name);
+                       ce = active_cache[pos];
                        if (stat_ret < 0) {
                                struct checkout costate;
                                if (errno != ENOENT)
                                costate.quiet = 0;
                                costate.not_new = 0;
                                costate.refresh_cache = 1;
-                               if (checkout_entry(active_cache[pos],
+                               if (checkout_entry(ce,
                                                   &costate,
                                                   NULL) ||
                                    lstat(old_name, &st))
                                        return -1;
                        }
-                       changed = ce_match_stat(active_cache[pos], &st, 1);
+                       if (!cached)
+                               changed = ce_match_stat(ce, &st, 1);
                        if (changed)
                                return error("%s: does not match index",
                                             old_name);
+                       if (cached)
+                               st_mode = ntohl(ce->ce_mode);
                }
                else if (stat_ret < 0)
                        return error("%s: %s", old_name, strerror(errno));
  
+               if (!cached)
+                       st_mode = ntohl(create_ce_mode(st.st_mode));
                if (patch->is_new < 0)
                        patch->is_new = 0;
-               st.st_mode = ntohl(create_ce_mode(st.st_mode));
                if (!patch->old_mode)
-                       patch->old_mode = st.st_mode;
-               if ((st.st_mode ^ patch->old_mode) & S_IFMT)
+                       patch->old_mode = st_mode;
+               if ((st_mode ^ patch->old_mode) & S_IFMT)
                        return error("%s: wrong type", old_name);
-               if (st.st_mode != patch->old_mode)
+               if (st_mode != patch->old_mode)
                        fprintf(stderr, "warning: %s has type %o, expected %o\n",
-                               old_name, st.st_mode, patch->old_mode);
+                               old_name, st_mode, patch->old_mode);
        }
  
        if (new_name && (patch->is_new | patch->is_rename | patch->is_copy)) {
                if (check_index && cache_name_pos(new_name, strlen(new_name)) >= 0)
                        return error("%s: already exists in index", new_name);
-               if (!lstat(new_name, &st))
+               if (!cached && !lstat(new_name, &st))
                        return error("%s: already exists in working directory", new_name);
                if (errno != ENOENT)
                        return error("%s: %s", new_name, strerror(errno));
                        return error("new mode (%o) of %s does not match old mode (%o)%s%s",
                                patch->new_mode, new_name, patch->old_mode,
                                same ? "" : " of ", same ? "" : old_name);
-       }       
+       }
  
-       if (apply_data(patch, &st) < 0)
+       if (apply_data(patch, &st, ce) < 0)
                return error("%s: patch does not apply", name);
        return 0;
  }
@@@ -1894,9 -1915,9 +1916,10 @@@ static void remove_file(struct patch *p
        if (write_index) {
                if (remove_file_from_cache(patch->old_name) < 0)
                        die("unable to remove %s from index", patch->old_name);
 +              cache_tree_invalidate_path(active_cache_tree, patch->old_name);
        }
-       unlink(patch->old_name);
+       if (!cached)
+               unlink(patch->old_name);
  }
  
  static void add_index_file(const char *path, unsigned mode, void *buf, unsigned long size)
        memcpy(ce->name, path, namelen);
        ce->ce_mode = create_ce_mode(mode);
        ce->ce_flags = htons(namelen);
-       if (lstat(path, &st) < 0)
-               die("unable to stat newly created file %s", path);
-       fill_stat_cache_info(ce, &st);
+       if (!cached) {
+               if (lstat(path, &st) < 0)
+                       die("unable to stat newly created file %s", path);
+               fill_stat_cache_info(ce, &st);
+       }
        if (write_sha1_file(buf, size, blob_type, ce->sha1) < 0)
                die("unable to create backing store for newly created file %s", path);
        if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD) < 0)
@@@ -1952,6 -1975,8 +1977,8 @@@ static int try_create_file(const char *
   */
  static void create_one_file(char *path, unsigned mode, const char *buf, unsigned long size)
  {
+       if (cached)
+               return;
        if (!try_create_file(path, mode, buf, size))
                return;
  
@@@ -1991,9 -2016,8 +2018,9 @@@ static void create_file(struct patch *p
  
        if (!mode)
                mode = S_IFREG | 0644;
 -      create_one_file(path, mode, buf, size); 
 +      create_one_file(path, mode, buf, size);
        add_index_file(path, mode, buf, size);
 +      cache_tree_invalidate_path(active_cache_tree, path);
  }
  
  static void write_out_one_result(struct patch *patch)
@@@ -2185,6 -2209,11 +2212,11 @@@ int main(int argc, char **argv
                        check_index = 1;
                        continue;
                }
+               if (!strcmp(arg, "--cached")) {
+                       check_index = 1;
+                       cached = 1;
+                       continue;
+               }
                if (!strcmp(arg, "--apply")) {
                        apply = 1;
                        continue;
diff --combined git-am.sh
index 33f208cb0b7a7d7bad264b41443a966a567156ff,f50dff22229b7940aea3d8a90a1836e62894a997..97ec2d0c7db521047e254e53120ffc83829868a9
+++ b/git-am.sh
@@@ -15,10 -15,6 +15,10 @@@ stop_here () 
  }
  
  stop_here_user_resolve () {
 +    if [ -n "$resolvemsg" ]; then
 +          echo "$resolvemsg"
 +          stop_here $1
 +    fi
      cmdline=$(basename $0)
      if test '' != "$interactive"
      then
@@@ -59,46 -55,12 +59,12 @@@ fall_back_3way () 
        GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \
        git-write-tree >"$dotest/patch-merge-base+" &&
        # index has the base tree now.
-       (
-           cd "$dotest/patch-merge-tmp-dir" &&
-           GIT_INDEX_FILE="../patch-merge-tmp-index" \
-           GIT_OBJECT_DIRECTORY="$O_OBJECT" \
-           git-apply $binary --index <../patch
-         )
+       GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \
+       git-apply $binary --cached <"$dotest/patch"
      then
        echo Using index info to reconstruct a base tree...
        mv "$dotest/patch-merge-base+" "$dotest/patch-merge-base"
        mv "$dotest/patch-merge-tmp-index" "$dotest/patch-merge-index"
-     else
-       # Otherwise, try nearby trees that can be used to apply the
-       # patch.
-       (
-           N=10
-           # Hoping the patch is against our recent commits...
-           git-rev-list --max-count=$N HEAD
-           # or hoping the patch is against known tags...
-           git-ls-remote --tags .
-       ) |
-       while read base junk
-       do
-           # See if we have it as a tree...
-           git-cat-file tree "$base" >/dev/null 2>&1 || continue
-           rm -fr "$dotest"/patch-merge-* &&
-           mkdir "$dotest/patch-merge-tmp-dir" || break
-           (
-               cd "$dotest/patch-merge-tmp-dir" &&
-               GIT_INDEX_FILE=../patch-merge-tmp-index &&
-               GIT_OBJECT_DIRECTORY="$O_OBJECT" &&
-               export GIT_INDEX_FILE GIT_OBJECT_DIRECTORY &&
-               git-read-tree "$base" &&
-               git-apply $binary --index &&
-               mv ../patch-merge-tmp-index ../patch-merge-index &&
-               echo "$base" >../patch-merge-base
-           ) <"$dotest/patch"  2>/dev/null && break
-       done
      fi
  
      test -f "$dotest/patch-merge-index" &&
  }
  
  prec=4
 -dotest=.dotest sign= utf8= keep= skip= interactive= resolved= binary= ws=
 +dotest=.dotest sign= utf8= keep= skip= interactive= resolved= binary= ws= resolvemsg=
  
  while case "$#" in 0) break;; esac
  do
        --whitespace=*)
        ws=$1; shift ;;
  
 +      --resolvemsg=*)
 +      resolvemsg=$(echo "$1" | sed -e "s/^--resolvemsg=//"); shift ;;
 +
        --)
        shift; break ;;
        -*)
@@@ -192,7 -151,7 +158,7 @@@ the
  else
        # Make sure we are not given --skip nor --resolved
        test ",$skip,$resolved," = ,,, ||
 -              die "we are not resuming."
 +              die "Resolve operation not in progress, we are not resuming."
  
        # Start afresh.
        mkdir -p "$dotest" || exit