static void update_index_from_diff(struct diff_queue_struct *q, struct diff_options *opt, void *data) { int i; int intent_to_add = *(int *)data; for (i = 0; i < q->nr; i++) { struct diff_filespec *one = q->queue[i]->one; int is_missing = !(one->mode && !is_null_sha1(one->sha1)); struct cache_entry *ce; if (is_missing && !intent_to_add) { remove_file_from_cache(one->path); continue; } ce = make_cache_entry(one->mode, one->sha1, one->path, 0, 0); if (!ce) die(_("make_cache_entry failed for path '%s'"), one->path); if (is_missing) { ce->ce_flags |= CE_INTENT_TO_ADD; set_object_name_for_intent_to_add_entry(ce); } add_cache_entry(ce, ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE); } }
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; /* See if there is such entry in the index. */ pos = cache_name_pos(path, namelen); if (pos < 0) { /* 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 < active_nr) { struct cache_entry *ce = active_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_sha1, path, namelen, 2); ce_3 = read_one_ent("their", merge_head_sha1, path, namelen, 3); if (!ce_2 || !ce_3) { ret = -1; goto free_return; } if (!hashcmp(ce_2->sha1, ce_3->sha1) && ce_2->ce_mode == ce_3->ce_mode) { fprintf(stderr, "%s: identical in both, skipping.\n", path); goto free_return; } remove_file_from_cache(path); if (add_cache_entry(ce_2, ADD_CACHE_OK_TO_ADD)) { error("%s: cannot add our version to the index.", path); ret = -1; goto free_return; } if (!add_cache_entry(ce_3, ADD_CACHE_OK_TO_ADD)) return 0; error("%s: cannot add their version to the index.", path); ret = -1; free_return: free(ce_2); free(ce_3); return ret; }
static void update_one(const char *path, const char *prefix, int prefix_length) { const char *p = prefix_path(prefix, prefix_length, path); if (!verify_path(p)) { fprintf(stderr, "Ignoring path %s\n", path); goto free_return; } if (mark_valid_only) { if (mark_ce_flags(p, CE_VALID, mark_valid_only == MARK_FLAG)) die("Unable to mark file %s", path); goto free_return; } if (mark_skip_worktree_only) { if (mark_ce_flags(p, CE_SKIP_WORKTREE, mark_skip_worktree_only == MARK_FLAG)) die("Unable to mark file %s", path); goto free_return; } if (force_remove) { if (remove_file_from_cache(p)) die("git update-index: unable to remove %s", path); report("remove '%s'", path); goto free_return; } if (process_path(p)) die("Unable to process path %s", path); report("add '%s'", path); free_return: if (p < path || p > path + strlen(path)) free((char *)p); }
static int process_path(const char *path) { int pos, len; struct stat st; const struct cache_entry *ce; len = strlen(path); if (has_symlink_leading_path(path, len)) return error("'%s' is beyond a symbolic link", path); pos = cache_name_pos(path, len); ce = pos < 0 ? NULL : active_cache[pos]; if (ce && ce_skip_worktree(ce)) { /* * working directory version is assumed "good" * so updating it does not make sense. * On the other hand, removing it from index should work */ if (allow_remove && remove_file_from_cache(path)) return error("%s: cannot remove from the index", path); return 0; } /* * First things first: get the stat information, to decide * what to do about the pathname! */ if (lstat(path, &st) < 0) return process_lstat_error(path, errno); if (S_ISDIR(st.st_mode)) return process_directory(path, len, &st); return add_one_path(ce, path, len, &st); }
static void update_one(const char *path) { if (!verify_path(path)) { fprintf(stderr, "Ignoring path %s\n", path); return; } if (mark_valid_only) { if (mark_ce_flags(path, CE_VALID, mark_valid_only == MARK_FLAG)) die("Unable to mark file %s", path); return; } if (mark_skip_worktree_only) { if (mark_ce_flags(path, CE_SKIP_WORKTREE, mark_skip_worktree_only == MARK_FLAG)) die("Unable to mark file %s", path); return; } if (force_remove) { if (remove_file_from_cache(path)) die("git update-index: unable to remove %s", path); report("remove '%s'", path); return; } if (process_path(path)) die("Unable to process path %s", path); report("add '%s'", path); }
static void update_index_from_diff(struct diff_queue_struct *q, struct diff_options *opt, void *data) { int i; int *discard_flag = data; /* do_diff_cache() mangled the index */ discard_cache(); *discard_flag = 1; read_cache(); for (i = 0; i < q->nr; i++) { struct diff_filespec *one = q->queue[i]->one; if (one->mode) { struct cache_entry *ce; ce = make_cache_entry(one->mode, one->sha1, one->path, 0, 0); if (!ce) die("make_cache_entry failed for path '%s'", one->path); add_cache_entry(ce, ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE); } else remove_file_from_cache(one->path); } }
static int remove_one_path(const char *path) { if (!allow_remove) return error("%s: does not exist and --remove not passed", path); if (remove_file_from_cache(path)) return error("%s: cannot remove from the index", path); return 0; }
static void conflict_rename_rename(struct merge_options *o, struct rename *ren1, const char *branch1, struct rename *ren2, const char *branch2) { char *del[2]; int delp = 0; const char *ren1_dst = ren1->pair->two->path; const char *ren2_dst = ren2->pair->two->path; const char *dst_name1 = ren1_dst; const char *dst_name2 = ren2_dst; if (string_list_has_string(&o->current_directory_set, ren1_dst)) { dst_name1 = del[delp++] = unique_path(o, ren1_dst, branch1); output(o, 1, "%s is a directory in %s adding as %s instead", ren1_dst, branch2, dst_name1); remove_file(o, 0, ren1_dst, 0); } if (string_list_has_string(&o->current_directory_set, ren2_dst)) { dst_name2 = del[delp++] = unique_path(o, ren2_dst, branch2); output(o, 1, "%s is a directory in %s adding as %s instead", ren2_dst, branch1, dst_name2); remove_file(o, 0, ren2_dst, 0); } if (o->call_depth) { remove_file_from_cache(dst_name1); remove_file_from_cache(dst_name2); /* * Uncomment to leave the conflicting names in the resulting tree * * update_file(o, 0, ren1->pair->two->sha1, ren1->pair->two->mode, dst_name1); * update_file(o, 0, ren2->pair->two->sha1, ren2->pair->two->mode, dst_name2); */ } else { update_stages(dst_name1, NULL, ren1->pair->two, NULL, 1); update_stages(dst_name2, NULL, NULL, ren2->pair->two, 1); } while (delp--) free(del[delp]); }
static void add_remove_files(struct path_list *list) { int i; for (i = 0; i < list->nr; i++) { struct stat st; struct path_list_item *p = &(list->items[i]); if (!lstat(p->path, &st)) add_to_cache(p->path, &st, 0); else remove_file_from_cache(p->path); } }
static void add_remove_files(struct string_list *list) { int i; for (i = 0; i < list->nr; i++) { struct stat st; struct string_list_item *p = &(list->items[i]); if (!lstat(p->string, &st)) { if (add_to_cache(p->string, &st, 0)) die("updating files failed"); } else remove_file_from_cache(p->string); } }
static int remove_file(struct merge_options *o, int clean, const char *path, int no_wd) { int update_cache = o->call_depth || clean; int update_working_directory = !o->call_depth && !no_wd; if (update_cache) { if (remove_file_from_cache(path)) return -1; } if (update_working_directory) { if (remove_path(path) && errno != ENOENT) return -1; } return 0; }
static int remove_file(int clean, const char *path, int no_wd) { int update_cache = index_only || clean; int update_working_directory = !index_only && !no_wd; if (update_cache) { if (remove_file_from_cache(path)) return -1; } if (update_working_directory) { unlink(path); if (errno != ENOENT || errno != EISDIR) return -1; remove_path(path); } return 0; }
static void add_remove_files(struct string_list *list) { int i; for (i = 0; i < list->nr; i++) { struct stat st; struct string_list_item *p = &(list->items[i]); /* p->util is skip-worktree */ if (p->util) continue; if (!lstat(p->string, &st)) { if (add_to_cache(p->string, &st, 0)) die(_("updating files failed")); } else remove_file_from_cache(p->string); } }
static int update_stages(const char *path, struct diff_filespec *o, struct diff_filespec *a, struct diff_filespec *b, int clear) { int options = ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE; if (clear) if (remove_file_from_cache(path)) return -1; if (o) if (add_cacheinfo(o->mode, o->sha1, path, 1, 0, options)) return -1; if (a) if (add_cacheinfo(a->mode, a->sha1, path, 2, 0, options)) return -1; if (b) if (add_cacheinfo(b->mode, b->sha1, path, 3, 0, options)) return -1; return 0; }
static void update_one(const char *path) { int stat_errno = 0; struct stat st; if (mark_valid_only || mark_skip_worktree_only || force_remove || mark_fsmonitor_only) st.st_mode = 0; else if (lstat(path, &st) < 0) { st.st_mode = 0; stat_errno = errno; } /* else stat is valid */ if (!verify_path(path, st.st_mode)) { fprintf(stderr, "Ignoring path %s\n", path); return; } if (mark_valid_only) { if (mark_ce_flags(path, CE_VALID, mark_valid_only == MARK_FLAG)) die("Unable to mark file %s", path); return; } if (mark_skip_worktree_only) { if (mark_ce_flags(path, CE_SKIP_WORKTREE, mark_skip_worktree_only == MARK_FLAG)) die("Unable to mark file %s", path); return; } if (mark_fsmonitor_only) { if (mark_ce_flags(path, CE_FSMONITOR_VALID, mark_fsmonitor_only == MARK_FLAG)) die("Unable to mark file %s", path); return; } if (force_remove) { if (remove_file_from_cache(path)) die("git update-index: unable to remove %s", path); report("remove '%s'", path); return; } if (process_path(path, &st, stat_errno)) die("Unable to process path %s", path); report("add '%s'", path); }
static void update_index_from_diff(struct diff_queue_struct *q, struct diff_options *opt, void *data) { int i; for (i = 0; i < q->nr; i++) { struct diff_filespec *one = q->queue[i]->one; if (one->mode && !is_null_sha1(one->sha1)) { struct cache_entry *ce; ce = make_cache_entry(one->mode, one->sha1, one->path, 0, 0); if (!ce) die(_("make_cache_entry failed for path '%s'"), one->path); add_cache_entry(ce, ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE); } else remove_file_from_cache(one->path); } }
static int add_file_to_cache(char *path) { int size, namelen; struct cache_entry *ce; struct stat st; int fd; fd = open(path, O_RDONLY); if (fd < 0) { if (errno == ENOENT) return remove_file_from_cache(path); return -1; } if (fstat(fd, &st) < 0) { close(fd); return -1; } namelen = strlen(path); size = cache_entry_size(namelen); ce = malloc(size); memset(ce, 0, size); memcpy(ce->name, path, namelen); ce->ctime.sec = st.st_ctime; ce->ctime.nsec = st.st_ctim.tv_nsec; ce->mtime.sec = st.st_mtime; ce->mtime.nsec = st.st_mtim.tv_nsec; ce->st_dev = st.st_dev; ce->st_ino = st.st_ino; ce->st_mode = st.st_mode; ce->st_uid = st.st_uid; ce->st_gid = st.st_gid; ce->st_size = st.st_size; ce->namelen = namelen; if (index_fd(path, namelen, ce, fd, &st) < 0) return -1; return add_cache_entry(ce); }
int cmd_rm(int argc, const char **argv, const char *prefix) { int i, newfd; const char **pathspec; char *seen; git_config(git_default_config, NULL); argc = parse_options(argc, argv, prefix, builtin_rm_options, builtin_rm_usage, 0); if (!argc) usage_with_options(builtin_rm_usage, builtin_rm_options); if (!index_only) setup_work_tree(); newfd = hold_locked_index(&lock_file, 1); if (read_cache() < 0) die(_("index file corrupt")); /* * Drop trailing directory separators from directories so we'll find * submodules in the index. */ for (i = 0; i < argc; i++) { size_t pathlen = strlen(argv[i]); if (pathlen && is_dir_sep(argv[i][pathlen - 1]) && is_directory(argv[i])) { do { pathlen--; } while (pathlen && is_dir_sep(argv[i][pathlen - 1])); argv[i] = xmemdupz(argv[i], pathlen); } } pathspec = get_pathspec(prefix, argv); refresh_index(&the_index, REFRESH_QUIET, pathspec, NULL, NULL); seen = NULL; for (i = 0; pathspec[i] ; i++) /* nothing */; seen = xcalloc(i, 1); for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; if (!match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen)) continue; ALLOC_GROW(list.entry, list.nr + 1, list.alloc); list.entry[list.nr].name = ce->name; list.entry[list.nr++].is_submodule = S_ISGITLINK(ce->ce_mode); } if (pathspec) { const char *match; int seen_any = 0; for (i = 0; (match = pathspec[i]) != NULL ; i++) { if (!seen[i]) { if (!ignore_unmatch) { die(_("pathspec '%s' did not match any files"), match); } } else { seen_any = 1; } if (!recursive && seen[i] == MATCHED_RECURSIVELY) die(_("not removing '%s' recursively without -r"), *match ? match : "."); } if (! seen_any) exit(0); } /* * If not forced, the file, the index and the HEAD (if exists) * must match; but the file can already been removed, since * this sequence is a natural "novice" way: * * rm F; git rm F * * Further, if HEAD commit exists, "diff-index --cached" must * report no changes unless forced. */ if (!force) { unsigned char sha1[20]; if (get_sha1("HEAD", sha1)) hashclr(sha1); if (check_local_mod(sha1, index_only)) exit(1); } else if (!index_only) { if (check_submodules_use_gitfiles()) exit(1); } /* * First remove the names from the index: we won't commit * the index unless all of them succeed. */ for (i = 0; i < list.nr; i++) { const char *path = list.entry[i].name; if (!quiet) printf("rm '%s'\n", path); if (remove_file_from_cache(path)) die(_("git rm: unable to remove %s"), path); } if (show_only) return 0; /* * Then, unless we used "--cached", remove the filenames from * the workspace. If we fail to remove the first one, we * abort the "git rm" (but once we've successfully removed * any file at all, we'll go ahead and commit to it all: * by then we've already committed ourselves and can't fail * in the middle) */ if (!index_only) { int removed = 0; for (i = 0; i < list.nr; i++) { const char *path = list.entry[i].name; if (list.entry[i].is_submodule) { if (is_empty_dir(path)) { if (!rmdir(path)) { removed = 1; continue; } } else { struct strbuf buf = STRBUF_INIT; strbuf_addstr(&buf, path); if (!remove_dir_recursively(&buf, 0)) { removed = 1; strbuf_release(&buf); continue; } strbuf_release(&buf); /* Fallthrough and let remove_path() fail. */ } } if (!remove_path(path)) { removed = 1; continue; } if (!removed) die_errno("git rm: '%s'", path); } } if (active_cache_changed) { if (write_cache(newfd, active_cache, active_nr) || commit_locked_index(&lock_file)) die(_("Unable to write new index file")); } return 0; }
int cmd_rm(int argc, const char **argv, const char *prefix) { int i, newfd; const char **pathspec; char *seen; git_config(git_default_config, NULL); argc = parse_options(argc, argv, prefix, builtin_rm_options, builtin_rm_usage, 0); if (!argc) usage_with_options(builtin_rm_usage, builtin_rm_options); if (!index_only) setup_work_tree(); newfd = hold_locked_index(&lock_file, 1); if (read_cache() < 0) die("index file corrupt"); refresh_cache(REFRESH_QUIET); pathspec = get_pathspec(prefix, argv); seen = NULL; for (i = 0; pathspec[i] ; i++) /* nothing */; seen = xcalloc(i, 1); for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; if (!match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen)) continue; add_list(ce->name); } if (pathspec) { const char *match; int seen_any = 0; for (i = 0; (match = pathspec[i]) != NULL ; i++) { if (!seen[i]) { if (!ignore_unmatch) { die("pathspec '%s' did not match any files", match); } } else { seen_any = 1; } if (!recursive && seen[i] == MATCHED_RECURSIVELY) die("not removing '%s' recursively without -r", *match ? match : "."); } if (! seen_any) exit(0); } /* * If not forced, the file, the index and the HEAD (if exists) * must match; but the file can already been removed, since * this sequence is a natural "novice" way: * * rm F; git rm F * * Further, if HEAD commit exists, "diff-index --cached" must * report no changes unless forced. */ if (!force) { unsigned char sha1[20]; if (get_sha1("HEAD", sha1)) hashclr(sha1); if (check_local_mod(sha1, index_only)) exit(1); } /* * First remove the names from the index: we won't commit * the index unless all of them succeed. */ for (i = 0; i < list.nr; i++) { const char *path = list.name[i]; if (!quiet) printf("rm '%s'\n", path); if (remove_file_from_cache(path)) die("git rm: unable to remove %s", path); } if (show_only) return 0; /* * Then, unless we used "--cached", remove the filenames from * the workspace. If we fail to remove the first one, we * abort the "git rm" (but once we've successfully removed * any file at all, we'll go ahead and commit to it all: * by then we've already committed ourselves and can't fail * in the middle) */ if (!index_only) { int removed = 0; for (i = 0; i < list.nr; i++) { const char *path = list.name[i]; if (!remove_path(path)) { removed = 1; continue; } if (!removed) die("git rm: %s: %s", path, strerror(errno)); } } if (active_cache_changed) { if (write_cache(newfd, active_cache, active_nr) || commit_locked_index(&lock_file)) die("Unable to write new index file"); } return 0; }
static void read_index_info(int line_termination) { struct strbuf buf = STRBUF_INIT; struct strbuf uq = STRBUF_INIT; while (strbuf_getline(&buf, stdin, line_termination) != EOF) { char *ptr, *tab; char *path_name; unsigned char sha1[20]; unsigned int mode; unsigned long ul; int stage; /* This reads lines formatted in one of three formats: * * (1) mode SP sha1 TAB path * The first format is what "git apply --index-info" * reports, and used to reconstruct a partial tree * that is used for phony merge base tree when falling * back on 3-way merge. * * (2) mode SP type SP sha1 TAB path * The second format is to stuff "git ls-tree" output * into the index file. * * (3) mode SP sha1 SP stage TAB path * This format is to put higher order stages into the * index file and matches "git ls-files --stage" output. */ errno = 0; ul = strtoul(buf.buf, &ptr, 8); if (ptr == buf.buf || *ptr != ' ' || errno || (unsigned int) ul != ul) goto bad_line; mode = ul; tab = strchr(ptr, '\t'); if (!tab || tab - ptr < 41) goto bad_line; if (tab[-2] == ' ' && '0' <= tab[-1] && tab[-1] <= '3') { stage = tab[-1] - '0'; ptr = tab + 1; /* point at the head of path */ tab = tab - 2; /* point at tail of sha1 */ } else { stage = 0; ptr = tab + 1; /* point at the head of path */ } if (get_sha1_hex(tab - 40, sha1) || tab[-41] != ' ') goto bad_line; path_name = ptr; if (line_termination && path_name[0] == '"') { strbuf_reset(&uq); if (unquote_c_style(&uq, path_name, NULL)) { die("git update-index: bad quoting of path name"); } path_name = uq.buf; } if (!verify_path(path_name)) { fprintf(stderr, "Ignoring path %s\n", path_name); continue; } if (!mode) { /* mode == 0 means there is no such path -- remove */ if (remove_file_from_cache(path_name)) die("git update-index: unable to remove %s", ptr); } else { /* mode ' ' sha1 '\t' name * ptr[-1] points at tab, * ptr[-41] is at the beginning of sha1 */ ptr[-42] = ptr[-1] = 0; if (add_cacheinfo(mode, sha1, path_name, stage)) die("git update-index: unable to update %s", path_name); } continue; bad_line: die("malformed index info %s", buf.buf); } strbuf_release(&buf); strbuf_release(&uq); }
int cmd_rm(int argc, const char **argv, const char *prefix) { int i; struct pathspec pathspec; char *seen; gitmodules_config(); git_config(git_default_config, NULL); argc = parse_options(argc, argv, prefix, builtin_rm_options, builtin_rm_usage, 0); if (!argc) usage_with_options(builtin_rm_usage, builtin_rm_options); if (!index_only) setup_work_tree(); hold_locked_index(&lock_file, 1); if (read_cache() < 0) die(_("index file corrupt")); parse_pathspec(&pathspec, 0, PATHSPEC_PREFER_CWD | PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP, prefix, argv); refresh_index(&the_index, REFRESH_QUIET, &pathspec, NULL, NULL); seen = xcalloc(pathspec.nr, 1); for (i = 0; i < active_nr; i++) { const struct cache_entry *ce = active_cache[i]; if (!ce_path_match(ce, &pathspec, seen)) continue; ALLOC_GROW(list.entry, list.nr + 1, list.alloc); list.entry[list.nr].name = xstrdup(ce->name); list.entry[list.nr].is_submodule = S_ISGITLINK(ce->ce_mode); if (list.entry[list.nr++].is_submodule && !is_staging_gitmodules_ok()) die (_("Please stage your changes to .gitmodules or stash them to proceed")); } if (pathspec.nr) { const char *original; int seen_any = 0; for (i = 0; i < pathspec.nr; i++) { original = pathspec.items[i].original; if (!seen[i]) { if (!ignore_unmatch) { die(_("pathspec '%s' did not match any files"), original); } } else { seen_any = 1; } if (!recursive && seen[i] == MATCHED_RECURSIVELY) die(_("not removing '%s' recursively without -r"), *original ? original : "."); } if (!seen_any) exit(0); } /* * If not forced, the file, the index and the HEAD (if exists) * must match; but the file can already been removed, since * this sequence is a natural "novice" way: * * rm F; git rm F * * Further, if HEAD commit exists, "diff-index --cached" must * report no changes unless forced. */ if (!force) { unsigned char sha1[20]; if (get_sha1("HEAD", sha1)) hashclr(sha1); if (check_local_mod(sha1, index_only)) exit(1); } else if (!index_only) { if (check_submodules_use_gitfiles()) exit(1); } /* * First remove the names from the index: we won't commit * the index unless all of them succeed. */ for (i = 0; i < list.nr; i++) { const char *path = list.entry[i].name; if (!quiet) printf("rm '%s'\n", path); if (remove_file_from_cache(path)) die(_("git rm: unable to remove %s"), path); } if (show_only) return 0; /* * Then, unless we used "--cached", remove the filenames from * the workspace. If we fail to remove the first one, we * abort the "git rm" (but once we've successfully removed * any file at all, we'll go ahead and commit to it all: * by then we've already committed ourselves and can't fail * in the middle) */ if (!index_only) { int removed = 0, gitmodules_modified = 0; for (i = 0; i < list.nr; i++) { const char *path = list.entry[i].name; if (list.entry[i].is_submodule) { if (is_empty_dir(path)) { if (!rmdir(path)) { removed = 1; if (!remove_path_from_gitmodules(path)) gitmodules_modified = 1; continue; } } else { struct strbuf buf = STRBUF_INIT; strbuf_addstr(&buf, path); if (!remove_dir_recursively(&buf, 0)) { removed = 1; if (!remove_path_from_gitmodules(path)) gitmodules_modified = 1; strbuf_release(&buf); continue; } else if (!file_exists(path)) /* Submodule was removed by user */ if (!remove_path_from_gitmodules(path)) gitmodules_modified = 1; strbuf_release(&buf); /* Fallthrough and let remove_path() fail. */ } } if (!remove_path(path)) { removed = 1; continue; } if (!removed) die_errno("git rm: '%s'", path); } if (gitmodules_modified) stage_updated_gitmodules(); } if (active_cache_changed) { if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK)) die(_("Unable to write new index file")); } return 0; }
static int process_renames(struct merge_options *o, struct string_list *a_renames, struct string_list *b_renames) { int clean_merge = 1, i, j; struct string_list a_by_dst = {NULL, 0, 0, 0}, b_by_dst = {NULL, 0, 0, 0}; const struct rename *sre; for (i = 0; i < a_renames->nr; i++) { sre = a_renames->items[i].util; string_list_insert(sre->pair->two->path, &a_by_dst)->util = sre->dst_entry; } for (i = 0; i < b_renames->nr; i++) { sre = b_renames->items[i].util; string_list_insert(sre->pair->two->path, &b_by_dst)->util = sre->dst_entry; } for (i = 0, j = 0; i < a_renames->nr || j < b_renames->nr;) { int compare; char *src; struct string_list *renames1, *renames2, *renames2Dst; struct rename *ren1 = NULL, *ren2 = NULL; const char *branch1, *branch2; const char *ren1_src, *ren1_dst; if (i >= a_renames->nr) { compare = 1; ren2 = b_renames->items[j++].util; } else if (j >= b_renames->nr) { compare = -1; ren1 = a_renames->items[i++].util; } else { compare = strcmp(a_renames->items[i].string, b_renames->items[j].string); if (compare <= 0) ren1 = a_renames->items[i++].util; if (compare >= 0) ren2 = b_renames->items[j++].util; } /* TODO: refactor, so that 1/2 are not needed */ if (ren1) { renames1 = a_renames; renames2 = b_renames; renames2Dst = &b_by_dst; branch1 = o->branch1; branch2 = o->branch2; } else { struct rename *tmp; renames1 = b_renames; renames2 = a_renames; renames2Dst = &a_by_dst; branch1 = o->branch2; branch2 = o->branch1; tmp = ren2; ren2 = ren1; ren1 = tmp; } src = ren1->pair->one->path; ren1->dst_entry->processed = 1; ren1->src_entry->processed = 1; if (ren1->processed) continue; ren1->processed = 1; ren1_src = ren1->pair->one->path; ren1_dst = ren1->pair->two->path; if (ren2) { const char *ren2_src = ren2->pair->one->path; const char *ren2_dst = ren2->pair->two->path; /* Renamed in 1 and renamed in 2 */ if (strcmp(ren1_src, ren2_src) != 0) die("ren1.src != ren2.src"); ren2->dst_entry->processed = 1; ren2->processed = 1; if (strcmp(ren1_dst, ren2_dst) != 0) { clean_merge = 0; output(o, 1, "CONFLICT (rename/rename): " "Rename \"%s\"->\"%s\" in branch \"%s\" " "rename \"%s\"->\"%s\" in \"%s\"%s", src, ren1_dst, branch1, src, ren2_dst, branch2, o->call_depth ? " (left unresolved)": ""); if (o->call_depth) { remove_file_from_cache(src); update_file(o, 0, ren1->pair->one->sha1, ren1->pair->one->mode, src); } conflict_rename_rename(o, ren1, branch1, ren2, branch2); } else { struct merge_file_info mfi; remove_file(o, 1, ren1_src, 1); mfi = merge_file(o, ren1->pair->one, ren1->pair->two, ren2->pair->two, branch1, branch2); if (mfi.merge || !mfi.clean) output(o, 1, "Renaming %s->%s", src, ren1_dst); if (mfi.merge) output(o, 2, "Auto-merging %s", ren1_dst); if (!mfi.clean) { output(o, 1, "CONFLICT (content): merge conflict in %s", ren1_dst); clean_merge = 0; if (!o->call_depth) update_stages(ren1_dst, ren1->pair->one, ren1->pair->two, ren2->pair->two, 1 /* clear */); } update_file(o, mfi.clean, mfi.sha, mfi.mode, ren1_dst); } } else { /* Renamed in 1, maybe changed in 2 */ struct string_list_item *item; /* we only use sha1 and mode of these */ struct diff_filespec src_other, dst_other; int try_merge, stage = a_renames == renames1 ? 3: 2; remove_file(o, 1, ren1_src, o->call_depth || stage == 3); hashcpy(src_other.sha1, ren1->src_entry->stages[stage].sha); src_other.mode = ren1->src_entry->stages[stage].mode; hashcpy(dst_other.sha1, ren1->dst_entry->stages[stage].sha); dst_other.mode = ren1->dst_entry->stages[stage].mode; try_merge = 0; if (string_list_has_string(&o->current_directory_set, ren1_dst)) { clean_merge = 0; output(o, 1, "CONFLICT (rename/directory): Rename %s->%s in %s " " directory %s added in %s", ren1_src, ren1_dst, branch1, ren1_dst, branch2); conflict_rename_dir(o, ren1, branch1); } else if (sha_eq(src_other.sha1, null_sha1)) { clean_merge = 0; output(o, 1, "CONFLICT (rename/delete): Rename %s->%s in %s " "and deleted in %s", ren1_src, ren1_dst, branch1, branch2); update_file(o, 0, ren1->pair->two->sha1, ren1->pair->two->mode, ren1_dst); update_stages(ren1_dst, NULL, branch1 == o->branch1 ? ren1->pair->two : NULL, branch1 == o->branch1 ? NULL : ren1->pair->two, 1); } else if (!sha_eq(dst_other.sha1, null_sha1)) { const char *new_path; clean_merge = 0; try_merge = 1; output(o, 1, "CONFLICT (rename/add): Rename %s->%s in %s. " "%s added in %s", ren1_src, ren1_dst, branch1, ren1_dst, branch2); new_path = unique_path(o, ren1_dst, branch2); output(o, 1, "Adding as %s instead", new_path); update_file(o, 0, dst_other.sha1, dst_other.mode, new_path); } else if ((item = string_list_lookup(ren1_dst, renames2Dst))) { ren2 = item->util; clean_merge = 0; ren2->processed = 1; output(o, 1, "CONFLICT (rename/rename): " "Rename %s->%s in %s. " "Rename %s->%s in %s", ren1_src, ren1_dst, branch1, ren2->pair->one->path, ren2->pair->two->path, branch2); conflict_rename_rename_2(o, ren1, branch1, ren2, branch2); } else try_merge = 1; if (try_merge) { struct diff_filespec *one, *a, *b; struct merge_file_info mfi; src_other.path = (char *)ren1_src; one = ren1->pair->one; if (a_renames == renames1) { a = ren1->pair->two; b = &src_other; } else { b = ren1->pair->two; a = &src_other; } mfi = merge_file(o, one, a, b, o->branch1, o->branch2); if (mfi.clean && sha_eq(mfi.sha, ren1->pair->two->sha1) && mfi.mode == ren1->pair->two->mode) /* * This messaged is part of * t6022 test. If you change * it update the test too. */ output(o, 3, "Skipped %s (merged same as existing)", ren1_dst); else { if (mfi.merge || !mfi.clean) output(o, 1, "Renaming %s => %s", ren1_src, ren1_dst); if (mfi.merge) output(o, 2, "Auto-merging %s", ren1_dst); if (!mfi.clean) { output(o, 1, "CONFLICT (rename/modify): Merge conflict in %s", ren1_dst); clean_merge = 0; if (!o->call_depth) update_stages(ren1_dst, one, a, b, 1); } update_file(o, mfi.clean, mfi.sha, mfi.mode, ren1_dst); } } } } string_list_clear(&a_by_dst, 0); string_list_clear(&b_by_dst, 0); return clean_merge; }