Merge branch 'jc/ll-merge-binary-ours'
"git merge -Xtheirs" did not help content-level merge of binary files; it should just take their version. Also "*.jpg binary" in the attributes did not imply they should use the binary ll-merge driver. * jc/ll-merge-binary-ours: ll-merge: warn about inability to merge binary files only when we can't attr: "binary" attribute should choose built-in "binary" merge driver merge: teach -Xours/-Xtheirs to binary ll-merge driver
This commit is contained in:
		@ -927,7 +927,7 @@ file at the toplevel (i.e. not in any subdirectory).  The built-in
 | 
				
			|||||||
macro attribute "binary" is equivalent to:
 | 
					macro attribute "binary" is equivalent to:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
------------
 | 
					------------
 | 
				
			||||||
[attr]binary -diff -text
 | 
					[attr]binary -diff -merge -text
 | 
				
			||||||
------------
 | 
					------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -32,13 +32,14 @@ ours;;
 | 
				
			|||||||
	This option forces conflicting hunks to be auto-resolved cleanly by
 | 
						This option forces conflicting hunks to be auto-resolved cleanly by
 | 
				
			||||||
	favoring 'our' version.  Changes from the other tree that do not
 | 
						favoring 'our' version.  Changes from the other tree that do not
 | 
				
			||||||
	conflict with our side are reflected to the merge result.
 | 
						conflict with our side are reflected to the merge result.
 | 
				
			||||||
 | 
						For a binary file, the entire contents are taken from our side.
 | 
				
			||||||
+
 | 
					+
 | 
				
			||||||
This should not be confused with the 'ours' merge strategy, which does not
 | 
					This should not be confused with the 'ours' merge strategy, which does not
 | 
				
			||||||
even look at what the other tree contains at all.  It discards everything
 | 
					even look at what the other tree contains at all.  It discards everything
 | 
				
			||||||
the other tree did, declaring 'our' history contains all that happened in it.
 | 
					the other tree did, declaring 'our' history contains all that happened in it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
theirs;;
 | 
					theirs;;
 | 
				
			||||||
	This is opposite of 'ours'.
 | 
						This is the opposite of 'ours'.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
