OSDN Git Service

Merge branch 'jc/cache-unmerge'
authorJunio C Hamano <gitster@pobox.com>
Wed, 20 Jan 2010 22:44:31 +0000 (14:44 -0800)
committerJunio C Hamano <gitster@pobox.com>
Wed, 20 Jan 2010 22:46:35 +0000 (14:46 -0800)
* jc/cache-unmerge:
  rerere forget path: forget recorded resolution
  rerere: refactor rerere logic to make it independent from I/O
  rerere: remove silly 1024-byte line limit
  resolve-undo: teach "update-index --unresolve" to use resolve-undo info
  resolve-undo: "checkout -m path" uses resolve-undo information
  resolve-undo: allow plumbing to clear the information
  resolve-undo: basic tests
  resolve-undo: record resolved conflicts in a new index extension section
  builtin-merge.c: use standard active_cache macros

Conflicts:
builtin-ls-files.c
builtin-merge.c
builtin-rerere.c

1  2 
Makefile
builtin-checkout.c
builtin-ls-files.c
builtin-merge.c
builtin-read-tree.c
builtin-rerere.c
builtin-update-index.c
cache.h
read-cache.c
rerere.c
rerere.h

diff --cc Makefile
Simple merge
Simple merge
@@@ -37,7 -40,7 +40,8 @@@ static const char *tag_removed = ""
  static const char *tag_other = "";
  static const char *tag_killed = "";
  static const char *tag_modified = "";
 +static const char *tag_skip_worktree = "";
