git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 7/8] apply: plug the three-way merge logic in

From
Junio C Hamano <gitster@pobox.com>
Date
May 10, 2012, 06:02 UTC
Message-ID
<1336629745-22436-8-git-send-email-gitster@pobox.com>
In-Reply-To
<1336629745-22436-1-git-send-email-gitster@pobox.com>

When a patch does not apply to what we have, but we know the preimage the patch was made against, we apply the patch to the preimage to compute what the patch author wanted the result to look like, and attempt a three-way merge between the result and our version, using the intended preimage as the base version.

When we are applying the patch using the index, we would additionally need to add the object names of these three blobs involved in the merge, which is not yet done in this step, but we add a field to "struct patch" so that later write-out step can use it.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 builtin/apply.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 47 insertions(+), 6 deletions(-)
diff --git a/builtin/apply.c b/builtin/apply.c
index 798a634..e090e18 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -16,6 +16,8 @@
 #include "dir.h"
 #include "diff.h"
 #include "parse-options.h"
+#include "xdiff-interface.h"
+#include "ll-merge.h"
 
 /*
  *  --check turns on checking that the working tree matches the
@@ -194,12 +196,17 @@ struct patch {
 	unsigned int is_copy:1;
 	unsigned int is_rename:1;
 	unsigned int recount:1;
+	unsigned int did_threeway:1;
+	unsigned int conflicted_threeway:1;
 	struct fragment *fragments;
 	char *result;
 	size_t resultsize;
 	char old_sha1_prefix[41];
 	char new_sha1_prefix[41];
 	struct patch *next;
+
+	/* three-way fallback result */
+	unsigned char threeway_stage[3][20];
 };
 
 static void free_fragment_list(struct fragment *list)
@@ -3075,11 +3082,33 @@ static int load_preimage(struct image *image,
 
 static int three_way_merge(struct image *image,
 			   char *path,
-			   unsigned char *base,
-			   unsigned char *ours,
-			   unsigned char *theirs)
+			   const unsigned char *base,
+			   const unsigned char *ours,
+			   const unsigned char *theirs)
 {
-	return -1; /* for now */
+	mmfile_t base_file, our_file, their_file;
+	mmbuffer_t result = { 0 };
+	int status;
+
+	read_mmblob(&base_file, base);
+	read_mmblob(&our_file, ours);
+	read_mmblob(&their_file, theirs);
+	status = ll_merge(&result, path,
+			  &base_file, "base",
+			  &our_file, "ours",
+			  &their_file, "theirs", NULL);
+	free(base_file.ptr);
+	free(our_file.ptr);
+	free(their_file.ptr);
+	if (status < 0 || !result.ptr) {
+		free(result.ptr);
+		return -1;
+	}
+	clear_image(image);
+	image->buf = result.ptr;
+	image->len = result.size;
+
+	return status;
 }
 
 static int try_threeway_fallback(struct image *image, struct patch *patch,
@@ -3088,6 +3117,7 @@ static int try_threeway_fallback(struct image *image, struct patch *patch,
 	unsigned char pre_sha1[20], post_sha1[20], our_sha1[20];
 	struct strbuf buf = STRBUF_INIT;
 	size_t len;
+	int status;
 	char *img;
 	struct image tmp_image;
 
@@ -3116,8 +3146,19 @@ static int try_threeway_fallback(struct image *image, struct patch *patch,
 	clear_image(&tmp_image);
 
 	/* in-core three-way merge between post and our using pre as base */
-	return three_way_merge(image,
-			       patch->new_name, pre_sha1, our_sha1, post_sha1);
+	status = three_way_merge(image, patch->new_name,
+				 pre_sha1, our_sha1, post_sha1);
+	if (status < 0)
+		return status;
+
+	patch->did_threeway = 1;
+	if (status) {
+		patch->conflicted_threeway = 1;
+		hashcpy(patch->threeway_stage[0], pre_sha1);
+		hashcpy(patch->threeway_stage[1], our_sha1);
+		hashcpy(patch->threeway_stage[2], post_sha1);
+	}
+	return 0;
 }
 
 static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)
-- 
1.7.10.1.562.gfc79b1c
Previous: Jeff KingNext: Junio C Hamano
Message 16 of 19 in “"git apply --threeway"”
  1. 0/8 "git apply --threeway"Junio C Hamano, May 10, 2012
  2. 1/8 apply: reformat commentJunio C Hamano, May 10, 2012
  3. 2/8 apply: accept --threeway command line optionJunio C Hamano, May 10, 2012
  4. Nguyen Thai Ngoc DuyMay 10, 2012
  5. Junio C HamanoMay 10, 2012
  6. 3/8 apply: split load_preimage() helper function outJunio C Hamano, May 10, 2012
  7. 4/8 apply: clear_image() clears things a bit moreJunio C Hamano, May 10, 2012
  8. 5/8 apply: refactor read_file_or_gitlink()Junio C Hamano, May 10, 2012
  9. 6/8 apply: fall back on three-way mergeJunio C Hamano, May 10, 2012
  10. Matthieu MoyMay 10, 2012
  11. Junio C HamanoMay 10, 2012
  12. Matthieu MoyMay 10, 2012
  13. Jeff KingMay 10, 2012
  14. Junio C HamanoMay 10, 2012
  15. Jeff KingMay 10, 2012
  16. 7/8 apply: plug the three-way merge logic inJunio C Hamano, May 10, 2012
  17. 8/8 apply: register conflicted stages to the indexJunio C Hamano, May 10, 2012
  18. Matthieu MoyMay 10, 2012
  19. Junio C HamanoMay 10, 2012

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.