static void checkout_all(const char *prefix, int prefix_length) { int i, errs = 0; struct cache_entry *last_ce = NULL; for (i = 0; i < active_nr ; i++) { struct cache_entry *ce = active_cache[i]; if (ce_stage(ce) != checkout_stage && (CHECKOUT_ALL != checkout_stage || !ce_stage(ce))) continue; if (prefix && *prefix && (ce_namelen(ce) <= prefix_length || memcmp(prefix, ce->name, prefix_length))) continue; if (last_ce && to_tempfile) { if (ce_namelen(last_ce) != ce_namelen(ce) || memcmp(last_ce->name, ce->name, ce_namelen(ce))) write_tempfile_record(last_ce->name, prefix); } if (checkout_entry(ce, &state, to_tempfile ? topath[ce_stage(ce)] : NULL) < 0) errs++; last_ce = ce; } if (last_ce && to_tempfile) write_tempfile_record(last_ce->name, prefix); if (errs) /* we have already done our error reporting. * exit with the same code as die(). */ exit(128); }
/* * Create a dictionary mapping file names to stage_data objects. The * dictionary contains one entry for every path with a non-zero stage entry. */ static struct string_list *get_unmerged(void) { struct string_list *unmerged = xcalloc(1, sizeof(struct string_list)); int i; unmerged->strdup_strings = 1; for (i = 0; i < active_nr; i++) { struct string_list_item *item; struct stage_data *e; struct cache_entry *ce = active_cache[i]; if (!ce_stage(ce)) continue; item = string_list_lookup(ce->name, unmerged); if (!item) { item = string_list_insert(ce->name, unmerged); item->util = xcalloc(1, sizeof(struct stage_data)); } e = item->util; e->stages[ce_stage(ce)].mode = ce->ce_mode; hashcpy(e->stages[ce_stage(ce)].sha, ce->sha1); } return unmerged; }
struct tree *write_tree_from_memory(struct merge_options *o) { struct tree *result = NULL; if (unmerged_cache()) { int i; output(o, 0, "There are unmerged index entries:"); for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; if (ce_stage(ce)) output(o, 0, "%d %.*s", ce_stage(ce), ce_namelen(ce), ce->name); } return NULL; } if (!active_cache_tree) active_cache_tree = cache_tree(); if (!cache_tree_fully_valid(active_cache_tree) && cache_tree_update(active_cache_tree, active_cache, active_nr, 0, 0) < 0) die("error building trees"); result = lookup_tree(active_cache_tree->sha1); return result; }
static void wt_status_collect_changes_initial(struct wt_status *s) { struct pathspec pathspec; int i; init_pathspec(&pathspec, s->pathspec); for (i = 0; i < active_nr; i++) { struct string_list_item *it; struct wt_status_change_data *d; struct cache_entry *ce = active_cache[i]; if (!ce_path_match(ce, &pathspec)) continue; it = string_list_insert(&s->change, ce->name); d = it->util; if (!d) { d = xcalloc(1, sizeof(*d)); it->util = d; } if (ce_stage(ce)) { d->index_status = DIFF_STATUS_UNMERGED; d->stagemask |= (1 << (ce_stage(ce) - 1)); } else d->index_status = DIFF_STATUS_ADDED; } free_pathspec(&pathspec); }
char *write_tree_from_memory(struct merge_options *o) { struct cache_tree *it; char root_id[41]; if (unmerged_index(o->index)) { int i; fprintf(stderr, "BUG: There are unmerged index entries:\n"); for (i = 0; i < o->index->cache_nr; i++) { struct cache_entry *ce = o->index->cache[i]; if (ce_stage(ce)) fprintf(stderr, "BUG: %d %.*s", ce_stage(ce), (int)ce_namelen(ce), ce->name); } g_assert(0); } /* if (!active_cache_tree) */ it = cache_tree(); if (cache_tree_update(it, o->index->cache, o->index->cache_nr, 0, 0, commit_trees_cb) < 0) { g_warning("error building trees"); cache_tree_free (&it); return NULL; } rawdata_to_hex(it->sha1, root_id, 20); cache_tree_free (&it); return g_strdup(root_id); }
struct tree *write_tree_from_memory(struct merge_options *o) { struct tree *result = NULL; if (unmerged_cache()) { int i; fprintf(stderr, "BUG: There are unmerged index entries:\n"); for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; if (ce_stage(ce)) fprintf(stderr, "BUG: %d %.*s", ce_stage(ce), (int)ce_namelen(ce), ce->name); } die("Bug in merge-recursive.c"); } if (!active_cache_tree) active_cache_tree = cache_tree(); if (!cache_tree_fully_valid(active_cache_tree) && cache_tree_update(active_cache_tree, active_cache, active_nr, 0, 0) < 0) die("error building trees"); result = lookup_tree(active_cache_tree->sha1); return result; }
/* * Look at a cache entry at "i" and see if it is not conflicting, * conflicting and we are willing to handle, or conflicting and * we are unable to handle, and return the determination in *type. * Return the cache index to be looked at next, by skipping the * stages we have already looked at in this invocation of this * function. */ static int check_one_conflict(int i, int *type) { const struct cache_entry *e = active_cache[i]; if (!ce_stage(e)) { *type = RESOLVED; return i + 1; } *type = PUNTED; while (i < active_nr && ce_stage(active_cache[i]) == 1) i++; /* Only handle regular files with both stages #2 and #3 */ if (i + 1 < active_nr) { const struct cache_entry *e2 = active_cache[i]; const struct cache_entry *e3 = active_cache[i + 1]; if (ce_stage(e2) == 2 && ce_stage(e3) == 3 && ce_same_name(e, e3) && S_ISREG(e2->ce_mode) && S_ISREG(e3->ce_mode)) *type = THREE_STAGED; } /* Skip the entries with the same name */ while (i < active_nr && ce_same_name(e, active_cache[i])) i++; return i; }
/* * Create a dictionary mapping file names to stage_data objects. The * dictionary contains one entry for every path with a non-zero stage entry. */ static GList *get_unmerged(struct index_state *index) { GList *unmerged = NULL; int i; for (i = 0; i < index->cache_nr; i++) { struct stage_data *e; struct cache_entry *ce = index->cache[i]; if (!ce_stage(ce)) continue; if (!ce_in_unmerged_list(unmerged, ce)) { e = (struct stage_data *)calloc(1, sizeof(struct stage_data)); e->path = g_strdup(ce->name); unmerged = g_list_prepend(unmerged, e); } e->stages[ce_stage(ce)].ctime = ce->ce_ctime.sec; e->stages[ce_stage(ce)].mtime = ce->ce_mtime.sec; e->stages[ce_stage(ce)].mode = ce->ce_mode; hashcpy(e->stages[ce_stage(ce)].sha, ce->sha1); } unmerged = g_list_reverse(unmerged); return unmerged; }
static int grep_cache(struct grep_opt *opt, struct repository *repo, const struct pathspec *pathspec, int cached) { int hit = 0; int nr; struct strbuf name = STRBUF_INIT; int name_base_len = 0; if (repo->submodule_prefix) { name_base_len = strlen(repo->submodule_prefix); strbuf_addstr(&name, repo->submodule_prefix); } if (repo_read_index(repo) < 0) die(_("index file corrupt")); for (nr = 0; nr < repo->index->cache_nr; nr++) { const struct cache_entry *ce = repo->index->cache[nr]; strbuf_setlen(&name, name_base_len); strbuf_addstr(&name, ce->name); if (S_ISREG(ce->ce_mode) && match_pathspec(repo->index, pathspec, name.buf, name.len, 0, NULL, S_ISDIR(ce->ce_mode) || S_ISGITLINK(ce->ce_mode))) { /* * If CE_VALID is on, we assume worktree file and its * cache entry are identical, even if worktree file has * been modified, so use cache version instead */ if (cached || (ce->ce_flags & CE_VALID) || ce_skip_worktree(ce)) { if (ce_stage(ce) || ce_intent_to_add(ce)) continue; hit |= grep_oid(opt, &ce->oid, name.buf, 0, name.buf); } else { hit |= grep_file(opt, name.buf); } } else if (recurse_submodules && S_ISGITLINK(ce->ce_mode) && submodule_path_match(repo->index, pathspec, name.buf, NULL)) { hit |= grep_submodule(opt, repo, pathspec, NULL, ce->name, ce->name); } else { continue; } if (ce_stage(ce)) { do { nr++; } while (nr < repo->index->cache_nr && !strcmp(ce->name, repo->index->cache[nr]->name)); nr--; /* compensate for loop control */ } if (hit && opt->status_only) break; } strbuf_release(&name); return hit; }
static int cmp_cache_name_compare(const void *a_, const void *b_) { const struct cache_entry *ce1, *ce2; ce1 = *((const struct cache_entry **)a_); ce2 = *((const struct cache_entry **)b_); return cache_name_stage_compare(ce1->name, ce1->ce_namelen, ce_stage(ce1), ce2->name, ce2->ce_namelen, ce_stage(ce2)); }
static int verify_cache(struct cache_entry **cache, int entries) { int i, funny; /* Verify that the tree is merged */ funny = 0; for (i = 0; i < entries; i++) { struct cache_entry *ce = cache[i]; if (ce_stage(ce) || (ce->ce_flags & CE_INTENT_TO_ADD)) { if (10 < ++funny) { fprintf(stderr, "...\n"); break; } if (ce_stage(ce)) fprintf(stderr, "%s: unmerged (%s)\n", ce->name, sha1_to_hex(ce->sha1)); else fprintf(stderr, "%s: not added yet\n", ce->name); } } if (funny) return -1; /* Also verify that the cache does not have path and path/file * at the same time. At this point we know the cache has only * stage 0 entries. */ funny = 0; for (i = 0; i < entries - 1; i++) { /* path/file always comes after path because of the way * the cache is sorted. Also path can appear only once, * which means conflicting one would immediately follow. */ const char *this_name = cache[i]->name; const char *next_name = cache[i+1]->name; int this_len = strlen(this_name); if (this_len < strlen(next_name) && strncmp(this_name, next_name, this_len) == 0 && next_name[this_len] == '/') { if (10 < ++funny) { fprintf(stderr, "...\n"); break; } fprintf(stderr, "You have both %s and %s\n", this_name, next_name); } } if (funny) return -1; return 0; }
/* * Read the tree specified with --with-tree option * (typically, HEAD) into stage #1 and then * squash them down to stage #0. This is used for * --error-unmatch to list and check the path patterns * that were given from the command line. We are not * going to write this index out. */ void overlay_tree_on_cache(const char *tree_name, const char *prefix) { struct tree *tree; unsigned char sha1[20]; const char **match; struct cache_entry *last_stage0 = NULL; int i; if (get_sha1(tree_name, sha1)) die("tree-ish %s not found.", tree_name); tree = parse_tree_indirect(sha1); if (!tree) die("bad tree-ish %s", tree_name); /* Hoist the unmerged entries up to stage #3 to make room */ for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; if (!ce_stage(ce)) continue; ce->ce_flags |= CE_STAGEMASK; } if (prefix) { static const char *(matchbuf[2]); matchbuf[0] = prefix; matchbuf[1] = NULL; match = matchbuf; } else match = NULL; if (read_tree(tree, 1, match)) die("unable to read tree entries %s", tree_name); for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; switch (ce_stage(ce)) { case 0: last_stage0 = ce; /* fallthru */ default: continue; case 1: /* * If there is stage #0 entry for this, we do not * need to show it. We use CE_UPDATE bit to mark * such an entry. */ if (last_stage0 && !strcmp(last_stage0->name, ce->name)) ce->ce_flags |= CE_UPDATE; } } }
static void show_files(struct dir_struct *dir, const char *prefix) { int i; /* For cached/deleted files we don't need to even do the readdir */ if (show_others || show_killed) { const char *path = ".", *base = ""; int baselen = prefix_len; if (baselen) path = base = prefix; read_directory(dir, path, base, baselen, pathspec); if (show_others) show_other_files(dir); if (show_killed) show_killed_files(dir); } if (show_cached | show_stage) { for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; int dtype = ce_to_dtype(ce); if (excluded(dir, ce->name, &dtype) != dir->show_ignored) continue; if (show_unmerged && !ce_stage(ce)) continue; if (ce->ce_flags & CE_UPDATE) continue; show_ce_entry(ce_stage(ce) ? tag_unmerged : tag_cached, ce); } } if (show_deleted | show_modified) { for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; struct stat st; int err; int dtype = ce_to_dtype(ce); if (excluded(dir, ce->name, &dtype) != dir->show_ignored) continue; if (ce->ce_flags & CE_UPDATE) continue; err = lstat(ce->name, &st); if (show_deleted && err) show_ce_entry(tag_removed, ce); if (show_modified && ce_modified(ce, &st, 0)) show_ce_entry(tag_modified, ce); } } }
static int grep_cache(struct grep_opt *opt, const char **paths, int cached) { int hit = 0; int nr; read_cache(); #if !NO_EXTERNAL_GREP /* * Use the external "grep" command for the case where * we grep through the checked-out files. It tends to * be a lot more optimized */ if (!cached && !builtin_grep) { hit = external_grep(opt, paths, cached); if (hit >= 0) return hit; } #endif for (nr = 0; nr < active_nr; nr++) { struct cache_entry *ce = active_cache[nr]; if (!S_ISREG(ce->ce_mode)) continue; if (!pathspec_matches(paths, ce->name)) continue; /* * If CE_VALID is on, we assume worktree file and its cache entry * are identical, even if worktree file has been modified, so use * cache version instead */ if (cached || (ce->ce_flags & CE_VALID)) { if (ce_stage(ce)) continue; hit |= grep_sha1(opt, ce->sha1, ce->name, 0); } else hit |= grep_file(opt, ce->name); if (ce_stage(ce)) { do { nr++; } while (nr < active_nr && !strcmp(ce->name, active_cache[nr]->name)); nr--; /* compensate for loop control */ } } free_grep_patterns(opt); return hit; }
static void show_files(struct dir_struct *dir, const char *prefix) { int i; /* For cached/deleted files we don't need to even do the readdir */ if (show_others || show_killed) { fill_directory(dir, pathspec); if (show_others) show_other_files(dir); if (show_killed) show_killed_files(dir); } if (show_cached | show_stage) { for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; int dtype = ce_to_dtype(ce); if (dir->flags & DIR_SHOW_IGNORED && !excluded(dir, ce->name, &dtype)) continue; if (show_unmerged && !ce_stage(ce)) continue; if (ce->ce_flags & CE_UPDATE) continue; show_ce_entry(ce_stage(ce) ? tag_unmerged : (ce_skip_worktree(ce) ? tag_skip_worktree : tag_cached), ce); } } if (show_deleted | show_modified) { for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; struct stat st; int err; int dtype = ce_to_dtype(ce); if (dir->flags & DIR_SHOW_IGNORED && !excluded(dir, ce->name, &dtype)) continue; if (ce->ce_flags & CE_UPDATE) continue; if (ce_skip_worktree(ce)) continue; err = lstat(ce->name, &st); if (show_deleted && err) show_ce_entry(tag_removed, ce); if (show_modified && ce_modified(ce, &st, 0)) show_ce_entry(tag_modified, ce); } } }
static void merge_stat_info(struct cache_entry **src, int nr) { static struct cache_entry null_entry; struct cache_entry **dst = src; struct cache_entry *old = &null_entry; while (nr) { struct cache_entry *ce; ce = src[0]; /* We throw away original cache entries except for the stat information */ if (!ce_stage(ce)) { old = ce; src++; nr--; active_nr--; continue; } if (path_matches(ce, old) && same(ce, old)) *ce = *old; ce->ce_flags &= ~htons(CE_STAGEMASK); *dst++ = ce; src++; nr--; } }
static int suggest_conflicts(void) { FILE *fp; int pos; fp = fopen(git_path("MERGE_MSG"), "a"); if (!fp) die("Could open %s for writing", git_path("MERGE_MSG")); fprintf(fp, "\nConflicts:\n"); for (pos = 0; pos < active_nr; pos++) { struct cache_entry *ce = active_cache[pos]; if (ce_stage(ce)) { fprintf(fp, "\t%s\n", ce->name); while (pos + 1 < active_nr && !strcmp(ce->name, active_cache[pos + 1]->name)) pos++; } } fclose(fp); rerere(); printf("Automatic merge failed; " "fix conflicts and then commit the result.\n"); return 1; }
int main(int ac, char **av) { struct split_index *si; int i; do_read_index(&the_index, av[1], 1); printf("own %s\n", sha1_to_hex(the_index.sha1)); si = the_index.split_index; if (!si) { printf("not a split index\n"); return 0; } printf("base %s\n", sha1_to_hex(si->base_sha1)); for (i = 0; i < the_index.cache_nr; i++) { struct cache_entry *ce = the_index.cache[i]; printf("%06o %s %d\t%s\n", ce->ce_mode, sha1_to_hex(ce->sha1), ce_stage(ce), ce->name); } printf("replacements:"); if (si->replace_bitmap) ewah_each_bit(si->replace_bitmap, show_bit, NULL); printf("\ndeletions:"); if (si->delete_bitmap) ewah_each_bit(si->delete_bitmap, show_bit, NULL); printf("\n"); return 0; }
/* * This gets a mix of an existing index and a tree, one pathname entry * at a time. The index entry may be a single stage-0 one, but it could * also be multiple unmerged entries (in which case idx_pos/idx_nr will * give you the position and number of entries in the index). */ static void do_oneway_diff(struct unpack_trees_options *o, const struct cache_entry *idx, const struct cache_entry *tree) { struct rev_info *revs = o->unpack_data; int match_missing, cached; /* * i-t-a entries do not actually exist in the index (if we're * looking at its content) */ if (o->index_only && revs->diffopt.ita_invisible_in_index && idx && ce_intent_to_add(idx)) { idx = NULL; if (!tree) return; /* nothing to diff.. */ } /* if the entry is not checked out, don't examine work tree */ cached = o->index_only || (idx && ((idx->ce_flags & CE_VALID) || ce_skip_worktree(idx))); /* * Backward compatibility wart - "diff-index -m" does * not mean "do not ignore merges", but "match_missing". * * But with the revision flag parsing, that's found in * "!revs->ignore_merges". */ match_missing = !revs->ignore_merges; if (cached && idx && ce_stage(idx)) { struct diff_filepair *pair; pair = diff_unmerge(&revs->diffopt, idx->name); if (tree) fill_filespec(pair->one, &tree->oid, 1, tree->ce_mode); return; } /* * Something added to the tree? */ if (!tree) { show_new_file(revs, idx, cached, match_missing); return; } /* * Something removed from the tree? */ if (!idx) { diff_index_show_file(revs, "-", tree, &tree->oid, 1, tree->ce_mode, 0); return; } /* Show difference between old and new */ show_modified(revs, tree, idx, 1, cached, match_missing); }
static void *preload_thread(void *_data) { int nr; struct thread_data *p = _data; struct index_state *index = p->index; struct cache_entry **cep = index->cache + p->offset; struct cache_def cache; memset(&cache, 0, sizeof(cache)); nr = p->nr; if (nr + p->offset > index->cache_nr) nr = index->cache_nr - p->offset; do { struct cache_entry *ce = *cep++; struct stat st; if (ce_stage(ce)) continue; if (ce_uptodate(ce)) continue; if (!ce_path_match(ce, p->pathspec)) continue; if (threaded_has_symlink_leading_path(&cache, ce->name, ce_namelen(ce))) continue; if (lstat(ce->name, &st)) continue; if (ie_match_stat(index, ce, &st, CE_MATCH_RACY_IS_DIRTY)) continue; ce_mark_uptodate(ce); } while (--nr > 0); return NULL; }
/* * Set/Clear CE_NEW_SKIP_WORKTREE according to $GIT_DIR/info/sparse-checkout */ static void mark_new_skip_worktree(struct exclude_list *el, struct index_state *the_index, int select_flag, int skip_wt_flag) { int i; /* * 1. Pretend the narrowest worktree: only unmerged entries * are checked out */ for (i = 0; i < the_index->cache_nr; i++) { struct cache_entry *ce = the_index->cache[i]; if (select_flag && !(ce->ce_flags & select_flag)) continue; if (!ce_stage(ce)) ce->ce_flags |= skip_wt_flag; else ce->ce_flags &= ~skip_wt_flag; } /* * 2. Widen worktree according to sparse-checkout file. * Matched entries will have skip_wt_flag cleared (i.e. "in") */ clear_ce_flags(the_index->cache, the_index->cache_nr, select_flag, skip_wt_flag, el); }
static int suggest_conflicts(int renormalizing) { const char *filename; FILE *fp; int pos; filename = git_path("MERGE_MSG"); fp = fopen(filename, "a"); if (!fp) die_errno(_("Could not open '%s' for writing"), filename); fprintf(fp, "\nConflicts:\n"); for (pos = 0; pos < active_nr; pos++) { struct cache_entry *ce = active_cache[pos]; if (ce_stage(ce)) { fprintf(fp, "\t%s\n", ce->name); while (pos + 1 < active_nr && !strcmp(ce->name, active_cache[pos + 1]->name)) pos++; } } fclose(fp); rerere(allow_rerere_auto); printf(_("Automatic merge failed; " "fix conflicts and then commit the result.\n")); return 1; }
static int merge_entry(int pos, const char *path) { int found; if (pos >= active_nr) die("git merge-index: %s not in the cache", path); arguments[0] = pgm; arguments[1] = ""; arguments[2] = ""; arguments[3] = ""; arguments[4] = path; arguments[5] = ""; arguments[6] = ""; arguments[7] = ""; arguments[8] = NULL; found = 0; do { static char hexbuf[4][60]; static char ownbuf[4][60]; struct cache_entry *ce = active_cache[pos]; int stage = ce_stage(ce); if (strcmp(ce->name, path)) break; found++; strcpy(hexbuf[stage], sha1_to_hex(ce->sha1)); sprintf(ownbuf[stage], "%o", ce->ce_mode); arguments[stage] = hexbuf[stage]; arguments[stage + 4] = ownbuf[stage]; } while (++pos < active_nr); if (!found) die("git merge-index: %s not in the cache", path); run_program(); return found; }
static int add_one_path(const struct cache_entry *old, const char *path, int len, struct stat *st) { int option, size; 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; size = cache_entry_size(len); ce = xcalloc(1, size); 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->sha1, path, st, info_only ? 0 : HASH_WRITE_OBJECT)) { free(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)) return error("%s: cannot add to the index - missing --add option?", path); return 0; }
gboolean files_locked_on_windows (struct index_state *index, const char *worktree) { gboolean ret = FALSE; int i, entries; struct cache_entry *ce; entries = index->cache_nr; for (i = 0; i < entries; ++i) { ce = index->cache[i]; if (ce_stage(ce)) { int mask = 0; mask |= 1 << (ce_stage(ce) - 1); while (i < entries) { struct cache_entry *nce = index->cache[i]; if (strcmp(ce->name, nce->name)) break; mask |= 1 << (ce_stage(nce) - 1); i++; } i--; /* Check unmerged cases that can potentially update or remove current files in the worktree. */ if (mask == 7 || /* both changed */ mask == 6 || /* both added */ mask == 3) /* others removed */ { if (do_check_file_locked (ce->name, worktree)) ret = TRUE; break; } } else if (ce->ce_flags & CE_UPDATE || ce->ce_flags & CE_WT_REMOVE) { if (do_check_file_locked (ce->name, worktree)) { ret = TRUE; break; } } } return ret; }
static int do_recursive_merge(struct commit *base, struct commit *next, const char *base_label, const char *next_label, unsigned char *head, struct strbuf *msgbuf, struct replay_opts *opts) { struct merge_options o; struct tree *result, *next_tree, *base_tree, *head_tree; int clean, index_fd; const char **xopt; static struct lock_file index_lock; index_fd = hold_locked_index(&index_lock, 1); read_cache(); init_merge_options(&o); o.ancestor = base ? base_label : "(empty tree)"; o.branch1 = "HEAD"; o.branch2 = next ? next_label : "(empty tree)"; head_tree = parse_tree_indirect(head); next_tree = next ? next->tree : empty_tree(); base_tree = base ? base->tree : empty_tree(); for (xopt = opts->xopts; xopt != opts->xopts + opts->xopts_nr; xopt++) parse_merge_opt(&o, *xopt); clean = merge_trees(&o, head_tree, next_tree, base_tree, &result); if (active_cache_changed && (write_cache(index_fd, active_cache, active_nr) || commit_locked_index(&index_lock))) /* TRANSLATORS: %s will be "revert" or "cherry-pick" */ die(_("%s: Unable to write new index file"), action_name(opts)); rollback_lock_file(&index_lock); if (opts->signoff) append_signoff(msgbuf, 0, 0); if (!clean) { int i; strbuf_addstr(msgbuf, "\nConflicts:\n"); for (i = 0; i < active_nr;) { const struct cache_entry *ce = active_cache[i++]; if (ce_stage(ce)) { strbuf_addch(msgbuf, '\t'); strbuf_addstr(msgbuf, ce->name); strbuf_addch(msgbuf, '\n'); while (i < active_nr && !strcmp(ce->name, active_cache[i]->name)) i++; } } } return !clean; }
static int checkout_file(const char *name, const char *prefix) { int namelen = strlen(name); int pos = cache_name_pos(name, namelen); int has_same_name = 0; int did_checkout = 0; int errs = 0; if (pos < 0) pos = -pos - 1; while (pos < active_nr) { struct cache_entry *ce = active_cache[pos]; if (ce_namelen(ce) != namelen || memcmp(ce->name, name, namelen)) break; has_same_name = 1; pos++; if (ce_stage(ce) != checkout_stage && (CHECKOUT_ALL != checkout_stage || !ce_stage(ce))) continue; did_checkout = 1; if (checkout_entry(ce, &state, to_tempfile ? topath[ce_stage(ce)] : NULL) < 0) errs++; } if (did_checkout) { if (to_tempfile) write_tempfile_record(name, prefix); return errs > 0 ? -1 : 0; } if (!state.quiet) { fprintf(stderr, "git checkout-index: %s ", name); if (!has_same_name) fprintf(stderr, "is not in the cache"); else if (checkout_stage) fprintf(stderr, "does not exist at stage %d", checkout_stage); else fprintf(stderr, "is unmerged"); fputc('\n', stderr); } return -1; }
static int handle_cache(const char *path, unsigned char *sha1, const char *output) { mmfile_t mmfile[3]; mmbuffer_t result = {NULL, 0}; struct cache_entry *ce; int pos, len, i, hunk_no; struct rerere_io_mem io; int marker_size = ll_merge_marker_size(path); /* * Reproduce the conflicted merge in-core */ len = strlen(path); pos = cache_name_pos(path, len); if (0 <= pos) return -1; pos = -pos - 1; for (i = 0; i < 3; i++) { enum object_type type; unsigned long size; mmfile[i].size = 0; mmfile[i].ptr = NULL; if (active_nr <= pos) break; ce = active_cache[pos++]; if (ce_namelen(ce) != len || memcmp(ce->name, path, len) || ce_stage(ce) != i + 1) break; mmfile[i].ptr = read_sha1_file(ce->sha1, &type, &size); mmfile[i].size = size; } for (i = 0; i < 3; i++) { if (!mmfile[i].ptr && !mmfile[i].size) mmfile[i].ptr = xstrdup(""); } ll_merge(&result, path, &mmfile[0], &mmfile[1], "ours", &mmfile[2], "theirs", 0); for (i = 0; i < 3; i++) free(mmfile[i].ptr); memset(&io, 0, sizeof(io)); io.io.getline = rerere_mem_getline; if (output) io.io.output = fopen(output, "w"); else io.io.output = NULL; strbuf_init(&io.input, 0); strbuf_attach(&io.input, result.ptr, result.size, result.size); hunk_no = handle_path(sha1, (struct rerere_io *)&io, marker_size); strbuf_release(&io.input); if (io.io.output) fclose(io.io.output); return hunk_no; }
int main(int argc, char **argv) { int i, newfd, merge; unsigned char sha1[20]; static char lockfile[MAXPATHLEN+1]; const char *indexfile = get_index_file(); snprintf(lockfile, sizeof(lockfile), "%s.lock", indexfile); newfd = open(lockfile, O_RDWR | O_CREAT | O_EXCL, 0600); if (newfd < 0) die("unable to create new cachefile"); atexit(remove_lock_file); lockfile_name = lockfile; merge = 0; for (i = 1; i < argc; i++) { const char *arg = argv[i]; /* "-m" stands for "merge", meaning we start in stage 1 */ if (!strcmp(arg, "-m")) { int i; if (stage) die("-m needs to come first"); read_cache(); for (i = 0; i < active_nr; i++) { if (ce_stage(active_cache[i])) die("you need to resolve your current index first"); } stage = 1; merge = 1; continue; } if (get_sha1_hex(arg, sha1) < 0) usage(read_tree_usage); if (stage > 3) usage(read_tree_usage); if (unpack_tree(sha1) < 0) die("failed to unpack tree object %s", arg); stage++; } if (merge) { switch (stage) { case 4: /* Three-way merge */ trivially_merge_cache(active_cache, active_nr); break; case 2: /* Just read a tree, merge with old cache contents */ merge_stat_info(active_cache, active_nr); break; default: die("just how do you expect me to merge %d trees?", stage-1); } } if (write_cache(newfd, active_cache, active_nr) || rename(lockfile, indexfile)) die("unable to write new index file"); lockfile_name = NULL; return 0; }
static int unmerged_mask(const char *path) { int pos, mask; struct cache_entry *ce; pos = cache_name_pos(path, strlen(path)); if (0 <= pos) return 0; mask = 0; pos = -pos-1; while (pos < active_nr) { ce = active_cache[pos++]; if (strcmp(ce->name, path) || !ce_stage(ce)) break; mask |= (1 << (ce_stage(ce) - 1)); } return mask; }