summaryrefslogtreecommitdiffstats
path: root/resolve-undo.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-09 13:34:27 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-09 13:34:27 +0000
commit4dbdc42d9e7c3968ff7f690d00680419c9b8cb0f (patch)
tree47c1d492e9c956c1cd2b74dbd3b9d8b0db44dc4e /resolve-undo.c
parentInitial commit. (diff)
downloadgit-4dbdc42d9e7c3968ff7f690d00680419c9b8cb0f.tar.xz
git-4dbdc42d9e7c3968ff7f690d00680419c9b8cb0f.zip
Adding upstream version 1:2.43.0.upstream/1%2.43.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'resolve-undo.c')
-rw-r--r--resolve-undo.c175
1 files changed, 175 insertions, 0 deletions
diff --git a/resolve-undo.c b/resolve-undo.c
new file mode 100644
index 0000000..cd02dc9
--- /dev/null
+++ b/resolve-undo.c
@@ -0,0 +1,175 @@
+#include "git-compat-util.h"
+#include "dir.h"
+#include "hash.h"
+#include "read-cache.h"
+#include "resolve-undo.h"
+#include "sparse-index.h"
+#include "string-list.h"
+
+/* The only error case is to run out of memory in string-list */
+void record_resolve_undo(struct index_state *istate, struct cache_entry *ce)
+{
+ struct string_list_item *lost;
+ struct resolve_undo_info *ui;
+ struct string_list *resolve_undo;
+ int stage = ce_stage(ce);
+
+ if (!stage)
+ return;
+
+ if (!istate->resolve_undo) {
+ CALLOC_ARRAY(resolve_undo, 1);
+ resolve_undo->strdup_strings = 1;
+ istate->resolve_undo = resolve_undo;
+ }
+ resolve_undo = istate->resolve_undo;
+ lost = string_list_insert(resolve_undo, ce->name);
+ if (!lost->util)
+ lost->util = xcalloc(1, sizeof(*ui));
+ ui = lost->util;
+ oidcpy(&ui->oid[stage - 1], &ce->oid);
+ ui->mode[stage - 1] = ce->ce_mode;
+}
+
+void resolve_undo_write(struct strbuf *sb, struct string_list *resolve_undo)
+{
+ struct string_list_item *item;
+ for_each_string_list_item(item, resolve_undo) {
+ struct resolve_undo_info *ui = item->util;
+ int i;
+
+ if (!ui)
+ continue;
+ strbuf_addstr(sb, item->string);
+ strbuf_addch(sb, 0);
+ for (i = 0; i < 3; i++)
+ strbuf_addf(sb, "%o%c", ui->mode[i], 0);
+ for (i = 0; i < 3; i++) {
+ if (!ui->mode[i])
+ continue;
+ strbuf_add(sb, ui->oid[i].hash, the_hash_algo->rawsz);
+ }
+ }
+}
+
+struct string_list *resolve_undo_read(const char *data, unsigned long size)
+{
+ struct string_list *resolve_undo;
+ size_t len;
+ char *endptr;
+ int i;
+ const unsigned rawsz = the_hash_algo->rawsz;
+
+ CALLOC_ARRAY(resolve_undo, 1);
+ resolve_undo->strdup_strings = 1;
+
+ while (size) {
+ struct string_list_item *lost;
+ struct resolve_undo_info *ui;
+
+ len = strlen(data) + 1;
+ if (size <= len)
+ goto error;
+ lost = string_list_insert(resolve_undo, data);
+ if (!lost->util)
+ lost->util = xcalloc(1, sizeof(*ui));
+ ui = lost->util;
+ size -= len;
+ data += len;
+
+ for (i = 0; i < 3; i++) {
+ ui->mode[i] = strtoul(data, &endptr, 8);
+ if (!endptr || endptr == data || *endptr)
+ goto error;
+ len = (endptr + 1) - (char*)data;
+ if (size <= len)
+ goto error;
+ size -= len;
+ data += len;
+ }
+
+ for (i = 0; i < 3; i++) {
+ if (!ui->mode[i])
+ continue;
+ if (size < rawsz)
+ goto error;
+ oidread(&ui->oid[i], (const unsigned char *)data);
+ size -= rawsz;
+ data += rawsz;
+ }
+ }
+ return resolve_undo;
+
+error:
+ string_list_clear(resolve_undo, 1);
+ error("Index records invalid resolve-undo information");
+ return NULL;
+}
+
+void resolve_undo_clear_index(struct index_state *istate)
+{
+ struct string_list *resolve_undo = istate->resolve_undo;
+ if (!resolve_undo)
+ return;
+ string_list_clear(resolve_undo, 1);
+ free(resolve_undo);
+ istate->resolve_undo = NULL;
+ istate->cache_changed |= RESOLVE_UNDO_CHANGED;
+}
+
+int unmerge_index_entry(struct index_state *istate, const char *path,
+ struct resolve_undo_info *ru, unsigned ce_flags)
+{
+ int i = index_name_pos(istate, path, strlen(path));
+
+ if (i < 0) {
+ /* unmerged? */
+ i = -i - 1;
+ if (i < istate->cache_nr &&
+ !strcmp(istate->cache[i]->name, path))
+ /* yes, it is already unmerged */
+ return 0;
+ /* fallthru: resolved to removal */
+ } else {
+ /* merged - remove it to replace it with unmerged entries */
+ remove_index_entry_at(istate, i);
+ }
+
+ for (i = 0; i < 3; i++) {
+ struct cache_entry *ce;
+ if (!ru->mode[i])
+ continue;
+ ce = make_cache_entry(istate, ru->mode[i], &ru->oid[i],
+ path, i + 1, 0);
+ ce->ce_flags |= ce_flags;
+ if (add_index_entry(istate, ce, ADD_CACHE_OK_TO_ADD))
+ return error("cannot unmerge '%s'", path);
+ }
+ return 0;
+}
+
+void unmerge_index(struct index_state *istate, const struct pathspec *pathspec,
+ unsigned ce_flags)
+{
+ struct string_list_item *item;
+
+ if (!istate->resolve_undo)
+ return;
+
+ /* TODO: audit for interaction with sparse-index. */
+ ensure_full_index(istate);
+
+ for_each_string_list_item(item, istate->resolve_undo) {
+ const char *path = item->string;
+ struct resolve_undo_info *ru = item->util;
+ if (!item->util)
+ continue;
+ if (!match_pathspec(istate, pathspec,
+ item->string, strlen(item->string),
+ 0, NULL, 0))
+ continue;
+ unmerge_index_entry(istate, path, ru, ce_flags);
+ free(ru);
+ item->util = NULL;
+ }
+}