Skip to content

Commit cfc5789

Browse files
committed
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 <[email protected]>
1 parent be6ff81 commit cfc5789

File tree

8 files changed

+160
-1
lines changed

8 files changed

+160
-1
lines changed

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,7 @@ LIB_H += reflog-walk.h
483483
LIB_H += refs.h
484484
LIB_H += remote.h
485485
LIB_H += rerere.h
486+
LIB_H += resolve-undo.h
486487
LIB_H += revision.h
487488
LIB_H += run-command.h
488489
LIB_H += sha1-lookup.h
@@ -578,6 +579,7 @@ LIB_OBJS += refs.o
578579
LIB_OBJS += remote.o
579580
LIB_OBJS += replace_object.o
580581
LIB_OBJS += rerere.o
582+
LIB_OBJS += resolve-undo.o
581583
LIB_OBJS += revision.o
582584
LIB_OBJS += run-command.o
583585
LIB_OBJS += server-info.o

builtin-checkout.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "blob.h"
1818
#include "xdiff-interface.h"
1919
#include "ll-merge.h"
20+
#include "resolve-undo.h"
2021

2122
static const char * const checkout_usage[] = {
2223
"git checkout [options] <branch>",
@@ -370,6 +371,7 @@ static int merge_working_tree(struct checkout_opts *opts,
370371
if (read_cache_preload(NULL) < 0)
371372
return error("corrupt index file");
372373

374+
resolve_undo_clear();
373375
if (opts->force) {
374376
ret = reset_tree(new->commit->tree, opts, 1);
375377
if (ret)

builtin-merge.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "rerere.h"
2525
#include "help.h"
2626
#include "merge-recursive.h"
27+
#include "resolve-undo.h"
2728

2829
#define DEFAULT_TWOHEAD (1<<0)
2930
#define DEFAULT_OCTOPUS (1<<1)
@@ -604,6 +605,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
604605
discard_cache();
605606
if (read_cache() < 0)
606607
die("failed to read the cache");
608+
resolve_undo_clear();
607609
return ret;
608610
}
609611
}
@@ -851,7 +853,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
851853
if (read_cache_unmerged())
852854
die("You are in the middle of a conflicted merge."
853855
" (index unmerged)");
854-
856+
resolve_undo_clear();
855857
/*
856858
* Check if we are _not_ on a detached HEAD, i.e. if there is a
857859
* current branch.

builtin-read-tree.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "dir.h"
1414
#include "builtin.h"
1515
#include "parse-options.h"
16+
#include "resolve-undo.h"
1617

1718
static int nr_trees;
1819
static struct tree *trees[MAX_UNPACK_TREES];
@@ -122,6 +123,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
122123
die("You need to resolve your current index first");
123124
stage = opts.merge = 1;
124125
}
126+
resolve_undo_clear();
125127

126128
for (i = 0; i < argc; i++) {
127129
const char *arg = argv[i];

cache.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@ static inline int ce_to_dtype(const struct cache_entry *ce)
282282
struct index_state {
283283
struct cache_entry **cache;
284284
unsigned int cache_nr, cache_alloc, cache_changed;
285+
struct string_list *resolve_undo;
285286
struct cache_tree *cache_tree;
286287
struct cache_time timestamp;
287288
void *alloc;
@@ -336,6 +337,7 @@ static inline void remove_name_hash(struct cache_entry *ce)
336337
#define ce_modified(ce, st, options) ie_modified(&the_index, (ce), (st), (options))
337338
#define cache_name_exists(name, namelen, igncase) index_name_exists(&the_index, (name), (namelen), (igncase))
338339
#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)
339341
#endif
340342

341343
enum object_type {

read-cache.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "diffcore.h"
1515
#include "revision.h"
1616
#include "blob.h"
17+
#include "resolve-undo.h"
1718

1819
/* Index extensions.
1920
*
@@ -26,6 +27,7 @@
2627

2728
#define CACHE_EXT(s) ( (s[0]<<24)|(s[1]<<16)|(s[2]<<8)|(s[3]) )
2829
#define CACHE_EXT_TREE 0x54524545 /* "TREE" */
30+
#define CACHE_EXT_RESOLVE_UNDO 0x52455543 /* "REUN" */
2931

3032
struct index_state the_index;
3133

@@ -449,6 +451,7 @@ int remove_index_entry_at(struct index_state *istate, int pos)
449451
{
450452
struct cache_entry *ce = istate->cache[pos];
451453

454+
record_resolve_undo(istate, ce);
452455
remove_name_hash(ce);
453456
istate->cache_changed = 1;
454457
istate->cache_nr--;
@@ -1170,6 +1173,9 @@ static int read_index_extension(struct index_state *istate,
11701173
case CACHE_EXT_TREE:
11711174
istate->cache_tree = cache_tree_read(data, sz);
11721175
break;
1176+
case CACHE_EXT_RESOLVE_UNDO:
1177+
istate->resolve_undo = resolve_undo_read(data, sz);
1178+
break;
11731179
default:
11741180
if (*ext < 'A' || 'Z' < *ext)
11751181
return error("index uses %.4s extension, which we do not understand",
@@ -1349,6 +1355,7 @@ int is_index_unborn(struct index_state *istate)
13491355

13501356
int discard_index(struct index_state *istate)
13511357
{
1358+
resolve_undo_clear_index(istate);
13521359
istate->cache_nr = 0;
13531360
istate->cache_changed = 0;
13541361
istate->timestamp.sec = 0;
@@ -1574,6 +1581,17 @@ int write_index(struct index_state *istate, int newfd)
15741581
if (err)
15751582
return -1;
15761583
}
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+
}
15771595

15781596
if (ce_flush(&c, newfd) || fstat(newfd, &st))
15791597
return -1;

resolve-undo.c

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

0 commit comments

Comments
 (0)