From 75118b13bc8187c629886b108929f996c47daf01 Mon Sep 17 00:00:00 2001
From: Linus Torvalds <torvalds@ppc970.osdl.org>
Date: Sun, 17 Apr 2005 19:52:54 -0700
Subject: [PATCH] Ass a "merge-cache" helper program to execute a merge on any
 unmerged files.

This one doesn't actually do the merging, but it makes it
easy to script the programs that do using it.
---
 Makefile      |   5 +-
 merge-cache.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 131 insertions(+), 1 deletion(-)
 create mode 100644 merge-cache.c

diff --git a/Makefile b/Makefile
index 871c0bb04..76c4f7ca4 100644
--- a/Makefile
+++ b/Makefile
@@ -14,7 +14,7 @@ CC=gcc
 
 PROG=   update-cache show-diff init-db write-tree read-tree commit-tree \
 	cat-file fsck-cache checkout-cache diff-tree rev-tree show-files \
-	check-files ls-tree merge-base
+	check-files ls-tree merge-base merge-cache
 
 all: $(PROG)
 
@@ -67,6 +67,9 @@ ls-tree: ls-tree.o read-cache.o
 merge-base: merge-base.o read-cache.o
 	$(CC) $(CFLAGS) -o merge-base merge-base.o read-cache.o $(LIBS)
 
+merge-cache: merge-cache.o read-cache.o
+	$(CC) $(CFLAGS) -o merge-cache merge-cache.o read-cache.o $(LIBS)
+
 read-cache.o: cache.h
 show-diff.o: cache.h
 
diff --git a/merge-cache.c b/merge-cache.c
new file mode 100644
index 000000000..3aa391be0
--- /dev/null
+++ b/merge-cache.c
@@ -0,0 +1,127 @@
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "cache.h"
+
+static const char *pgm = NULL;
+static const char *arguments[5];
+
+static void run_program(void)
+{
+	int pid = fork(), status;
+
+	if (pid < 0)
+		die("unable to fork");
+	if (!pid) {
+		execlp(pgm, arguments[0],
+			    arguments[1],
+			    arguments[2],
+			    arguments[3],
+			    arguments[4],
+			    NULL);
+		die("unable to execute '%s'", pgm);
+	}
+	if (waitpid(pid, &status, 0) < 0 || !WIFEXITED(status) || WEXITSTATUS(status))
+		die("merge program failed");
+}
+
+static char *create_temp_file(int stage, unsigned char *sha1)
+{
+	static char template[4][50];
+	char *path = template[stage];
+	void *buf;
+	char type[100];
+	unsigned long size;
+	int fd;
+
+	buf = read_sha1_file(sha1, type, &size);
+	if (!buf || strcmp(type, "blob"))
+		die("unable to read blob object %s", sha1_to_hex(sha1));
+
+	strcpy(path, ".merge_file_XXXXXX");
+	fd = mkstemp(path);
+	if (fd < 0)
+		die("unable to create temp-file");
+	if (write(fd, buf, size) != size)
+		die("unable to write temp-file");
+	close(fd);
+	return path;
+}
+
+static int merge_entry(int pos, const char *path)
+{
+	int found;
+	
+	if (pos >= active_nr)
+		die("merge-cache: %s not in the cache", path);
+	arguments[0] = pgm;
+	arguments[1] = "";
+	arguments[2] = "";
+	arguments[3] = "";
+	arguments[4] = path;
+	found = 0;
+	do {
+		struct cache_entry *ce = active_cache[pos];
+		int stage = ce_stage(ce);
+
+		if (strcmp(ce->name, path))
+			break;
+		found++;
+		arguments[stage] = create_temp_file(stage, ce->sha1);
+	} while (++pos < active_nr);
+	if (!found)
+		die("merge-cache: %s not in the cache", path);
+	run_program();
+	return found;
+}
+
+static void merge_file(const char *path)
+{
+	int pos = cache_name_pos(path, strlen(path));
+
+	/*
+	 * If it already exists in the cache as stage0, it's
+	 * already merged and there is nothing to do.
+	 */
+	if (pos < 0)
+		merge_entry(-pos-1, path);
+}
+
+static void merge_all(void)
+{
+	int i;
+	for (i = 0; i < active_nr; i++) {
+		struct cache_entry *ce = active_cache[i];
+		if (!ce_stage(ce))
+			continue;
+		i += merge_entry(i, ce->name)-1;
+	}
+}
+
+int main(int argc, char **argv)
+{
+	int i, force_file = 0;
+
+	if (argc < 3)
+		usage("merge-cache <merge-program> (-a | <filename>*)");
+
+	read_cache();
+
+	pgm = argv[1];
+	for (i = 2; i < argc; i++) {
+		char *arg = argv[i];
+		if (!force_file && *arg == '-') {
+			if (!strcmp(arg, "--")) {
+				force_file = 1;
+				continue;
+			}
+			if (!strcmp(arg, "-a")) {
+				merge_all();
+				continue;
+			}
+			die("merge-cache: unknown option %s", arg);
+		}
+		merge_file(arg);
+	}
+	return 0;
+}
-- 
2.26.2