Merge branch 'jc/unresolve-removal'
"checkout --merge -- path" and "update-index --unresolve path" did not resurrect conflicted state that was resolved to remove path, but now they do. * jc/unresolve-removal: checkout: allow "checkout -m path" to unmerge removed paths checkout/restore: add basic tests for --merge checkout/restore: refuse unmerging paths unless checking out of the index update-index: remove stale fallback code for "--unresolve" update-index: use unmerge_index_entry() to support removal resolve-undo: allow resurrecting conflicted state that resolved to deletion update-index: do not read HEAD and MERGE_HEAD unconditionally
This commit is contained in:
@ -609,9 +609,6 @@ static const char * const update_index_usage[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct object_id head_oid;
|
||||
static struct object_id merge_head_oid;
|
||||
|
||||
static struct cache_entry *read_one_ent(const char *which,
|
||||
struct object_id *ent, const char *path,
|
||||
int namelen, int stage)
|
||||
@ -642,84 +639,17 @@ static struct cache_entry *read_one_ent(const char *which,
|
||||
|
||||
static int unresolve_one(const char *path)
|
||||
{
|
||||
int namelen = strlen(path);
|
||||
int pos;
|
||||
int ret = 0;
|
||||
struct cache_entry *ce_2 = NULL, *ce_3 = NULL;
|
||||
struct string_list_item *item;
|
||||
int res = 0;
|
||||
|
||||
/* See if there is such entry in the index. */
|
||||
pos = index_name_pos(&the_index, path, namelen);
|
||||
if (0 <= pos) {
|
||||
/* already merged */
|
||||
pos = unmerge_index_entry_at(&the_index, pos);
|
||||
if (pos < the_index.cache_nr) {
|
||||
const struct cache_entry *ce = the_index.cache[pos];
|
||||
if (ce_stage(ce) &&
|
||||
ce_namelen(ce) == namelen &&
|
||||
!memcmp(ce->name, path, namelen))
|
||||
return 0;
|
||||
}
|
||||
/* no resolve-undo information; fall back */
|
||||
} else {
|
||||
/* If there isn't, either it is unmerged, or
|
||||
* resolved as "removed" by mistake. We do not
|
||||
* want to do anything in the former case.
|
||||
*/
|
||||
pos = -pos-1;
|
||||
if (pos < the_index.cache_nr) {
|
||||
const struct cache_entry *ce = the_index.cache[pos];
|
||||
if (ce_namelen(ce) == namelen &&
|
||||
!memcmp(ce->name, path, namelen)) {
|
||||
fprintf(stderr,
|
||||
"%s: skipping still unmerged path.\n",
|
||||
path);
|
||||
goto free_return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Grab blobs from given path from HEAD and MERGE_HEAD,
|
||||
* stuff HEAD version in stage #2,
|
||||
* stuff MERGE_HEAD version in stage #3.
|
||||
*/
|
||||
ce_2 = read_one_ent("our", &head_oid, path, namelen, 2);
|
||||
ce_3 = read_one_ent("their", &merge_head_oid, path, namelen, 3);
|
||||
|
||||
if (!ce_2 || !ce_3) {
|
||||
ret = -1;
|
||||
goto free_return;
|
||||
}
|
||||
if (oideq(&ce_2->oid, &ce_3->oid) &&
|
||||
ce_2->ce_mode == ce_3->ce_mode) {
|
||||
fprintf(stderr, "%s: identical in both, skipping.\n",
|
||||
path);
|
||||
goto free_return;
|
||||
}
|
||||
|
||||
remove_file_from_index(&the_index, path);
|
||||
if (add_index_entry(&the_index, ce_2, ADD_CACHE_OK_TO_ADD)) {
|
||||
error("%s: cannot add our version to the index.", path);
|
||||
ret = -1;
|
||||
goto free_return;
|
||||
}
|
||||
if (!add_index_entry(&the_index, ce_3, ADD_CACHE_OK_TO_ADD))
|
||||
return 0;
|
||||
error("%s: cannot add their version to the index.", path);
|
||||
ret = -1;
|
||||
free_return:
|
||||
discard_cache_entry(ce_2);
|
||||
discard_cache_entry(ce_3);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void read_head_pointers(void)
|
||||
{
|
||||
if (read_ref("HEAD", &head_oid))
|
||||
die("No HEAD -- no initial commit yet?");
|
||||
if (read_ref("MERGE_HEAD", &merge_head_oid)) {
|
||||
fprintf(stderr, "Not in the middle of a merge.\n");
|
||||
exit(0);
|
||||
}
|
||||
if (!the_index.resolve_undo)
|
||||
return res;
|
||||
item = string_list_lookup(the_index.resolve_undo, path);
|
||||
if (!item)
|
||||
return res; /* no resolve-undo record for the path */
|
||||
res = unmerge_index_entry(&the_index, path, item->util, 0);
|
||||
FREE_AND_NULL(item->util);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int do_unresolve(int ac, const char **av,
|
||||
@ -728,11 +658,6 @@ static int do_unresolve(int ac, const char **av,
|
||||
int i;
|
||||
int err = 0;
|
||||
|
||||
/* Read HEAD and MERGE_HEAD; if MERGE_HEAD does not exist, we
|
||||
* are not doing a merge, so exit with success status.
|
||||
*/
|
||||
read_head_pointers();
|
||||
|
||||
for (i = 1; i < ac; i++) {
|
||||
const char *arg = av[i];
|
||||
char *p = prefix_path(prefix, prefix_length, arg);
|
||||
@ -751,6 +676,7 @@ static int do_reupdate(const char **paths,
|
||||
int pos;
|
||||
int has_head = 1;
|
||||
struct pathspec pathspec;
|
||||
struct object_id head_oid;
|
||||
|
||||
parse_pathspec(&pathspec, 0,
|
||||
PATHSPEC_PREFER_CWD,
|
||||
|
Reference in New Issue
Block a user