static void update_file(int clean, const unsigned char *sha, unsigned mode, const char *path) { update_file_flags(sha, mode, path, index_only || clean, !index_only); }
static int update_file(struct merge_options *o, int clean, const unsigned char *sha, unsigned mode, const char *path) { return update_file_flags(o, sha, mode, path, clean, 1); }
static void update_file(struct merge_options *o, int clean, const unsigned char *sha, unsigned mode, const char *path) { update_file_flags(o, sha, mode, path, o->call_depth || clean, !o->call_depth); }
/* Per entry merge function */ static int process_entry(struct merge_options *o, const char *path, struct stage_data *entry) { /* printf("processing entry, clean cache: %s\n", index_only ? "yes": "no"); print_index_entry("\tpath: ", entry); */ int clean_merge = 1; unsigned o_mode = entry->stages[1].mode; unsigned a_mode = entry->stages[2].mode; unsigned b_mode = entry->stages[3].mode; unsigned char *o_sha = o_mode ? entry->stages[1].sha : NULL; unsigned char *a_sha = a_mode ? entry->stages[2].sha : NULL; unsigned char *b_sha = b_mode ? entry->stages[3].sha : NULL; unsigned int a_ctime = entry->stages[2].ctime; unsigned int a_mtime = entry->stages[2].mtime; /* if (entry->rename_df_conflict_info) */ /* return 1; /\* Such cases are handled elsewhere. *\/ */ entry->processed = 1; if (o_sha && (!a_sha || !b_sha)) { /* Case A: Deleted in one */ if ((!a_sha && !b_sha) || (!b_sha && memcmp(o_sha, a_sha, 20) == 0 && o_mode == a_mode) || (!a_sha && memcmp(o_sha, b_sha, 20) == 0 && o_mode == b_mode)) { /* Deleted in both or deleted in one and * unchanged in the other */ /* do not touch working file if it did not exist */ /* do not remove working file if it's changed. */ remove_file(o, 1, path, !a_sha, a_ctime, a_mtime); } else if (g_hash_table_lookup(o->current_directory_set, path)) { /* file -> (file, directory), the file side. */ entry->processed = 0; return 1; } else { /* Deleted in one and changed in the other */ /* or directory -> (file, directory), directory side */ clean_merge = 0; handle_delete_modify(o, path, path, a_sha, a_mode, b_sha, b_mode); } } else if ((!o_sha && a_sha && !b_sha) || (!o_sha && !a_sha && b_sha)) { /* Case B: Added in one. */ if (g_hash_table_lookup(o->current_directory_set, path)) { /* directory -> (file, directory), file side. */ entry->processed = 0; return 1; } else { /* Added in one */ /* or file -> (file, directory), directory side */ if (b_sha) clean_merge = update_file(o, 1, b_sha, b_mode, path); else /* For my file, just set index entry to stage 0, * without updating worktree. */ update_file_flags (o, a_sha, a_mode, path, 1, 0); } } else if (a_sha && b_sha) { /* Case C: Added in both (check for same permissions) and */ /* case D: Modified in both, but differently. */ if (memcmp(a_sha, b_sha, 20) != 0 || a_mode != b_mode) { char *new_path = NULL; char *conflict_suffix = NULL; clean_merge = 0; if (S_ISDIR (b_mode)) goto out; if (!o->collect_blocks_only) { conflict_suffix = get_last_changer_of_file (o->remote_head, path); if (!conflict_suffix) conflict_suffix = g_strdup(o->branch2); new_path = gen_conflict_path (path, conflict_suffix); } /* Dont update index. */ /* Keep my version, rename other's version. */ update_file_flags(o, b_sha, b_mode, new_path, 0, 1); g_free (new_path); g_free (conflict_suffix); } else { update_file_flags (o, a_sha, b_mode, path, 1, 0); } } else if (!o_sha && !a_sha && !b_sha) { /* * this entry was deleted altogether. a_mode == 0 means * we had that path and want to actively remove it. */ remove_file(o, 1, path, !a_mode, a_ctime, a_mtime); } else g_error("Fatal merge failure, shouldn't happen."); out: return clean_merge; }
/* Per entry merge function */ static int process_entry(struct merge_options *o, const char *path, struct stage_data *entry) { /* printf("processing entry, clean cache: %s\n", index_only ? "yes": "no"); print_index_entry("\tpath: ", entry); */ int clean_merge = 1; unsigned o_mode = entry->stages[1].mode; unsigned a_mode = entry->stages[2].mode; unsigned b_mode = entry->stages[3].mode; unsigned char *o_sha = stage_sha(entry->stages[1].sha, o_mode); unsigned char *a_sha = stage_sha(entry->stages[2].sha, a_mode); unsigned char *b_sha = stage_sha(entry->stages[3].sha, b_mode); if (o_sha && (!a_sha || !b_sha)) { /* Case A: Deleted in one */ if ((!a_sha && !b_sha) || (sha_eq(a_sha, o_sha) && !b_sha) || (!a_sha && sha_eq(b_sha, o_sha))) { /* Deleted in both or deleted in one and * unchanged in the other */ if (a_sha) output(o, 2, "Removing %s", path); /* do not touch working file if it did not exist */ remove_file(o, 1, path, !a_sha); } else { /* Deleted in one and changed in the other */ clean_merge = 0; if (!a_sha) { output(o, 1, "CONFLICT (delete/modify): %s deleted in %s " "and modified in %s. Version %s of %s left in tree.", path, o->branch1, o->branch2, o->branch2, path); update_file(o, 0, b_sha, b_mode, path); } else { output(o, 1, "CONFLICT (delete/modify): %s deleted in %s " "and modified in %s. Version %s of %s left in tree.", path, o->branch2, o->branch1, o->branch1, path); update_file(o, 0, a_sha, a_mode, path); } } } else if ((!o_sha && a_sha && !b_sha) || (!o_sha && !a_sha && b_sha)) { /* Case B: Added in one. */ const char *add_branch; const char *other_branch; unsigned mode; const unsigned char *sha; const char *conf; if (a_sha) { add_branch = o->branch1; other_branch = o->branch2; mode = a_mode; sha = a_sha; conf = "file/directory"; } else { add_branch = o->branch2; other_branch = o->branch1; mode = b_mode; sha = b_sha; conf = "directory/file"; } if (string_list_has_string(&o->current_directory_set, path)) { const char *new_path = unique_path(o, path, add_branch); clean_merge = 0; output(o, 1, "CONFLICT (%s): There is a directory with name %s in %s. " "Adding %s as %s", conf, path, other_branch, path, new_path); remove_file(o, 0, path, 0); update_file(o, 0, sha, mode, new_path); } else { output(o, 2, "Adding %s", path); update_file(o, 1, sha, mode, path); } } else if (a_sha && b_sha) { /* Case C: Added in both (check for same permissions) and */ /* case D: Modified in both, but differently. */ const char *reason = "content"; struct merge_file_info mfi; struct diff_filespec one, a, b; if (!o_sha) { reason = "add/add"; o_sha = (unsigned char *)null_sha1; } output(o, 2, "Auto-merging %s", path); one.path = a.path = b.path = (char *)path; hashcpy(one.sha1, o_sha); one.mode = o_mode; hashcpy(a.sha1, a_sha); a.mode = a_mode; hashcpy(b.sha1, b_sha); b.mode = b_mode; mfi = merge_file(o, &one, &a, &b, o->branch1, o->branch2); clean_merge = mfi.clean; if (mfi.clean) update_file(o, 1, mfi.sha, mfi.mode, path); else if (S_ISGITLINK(mfi.mode)) output(o, 1, "CONFLICT (submodule): Merge conflict in %s " "- needs %s", path, sha1_to_hex(b.sha1)); else { output(o, 1, "CONFLICT (%s): Merge conflict in %s", reason, path); if (o->call_depth) update_file(o, 0, mfi.sha, mfi.mode, path); else update_file_flags(o, mfi.sha, mfi.mode, path, 0 /* update_cache */, 1 /* update_working_directory */); } } else if (!o_sha && !a_sha && !b_sha) { /* * this entry was deleted altogether. a_mode == 0 means * we had that path and want to actively remove it. */ remove_file(o, 1, path, !a_mode); } else die("Fatal merge failure, shouldn't happen."); return clean_merge; }