|
|
@ -343,22 +343,24 @@ static int add_cacheinfo(struct merge_options *o, |
|
|
|
unsigned int mode, const struct object_id *oid, |
|
|
|
unsigned int mode, const struct object_id *oid, |
|
|
|
const char *path, int stage, int refresh, int options) |
|
|
|
const char *path, int stage, int refresh, int options) |
|
|
|
{ |
|
|
|
{ |
|
|
|
|
|
|
|
struct index_state *istate = o->repo->index; |
|
|
|
struct cache_entry *ce; |
|
|
|
struct cache_entry *ce; |
|
|
|
int ret; |
|
|
|
int ret; |
|
|
|
|
|
|
|
|
|
|
|
ce = make_cache_entry(&the_index, mode, oid ? oid : &null_oid, path, stage, 0); |
|
|
|
ce = make_cache_entry(istate, mode, oid ? oid : &null_oid, path, stage, 0); |
|
|
|
if (!ce) |
|
|
|
if (!ce) |
|
|
|
return err(o, _("add_cacheinfo failed for path '%s'; merge aborting."), path); |
|
|
|
return err(o, _("add_cacheinfo failed for path '%s'; merge aborting."), path); |
|
|
|
|
|
|
|
|
|
|
|
ret = add_cache_entry(ce, options); |
|
|
|
ret = add_index_entry(istate, ce, options); |
|
|
|
if (refresh) { |
|
|
|
if (refresh) { |
|
|
|
struct cache_entry *nce; |
|
|
|
struct cache_entry *nce; |
|
|
|
|
|
|
|
|
|
|
|
nce = refresh_cache_entry(&the_index, ce, CE_MATCH_REFRESH | CE_MATCH_IGNORE_MISSING); |
|
|
|
nce = refresh_cache_entry(istate, ce, |
|
|
|
|
|
|
|
CE_MATCH_REFRESH | CE_MATCH_IGNORE_MISSING); |
|
|
|
if (!nce) |
|
|
|
if (!nce) |
|
|
|
return err(o, _("add_cacheinfo failed to refresh for path '%s'; merge aborting."), path); |
|
|
|
return err(o, _("add_cacheinfo failed to refresh for path '%s'; merge aborting."), path); |
|
|
|
if (nce != ce) |
|
|
|
if (nce != ce) |
|
|
|
ret = add_cache_entry(nce, options); |
|
|
|
ret = add_index_entry(istate, nce, options); |
|
|
|
} |
|
|
|
} |
|
|
|
return ret; |
|
|
|
return ret; |
|
|
|
} |
|
|
|
} |
|
|
@ -386,7 +388,7 @@ static int unpack_trees_start(struct merge_options *o, |
|
|
|
o->unpack_opts.merge = 1; |
|
|
|
o->unpack_opts.merge = 1; |
|
|
|
o->unpack_opts.head_idx = 2; |
|
|
|
o->unpack_opts.head_idx = 2; |
|
|
|
o->unpack_opts.fn = threeway_merge; |
|
|
|
o->unpack_opts.fn = threeway_merge; |
|
|
|
o->unpack_opts.src_index = &the_index; |
|
|
|
o->unpack_opts.src_index = o->repo->index; |
|
|
|
o->unpack_opts.dst_index = &tmp_index; |
|
|
|
o->unpack_opts.dst_index = &tmp_index; |
|
|
|
o->unpack_opts.aggressive = !merge_detect_rename(o); |
|
|
|
o->unpack_opts.aggressive = !merge_detect_rename(o); |
|
|
|
setup_unpack_trees_porcelain(&o->unpack_opts, "merge"); |
|
|
|
setup_unpack_trees_porcelain(&o->unpack_opts, "merge"); |
|
|
@ -396,16 +398,16 @@ static int unpack_trees_start(struct merge_options *o, |
|
|
|
init_tree_desc_from_tree(t+2, merge); |
|
|
|
init_tree_desc_from_tree(t+2, merge); |
|
|
|
|
|
|
|
|
|
|
|
rc = unpack_trees(3, t, &o->unpack_opts); |
|
|
|
rc = unpack_trees(3, t, &o->unpack_opts); |
|
|
|
cache_tree_free(&active_cache_tree); |
|
|
|
cache_tree_free(&o->repo->index->cache_tree); |
|
|
|
|
|
|
|
|
|
|
|
/* |
|
|
|
/* |
|
|
|
* Update the_index to match the new results, AFTER saving a copy |
|
|
|
* Update o->repo->index to match the new results, AFTER saving a copy |
|
|
|
* in o->orig_index. Update src_index to point to the saved copy. |
|
|
|
* in o->orig_index. Update src_index to point to the saved copy. |
|
|
|
* (verify_uptodate() checks src_index, and the original index is |
|
|
|
* (verify_uptodate() checks src_index, and the original index is |
|
|
|
* the one that had the necessary modification timestamps.) |
|
|
|
* the one that had the necessary modification timestamps.) |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
o->orig_index = the_index; |
|
|
|
o->orig_index = *o->repo->index; |
|
|
|
the_index = tmp_index; |
|
|
|
*o->repo->index = tmp_index; |
|
|
|
o->unpack_opts.src_index = &o->orig_index; |
|
|
|
o->unpack_opts.src_index = &o->orig_index; |
|
|
|
|
|
|
|
|
|
|
|
return rc; |
|
|
|
return rc; |
|
|
@ -420,12 +422,13 @@ static void unpack_trees_finish(struct merge_options *o) |
|
|
|
struct tree *write_tree_from_memory(struct merge_options *o) |
|
|
|
struct tree *write_tree_from_memory(struct merge_options *o) |
|
|
|
{ |
|
|
|
{ |
|
|
|
struct tree *result = NULL; |
|
|
|
struct tree *result = NULL; |
|
|
|
|
|
|
|
struct index_state *istate = o->repo->index; |
|
|
|
|
|
|
|
|
|
|
|
if (unmerged_cache()) { |
|
|
|
if (unmerged_index(istate)) { |
|
|
|
int i; |
|
|
|
int i; |
|
|
|
fprintf(stderr, "BUG: There are unmerged index entries:\n"); |
|
|
|
fprintf(stderr, "BUG: There are unmerged index entries:\n"); |
|
|
|
for (i = 0; i < active_nr; i++) { |
|
|
|
for (i = 0; i < istate->cache_nr; i++) { |
|
|
|
const struct cache_entry *ce = active_cache[i]; |
|
|
|
const struct cache_entry *ce = istate->cache[i]; |
|
|
|
if (ce_stage(ce)) |
|
|
|
if (ce_stage(ce)) |
|
|
|
fprintf(stderr, "BUG: %d %.*s\n", ce_stage(ce), |
|
|
|
fprintf(stderr, "BUG: %d %.*s\n", ce_stage(ce), |
|
|
|
(int)ce_namelen(ce), ce->name); |
|
|
|
(int)ce_namelen(ce), ce->name); |
|
|
@ -433,16 +436,16 @@ struct tree *write_tree_from_memory(struct merge_options *o) |
|
|
|
BUG("unmerged index entries in merge-recursive.c"); |
|
|
|
BUG("unmerged index entries in merge-recursive.c"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (!active_cache_tree) |
|
|
|
if (!istate->cache_tree) |
|
|
|
active_cache_tree = cache_tree(); |
|
|
|
istate->cache_tree = cache_tree(); |
|
|
|
|
|
|
|
|
|
|
|
if (!cache_tree_fully_valid(active_cache_tree) && |
|
|
|
if (!cache_tree_fully_valid(istate->cache_tree) && |
|
|
|
cache_tree_update(&the_index, 0) < 0) { |
|
|
|
cache_tree_update(istate, 0) < 0) { |
|
|
|
err(o, _("error building trees")); |
|
|
|
err(o, _("error building trees")); |
|
|
|
return NULL; |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
result = lookup_tree(the_repository, &active_cache_tree->oid); |
|
|
|
result = lookup_tree(the_repository, &istate->cache_tree->oid); |
|
|
|
|
|
|
|
|
|
|
|
return result; |
|
|
|
return result; |
|
|
|
} |
|
|
|
} |
|
|
@ -512,17 +515,17 @@ static struct stage_data *insert_stage_data(const char *path, |
|
|
|
* Create a dictionary mapping file names to stage_data objects. The |
|
|
|
* Create a dictionary mapping file names to stage_data objects. The |
|
|
|
* dictionary contains one entry for every path with a non-zero stage entry. |
|
|
|
* dictionary contains one entry for every path with a non-zero stage entry. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
static struct string_list *get_unmerged(void) |
|
|
|
static struct string_list *get_unmerged(struct index_state *istate) |
|
|
|
{ |
|
|
|
{ |
|
|
|
struct string_list *unmerged = xcalloc(1, sizeof(struct string_list)); |
|
|
|
struct string_list *unmerged = xcalloc(1, sizeof(struct string_list)); |
|
|
|
int i; |
|
|
|
int i; |
|
|
|
|
|
|
|
|
|
|
|
unmerged->strdup_strings = 1; |
|
|
|
unmerged->strdup_strings = 1; |
|
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < active_nr; i++) { |
|
|
|
for (i = 0; i < istate->cache_nr; i++) { |
|
|
|
struct string_list_item *item; |
|
|
|
struct string_list_item *item; |
|
|
|
struct stage_data *e; |
|
|
|
struct stage_data *e; |
|
|
|
const struct cache_entry *ce = active_cache[i]; |
|
|
|
const struct cache_entry *ce = istate->cache[i]; |
|
|
|
if (!ce_stage(ce)) |
|
|
|
if (!ce_stage(ce)) |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
@ -682,7 +685,7 @@ static int update_stages(struct merge_options *opt, const char *path, |
|
|
|
int clear = 1; |
|
|
|
int clear = 1; |
|
|
|
int options = ADD_CACHE_OK_TO_ADD | ADD_CACHE_SKIP_DFCHECK; |
|
|
|
int options = ADD_CACHE_OK_TO_ADD | ADD_CACHE_SKIP_DFCHECK; |
|
|
|
if (clear) |
|
|
|
if (clear) |
|
|
|
if (remove_file_from_cache(path)) |
|
|
|
if (remove_file_from_index(opt->repo->index, path)) |
|
|
|
return -1; |
|
|
|
return -1; |
|
|
|
if (o) |
|
|
|
if (o) |
|
|
|
if (add_cacheinfo(opt, o->mode, &o->oid, path, 1, 0, options)) |
|
|
|
if (add_cacheinfo(opt, o->mode, &o->oid, path, 1, 0, options)) |
|
|
@ -717,13 +720,14 @@ static int remove_file(struct merge_options *o, int clean, |
|
|
|
int update_working_directory = !o->call_depth && !no_wd; |
|
|
|
int update_working_directory = !o->call_depth && !no_wd; |
|
|
|
|
|
|
|
|
|
|
|
if (update_cache) { |
|
|
|
if (update_cache) { |
|
|
|
if (remove_file_from_cache(path)) |
|
|
|
if (remove_file_from_index(o->repo->index, path)) |
|
|
|
return -1; |
|
|
|
return -1; |
|
|
|
} |
|
|
|
} |
|
|
|
if (update_working_directory) { |
|
|
|
if (update_working_directory) { |
|
|
|
if (ignore_case) { |
|
|
|
if (ignore_case) { |
|
|
|
struct cache_entry *ce; |
|
|
|
struct cache_entry *ce; |
|
|
|
ce = cache_file_exists(path, strlen(path), ignore_case); |
|
|
|
ce = index_file_exists(o->repo->index, path, strlen(path), |
|
|
|
|
|
|
|
ignore_case); |
|
|
|
if (ce && ce_stage(ce) == 0 && strcmp(path, ce->name)) |
|
|
|
if (ce && ce_stage(ce) == 0 && strcmp(path, ce->name)) |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
@ -773,7 +777,8 @@ static char *unique_path(struct merge_options *o, const char *path, const char * |
|
|
|
* check the working directory. If empty_ok is non-zero, also return |
|
|
|
* check the working directory. If empty_ok is non-zero, also return |
|
|
|
* 0 in the case where the working-tree dir exists but is empty. |
|
|
|
* 0 in the case where the working-tree dir exists but is empty. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
static int dir_in_way(const char *path, int check_working_copy, int empty_ok) |
|
|
|
static int dir_in_way(struct index_state *istate, const char *path, |
|
|
|
|
|
|
|
int check_working_copy, int empty_ok) |
|
|
|
{ |
|
|
|
{ |
|
|
|
int pos; |
|
|
|
int pos; |
|
|
|
struct strbuf dirpath = STRBUF_INIT; |
|
|
|
struct strbuf dirpath = STRBUF_INIT; |
|
|
@ -782,12 +787,12 @@ static int dir_in_way(const char *path, int check_working_copy, int empty_ok) |
|
|
|
strbuf_addstr(&dirpath, path); |
|
|
|
strbuf_addstr(&dirpath, path); |
|
|
|
strbuf_addch(&dirpath, '/'); |
|
|
|
strbuf_addch(&dirpath, '/'); |
|
|
|
|
|
|
|
|
|
|
|
pos = cache_name_pos(dirpath.buf, dirpath.len); |
|
|
|
pos = index_name_pos(istate, dirpath.buf, dirpath.len); |
|
|
|
|
|
|
|
|
|
|
|
if (pos < 0) |
|
|
|
if (pos < 0) |
|
|
|
pos = -1 - pos; |
|
|
|
pos = -1 - pos; |
|
|
|
if (pos < active_nr && |
|
|
|
if (pos < istate->cache_nr && |
|
|
|
!strncmp(dirpath.buf, active_cache[pos]->name, dirpath.len)) { |
|
|
|
!strncmp(dirpath.buf, istate->cache[pos]->name, dirpath.len)) { |
|
|
|
strbuf_release(&dirpath); |
|
|
|
strbuf_release(&dirpath); |
|
|
|
return 1; |
|
|
|
return 1; |
|
|
|
} |
|
|
|
} |
|
|
@ -830,8 +835,10 @@ static int was_tracked(struct merge_options *o, const char *path) |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int would_lose_untracked(const char *path) |
|
|
|
static int would_lose_untracked(struct merge_options *o, const char *path) |
|
|
|
{ |
|
|
|
{ |
|
|
|
|
|
|
|
struct index_state *istate = o->repo->index; |
|
|
|
|
|
|
|
|
|
|
|
/* |
|
|
|
/* |
|
|
|
* This may look like it can be simplified to: |
|
|
|
* This may look like it can be simplified to: |
|
|
|
* return !was_tracked(o, path) && file_exists(path) |
|
|
|
* return !was_tracked(o, path) && file_exists(path) |
|
|
@ -849,19 +856,19 @@ static int would_lose_untracked(const char *path) |
|
|
|
* update_file()/would_lose_untracked(); see every comment in this |
|
|
|
* update_file()/would_lose_untracked(); see every comment in this |
|
|
|
* file which mentions "update_stages". |
|
|
|
* file which mentions "update_stages". |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
int pos = cache_name_pos(path, strlen(path)); |
|
|
|
int pos = index_name_pos(istate, path, strlen(path)); |
|
|
|
|
|
|
|
|
|
|
|
if (pos < 0) |
|
|
|
if (pos < 0) |
|
|
|
pos = -1 - pos; |
|
|
|
pos = -1 - pos; |
|
|
|
while (pos < active_nr && |
|
|
|
while (pos < istate->cache_nr && |
|
|
|
!strcmp(path, active_cache[pos]->name)) { |
|
|
|
!strcmp(path, istate->cache[pos]->name)) { |
|
|
|
/* |
|
|
|
/* |
|
|
|
* If stage #0, it is definitely tracked. |
|
|
|
* If stage #0, it is definitely tracked. |
|
|
|
* If it has stage #2 then it was tracked |
|
|
|
* If it has stage #2 then it was tracked |
|
|
|
* before this merge started. All other |
|
|
|
* before this merge started. All other |
|
|
|
* cases the path was not tracked. |
|
|
|
* cases the path was not tracked. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
switch (ce_stage(active_cache[pos])) { |
|
|
|
switch (ce_stage(istate->cache[pos])) { |
|
|
|
case 0: |
|
|
|
case 0: |
|
|
|
case 2: |
|
|
|
case 2: |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
@ -921,7 +928,7 @@ static int make_room_for_path(struct merge_options *o, const char *path) |
|
|
|
* Do not unlink a file in the work tree if we are not |
|
|
|
* Do not unlink a file in the work tree if we are not |
|
|
|
* tracking it. |
|
|
|
* tracking it. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
if (would_lose_untracked(path)) |
|
|
|
if (would_lose_untracked(o, path)) |
|
|
|
return err(o, _("refusing to lose untracked file at '%s'"), |
|
|
|
return err(o, _("refusing to lose untracked file at '%s'"), |
|
|
|
path); |
|
|
|
path); |
|
|
|
|
|
|
|
|
|
|
@ -971,7 +978,7 @@ static int update_file_flags(struct merge_options *o, |
|
|
|
} |
|
|
|
} |
|
|
|
if (S_ISREG(mode)) { |
|
|
|
if (S_ISREG(mode)) { |
|
|
|
struct strbuf strbuf = STRBUF_INIT; |
|
|
|
struct strbuf strbuf = STRBUF_INIT; |
|
|
|
if (convert_to_working_tree(&the_index, path, buf, size, &strbuf)) { |
|
|
|
if (convert_to_working_tree(o->repo->index, path, buf, size, &strbuf)) { |
|
|
|
free(buf); |
|
|
|
free(buf); |
|
|
|
size = strbuf.len; |
|
|
|
size = strbuf.len; |
|
|
|
buf = strbuf_detach(&strbuf, NULL); |
|
|
|
buf = strbuf_detach(&strbuf, NULL); |
|
|
@ -1091,7 +1098,7 @@ static int merge_3way(struct merge_options *o, |
|
|
|
|
|
|
|
|
|
|
|
merge_status = ll_merge(result_buf, a->path, &orig, base_name, |
|
|
|
merge_status = ll_merge(result_buf, a->path, &orig, base_name, |
|
|
|
&src1, name1, &src2, name2, |
|
|
|
&src1, name1, &src2, name2, |
|
|
|
&the_index, &ll_opts); |
|
|
|
o->repo->index, &ll_opts); |
|
|
|
|
|
|
|
|
|
|
|
free(base_name); |
|
|
|
free(base_name); |
|
|
|
free(name1); |
|
|
|
free(name1); |
|
|
@ -1102,7 +1109,8 @@ static int merge_3way(struct merge_options *o, |
|
|
|
return merge_status; |
|
|
|
return merge_status; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int find_first_merges(struct object_array *result, const char *path, |
|
|
|
static int find_first_merges(struct repository *repo, |
|
|
|
|
|
|
|
struct object_array *result, const char *path, |
|
|
|
struct commit *a, struct commit *b) |
|
|
|
struct commit *a, struct commit *b) |
|
|
|
{ |
|
|
|
{ |
|
|
|
int i, j; |
|
|
|
int i, j; |
|
|
@ -1122,7 +1130,7 @@ static int find_first_merges(struct object_array *result, const char *path, |
|
|
|
/* get all revisions that merge commit a */ |
|
|
|
/* get all revisions that merge commit a */ |
|
|
|
xsnprintf(merged_revision, sizeof(merged_revision), "^%s", |
|
|
|
xsnprintf(merged_revision, sizeof(merged_revision), "^%s", |
|
|
|
oid_to_hex(&a->object.oid)); |
|
|
|
oid_to_hex(&a->object.oid)); |
|
|
|
repo_init_revisions(the_repository, &revs, NULL); |
|
|
|
repo_init_revisions(repo, &revs, NULL); |
|
|
|
rev_opts.submodule = path; |
|
|
|
rev_opts.submodule = path; |
|
|
|
/* FIXME: can't handle linked worktrees in submodules yet */ |
|
|
|
/* FIXME: can't handle linked worktrees in submodules yet */ |
|
|
|
revs.single_worktree = path != NULL; |
|
|
|
revs.single_worktree = path != NULL; |
|
|
@ -1252,7 +1260,8 @@ static int merge_submodule(struct merge_options *o, |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
|
|
/* find commit which merges them */ |
|
|
|
/* find commit which merges them */ |
|
|
|
parent_count = find_first_merges(&merges, path, commit_a, commit_b); |
|
|
|
parent_count = find_first_merges(o->repo, &merges, path, |
|
|
|
|
|
|
|
commit_a, commit_b); |
|
|
|
switch (parent_count) { |
|
|
|
switch (parent_count) { |
|
|
|
case 0: |
|
|
|
case 0: |
|
|
|
output(o, 1, _("Failed to merge submodule %s (merge following commits not found)"), path); |
|
|
|
output(o, 1, _("Failed to merge submodule %s (merge following commits not found)"), path); |
|
|
@ -1400,7 +1409,7 @@ static int handle_rename_via_dir(struct merge_options *o, |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
const struct diff_filespec *dest = pair->two; |
|
|
|
const struct diff_filespec *dest = pair->two; |
|
|
|
|
|
|
|
|
|
|
|
if (!o->call_depth && would_lose_untracked(dest->path)) { |
|
|
|
if (!o->call_depth && would_lose_untracked(o, dest->path)) { |
|
|
|
char *alt_path = unique_path(o, dest->path, rename_branch); |
|
|
|
char *alt_path = unique_path(o, dest->path, rename_branch); |
|
|
|
|
|
|
|
|
|
|
|
output(o, 1, _("Error: Refusing to lose untracked file at %s; " |
|
|
|
output(o, 1, _("Error: Refusing to lose untracked file at %s; " |
|
|
@ -1438,8 +1447,8 @@ static int handle_change_delete(struct merge_options *o, |
|
|
|
const char *update_path = path; |
|
|
|
const char *update_path = path; |
|
|
|
int ret = 0; |
|
|
|
int ret = 0; |
|
|
|
|
|
|
|
|
|
|
|
if (dir_in_way(path, !o->call_depth, 0) || |
|
|
|
if (dir_in_way(o->repo->index, path, !o->call_depth, 0) || |
|
|
|
(!o->call_depth && would_lose_untracked(path))) { |
|
|
|
(!o->call_depth && would_lose_untracked(o, path))) { |
|
|
|
update_path = alt_path = unique_path(o, path, change_branch); |
|
|
|
update_path = alt_path = unique_path(o, path, change_branch); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -1449,7 +1458,7 @@ static int handle_change_delete(struct merge_options *o, |
|
|
|
* correct; since there is no true "middle point" between |
|
|
|
* correct; since there is no true "middle point" between |
|
|
|
* them, simply reuse the base version for virtual merge base. |
|
|
|
* them, simply reuse the base version for virtual merge base. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
ret = remove_file_from_cache(path); |
|
|
|
ret = remove_file_from_index(o->repo->index, path); |
|
|
|
if (!ret) |
|
|
|
if (!ret) |
|
|
|
ret = update_file(o, 0, o_oid, o_mode, update_path); |
|
|
|
ret = update_file(o, 0, o_oid, o_mode, update_path); |
|
|
|
} else { |
|
|
|
} else { |
|
|
@ -1525,7 +1534,7 @@ static int handle_rename_delete(struct merge_options *o, |
|
|
|
return -1; |
|
|
|
return -1; |
|
|
|
|
|
|
|
|
|
|
|
if (o->call_depth) |
|
|
|
if (o->call_depth) |
|
|
|
return remove_file_from_cache(dest->path); |
|
|
|
return remove_file_from_index(o->repo->index, dest->path); |
|
|
|
else |
|
|
|
else |
|
|
|
return update_stages(o, dest->path, NULL, |
|
|
|
return update_stages(o, dest->path, NULL, |
|
|
|
rename_branch == o->branch1 ? dest : NULL, |
|
|
|
rename_branch == o->branch1 ? dest : NULL, |
|
|
@ -1606,10 +1615,10 @@ static int handle_file_collision(struct merge_options *o, |
|
|
|
/* Remove rename sources if rename/add or rename/rename(2to1) */ |
|
|
|
/* Remove rename sources if rename/add or rename/rename(2to1) */ |
|
|
|
if (prev_path1) |
|
|
|
if (prev_path1) |
|
|
|
remove_file(o, 1, prev_path1, |
|
|
|
remove_file(o, 1, prev_path1, |
|
|
|
o->call_depth || would_lose_untracked(prev_path1)); |
|
|
|
o->call_depth || would_lose_untracked(o, prev_path1)); |
|
|
|
if (prev_path2) |
|
|
|
if (prev_path2) |
|
|
|
remove_file(o, 1, prev_path2, |
|
|
|
remove_file(o, 1, prev_path2, |
|
|
|
o->call_depth || would_lose_untracked(prev_path2)); |
|
|
|
o->call_depth || would_lose_untracked(o, prev_path2)); |
|
|
|
|
|
|
|
|
|
|
|
/* |
|
|
|
/* |
|
|
|
* Remove the collision path, if it wouldn't cause dirty contents |
|
|
|
* Remove the collision path, if it wouldn't cause dirty contents |
|
|
@ -1620,7 +1629,7 @@ static int handle_file_collision(struct merge_options *o, |
|
|
|
output(o, 1, _("Refusing to lose dirty file at %s"), |
|
|
|
output(o, 1, _("Refusing to lose dirty file at %s"), |
|
|
|
collide_path); |
|
|
|
collide_path); |
|
|
|
update_path = alt_path = unique_path(o, collide_path, "merged"); |
|
|
|
update_path = alt_path = unique_path(o, collide_path, "merged"); |
|
|
|
} else if (would_lose_untracked(collide_path)) { |
|
|
|
} else if (would_lose_untracked(o, collide_path)) { |
|
|
|
/* |
|
|
|
/* |
|
|
|
* Only way we get here is if both renames were from |
|
|
|
* Only way we get here is if both renames were from |
|
|
|
* a directory rename AND user had an untracked file |
|
|
|
* a directory rename AND user had an untracked file |
|
|
@ -1716,12 +1725,12 @@ static char *find_path_for_conflict(struct merge_options *o, |
|
|
|
const char *branch2) |
|
|
|
const char *branch2) |
|
|
|
{ |
|
|
|
{ |
|
|
|
char *new_path = NULL; |
|
|
|
char *new_path = NULL; |
|
|
|
if (dir_in_way(path, !o->call_depth, 0)) { |
|
|
|
if (dir_in_way(o->repo->index, path, !o->call_depth, 0)) { |
|
|
|
new_path = unique_path(o, path, branch1); |
|
|
|
new_path = unique_path(o, path, branch1); |
|
|
|
output(o, 1, _("%s is a directory in %s adding " |
|
|
|
output(o, 1, _("%s is a directory in %s adding " |
|
|
|
"as %s instead"), |
|
|
|
"as %s instead"), |
|
|
|
path, branch2, new_path); |
|
|
|
path, branch2, new_path); |
|
|
|
} else if (would_lose_untracked(path)) { |
|
|
|
} else if (would_lose_untracked(o, path)) { |
|
|
|
new_path = unique_path(o, path, branch1); |
|
|
|
new_path = unique_path(o, path, branch1); |
|
|
|
output(o, 1, _("Refusing to lose untracked file" |
|
|
|
output(o, 1, _("Refusing to lose untracked file" |
|
|
|
" at %s; adding as %s instead"), |
|
|
|
" at %s; adding as %s instead"), |
|
|
@ -1782,14 +1791,14 @@ static int handle_rename_rename_1to2(struct merge_options *o, |
|
|
|
return -1; |
|
|
|
return -1; |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
else |
|
|
|
remove_file_from_cache(a->path); |
|
|
|
remove_file_from_index(o->repo->index, a->path); |
|
|
|
add = filespec_from_entry(&other, ci->dst_entry2, 3 ^ 1); |
|
|
|
add = filespec_from_entry(&other, ci->dst_entry2, 3 ^ 1); |
|
|
|
if (add) { |
|
|
|
if (add) { |
|
|
|
if (update_file(o, 0, &add->oid, add->mode, b->path)) |
|
|
|
if (update_file(o, 0, &add->oid, add->mode, b->path)) |
|
|
|
return -1; |
|
|
|
return -1; |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
else |
|
|
|
remove_file_from_cache(b->path); |
|
|
|
remove_file_from_index(o->repo->index, b->path); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
/* |
|
|
|
/* |
|
|
|
* For each destination path, we need to see if there is a |
|
|
|
* For each destination path, we need to see if there is a |
|
|
@ -1886,7 +1895,7 @@ static struct diff_queue_struct *get_diffpairs(struct merge_options *o, |
|
|
|
struct diff_queue_struct *ret; |
|
|
|
struct diff_queue_struct *ret; |
|
|
|
struct diff_options opts; |
|
|
|
struct diff_options opts; |
|
|
|
|
|
|
|
|
|
|
|
repo_diff_setup(the_repository, &opts); |
|
|
|
repo_diff_setup(o->repo, &opts); |
|
|
|
opts.flags.recursive = 1; |
|
|
|
opts.flags.recursive = 1; |
|
|
|
opts.flags.rename_empty = 0; |
|
|
|
opts.flags.rename_empty = 0; |
|
|
|
opts.detect_rename = merge_detect_rename(o); |
|
|
|
opts.detect_rename = merge_detect_rename(o); |
|
|
@ -3041,8 +3050,8 @@ static int blob_unchanged(struct merge_options *opt, |
|
|
|
* performed. Comparison can be skipped if both files are |
|
|
|
* performed. Comparison can be skipped if both files are |
|
|
|
* unchanged since their sha1s have already been compared. |
|
|
|
* unchanged since their sha1s have already been compared. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
if (renormalize_buffer(&the_index, path, o.buf, o.len, &o) | |
|
|
|
if (renormalize_buffer(opt->repo->index, path, o.buf, o.len, &o) | |
|
|
|
renormalize_buffer(&the_index, path, a.buf, a.len, &a)) |
|
|
|
renormalize_buffer(opt->repo->index, path, a.buf, a.len, &a)) |
|
|
|
ret = (o.len == a.len && !memcmp(o.buf, a.buf, o.len)); |
|
|
|
ret = (o.len == a.len && !memcmp(o.buf, a.buf, o.len)); |
|
|
|
|
|
|
|
|
|
|
|
error_return: |
|
|
|
error_return: |
|
|
@ -3123,7 +3132,7 @@ static int handle_content_merge(struct merge_options *o, |
|
|
|
a.path = (char *)path1; |
|
|
|
a.path = (char *)path1; |
|
|
|
b.path = (char *)path2; |
|
|
|
b.path = (char *)path2; |
|
|
|
|
|
|
|
|
|
|
|
if (dir_in_way(path, !o->call_depth, |
|
|
|
if (dir_in_way(o->repo->index, path, !o->call_depth, |
|
|
|
S_ISGITLINK(pair1->two->mode))) |
|
|
|
S_ISGITLINK(pair1->two->mode))) |
|
|
|
df_conflict_remains = 1; |
|
|
|
df_conflict_remains = 1; |
|
|
|
} |
|
|
|
} |
|
|
@ -3157,8 +3166,8 @@ static int handle_content_merge(struct merge_options *o, |
|
|
|
pos = index_name_pos(&o->orig_index, path, strlen(path)); |
|
|
|
pos = index_name_pos(&o->orig_index, path, strlen(path)); |
|
|
|
ce = o->orig_index.cache[pos]; |
|
|
|
ce = o->orig_index.cache[pos]; |
|
|
|
if (ce_skip_worktree(ce)) { |
|
|
|
if (ce_skip_worktree(ce)) { |
|
|
|
pos = index_name_pos(&the_index, path, strlen(path)); |
|
|
|
pos = index_name_pos(o->repo->index, path, strlen(path)); |
|
|
|
ce = the_index.cache[pos]; |
|
|
|
ce = o->repo->index->cache[pos]; |
|
|
|
ce->ce_flags |= CE_SKIP_WORKTREE; |
|
|
|
ce->ce_flags |= CE_SKIP_WORKTREE; |
|
|
|
} |
|
|
|
} |
|
|
|
return mfi.clean; |
|
|
|
return mfi.clean; |
|
|
@ -3177,7 +3186,7 @@ static int handle_content_merge(struct merge_options *o, |
|
|
|
if (df_conflict_remains || is_dirty) { |
|
|
|
if (df_conflict_remains || is_dirty) { |
|
|
|
char *new_path; |
|
|
|
char *new_path; |
|
|
|
if (o->call_depth) { |
|
|
|
if (o->call_depth) { |
|
|
|
remove_file_from_cache(path); |
|
|
|
remove_file_from_index(o->repo->index, path); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
if (!mfi.clean) { |
|
|
|
if (!mfi.clean) { |
|
|
|
if (update_stages(o, path, &one, &a, &b)) |
|
|
|
if (update_stages(o, path, &one, &a, &b)) |
|
|
@ -3337,7 +3346,7 @@ static int process_entry(struct merge_options *o, |
|
|
|
oid = b_oid; |
|
|
|
oid = b_oid; |
|
|
|
conf = _("directory/file"); |
|
|
|
conf = _("directory/file"); |
|
|
|
} |
|
|
|
} |
|
|
|
if (dir_in_way(path, |
|
|
|
if (dir_in_way(o->repo->index, path, |
|
|
|
!o->call_depth && !S_ISGITLINK(a_mode), |
|
|
|
!o->call_depth && !S_ISGITLINK(a_mode), |
|
|
|
0)) { |
|
|
|
0)) { |
|
|
|
char *new_path = unique_path(o, path, add_branch); |
|
|
|
char *new_path = unique_path(o, path, add_branch); |
|
|
@ -3348,7 +3357,7 @@ static int process_entry(struct merge_options *o, |
|
|
|
if (update_file(o, 0, oid, mode, new_path)) |
|
|
|
if (update_file(o, 0, oid, mode, new_path)) |
|
|
|
clean_merge = -1; |
|
|
|
clean_merge = -1; |
|
|
|
else if (o->call_depth) |
|
|
|
else if (o->call_depth) |
|
|
|
remove_file_from_cache(path); |
|
|
|
remove_file_from_index(o->repo->index, path); |
|
|
|
free(new_path); |
|
|
|
free(new_path); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
output(o, 2, _("Adding %s"), path); |
|
|
|
output(o, 2, _("Adding %s"), path); |
|
|
@ -3396,10 +3405,11 @@ int merge_trees(struct merge_options *o, |
|
|
|
struct tree *common, |
|
|
|
struct tree *common, |
|
|
|
struct tree **result) |
|
|
|
struct tree **result) |
|
|
|
{ |
|
|
|
{ |
|
|
|
|
|
|
|
struct index_state *istate = o->repo->index; |
|
|
|
int code, clean; |
|
|
|
int code, clean; |
|
|
|
struct strbuf sb = STRBUF_INIT; |
|
|
|
struct strbuf sb = STRBUF_INIT; |
|
|
|
|
|
|
|
|
|
|
|
if (!o->call_depth && index_has_changes(&the_index, head, &sb)) { |
|
|
|
if (!o->call_depth && index_has_changes(istate, head, &sb)) { |
|
|
|
err(o, _("Your local changes to the following files would be overwritten by merge:\n %s"), |
|
|
|
err(o, _("Your local changes to the following files would be overwritten by merge:\n %s"), |
|
|
|
sb.buf); |
|
|
|
sb.buf); |
|
|
|
return -1; |
|
|
|
return -1; |
|
|
@ -3427,7 +3437,7 @@ int merge_trees(struct merge_options *o, |
|
|
|
return -1; |
|
|
|
return -1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (unmerged_cache()) { |
|
|
|
if (unmerged_index(istate)) { |
|
|
|
struct string_list *entries; |
|
|
|
struct string_list *entries; |
|
|
|
struct rename_info re_info; |
|
|
|
struct rename_info re_info; |
|
|
|
int i; |
|
|
|
int i; |
|
|
@ -3442,7 +3452,7 @@ int merge_trees(struct merge_options *o, |
|
|
|
get_files_dirs(o, head); |
|
|
|
get_files_dirs(o, head); |
|
|
|
get_files_dirs(o, merge); |
|
|
|
get_files_dirs(o, merge); |
|
|
|
|
|
|
|
|
|
|
|
entries = get_unmerged(); |
|
|
|
entries = get_unmerged(o->repo->index); |
|
|
|
clean = detect_and_process_renames(o, common, head, merge, |
|
|
|
clean = detect_and_process_renames(o, common, head, merge, |
|
|
|
entries, &re_info); |
|
|
|
entries, &re_info); |
|
|
|
record_df_conflict_files(o, entries); |
|
|
|
record_df_conflict_files(o, entries); |
|
|
@ -3558,7 +3568,7 @@ int merge_recursive(struct merge_options *o, |
|
|
|
* overwritten it: the committed "conflicts" were |
|
|
|
* overwritten it: the committed "conflicts" were |
|
|
|
* already resolved. |
|
|
|
* already resolved. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
discard_cache(); |
|
|
|
discard_index(o->repo->index); |
|
|
|
saved_b1 = o->branch1; |
|
|
|
saved_b1 = o->branch1; |
|
|
|
saved_b2 = o->branch2; |
|
|
|
saved_b2 = o->branch2; |
|
|
|
o->branch1 = "Temporary merge branch 1"; |
|
|
|
o->branch1 = "Temporary merge branch 1"; |
|
|
@ -3574,9 +3584,9 @@ int merge_recursive(struct merge_options *o, |
|
|
|
return err(o, _("merge returned no commit")); |
|
|
|
return err(o, _("merge returned no commit")); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
discard_cache(); |
|
|
|
discard_index(o->repo->index); |
|
|
|
if (!o->call_depth) |
|
|
|
if (!o->call_depth) |
|
|
|
repo_read_index(the_repository); |
|
|
|
repo_read_index(o->repo); |
|
|
|
|
|
|
|
|
|
|
|
o->ancestor = "merged common ancestors"; |
|
|
|
o->ancestor = "merged common ancestors"; |
|
|
|
clean = merge_trees(o, get_commit_tree(h1), get_commit_tree(h2), |
|
|
|
clean = merge_trees(o, get_commit_tree(h1), get_commit_tree(h2), |
|
|
@ -3643,7 +3653,7 @@ int merge_recursive_generic(struct merge_options *o, |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
repo_hold_locked_index(the_repository, &lock, LOCK_DIE_ON_ERROR); |
|
|
|
repo_hold_locked_index(o->repo, &lock, LOCK_DIE_ON_ERROR); |
|
|
|
clean = merge_recursive(o, head_commit, next_commit, ca, |
|
|
|
clean = merge_recursive(o, head_commit, next_commit, ca, |
|
|
|
result); |
|
|
|
result); |
|
|
|
if (clean < 0) { |
|
|
|
if (clean < 0) { |
|
|
@ -3651,7 +3661,7 @@ int merge_recursive_generic(struct merge_options *o, |
|
|
|
return clean; |
|
|
|
return clean; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (write_locked_index(&the_index, &lock, |
|
|
|
if (write_locked_index(o->repo->index, &lock, |
|
|
|
COMMIT_LOCK | SKIP_IF_UNCHANGED)) |
|
|
|
COMMIT_LOCK | SKIP_IF_UNCHANGED)) |
|
|
|
return err(o, _("Unable to write index.")); |
|
|
|
return err(o, _("Unable to write index.")); |
|
|
|
|
|
|
|
|
|
|
@ -3675,10 +3685,12 @@ static void merge_recursive_config(struct merge_options *o) |
|
|
|
git_config(git_xmerge_config, NULL); |
|
|
|
git_config(git_xmerge_config, NULL); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void init_merge_options(struct merge_options *o) |
|
|
|
void init_merge_options(struct merge_options *o, |
|
|
|
|
|
|
|
struct repository *repo) |
|
|
|
{ |
|
|
|
{ |
|
|
|
const char *merge_verbosity; |
|
|
|
const char *merge_verbosity; |
|
|
|
memset(o, 0, sizeof(struct merge_options)); |
|
|
|
memset(o, 0, sizeof(struct merge_options)); |
|
|
|
|
|
|
|
o->repo = repo; |
|
|
|
o->verbosity = 2; |
|
|
|
o->verbosity = 2; |
|
|
|
o->buffer_output = 1; |
|
|
|
o->buffer_output = 1; |
|
|
|
o->diff_rename_limit = -1; |
|
|
|
o->diff_rename_limit = -1; |
|
|
|