+ static const char *tag_resolve_undo = "";
  
  static void show_dir_entry(const char *tag, struct dir_entry *ent)
  {
@@@ -497,7 -528,7 +535,8 @@@ int cmd_ls_files(int argc, const char *
                tag_modified = "C ";
                tag_other = "? ";
                tag_killed = "K ";
 +              tag_skip_worktree = "S ";
+               tag_resolve_undo = "U ";
        }
        if (show_modified || show_others || show_deleted || (dir.flags & DIR_SHOW_IGNORED) || show_killed)
                require_work_tree = 1;
diff --cc builtin-merge.c
@@@ -849,21 -848,12 +850,22 @@@ int cmd_merge(int argc, const char **ar
        const char *best_strategy = NULL, *wt_strategy = NULL;
        struct commit_list **remotes = &remoteheads;
  
 -      if (file_exists(git_path("MERGE_HEAD")))
 -              die("You have not concluded your merge. (MERGE_HEAD exists)");
 -      if (read_cache_unmerged())
 -              die("You are in the middle of a conflicted merge."
 -                              " (index unmerged)");
 +      if (read_cache_unmerged()) {
 +              die_resolve_conflict("merge");
 +      }
 +      if (file_exists(git_path("MERGE_HEAD"))) {
 +              /*
 +               * There is no unmerged entry, don't advise 'git
 +               * add/rm <file>', just 'git commit'.
 +               */
 +              if (advice_resolve_conflict)
 +                      die("You have not concluded your merge (MERGE_HEAD exists).\n"
 +                          "Please, commit your changes before you can merge.");
 +              else
 +                      die("You have not concluded your merge (MERGE_HEAD exists).");
 +      }
 +
+       resolve_undo_clear();
        /*
         * Check if we are _not_ on a detached HEAD, i.e. if there is a
         * current branch.
Simple merge
@@@ -103,24 -103,17 +103,27 @@@ static int diff_two(const char *file1, 
  int cmd_rerere(int argc, const char **argv, const char *prefix)
  {
        struct string_list merge_rr = { NULL, 0, 0, 1 };
 -      int i, fd;
 -
 +      int i, fd, flags = 0;
 +
 +      if (2 < argc) {
 +              if (!strcmp(argv[1], "-h"))
 +                      usage(git_rerere_usage);
 +              if (!strcmp(argv[1], "--rerere-autoupdate"))
 +                      flags = RERERE_AUTOUPDATE;
 +              else if (!strcmp(argv[1], "--no-rerere-autoupdate"))
 +                      flags = RERERE_NOAUTOUPDATE;
 +              if (flags) {
 +                      argc--;
 +                      argv++;
 +              }
 +      }
        if (argc < 2)
 -              return rerere();
 +              return rerere(flags);
  
 -      if (!strcmp(argv[1], "-h"))
 -              usage(git_rerere_usage);
 -      else if (!strcmp(argv[1], "forget"))
++      if (!strcmp(argv[1], "forget"))
+               return rerere_forget(argv + 2);
 -      fd = setup_rerere(&merge_rr);
 +      fd = setup_rerere(&merge_rr, flags);
        if (fd < 0)
                return 0;
  
Simple merge
diff --cc cache.h
Simple merge
diff --cc read-cache.c
  #include "diffcore.h"
  #include "revision.h"
  #include "blob.h"
+ #include "resolve-undo.h"
  
 +static struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really);
 +
  /* Index extensions.
   *
   * The first letter should be 'A'..'Z' for extensions that are not
diff --cc rerere.c
+++ b/rerere.c
@@@ -394,3 -518,52 +520,52 @@@ int rerere(int flags
                return 0;
        return do_plain_rerere(&merge_rr, fd);
  }
 -      fd = setup_rerere(&merge_rr);
+ static int rerere_forget_one_path(const char *path, struct string_list *rr)
+ {
+       const char *filename;
+       char *hex;
+       unsigned char sha1[20];
+       int ret;
+       ret = handle_cache(path, sha1, NULL);
+       if (ret < 1)
+               return error("Could not parse conflict hunks in '%s'", path);
+       hex = xstrdup(sha1_to_hex(sha1));
+       filename = rerere_path(hex, "postimage");
+       if (unlink(filename))
+               return (errno == ENOENT
+                       ? error("no remembered resolution for %s", path)
+                       : error("cannot unlink %s: %s", filename, strerror(errno)));
+       handle_cache(path, sha1, rerere_path(hex, "preimage"));
+       fprintf(stderr, "Updated preimage for '%s'\n", path);
+       string_list_insert(path, rr)->util = hex;
+       fprintf(stderr, "Forgot resolution for %s\n", path);
+       return 0;
+ }
+ int rerere_forget(const char **pathspec)
+ {
+       int i, fd;
+       struct string_list conflict = { NULL, 0, 0, 1 };
+       struct string_list merge_rr = { NULL, 0, 0, 1 };
+       if (read_cache() < 0)
+               return error("Could not read index");
++      fd = setup_rerere(&merge_rr, RERERE_NOAUTOUPDATE);
+       unmerge_cache(pathspec);
+       find_conflict(&conflict);
+       for (i = 0; i < conflict.nr; i++) {
+               struct string_list_item *it = &conflict.items[i];
+               if (!match_pathspec(pathspec, it->string, strlen(it->string),
+                                   0, NULL))
+                       continue;
+               rerere_forget_one_path(it->string, &merge_rr);
+       }
+       return write_rr(&merge_rr, fd);
+ }
diff --cc rerere.h
+++ b/rerere.h
@@@ -3,15 -3,10 +3,16 @@@
  
  #include "string-list.h"
  
 -extern int setup_rerere(struct string_list *);
 -extern int rerere(void);
 +#define RERERE_AUTOUPDATE   01
 +#define RERERE_NOAUTOUPDATE 02
 +
 +extern int setup_rerere(struct string_list *, int);
 +extern int rerere(int);
  extern const char *rerere_path(const char *hex, const char *file);
  extern int has_rerere_resolution(const char *hex);
+ extern int rerere_forget(const char **);
  
 +#define OPT_RERERE_AUTOUPDATE(v) OPT_UYN(0, "rerere-autoupdate", (v), \
 +      "update the index with reused conflict resolution if possible")
 +
  #endif