git
/
resolve-undo.c
178 строк · 4.2 Кб
1#define USE_THE_REPOSITORY_VARIABLE2
3#include "git-compat-util.h"4#include "dir.h"5#include "hash.h"6#include "read-cache.h"7#include "resolve-undo.h"8#include "sparse-index.h"9#include "string-list.h"10
11/* The only error case is to run out of memory in string-list */
12void record_resolve_undo(struct index_state *istate, struct cache_entry *ce)13{
14struct string_list_item *lost;15struct resolve_undo_info *ui;16struct string_list *resolve_undo;17int stage = ce_stage(ce);18
19if (!stage)20return;21
22if (!istate->resolve_undo) {23CALLOC_ARRAY(resolve_undo, 1);24resolve_undo->strdup_strings = 1;25istate->resolve_undo = resolve_undo;26}27resolve_undo = istate->resolve_undo;28lost = string_list_insert(resolve_undo, ce->name);29if (!lost->util)30lost->util = xcalloc(1, sizeof(*ui));31ui = lost->util;32oidcpy(&ui->oid[stage - 1], &ce->oid);33ui->mode[stage - 1] = ce->ce_mode;34}
35
36void resolve_undo_write(struct strbuf *sb, struct string_list *resolve_undo)37{
38struct string_list_item *item;39for_each_string_list_item(item, resolve_undo) {40struct resolve_undo_info *ui = item->util;41int i;42
43if (!ui)44continue;45strbuf_addstr(sb, item->string);46strbuf_addch(sb, 0);47for (i = 0; i < 3; i++)48strbuf_addf(sb, "%o%c", ui->mode[i], 0);49for (i = 0; i < 3; i++) {50if (!ui->mode[i])51continue;52strbuf_add(sb, ui->oid[i].hash, the_hash_algo->rawsz);53}54}55}
56
57struct string_list *resolve_undo_read(const char *data, unsigned long size)58{
59struct string_list *resolve_undo;60size_t len;61char *endptr;62int i;63const unsigned rawsz = the_hash_algo->rawsz;64
65CALLOC_ARRAY(resolve_undo, 1);66resolve_undo->strdup_strings = 1;67
68while (size) {69struct string_list_item *lost;70struct resolve_undo_info *ui;71
72len = strlen(data) + 1;73if (size <= len)74goto error;75lost = string_list_insert(resolve_undo, data);76if (!lost->util)77lost->util = xcalloc(1, sizeof(*ui));78ui = lost->util;79size -= len;80data += len;81
82for (i = 0; i < 3; i++) {83ui->mode[i] = strtoul(data, &endptr, 8);84if (!endptr || endptr == data || *endptr)85goto error;86len = (endptr + 1) - (char*)data;87if (size <= len)88goto error;89size -= len;90data += len;91}92
93for (i = 0; i < 3; i++) {94if (!ui->mode[i])95continue;96if (size < rawsz)97goto error;98oidread(&ui->oid[i], (const unsigned char *)data,99the_repository->hash_algo);100size -= rawsz;101data += rawsz;102}103}104return resolve_undo;105
106error:107string_list_clear(resolve_undo, 1);108error("Index records invalid resolve-undo information");109return NULL;110}
111
112void resolve_undo_clear_index(struct index_state *istate)113{
114struct string_list *resolve_undo = istate->resolve_undo;115if (!resolve_undo)116return;117string_list_clear(resolve_undo, 1);118free(resolve_undo);119istate->resolve_undo = NULL;120istate->cache_changed |= RESOLVE_UNDO_CHANGED;121}
122
123int unmerge_index_entry(struct index_state *istate, const char *path,124struct resolve_undo_info *ru, unsigned ce_flags)125{
126int i = index_name_pos(istate, path, strlen(path));127
128if (i < 0) {129/* unmerged? */130i = -i - 1;131if (i < istate->cache_nr &&132!strcmp(istate->cache[i]->name, path))133/* yes, it is already unmerged */134return 0;135/* fallthru: resolved to removal */136} else {137/* merged - remove it to replace it with unmerged entries */138remove_index_entry_at(istate, i);139}140
141for (i = 0; i < 3; i++) {142struct cache_entry *ce;143if (!ru->mode[i])144continue;145ce = make_cache_entry(istate, ru->mode[i], &ru->oid[i],146path, i + 1, 0);147ce->ce_flags |= ce_flags;148if (add_index_entry(istate, ce, ADD_CACHE_OK_TO_ADD))149return error("cannot unmerge '%s'", path);150}151return 0;152}
153
154void unmerge_index(struct index_state *istate, const struct pathspec *pathspec,155unsigned ce_flags)156{
157struct string_list_item *item;158
159if (!istate->resolve_undo)160return;161
162/* TODO: audit for interaction with sparse-index. */163ensure_full_index(istate);164
165for_each_string_list_item(item, istate->resolve_undo) {166const char *path = item->string;167struct resolve_undo_info *ru = item->util;168if (!item->util)169continue;170if (!match_pathspec(istate, pathspec,171item->string, strlen(item->string),1720, NULL, 0))173continue;174unmerge_index_entry(istate, path, ru, ce_flags);175free(ru);176item->util = NULL;177}178}
179