patience;;
 | 
					patience;;
 | 
				
			||||||
	With this option, 'merge-recursive' spends a little extra time
 | 
						With this option, 'merge-recursive' spends a little extra time
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								attr.c
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								attr.c
									
									
									
									
									
								
							@ -306,7 +306,7 @@ static void free_attr_elem(struct attr_stack *e)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *builtin_attr[] = {
 | 
					static const char *builtin_attr[] = {
 | 
				
			||||||
	"[attr]binary -diff -text",
 | 
						"[attr]binary -diff -merge -text",
 | 
				
			||||||
	NULL,
 | 
						NULL,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										32
									
								
								ll-merge.c
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								ll-merge.c
									
									
									
									
									
								
							@ -35,7 +35,7 @@ struct ll_merge_driver {
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
static int ll_binary_merge(const struct ll_merge_driver *drv_unused,
 | 
					static int ll_binary_merge(const struct ll_merge_driver *drv_unused,
 | 
				
			||||||
			   mmbuffer_t *result,
 | 
								   mmbuffer_t *result,
 | 
				
			||||||
			   const char *path_unused,
 | 
								   const char *path,
 | 
				
			||||||
			   mmfile_t *orig, const char *orig_name,
 | 
								   mmfile_t *orig, const char *orig_name,
 | 
				
			||||||
			   mmfile_t *src1, const char *name1,
 | 
								   mmfile_t *src1, const char *name1,
 | 
				
			||||||
			   mmfile_t *src2, const char *name2,
 | 
								   mmfile_t *src2, const char *name2,
 | 
				
			||||||
@ -46,16 +46,34 @@ static int ll_binary_merge(const struct ll_merge_driver *drv_unused,
 | 
				
			|||||||
	assert(opts);
 | 
						assert(opts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * The tentative merge result is "ours" for the final round,
 | 
						 * The tentative merge result is the or common ancestor for an internal merge.
 | 
				
			||||||
	 * or common ancestor for an internal merge.  Still return
 | 
					 | 
				
			||||||
	 * "conflicted merge" status.
 | 
					 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	stolen = opts->virtual_ancestor ? orig : src1;
 | 
						if (opts->virtual_ancestor) {
 | 
				
			||||||
 | 
							stolen = orig;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							switch (opts->variant) {
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								warning("Cannot merge binary files: %s (%s vs. %s)",
 | 
				
			||||||
 | 
									path, name1, name2);
 | 
				
			||||||
 | 
								/* fallthru */
 | 
				
			||||||
 | 
							case XDL_MERGE_FAVOR_OURS:
 | 
				
			||||||
 | 
								stolen = src1;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case XDL_MERGE_FAVOR_THEIRS:
 | 
				
			||||||
 | 
								stolen = src2;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	result->ptr = stolen->ptr;
 | 
						result->ptr = stolen->ptr;
 | 
				
			||||||
	result->size = stolen->size;
 | 
						result->size = stolen->size;
 | 
				
			||||||
	stolen->ptr = NULL;
 | 
						stolen->ptr = NULL;
 | 
				
			||||||
	return 1;
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * With -Xtheirs or -Xours, we have cleanly merged;
 | 
				
			||||||
 | 
						 * otherwise we got a conflict.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						return (opts->variant ? 0 : 1);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,
 | 
					static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,
 | 
				
			||||||
@ -73,8 +91,6 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,
 | 
				
			|||||||
	if (buffer_is_binary(orig->ptr, orig->size) ||
 | 
						if (buffer_is_binary(orig->ptr, orig->size) ||
 | 
				
			||||||
	    buffer_is_binary(src1->ptr, src1->size) ||
 | 
						    buffer_is_binary(src1->ptr, src1->size) ||
 | 
				
			||||||
	    buffer_is_binary(src2->ptr, src2->size)) {
 | 
						    buffer_is_binary(src2->ptr, src2->size)) {
 | 
				
			||||||
		warning("Cannot merge binary files: %s (%s vs. %s)",
 | 
					 | 
				
			||||||
			path, name1, name2);
 | 
					 | 
				
			||||||
		return ll_binary_merge(drv_unused, result,
 | 
							return ll_binary_merge(drv_unused, result,
 | 
				
			||||||
				       path,
 | 
									       path,
 | 
				
			||||||
				       orig, orig_name,
 | 
									       orig, orig_name,
 | 
				
			||||||
 | 
				
			|||||||
@ -53,7 +53,19 @@ test_expect_success 'recursive favouring ours' '
 | 
				
			|||||||
	! grep 1 file
 | 
						! grep 1 file
 | 
				
			||||||
'
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_expect_success 'pull with -X' '
 | 
					test_expect_success 'binary file with -Xours/-Xtheirs' '
 | 
				
			||||||
 | 
						echo file binary >.gitattributes &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						git reset --hard master &&
 | 
				
			||||||
 | 
						git merge -s recursive -X theirs side &&
 | 
				
			||||||
 | 
						git diff --exit-code side HEAD -- file &&
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						git reset --hard master &&
 | 
				
			||||||
 | 
						git merge -s recursive -X ours side &&
 | 
				
			||||||
 | 
						git diff --exit-code master HEAD -- file
 | 
				
			||||||
 | 
					'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_expect_success 'pull passes -X to underlying merge' '
 | 
				
			||||||
	git reset --hard master && git pull -s recursive -Xours . side &&
 | 
						git reset --hard master && git pull -s recursive -Xours . side &&
 | 
				
			||||||
	git reset --hard master && git pull -s recursive -X ours . side &&
 | 
						git reset --hard master && git pull -s recursive -X ours . side &&
 | 
				
			||||||
	git reset --hard master && git pull -s recursive -Xtheirs . side &&
 | 
						git reset --hard master && git pull -s recursive -Xtheirs . side &&
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user