mirror of
https://github.com/git/git
synced 2024-11-04 16:17:49 +00:00
checkout: allow "checkout -m path" to unmerge removed paths
"git checkout -m -- path" uses the unmerge_marked_index() API, whose implementation is incapable of unresolving a path that was resolved as removed. Extend the unmerge_index() API function so that we can mark the ce_flags member of the cache entries we add to the index as unmerged, and replace use of unmerge_marked_index() with it. Now, together with its unmerge_index_entry_at() helper function, unmerge_marked_index() function is no longer called by anybody, and can safely be removed. This makes two known test failures in t2070 and t7201 to succeed. Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
ed3789f2f0
commit
5bdedac3c7
7 changed files with 13 additions and 82 deletions
|
@ -566,6 +566,8 @@ static int checkout_paths(const struct checkout_opts *opts,
|
||||||
|
|
||||||
if (opts->source_tree)
|
if (opts->source_tree)
|
||||||
read_tree_some(opts->source_tree, &opts->pathspec);
|
read_tree_some(opts->source_tree, &opts->pathspec);
|
||||||
|
if (opts->merge)
|
||||||
|
unmerge_index(&the_index, &opts->pathspec, CE_MATCHED);
|
||||||
|
|
||||||
ps_matched = xcalloc(opts->pathspec.nr, 1);
|
ps_matched = xcalloc(opts->pathspec.nr, 1);
|
||||||
|
|
||||||
|
@ -589,10 +591,6 @@ static int checkout_paths(const struct checkout_opts *opts,
|
||||||
}
|
}
|
||||||
free(ps_matched);
|
free(ps_matched);
|
||||||
|
|
||||||
/* "checkout -m path" to recreate conflicted state */
|
|
||||||
if (opts->merge)
|
|
||||||
unmerge_marked_index(&the_index);
|
|
||||||
|
|
||||||
/* Any unmerged paths? */
|
/* Any unmerged paths? */
|
||||||
for (pos = 0; pos < the_index.cache_nr; pos++) {
|
for (pos = 0; pos < the_index.cache_nr; pos++) {
|
||||||
const struct cache_entry *ce = the_index.cache[pos];
|
const struct cache_entry *ce = the_index.cache[pos];
|
||||||
|
|
|
@ -646,7 +646,7 @@ static int unresolve_one(const char *path)
|
||||||
item = string_list_lookup(the_index.resolve_undo, path);
|
item = string_list_lookup(the_index.resolve_undo, path);
|
||||||
if (!item)
|
if (!item)
|
||||||
return res; /* no resolve-undo record for the path */
|
return res; /* no resolve-undo record for the path */
|
||||||
res = unmerge_index_entry(&the_index, path, item->util);
|
res = unmerge_index_entry(&the_index, path, item->util, 0);
|
||||||
FREE_AND_NULL(item->util);
|
FREE_AND_NULL(item->util);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
2
rerere.c
2
rerere.c
|
@ -1112,7 +1112,7 @@ int rerere_forget(struct repository *r, struct pathspec *pathspec)
|
||||||
* recover the original conflicted state and then
|
* recover the original conflicted state and then
|
||||||
* find the conflicted paths.
|
* find the conflicted paths.
|
||||||
*/
|
*/
|
||||||
unmerge_index(r->index, pathspec);
|
unmerge_index(r->index, pathspec, 0);
|
||||||
find_conflict(r, &conflict);
|
find_conflict(r, &conflict);
|
||||||
for (i = 0; i < conflict.nr; i++) {
|
for (i = 0; i < conflict.nr; i++) {
|
||||||
struct string_list_item *it = &conflict.items[i];
|
struct string_list_item *it = &conflict.items[i];
|
||||||
|
|
|
@ -115,75 +115,8 @@ void resolve_undo_clear_index(struct index_state *istate)
|
||||||
istate->cache_changed |= RESOLVE_UNDO_CHANGED;
|
istate->cache_changed |= RESOLVE_UNDO_CHANGED;
|
||||||
}
|
}
|
||||||
|
|
||||||
int unmerge_index_entry_at(struct index_state *istate, int pos)
|
|
||||||
{
|
|
||||||
const struct cache_entry *ce;
|
|
||||||
struct string_list_item *item;
|
|
||||||
struct resolve_undo_info *ru;
|
|
||||||
int i, err = 0, matched;
|
|
||||||
char *name;
|
|
||||||
|
|
||||||
if (!istate->resolve_undo)
|
|
||||||
return pos;
|
|
||||||
|
|
||||||
ce = istate->cache[pos];
|
|
||||||
if (ce_stage(ce)) {
|
|
||||||
/* already unmerged */
|
|
||||||
while ((pos < istate->cache_nr) &&
|
|
||||||
! strcmp(istate->cache[pos]->name, ce->name))
|
|
||||||
pos++;
|
|
||||||
return pos - 1; /* return the last entry processed */
|
|
||||||
}
|
|
||||||
item = string_list_lookup(istate->resolve_undo, ce->name);
|
|
||||||
if (!item)
|
|
||||||
return pos;
|
|
||||||
ru = item->util;
|
|
||||||
if (!ru)
|
|
||||||
return pos;
|
|
||||||
matched = ce->ce_flags & CE_MATCHED;
|
|
||||||
name = xstrdup(ce->name);
|
|
||||||
remove_index_entry_at(istate, pos);
|
|
||||||
for (i = 0; i < 3; i++) {
|
|
||||||
struct cache_entry *nce;
|
|
||||||
if (!ru->mode[i])
|
|
||||||
continue;
|
|
||||||
nce = make_cache_entry(istate,
|
|
||||||
ru->mode[i],
|
|
||||||
&ru->oid[i],
|
|
||||||
name, i + 1, 0);
|
|
||||||
if (matched)
|
|
||||||
nce->ce_flags |= CE_MATCHED;
|
|
||||||
if (add_index_entry(istate, nce, ADD_CACHE_OK_TO_ADD)) {
|
|
||||||
err = 1;
|
|
||||||
error("cannot unmerge '%s'", name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(name);
|
|
||||||
if (err)
|
|
||||||
return pos;
|
|
||||||
free(ru);
|
|
||||||
item->util = NULL;
|
|
||||||
return unmerge_index_entry_at(istate, pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
void unmerge_marked_index(struct index_state *istate)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (!istate->resolve_undo)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* TODO: audit for interaction with sparse-index. */
|
|
||||||
ensure_full_index(istate);
|
|
||||||
for (i = 0; i < istate->cache_nr; i++) {
|
|
||||||
const struct cache_entry *ce = istate->cache[i];
|
|
||||||
if (ce->ce_flags & CE_MATCHED)
|
|
||||||
i = unmerge_index_entry_at(istate, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int unmerge_index_entry(struct index_state *istate, const char *path,
|
int unmerge_index_entry(struct index_state *istate, const char *path,
|
||||||
struct resolve_undo_info *ru)
|
struct resolve_undo_info *ru, unsigned ce_flags)
|
||||||
{
|
{
|
||||||
int i = index_name_pos(istate, path, strlen(path));
|
int i = index_name_pos(istate, path, strlen(path));
|
||||||
|
|
||||||
|
@ -206,13 +139,15 @@ int unmerge_index_entry(struct index_state *istate, const char *path,
|
||||||
continue;
|
continue;
|
||||||
ce = make_cache_entry(istate, ru->mode[i], &ru->oid[i],
|
ce = make_cache_entry(istate, ru->mode[i], &ru->oid[i],
|
||||||
path, i + 1, 0);
|
path, i + 1, 0);
|
||||||
|
ce->ce_flags |= ce_flags;
|
||||||
if (add_index_entry(istate, ce, ADD_CACHE_OK_TO_ADD))
|
if (add_index_entry(istate, ce, ADD_CACHE_OK_TO_ADD))
|
||||||
return error("cannot unmerge '%s'", path);
|
return error("cannot unmerge '%s'", path);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void unmerge_index(struct index_state *istate, const struct pathspec *pathspec)
|
void unmerge_index(struct index_state *istate, const struct pathspec *pathspec,
|
||||||
|
unsigned ce_flags)
|
||||||
{
|
{
|
||||||
struct string_list_item *item;
|
struct string_list_item *item;
|
||||||
|
|
||||||
|
@ -231,7 +166,7 @@ void unmerge_index(struct index_state *istate, const struct pathspec *pathspec)
|
||||||
item->string, strlen(item->string),
|
item->string, strlen(item->string),
|
||||||
0, NULL, 0))
|
0, NULL, 0))
|
||||||
continue;
|
continue;
|
||||||
unmerge_index_entry(istate, path, ru);
|
unmerge_index_entry(istate, path, ru, ce_flags);
|
||||||
free(ru);
|
free(ru);
|
||||||
item->util = NULL;
|
item->util = NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,9 +17,7 @@ void record_resolve_undo(struct index_state *, struct cache_entry *);
|
||||||
void resolve_undo_write(struct strbuf *, struct string_list *);
|
void resolve_undo_write(struct strbuf *, struct string_list *);
|
||||||
struct string_list *resolve_undo_read(const char *, unsigned long);
|
struct string_list *resolve_undo_read(const char *, unsigned long);
|
||||||
void resolve_undo_clear_index(struct index_state *);
|
void resolve_undo_clear_index(struct index_state *);
|
||||||
int unmerge_index_entry_at(struct index_state *, int);
|
int unmerge_index_entry(struct index_state *, const char *, struct resolve_undo_info *, unsigned);
|
||||||
int unmerge_index_entry(struct index_state *, const char *, struct resolve_undo_info *);
|
void unmerge_index(struct index_state *, const struct pathspec *, unsigned);
|
||||||
void unmerge_index(struct index_state *, const struct pathspec *);
|
|
||||||
void unmerge_marked_index(struct index_state *);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -180,7 +180,7 @@ test_expect_success 'restore --merge to unresolve after (mistaken) resolution' '
|
||||||
test_cmp expect file
|
test_cmp expect file
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_failure 'restore --merge to unresolve after (mistaken) resolution' '
|
test_expect_success 'restore --merge to unresolve after (mistaken) resolution' '
|
||||||
O=$(echo original | git hash-object -w --stdin) &&
|
O=$(echo original | git hash-object -w --stdin) &&
|
||||||
A=$(echo ourside | git hash-object -w --stdin) &&
|
A=$(echo ourside | git hash-object -w --stdin) &&
|
||||||
B=$(echo theirside | git hash-object -w --stdin) &&
|
B=$(echo theirside | git hash-object -w --stdin) &&
|
||||||
|
|
|
@ -543,7 +543,7 @@ test_expect_success 'checkout -m works after (mistaken) resolution' '
|
||||||
test_cmp merged file
|
test_cmp merged file
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_failure 'checkout -m works after (mistaken) resolution to remove' '
|
test_expect_success 'checkout -m works after (mistaken) resolution to remove' '
|
||||||
setup_conflicting_index &&
|
setup_conflicting_index &&
|
||||||
echo "none of the above" >sample &&
|
echo "none of the above" >sample &&
|
||||||
cat sample >fild &&
|
cat sample >fild &&
|
||||||
|
|
Loading…
Reference in a new issue