@matheusbsbs / matheus-bagliano / commits / cfc5789ada
Fork 0

resolve-undo: record resolved conflicts in a new index extension section

When resolving a conflict using "git add" to create a stage #0 entry, or "git rm" to remove entries at higher stages, remove_index_entry_at() function is eventually called to remove unmerged (i.e. higher stage) entries from the index. Introduce a "resolve_undo_info" structure and keep track of the removed cache entries, and save it in a new index extension section in the index_state. Operations like "read-tree -m", "merge", "checkout [-m] <branch>" and "reset" are signs that recorded information in the index is no longer necessary. The data is removed from the index extension when operations start; they may leave conflicted entries in the index, and later user actions like "git add" will record their conflicted states afresh. Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed Dec 25, 2009 at 00:30 UTC cfc5789ada444423232fa1533f401b5972eb3f6c
8 files changed +160 -1
Makefile
+2
@@ -483,6 +483,7 @@ LIB_H += reflog-walk.h
483 LIB_H += refs.h
484 LIB_H += remote.h
485 LIB_H += rerere.h
486 +LIB_H += resolve-undo.h
487 LIB_H += revision.h
488 LIB_H += run-command.h
489 LIB_H += sha1-lookup.h
@@ -578,6 +579,7 @@ LIB_OBJS += refs.o
579 LIB_OBJS += remote.o
580 LIB_OBJS += replace_object.o
581 LIB_OBJS += rerere.o
582 +LIB_OBJS += resolve-undo.o
583 LIB_OBJS += revision.o
584 LIB_OBJS += run-command.o
585 LIB_OBJS += server-info.o
builtin-checkout.c
+2
@@ -17,6 +17,7 @@
17 #include "blob.h"
18 #include "xdiff-interface.h"
19 #include "ll-merge.h"
20 +#include "resolve-undo.h"
21
22 static const char * const checkout_usage[] = {
23 "git checkout [options] <branch>",
@@ -370,6 +371,7 @@ static int merge_working_tree(struct checkout_opts *opts,
371 if (read_cache_preload(NULL) < 0)
372 return error("corrupt index file");
373
374 + resolve_undo_clear();
375 if (opts->force) {
376 ret = reset_tree(new->commit->tree, opts, 1);
377 if (ret)
builtin-merge.c
+3 -1
@@ -24,6 +24,7 @@
24 #include "rerere.h"
25 #include "help.h"
26 #include "merge-recursive.h"
27 +#include "resolve-undo.h"
28
29 #define DEFAULT_TWOHEAD (1<<0)
30 #define DEFAULT_OCTOPUS (1<<1)
@@ -604,6 +605,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
605 discard_cache();
606 if (read_cache() < 0)
607 die("failed to read the cache");
608 + resolve_undo_clear();
609 return ret;
610 }
611 }
@@ -851,7 +853,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
853 if (read_cache_unmerged())
854 die("You are in the middle of a conflicted merge."
855 " (index unmerged)");
854 -
856 + resolve_undo_clear();
857 /*
858 * Check if we are _not_ on a detached HEAD, i.e. if there is a
859 * current branch.
builtin-read-tree.c
+2
@@ -13,6 +13,7 @@
13 #include "dir.h"
14 #include "builtin.h"
15 #include "parse-options.h"
16 +#include "resolve-undo.h"
17
18 static int nr_trees;
19 static struct tree *trees[MAX_UNPACK_TREES];
@@ -122,6 +123,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
123 die("You need to resolve your current index first");
124 stage = opts.merge = 1;
125 }
126 + resolve_undo_clear();
127
128 for (i = 0; i < argc; i++) {
129 const char *arg = argv[i];
cache.h
+2
@@ -282,6 +282,7 @@ static inline int ce_to_dtype(const struct cache_entry *ce)
282 struct index_state {
283 struct cache_entry **cache;
284 unsigned int cache_nr, cache_alloc, cache_changed;
285 + struct string_list *resolve_undo;
286 struct cache_tree *cache_tree;
287 struct cache_time timestamp;
288 void *alloc;
@@ -336,6 +337,7 @@ static inline void remove_name_hash(struct cache_entry *ce)
337 #define ce_modified(ce, st, options) ie_modified(&the_index, (ce), (st), (options))
338 #define cache_name_exists(name, namelen, igncase) index_name_exists(&the_index, (name), (namelen), (igncase))
339 #define cache_name_is_other(name, namelen) index_name_is_other(&the_index, (name), (namelen))
340 +#define resolve_undo_clear() resolve_undo_clear_index(&the_index)
341 #endif
342
343 enum object_type {
read-cache.c
+18
@@ -14,6 +14,7 @@
14 #include "diffcore.h"
15 #include "revision.h"
16 #include "blob.h"
17 +#include "resolve-undo.h"
18
19 /* Index extensions.
20 *
@@ -26,6 +27,7 @@
27
28 #define CACHE_EXT(s) ( (s[0]<<24)|(s[1]<<16)|(s[2]<<8)|(s[3]) )
29 #define CACHE_EXT_TREE 0x54524545 /* "TREE" */
30 +#define CACHE_EXT_RESOLVE_UNDO 0x52455543 /* "REUN" */
31
32 struct index_state the_index;
33
@@ -449,6 +451,7 @@ int remove_index_entry_at(struct index_state *istate, int pos)
451 {
452 struct cache_entry *ce = istate->cache[pos];
453
454 + record_resolve_undo(istate, ce);
455 remove_name_hash(ce);
456 istate->cache_changed = 1;
457 istate->cache_nr--;
@@ -1170,6 +1173,9 @@ static int read_index_extension(struct index_state *istate,
1173 case CACHE_EXT_TREE:
1174 istate->cache_tree = cache_tree_read(data, sz);
1175 break;
1176 + case CACHE_EXT_RESOLVE_UNDO:
1177 + istate->resolve_undo = resolve_undo_read(data, sz);
1178 + break;
1179 default:
1180 if (*ext < 'A' || 'Z' < *ext)
1181 return error("index uses %.4s extension, which we do not understand",
@@ -1349,6 +1355,7 @@ int is_index_unborn(struct index_state *istate)
1355
1356 int discard_index(struct index_state *istate)
1357 {
1358 + resolve_undo_clear_index(istate);
1359 istate->cache_nr = 0;
1360 istate->cache_changed = 0;
1361 istate->timestamp.sec = 0;
@@ -1574,6 +1581,17 @@ int write_index(struct index_state *istate, int newfd)
1581 if (err)
1582 return -1;
1583 }
1584 + if (istate->resolve_undo) {
1585 + struct strbuf sb = STRBUF_INIT;
1586 +
1587 + resolve_undo_write(&sb, istate->resolve_undo);
1588 + err = write_index_ext_header(&c, newfd, CACHE_EXT_RESOLVE_UNDO,
1589 + sb.len) < 0
1590 + || ce_write(&c, newfd, sb.buf, sb.len) < 0;
1591 + strbuf_release(&sb);
1592 + if (err)
1593 + return -1;
1594 + }
1595
1596 if (ce_flush(&c, newfd) || fstat(newfd, &st))
1597 return -1;
resolve-undo.c new
+117
@@ -0,0 +1,117 @@
1 +#include "cache.h"
2 +#include "resolve-undo.h"
3 +#include "string-list.h"
4 +
5 +/* The only error case is to run out of memory in string-list */
6 +void record_resolve_undo(struct index_state *istate, struct cache_entry *ce)
7 +{
8 + struct string_list_item *lost;
9 + struct resolve_undo_info *ui;
10 + struct string_list *resolve_undo;
11 + int stage = ce_stage(ce);
12 +
13 + if (!stage)
14 + return;
15 +
16 + if (!istate->resolve_undo) {
17 + resolve_undo = xcalloc(1, sizeof(*resolve_undo));
18 + resolve_undo->strdup_strings = 1;
19 + istate->resolve_undo = resolve_undo;
20 + }
21 + resolve_undo = istate->resolve_undo;
22 + lost = string_list_insert(ce->name, resolve_undo);
23 + if (!lost->util)
24 + lost->util = xcalloc(1, sizeof(*ui));
25 + ui = lost->util;
26 + hashcpy(ui->sha1[stage - 1], ce->sha1);
27 + ui->mode[stage - 1] = ce->ce_mode;
28 +}
29 +
30 +static int write_one(struct string_list_item *item, void *cbdata)
31 +{
32 + struct strbuf *sb = cbdata;
33 + struct resolve_undo_info *ui = item->util;
34 + int i;
35 +
36 + if (!ui)
37 + return 0;
38 + strbuf_addstr(sb, item->string);
39 + strbuf_addch(sb, 0);
40 + for (i = 0; i < 3; i++)
41 + strbuf_addf(sb, "%o%c", ui->mode[i], 0);
42 + for (i = 0; i < 3; i++) {
43 + if (!ui->mode[i])
44 + continue;
45 + strbuf_add(sb, ui->sha1[i], 20);
46 + }
47 + return 0;
48 +}
49 +
50 +void resolve_undo_write(struct strbuf *sb, struct string_list *resolve_undo)
51 +{
52 + for_each_string_list(write_one, resolve_undo, sb);
53 +}
54 +
55 +struct string_list *resolve_undo_read(void *data, unsigned long size)
56 +{
57 + struct string_list *resolve_undo;
58 + size_t len;
59 + char *endptr;
60 + int i;
61 +
62 + resolve_undo = xcalloc(1, sizeof(*resolve_undo));
63 + resolve_undo->strdup_strings = 1;
64 +
65 + while (size) {
66 + struct string_list_item *lost;
67 + struct resolve_undo_info *ui;
68 +
69 + len = strlen(data) + 1;
70 + if (size <= len)
71 + goto error;
72 + lost = string_list_insert(data, resolve_undo);
73 + if (!lost->util)
74 + lost->util = xcalloc(1, sizeof(*ui));
75 + ui = lost->util;
76 + size -= len;
77 + data += len;
78 +
79 + for (i = 0; i < 3; i++) {
80 + ui->mode[i] = strtoul(data, &endptr, 8);
81 + if (!endptr || endptr == data || *endptr)
82 + goto error;
83 + len = (endptr + 1) - (char*)data;
84 + if (size <= len)
85 + goto error;
86 + size -= len;
87 + data += len;
88 + }
89 +
90 + for (i = 0; i < 3; i++) {
91 + if (!ui->mode[i])
92 + continue;
93 + if (size < 20)
94 + goto error;
95 + hashcpy(ui->sha1[i], data);
96 + size -= 20;
97 + data += 20;
98 + }
99 + }
100 + return resolve_undo;
101 +
102 +error:
103 + string_list_clear(resolve_undo, 1);
104 + error("Index records invalid resolve-undo information");
105 + return NULL;
106 +}
107 +
108 +void resolve_undo_clear_index(struct index_state *istate)
109 +{
110 + struct string_list *resolve_undo = istate->resolve_undo;
111 + if (!resolve_undo)
112 + return;
113 + string_list_clear(resolve_undo, 1);
114 + free(resolve_undo);
115 + istate->resolve_undo = NULL;
116 + istate->cache_changed = 1;
117 +}
resolve-undo.h new
+14
@@ -0,0 +1,14 @@
1 +#ifndef RESOLVE_UNDO_H
2 +#define RESOLVE_UNDO_H
3 +
4 +struct resolve_undo_info {
5 + unsigned int mode[3];
6 + unsigned char sha1[3][20];
7 +};
8 +
9 +extern void record_resolve_undo(struct index_state *, struct cache_entry *);
10 +extern void resolve_undo_write(struct strbuf *, struct string_list *);
11 +extern struct string_list *resolve_undo_read(void *, unsigned long);
12 +extern void resolve_undo_clear_index(struct index_state *);
13 +
14 +#endif