static int add_one_path(const struct cache_entry *old, const char *path, int len, struct stat *st) { int option; struct cache_entry *ce; /* Was the old index entry already up-to-date? */ if (old && !ce_stage(old) && !ce_match_stat(old, st, 0)) return 0; ce = make_empty_cache_entry(&the_index, len); memcpy(ce->name, path, len); ce->ce_flags = create_ce_flags(0); ce->ce_namelen = len; fill_stat_cache_info(ce, st); ce->ce_mode = ce_mode_from_stat(old, st->st_mode); if (index_path(&ce->oid, path, st, info_only ? 0 : HASH_WRITE_OBJECT)) { discard_cache_entry(ce); return -1; } option = allow_add ? ADD_CACHE_OK_TO_ADD : 0; option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0; if (add_cache_entry(ce, option)) { discard_cache_entry(ce); return error("%s: cannot add to the index - missing --add option?", path); } return 0; }
static int do_reupdate(int ac, const char **av, const char *prefix, int prefix_length) { /* Read HEAD and run update-index on paths that are * merged and already different between index and HEAD. */ int pos; int has_head = 1; struct pathspec pathspec; parse_pathspec(&pathspec, 0, PATHSPEC_PREFER_CWD, prefix, av + 1); if (read_ref("HEAD", &head_oid)) /* If there is no HEAD, that means it is an initial * commit. Update everything in the index. */ has_head = 0; redo: for (pos = 0; pos < active_nr; pos++) { const struct cache_entry *ce = active_cache[pos]; struct cache_entry *old = NULL; int save_nr; char *path; if (ce_stage(ce) || !ce_path_match(&the_index, ce, &pathspec, NULL)) continue; if (has_head) old = read_one_ent(NULL, &head_oid, ce->name, ce_namelen(ce), 0); if (old && ce->ce_mode == old->ce_mode && !oidcmp(&ce->oid, &old->oid)) { discard_cache_entry(old); continue; /* unchanged */ } /* Be careful. The working tree may not have the * path anymore, in which case, under 'allow_remove', * or worse yet 'allow_replace', active_nr may decrease. */ save_nr = active_nr; path = xstrdup(ce->name); update_one(path); free(path); discard_cache_entry(old); if (save_nr != active_nr) goto redo; } clear_pathspec(&pathspec); return 0; }
static int update_some(const struct object_id *oid, struct strbuf *base, const char *pathname, unsigned mode, int stage, void *context) { int len; struct cache_entry *ce; int pos; if (S_ISDIR(mode)) return READ_TREE_RECURSIVE; len = base->len + strlen(pathname); ce = make_empty_cache_entry(&the_index, len); oidcpy(&ce->oid, oid); memcpy(ce->name, base->buf, base->len); memcpy(ce->name + base->len, pathname, len - base->len); ce->ce_flags = create_ce_flags(0) | CE_UPDATE; ce->ce_namelen = len; ce->ce_mode = create_ce_mode(mode); /* * If the entry is the same as the current index, we can leave the old * entry in place. Whether it is UPTODATE or not, checkout_entry will * do the right thing. */ pos = cache_name_pos(ce->name, ce->ce_namelen); if (pos >= 0) { struct cache_entry *old = active_cache[pos]; if (ce->ce_mode == old->ce_mode && oideq(&ce->oid, &old->oid)) { old->ce_flags |= CE_UPDATE; discard_cache_entry(ce); return 0; } } add_cache_entry(ce, ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE); return 0; }
static int checkout_merged(int pos, const struct checkout *state, int *nr_checkouts) { struct cache_entry *ce = active_cache[pos]; const char *path = ce->name; mmfile_t ancestor, ours, theirs; int status; struct object_id oid; mmbuffer_t result_buf; struct object_id threeway[3]; unsigned mode = 0; memset(threeway, 0, sizeof(threeway)); while (pos < active_nr) { int stage; stage = ce_stage(ce); if (!stage || strcmp(path, ce->name)) break; oidcpy(&threeway[stage - 1], &ce->oid); if (stage == 2) mode = create_ce_mode(ce->ce_mode); pos++; ce = active_cache[pos]; } if (is_null_oid(&threeway[1]) || is_null_oid(&threeway[2])) return error(_("path '%s' does not have necessary versions"), path); read_mmblob(&ancestor, &threeway[0]); read_mmblob(&ours, &threeway[1]); read_mmblob(&theirs, &threeway[2]); /* * NEEDSWORK: re-create conflicts from merges with * merge.renormalize set, too */ status = ll_merge(&result_buf, path, &ancestor, "base", &ours, "ours", &theirs, "theirs", state->istate, NULL); free(ancestor.ptr); free(ours.ptr); free(theirs.ptr); if (status < 0 || !result_buf.ptr) { free(result_buf.ptr); return error(_("path '%s': cannot merge"), path); } /* * NEEDSWORK: * There is absolutely no reason to write this as a blob object * and create a phony cache entry. This hack is primarily to get * to the write_entry() machinery that massages the contents to * work-tree format and writes out which only allows it for a * cache entry. The code in write_entry() needs to be refactored * to allow us to feed a <buffer, size, mode> instead of a cache * entry. Such a refactoring would help merge_recursive as well * (it also writes the merge result to the object database even * when it may contain conflicts). */ if (write_object_file(result_buf.ptr, result_buf.size, blob_type, &oid)) die(_("Unable to add merge result for '%s'"), path); free(result_buf.ptr); ce = make_transient_cache_entry(mode, &oid, path, 2); if (!ce) die(_("make_cache_entry failed for path '%s'"), path); status = checkout_entry(ce, state, NULL, nr_checkouts); discard_cache_entry(ce); return status; }
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 (0 <= pos) { /* already merged */ pos = unmerge_cache_entry_at(pos); if (pos < active_nr) { const struct cache_entry *ce = active_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 < active_nr) { const 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_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 (!oidcmp(&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_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: discard_cache_entry(ce_2); discard_cache_entry(ce_3); return ret; }