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

[PATCH v2 09/17] merge-recursive: handle return values indicating errors

From
Johannes Schindelin <johannes.schindelin@gmx.de>
Date
Jul 5, 2016, 11:23 UTC
Message-ID
<aff644a7766787d3538eeec55b8165004403f860.1467717730.git.johannes.schindelin@gmx.de>
In-Reply-To
<cover.1467717729.git.johannes.schindelin@gmx.de>

We are about to libify the recursive merge machinery, where we only die() in case of a bug or memory contention. To that end, we must heed negative return values as indicating errors.

This requires our functions to be careful to pass through error conditions in call chains, and for quite a few functions this means that they have to return values to begin with.

The next step will be to convert the places where we currently die() to return negative values (read: -1) instead.

Note that we ignore errors reported by make_room_for_path(), consistent with the previous behavior (update_file_flags() used the return value of make_room_for_path() only to indicate an early return, but not a fatal error): if the error is really a fatal error, we will notice later; If not, it was not that serious a problem to begin with. (Witnesses in favor of this reasoning are t4151-am-abort and t7610-mergetool, which would start failing if we stopped on errors reported by make_room_for_path()).

Note: while this patch makes the code slightly less readable in
update_file_flags() (we introduce a new "goto free_buf;" instead of
an explicit "free(buf); return;"), it is a preparatory change for
the next patch where we will convert all of the die() calls in the same
function to go through the free_buf return path instead.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 merge-recursive.c | 196 +++++++++++++++++++++++++++++++++---------------------
 1 file changed, 121 insertions(+), 75 deletions(-)
diff --git a/merge-recursive.c b/merge-recursive.c
index 99f4202..209427c 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -734,7 +734,7 @@ static int make_room_for_path(struct merge_options *o, const char *path)
 	return error(msg, path, _(": perhaps a D/F conflict?"));
 }
 
-static void update_file_flags(struct merge_options *o,
+static int update_file_flags(struct merge_options *o,
 			      const unsigned char *sha,
 			      unsigned mode,
 			      const char *path,
@@ -775,8 +775,7 @@ static void update_file_flags(struct merge_options *o,
 
 		if (make_room_for_path(o, path) < 0) {
 			update_wd = 0;
-			free(buf);
-			goto update_index;
+			goto free_buf;
 		}
 		if (S_ISREG(mode) || (!has_symlinks && S_ISLNK(mode))) {
 			int fd;
@@ -799,20 +798,22 @@ static void update_file_flags(struct merge_options *o,
 		} else
 			die(_("do not know what to do with %06o %s '%s'"),
 			    mode, sha1_to_hex(sha), path);
+ free_buf:
 		free(buf);
 	}
  update_index:
 	if (update_cache)
 		add_cacheinfo(mode, sha, path, 0, update_wd, ADD_CACHE_OK_TO_ADD);
+	return 0;
 }
 
-static void update_file(struct merge_options *o,
+static int update_file(struct merge_options *o,
 			int clean,
 			const unsigned char *sha,
 			unsigned mode,
 			const char *path)
 {
-	update_file_flags(o, sha, mode, path, o->call_depth || clean, !o->call_depth);
+	return update_file_flags(o, sha, mode, path, o->call_depth || clean, !o->call_depth);
 }
 
 /* Low level file merging, update and removal */
@@ -1008,7 +1009,7 @@ static int merge_file_one(struct merge_options *o,
 	return merge_file_1(o, &one, &a, &b, branch1, branch2, mfi);
 }
 
-static void handle_change_delete(struct merge_options *o,
+static int handle_change_delete(struct merge_options *o,
 				 const char *path,
 				 const unsigned char *o_sha, int o_mode,
 				 const unsigned char *a_sha, int a_mode,
@@ -1016,6 +1017,7 @@ static void handle_change_delete(struct merge_options *o,
 				 const char *change, const char *change_past)
 {
 	char *renamed = NULL;
+	int ret = 0;
 	if (dir_in_way(path, !o->call_depth)) {
 		renamed = unique_path(o, path, a_sha ? o->branch1 : o->branch2);
 	}
@@ -1026,21 +1028,23 @@ static void handle_change_delete(struct merge_options *o,
 		 * correct; since there is no true "middle point" between
 		 * them, simply reuse the base version for virtual merge base.
 		 */
-		remove_file_from_cache(path);
-		update_file(o, 0, o_sha, o_mode, renamed ? renamed : path);
+		ret = remove_file_from_cache(path);
+		if (!ret)
+			ret = update_file(o, 0, o_sha, o_mode,
+					  renamed ? renamed : path);
 	} else if (!a_sha) {
 		if (!renamed) {
 			output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
 			       "and %s in %s. Version %s of %s left in tree."),
 			       change, path, o->branch1, change_past,
 			       o->branch2, o->branch2, path);
-			update_file(o, 0, b_sha, b_mode, path);
+			ret = update_file(o, 0, b_sha, b_mode, path);
 		} else {
 			output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
 			       "and %s in %s. Version %s of %s left in tree at %s."),
 			       change, path, o->branch1, change_past,
 			       o->branch2, o->branch2, path, renamed);
-			update_file(o, 0, b_sha, b_mode, renamed);
+			ret = update_file(o, 0, b_sha, b_mode, renamed);
 		}
 	} else {
 		if (!renamed) {
@@ -1053,7 +1057,7 @@ static void handle_change_delete(struct merge_options *o,
 			       "and %s in %s. Version %s of %s left in tree at %s."),
 			       change, path, o->branch2, change_past,
 			       o->branch1, o->branch1, path, renamed);
-			update_file(o, 0, a_sha, a_mode, renamed);
+			ret = update_file(o, 0, a_sha, a_mode, renamed);
 		}
 		/*
 		 * No need to call update_file() on path when !renamed, since
@@ -1063,9 +1067,11 @@ static void handle_change_delete(struct merge_options *o,
 		 */
 	}
 	free(renamed);
+
+	return ret;
 }
 
-static void conflict_rename_delete(struct merge_options *o,
+static int conflict_rename_delete(struct merge_options *o,
 				   struct diff_filepair *pair,
 				   const char *rename_branch,
 				   const char *other_branch)
@@ -1085,21 +1091,19 @@ static void conflict_rename_delete(struct merge_options *o,
 		b_mode = dest->mode;
 	}
 
-	handle_change_delete(o,
+	if (handle_change_delete(o,
 			     o->call_depth ? orig->path : dest->path,
 			     orig->sha1, orig->mode,
 			     a_sha, a_mode,
 			     b_sha, b_mode,
-			     _("rename"), _("renamed"));
-
-	if (o->call_depth) {
-		remove_file_from_cache(dest->path);
-	} else {
-		update_stages(dest->path, NULL,
+			     _("rename"), _("renamed")))
+		return -1;
+	if (o->call_depth)
+		return remove_file_from_cache(dest->path);
+	else
+		return update_stages(dest->path, NULL,
 			      rename_branch == o->branch1 ? dest : NULL,
 			      rename_branch == o->branch1 ? NULL : dest);
-	}
-
 }
 
 static struct diff_filespec *filespec_from_entry(struct diff_filespec *target,
@@ -1115,7 +1119,7 @@ static struct diff_filespec *filespec_from_entry(struct diff_filespec *target,
 	return target;
 }
 
-static void handle_file(struct merge_options *o,
+static int handle_file(struct merge_options *o,
 			struct diff_filespec *rename,
 			int stage,
 			struct rename_conflict_info *ci)
@@ -1125,6 +1129,7 @@ static void handle_file(struct merge_options *o,
 	const char *cur_branch, *other_branch;
 	struct diff_filespec other;
 	struct diff_filespec *add;
+	int ret;
 
 	if (stage == 2) {
 		dst_entry = ci->dst_entry1;
@@ -1139,7 +1144,8 @@ static void handle_file(struct merge_options *o,
 	add = filespec_from_entry(&other, dst_entry, stage ^ 1);
 	if (add) {
 		char *add_name = unique_path(o, rename->path, other_branch);
-		update_file(o, 0, add->sha1, add->mode, add_name);
+		if (update_file(o, 0, add->sha1, add->mode, add_name))
+			return -1;
 
 		remove_file(o, 0, rename->path, 0);
 		dst_name = unique_path(o, rename->path, cur_branch);
@@ -1150,17 +1156,20 @@ static void handle_file(struct merge_options *o,
 			       rename->path, other_branch, dst_name);
 		}
 	}
-	update_file(o, 0, rename->sha1, rename->mode, dst_name);
-	if (stage == 2)
-		update_stages(rename->path, NULL, rename, add);
+	if ((ret = update_file(o, 0, rename->sha1, rename->mode, dst_name)))
+		; /* fall through, do allow dst_name to be released */
+	else if (stage == 2)
+		ret = update_stages(rename->path, NULL, rename, add);
 	else
-		update_stages(rename->path, NULL, add, rename);
+		ret = update_stages(rename->path, NULL, add, rename);
 
 	if (dst_name != rename->path)
 		free(dst_name);
+
+	return ret;
 }
 
-static void conflict_rename_rename_1to2(struct merge_options *o,
+static int conflict_rename_rename_1to2(struct merge_options *o,
 					struct rename_conflict_info *ci)
 {
 	/* One file was renamed in both branches, but to different names. */
@@ -1184,7 +1193,7 @@ static void conflict_rename_rename_1to2(struct merge_options *o,
 				 a->sha1, a->mode,
 				 b->sha1, b->mode,
 				 ci->branch1, ci->branch2, &mfi))
-			return;
+			return -1;
 
 		/*
 		 * FIXME: For rename/add-source conflicts (if we could detect
@@ -1192,7 +1201,8 @@ static void conflict_rename_rename_1to2(struct merge_options *o,
 		 * pathname and then either rename the add-source file to that
 		 * unique path, or use that unique path instead of src here.
 		 */
-		update_file(o, 0, mfi.sha, mfi.mode, one->path);
+		if (update_file(o, 0, mfi.sha, mfi.mode, one->path))
+			return -1;
 
 		/*
 		 * Above, we put the merged content at the merge-base's
@@ -1203,22 +1213,26 @@ static void conflict_rename_rename_1to2(struct merge_options *o,
 		 * resolving the conflict at that path in its favor.
 		 */
 		add = filespec_from_entry(&other, ci->dst_entry1, 2 ^ 1);
-		if (add)
-			update_file(o, 0, add->sha1, add->mode, a->path);
+		if (add) {
+			if (update_file(o, 0, add->sha1, add->mode, a->path))
+				return -1;
+		}
 		else
 			remove_file_from_cache(a->path);
 		add = filespec_from_entry(&other, ci->dst_entry2, 3 ^ 1);
-		if (add)
-			update_file(o, 0, add->sha1, add->mode, b->path);
+		if (add) {
+			if (update_file(o, 0, add->sha1, add->mode, b->path))
+				return -1;
+		}
 		else
 			remove_file_from_cache(b->path);
-	} else {
-		handle_file(o, a, 2, ci);
-		handle_file(o, b, 3, ci);
-	}
+	} else if (handle_file(o, a, 2, ci) || handle_file(o, b, 3, ci))
+		return -1;
+
+	return 0;
 }
 
-static void conflict_rename_rename_2to1(struct merge_options *o,
+static int conflict_rename_rename_2to1(struct merge_options *o,
 					struct rename_conflict_info *ci)
 {
 	/* Two files, a & b, were renamed to the same thing, c. */
@@ -1229,6 +1243,7 @@ static void conflict_rename_rename_2to1(struct merge_options *o,
 	char *path = c1->path; /* == c2->path */
 	struct merge_file_info mfi_c1;
 	struct merge_file_info mfi_c2;
+	int ret;
 
 	output(o, 1, _("CONFLICT (rename/rename): "
 	       "Rename %s->%s in %s. "
@@ -1245,7 +1260,7 @@ static void conflict_rename_rename_2to1(struct merge_options *o,
 	    merge_file_special_markers(o, b, &ci->ren2_other, c2,
 					    o->branch1, ci->ren2_other.path,
 					    o->branch2, c2->path, &mfi_c2))
-		return;
+		return -1;
 
 	if (o->call_depth) {
 		/*
@@ -1256,19 +1271,25 @@ static void conflict_rename_rename_2to1(struct merge_options *o,
 		 * again later for the non-recursive merge.
 		 */
 		remove_file(o, 0, path, 0);
-		update_file(o, 0, mfi_c1.sha, mfi_c1.mode, a->path);
-		update_file(o, 0, mfi_c2.sha, mfi_c2.mode, b->path);
+		ret = update_file(o, 0, mfi_c1.sha, mfi_c1.mode, a->path);
+		if (!ret)
+			ret = update_file(o, 0, mfi_c2.sha, mfi_c2.mode,
+				b->path);
 	} else {
 		char *new_path1 = unique_path(o, path, ci->branch1);
 		char *new_path2 = unique_path(o, path, ci->branch2);
 		output(o, 1, _("Renaming %s to %s and %s to %s instead"),
 		       a->path, new_path1, b->path, new_path2);
 		remove_file(o, 0, path, 0);
-		update_file(o, 0, mfi_c1.sha, mfi_c1.mode, new_path1);
-		update_file(o, 0, mfi_c2.sha, mfi_c2.mode, new_path2);
+		ret = update_file(o, 0, mfi_c1.sha, mfi_c1.mode, new_path1);
+		if (!ret)
+			ret = update_file(o, 0, mfi_c2.sha, mfi_c2.mode,
+				new_path2);
 		free(new_path2);
 		free(new_path1);
 	}
+
+	return ret;
 }
 
 static int process_renames(struct merge_options *o,
@@ -1451,12 +1472,13 @@ static int process_renames(struct merge_options *o,
 				 * update_file_flags() instead of
 				 * update_file().
 				 */
-				update_file_flags(o,
+				if (update_file_flags(o,
 						  ren1->pair->two->sha1,
 						  ren1->pair->two->mode,
 						  ren1_dst,
 						  1, /* update_cache */
-						  0  /* update_wd    */);
+						  0  /* update_wd    */))
+					clean_merge = -1;
 			} else if (!sha_eq(dst_other.sha1, null_sha1)) {
 				clean_merge = 0;
 				try_merge = 1;
@@ -1469,20 +1491,26 @@ static int process_renames(struct merge_options *o,
 					if (merge_file_one(o, ren1_dst, null_sha1, 0,
 							 ren1->pair->two->sha1, ren1->pair->two->mode,
 							 dst_other.sha1, dst_other.mode,
-							 branch1, branch2, &mfi))
-						return -1;
+							 branch1, branch2, &mfi)) {
+						clean_merge = -1;
+						goto cleanup_and_return;
+					}
 					output(o, 1, _("Adding merged %s"), ren1_dst);
-					update_file(o, 0, mfi.sha, mfi.mode, ren1_dst);
+					if (update_file(o, 0, mfi.sha, mfi.mode, ren1_dst))
+						clean_merge = -1;
 					try_merge = 0;
 				} else {
 					char *new_path = unique_path(o, ren1_dst, branch2);
 					output(o, 1, _("Adding as %s instead"), new_path);
-					update_file(o, 0, dst_other.sha1, dst_other.mode, new_path);
+					if (update_file(o, 0, dst_other.sha1, dst_other.mode, new_path))
+						clean_merge = -1;
 					free(new_path);
 				}
 			} else
 				try_merge = 1;
 
+			if (clean_merge < 0)
+				goto cleanup_and_return;
 			if (try_merge) {
 				struct diff_filespec *one, *a, *b;
 				src_other.path = (char *)ren1_src;
@@ -1509,6 +1537,7 @@ static int process_renames(struct merge_options *o,
 			}
 		}
 	}
+cleanup_and_return:
 	string_list_clear(&a_by_dst, 0);
 	string_list_clear(&b_by_dst, 0);
 
@@ -1571,13 +1600,13 @@ error_return:
 	return ret;
 }
 
-static void handle_modify_delete(struct merge_options *o,
+static int handle_modify_delete(struct merge_options *o,
 				 const char *path,
 				 unsigned char *o_sha, int o_mode,
 				 unsigned char *a_sha, int a_mode,
 				 unsigned char *b_sha, int b_mode)
 {
-	handle_change_delete(o,
+	return handle_change_delete(o,
 			     path,
 			     o_sha, o_mode,
 			     a_sha, a_mode,
@@ -1656,7 +1685,8 @@ static int merge_content(struct merge_options *o,
 		output(o, 1, _("CONFLICT (%s): Merge conflict in %s"),
 				reason, path);
 		if (rename_conflict_info && !df_conflict_remains)
-			update_stages(path, &one, &a, &b);
+			if (update_stages(path, &one, &a, &b))
+				return -1;
 	}
 
 	if (df_conflict_remains) {
@@ -1664,30 +1694,33 @@ static int merge_content(struct merge_options *o,
 		if (o->call_depth) {
 			remove_file_from_cache(path);
 		} else {
-			if (!mfi.clean)
-				update_stages(path, &one, &a, &b);
-			else {
+			if (!mfi.clean) {
+				if (update_stages(path, &one, &a, &b))
+					return -1;
+			} else {
 				int file_from_stage2 = was_tracked(path);
 				struct diff_filespec merged;
 				hashcpy(merged.sha1, mfi.sha);
 				merged.mode = mfi.mode;
 
-				update_stages(path, NULL,
+				if (update_stages(path, NULL,
 					      file_from_stage2 ? &merged : NULL,
-					      file_from_stage2 ? NULL : &merged);
+					      file_from_stage2 ? NULL : &merged))
+					return -1;
 			}
 
 		}
 		new_path = unique_path(o, path, rename_conflict_info->branch1);
 		output(o, 1, _("Adding as %s instead"), new_path);
-		update_file(o, 0, mfi.sha, mfi.mode, new_path);
+		if (update_file(o, 0, mfi.sha, mfi.mode, new_path)) {
+			free(new_path);
+			return -1;
+		}
 		free(new_path);
 		mfi.clean = 0;
-	} else {
-		update_file(o, mfi.clean, mfi.sha, mfi.mode, path);
-	}
+	} else if (update_file(o, mfi.clean, mfi.sha, mfi.mode, path))
+		return -1;
 	return mfi.clean;
-
 }
 
 /* Per entry merge function */
@@ -1715,17 +1748,21 @@ static int process_entry(struct merge_options *o,
 			break;
 		case RENAME_DELETE:
 			clean_merge = 0;
-			conflict_rename_delete(o, conflict_info->pair1,
+			if (conflict_rename_delete(o,
+					       conflict_info->pair1,
 					       conflict_info->branch1,
-					       conflict_info->branch2);
+					       conflict_info->branch2))
+				clean_merge = -1;
 			break;
 		case RENAME_ONE_FILE_TO_TWO:
 			clean_merge = 0;
-			conflict_rename_rename_1to2(o, conflict_info);
+			if (conflict_rename_rename_1to2(o, conflict_info))
+				clean_merge = -1;
 			break;
 		case RENAME_TWO_FILES_TO_ONE:
 			clean_merge = 0;
-			conflict_rename_rename_2to1(o, conflict_info);
+			if (conflict_rename_rename_2to1(o, conflict_info))
+				clean_merge = -1;
 			break;
 		default:
 			entry->processed = 0;
@@ -1745,8 +1782,9 @@ static int process_entry(struct merge_options *o,
 		} else {
 			/* Modify/delete; deleted side may have put a directory in the way */
 			clean_merge = 0;
-			handle_modify_delete(o, path, o_sha, o_mode,
-					     a_sha, a_mode, b_sha, b_mode);
+			if (handle_modify_delete(o, path, o_sha, o_mode,
+						 a_sha, a_mode, b_sha, b_mode))
+				clean_merge = -1;
 		}
 	} else if ((!o_sha && a_sha && !b_sha) ||
 		   (!o_sha && !a_sha && b_sha)) {
@@ -1778,14 +1816,16 @@ static int process_entry(struct merge_options *o,
 			output(o, 1, _("CONFLICT (%s): There is a directory with name %s in %s. "
 			       "Adding %s as %s"),
 			       conf, path, other_branch, path, new_path);
-			update_file(o, 0, sha, mode, new_path);
-			if (o->call_depth)
+			if (update_file(o, 0, sha, mode, new_path))
+				clean_merge = -1;
+			else if (o->call_depth)
 				remove_file_from_cache(path);
 			free(new_path);
 		} else {
 			output(o, 2, _("Adding %s"), path);
 			/* do not overwrite file if already present */
-			update_file_flags(o, sha, mode, path, 1, !a_sha);
+			if (update_file_flags(o, sha, mode, path, 1, !a_sha))
+				clean_merge = -1;
 		}
 	} else if (a_sha && b_sha) {
 		/* Case C: Added in both (check for same permissions) and */
@@ -1848,12 +1888,18 @@ int merge_trees(struct merge_options *o,
 		re_head  = get_renames(o, head, common, head, merge, entries);
 		re_merge = get_renames(o, merge, common, head, merge, entries);
 		clean = process_renames(o, re_head, re_merge);
+		if (clean < 0)
+			return clean;
 		for (i = entries->nr-1; 0 <= i; i--) {
 			const char *path = entries->items[i].string;
 			struct stage_data *e = entries->items[i].util;
-			if (!e->processed
-				&& !process_entry(o, path, e))
-				clean = 0;
+			if (!e->processed) {
+				int ret = process_entry(o, path, e);
+				if (!ret)
+					clean = 0;
+				else if (ret < 0)
+					return ret;
+			}
 		}
 		for (i = 0; i < entries->nr; i++) {
 			struct stage_data *e = entries->items[i].util;
-- 
2.9.0.280.g32e2a70
Previous: Johannes SchindelinNext: Johannes Schindelin
Message 63 of 262 in “Use merge_recursive() directly in the builtin am”
  1. 0/9 Use merge_recursive() directly in the builtin amJohannes Schindelin, Jun 29, 2016
  2. 1/9 Report bugs consistentlyJohannes Schindelin, Jun 29, 2016
  3. Johannes SchindelinJun 29, 2016
  4. Eric SunshineJun 29, 2016
  5. Johannes SchindelinJun 30, 2016
  6. Junio C HamanoJun 29, 2016
  7. Johannes SchindelinJun 30, 2016
  8. Jeff KingJun 30, 2016
  9. Johannes SchindelinJul 1, 2016
  10. Jeff KingJul 1, 2016
  11. Johannes SixtJun 30, 2016
  12. Johannes SchindelinJun 30, 2016
  13. Duy NguyenJul 2, 2016
  14. Johannes SchindelinJul 2, 2016
  15. Duy NguyenJul 2, 2016
  16. Johannes SchindelinJul 5, 2016
  17. 2/9 merge-recursive: clarify code in was_tracked()Johannes Schindelin, Jun 29, 2016
  18. Junio C HamanoJun 29, 2016
  19. Johannes SchindelinJul 1, 2016
  20. Junio C HamanoJul 1, 2016
  21. Johannes SchindelinJul 2, 2016
  22. Junio C HamanoJul 6, 2016
  23. Johannes SchindelinJul 7, 2016
  24. 4/9 merge_recursive: abort properly upon errorsJohannes Schindelin, Jun 29, 2016
  25. Junio C HamanoJun 29, 2016
  26. Johannes SchindelinJul 1, 2016
  27. Junio C HamanoJul 1, 2016
  28. Johannes SchindelinJul 2, 2016
  29. 3/9 Prepare the builtins for a libified merge_recursive()Johannes Schindelin, Jun 29, 2016
  30. Junio C HamanoJun 29, 2016
  31. Johannes SchindelinJul 1, 2016
  32. Junio C HamanoJul 1, 2016
  33. Johannes SchindelinJul 2, 2016
  34. 6/9 merge-recursive: allow write_tree_from_memory() to error outJohannes Schindelin, Jun 29, 2016
  35. 7/9 merge-recursive: handle return values indicating errorsJohannes Schindelin, Jun 29, 2016
  36. Junio C HamanoJun 29, 2016
  37. Johannes SchindelinJul 1, 2016
  38. 5/9 merge-recursive: avoid returning a wholesale structJohannes Schindelin, Jun 29, 2016
  39. Junio C HamanoJun 29, 2016
  40. Johannes SchindelinJul 1, 2016
  41. Eric WongJul 1, 2016
  42. 8/9 merge-recursive: switch to returning errors instead of dyingJohannes Schindelin, Jun 29, 2016
  43. Junio C HamanoJun 29, 2016
  44. Johannes SchindelinJul 1, 2016
  45. 9/9 am: make a direct call to merge_recursiveJohannes Schindelin, Jun 29, 2016
  46. Junio C HamanoJun 29, 2016
  47. Johannes SchindelinJun 30, 2016
  48. Junio C HamanoJul 1, 2016
  49. Junio C HamanoJun 29, 2016
  50. Johannes SchindelinJul 1, 2016
  51. 00/17 Use merge_recursive() directly in the builtin amJohannes Schindelin, Jul 5, 2016
  52. 01/17 Verify that `git pull --rebase` shows the helpful advice when failingJohannes Schindelin, Jul 5, 2016
  53. 02/17 Report bugs consistentlyJohannes Schindelin, Jul 5, 2016
  54. Jakub NarębskiJul 5, 2016
  55. Johannes SchindelinJul 5, 2016
  56. Duy NguyenJul 6, 2016
  57. Johannes SchindelinJul 7, 2016
  58. 04/17 merge-recursive: clarify code in was_tracked()Johannes Schindelin, Jul 5, 2016
  59. 03/17 Avoid translating bug messagesJohannes Schindelin, Jul 5, 2016
  60. 06/17 merge_recursive: abort properly upon errorsJohannes Schindelin, Jul 5, 2016
  61. 07/17 merge-recursive: avoid returning a wholesale structJohannes Schindelin, Jul 5, 2016
  62. 05/17 Prepare the builtins for a libified merge_recursive()Johannes Schindelin, Jul 5, 2016
  63. 09/17 merge-recursive: handle return values indicating errorsJohannes Schindelin, Jul 5, 2016
  64. 08/17 merge-recursive: allow write_tree_from_memory() to error outJohannes Schindelin, Jul 5, 2016
  65. 10/17 merge-recursive: switch to returning errors instead of dyingJohannes Schindelin, Jul 5, 2016
  66. 12/17 am -3: use merge_recursive() directly againJohannes Schindelin, Jul 5, 2016
  67. 11/17 am: counteract gender biasJohannes Schindelin, Jul 5, 2016
  68. Junio C HamanoJul 6, 2016
  69. Johannes SchindelinJul 7, 2016
  70. Junio C HamanoJul 7, 2016
  71. Johannes SchindelinJul 7, 2016
  72. Junio C HamanoJul 7, 2016
  73. 13/17 merge-recursive: flush output buffer before printing error messagesJohannes Schindelin, Jul 5, 2016
  74. 14/17 merge-recursive: write the commit title in one goJohannes Schindelin, Jul 5, 2016
  75. 16/17 Ensure that the output buffer is released after calling merge_trees()Johannes Schindelin, Jul 5, 2016
  76. 15/17 merge-recursive: offer an option to retain the output in 'obuf'Johannes Schindelin, Jul 5, 2016
  77. 17/17 merge-recursive: flush output buffer even when erroring outJohannes Schindelin, Jul 5, 2016
  78. Junio C HamanoJul 6, 2016
  79. Johannes SchindelinJul 7, 2016
  80. 00/16 Use merge_recursive() directly in the builtin amJohannes Schindelin, Jul 7, 2016
  81. 02/16 Report bugs consistentlyJohannes Schindelin, Jul 7, 2016
  82. 03/16 Avoid translating bug messagesJohannes Schindelin, Jul 7, 2016
  83. 05/16 Prepare the builtins for a libified merge_recursive()Johannes Schindelin, Jul 7, 2016
  84. 06/16 merge_recursive: abort properly upon errorsJohannes Schindelin, Jul 7, 2016
  85. 04/16 merge-recursive: clarify code in was_tracked()Johannes Schindelin, Jul 7, 2016
  86. 01/16 Verify that `git pull --rebase` shows the helpful advice when failingJohannes Schindelin, Jul 7, 2016
  87. 07/16 merge-recursive: avoid returning a wholesale structJohannes Schindelin, Jul 7, 2016
  88. 08/16 merge-recursive: allow write_tree_from_memory() to error outJohannes Schindelin, Jul 7, 2016
  89. 09/16 merge-recursive: handle return values indicating errorsJohannes Schindelin, Jul 7, 2016
  90. 11/16 am -3: use merge_recursive() directly againJohannes Schindelin, Jul 7, 2016
  91. 10/16 merge-recursive: switch to returning errors instead of dyingJohannes Schindelin, Jul 7, 2016
  92. 12/16 merge-recursive: flush output buffer before printing error messagesJohannes Schindelin, Jul 7, 2016
  93. 14/16 merge-recursive: offer an option to retain the output in 'obuf'Johannes Schindelin, Jul 7, 2016
  94. 13/16 merge-recursive: write the commit title in one goJohannes Schindelin, Jul 7, 2016
  95. 15/16 Ensure that the output buffer is released after calling merge_trees()Johannes Schindelin, Jul 7, 2016
  96. 16/16 merge-recursive: flush output buffer even when erroring outJohannes Schindelin, Jul 7, 2016
  97. Junio C HamanoJul 12, 2016
  98. Johannes SchindelinJul 14, 2016
  99. Junio C HamanoJul 14, 2016
  100. Junio C HamanoJul 19, 2016
  101. Johannes SchindelinJul 19, 2016
  102. Johannes SchindelinJul 19, 2016
  103. Junio C HamanoJul 19, 2016
  104. 00/16 Use merge_recursive() directly in the builtin amJohannes Schindelin, Jul 22, 2016
  105. 01/16 Verify that `git pull --rebase` shows the helpful advice when failingJohannes Schindelin, Jul 22, 2016
  106. Junio C HamanoJul 25, 2016
  107. Johannes SchindelinJul 26, 2016
  108. 02/16 Report bugs consistentlyJohannes Schindelin, Jul 22, 2016
  109. Junio C HamanoJul 25, 2016
  110. Jeff KingJul 25, 2016
  111. Junio C HamanoJul 25, 2016
  112. Johannes SchindelinJul 26, 2016
  113. 03/16 Avoid translating bug messagesJohannes Schindelin, Jul 22, 2016
  114. 04/16 merge-recursive: clarify code in was_tracked()Johannes Schindelin, Jul 22, 2016
  115. 05/16 Prepare the builtins for a libified merge_recursive()Johannes Schindelin, Jul 22, 2016
  116. 06/16 merge_recursive: abort properly upon errorsJohannes Schindelin, Jul 22, 2016
  117. Junio C HamanoJul 25, 2016
  118. Johannes SchindelinJul 26, 2016
  119. 07/16 merge-recursive: avoid returning a wholesale structJohannes Schindelin, Jul 22, 2016
  120. 08/16 merge-recursive: allow write_tree_from_memory() to error outJohannes Schindelin, Jul 22, 2016
  121. 09/16 merge-recursive: handle return values indicating errorsJohannes Schindelin, Jul 22, 2016
  122. 10/16 merge-recursive: switch to returning errors instead of dyingJohannes Schindelin, Jul 22, 2016
  123. 11/16 am -3: use merge_recursive() directly againJohannes Schindelin, Jul 22, 2016
  124. Junio C HamanoJul 25, 2016
  125. Johannes SchindelinJul 26, 2016
  126. Junio C HamanoJul 26, 2016
  127. 12/16 merge-recursive: flush output buffer before printing error messagesJohannes Schindelin, Jul 22, 2016
  128. 14/16 merge-recursive: offer an option to retain the output in 'obuf'Johannes Schindelin, Jul 22, 2016
  129. 15/16 Ensure that the output buffer is released after calling merge_trees()Johannes Schindelin, Jul 22, 2016
  130. 13/16 merge-recursive: write the commit title in one goJohannes Schindelin, Jul 22, 2016
  131. 16/16 merge-recursive: flush output buffer even when erroring outJohannes Schindelin, Jul 22, 2016
  132. 00/16 Use merge_recursive() directly in the builtin amJohannes Schindelin, Jul 26, 2016
  133. 01/16 t5520: verify that `pull --rebase` shows the helpful advice when failingJohannes Schindelin, Jul 26, 2016
  134. 02/16 Report bugs consistentlyJohannes Schindelin, Jul 26, 2016
  135. 03/16 Avoid translating bug messagesJohannes Schindelin, Jul 26, 2016
  136. 04/16 merge-recursive: clarify code in was_tracked()Johannes Schindelin, Jul 26, 2016
  137. 05/16 Prepare the builtins for a libified merge_recursive()Johannes Schindelin, Jul 26, 2016
  138. 06/16 merge_recursive: abort properly upon errorsJohannes Schindelin, Jul 26, 2016
  139. 07/16 merge-recursive: avoid returning a wholesale structJohannes Schindelin, Jul 26, 2016
  140. 08/16 merge-recursive: allow write_tree_from_memory() to error outJohannes Schindelin, Jul 26, 2016
  141. 09/16 merge-recursive: handle return values indicating errorsJohannes Schindelin, Jul 26, 2016
  142. 10/16 merge-recursive: switch to returning errors instead of dyingJohannes Schindelin, Jul 26, 2016
  143. 13/16 merge-recursive: write the commit title in one goJohannes Schindelin, Jul 26, 2016
  144. Junio C HamanoJul 27, 2016
  145. Johannes SchindelinAug 1, 2016
  146. 11/16 am -3: use merge_recursive() directly againJohannes Schindelin, Jul 26, 2016
  147. 12/16 merge-recursive: flush output buffer before printing error messagesJohannes Schindelin, Jul 26, 2016
  148. Junio C HamanoJul 27, 2016
  149. Junio C HamanoJul 27, 2016
  150. Johannes SchindelinAug 1, 2016
  151. 14/16 merge-recursive: offer an option to retain the output in 'obuf'Johannes Schindelin, Jul 26, 2016
  152. Junio C HamanoJul 27, 2016
  153. Junio C HamanoJul 28, 2016
  154. Johannes SchindelinAug 1, 2016
  155. Junio C HamanoAug 1, 2016
  156. Johannes SchindelinAug 2, 2016
  157. Junio C HamanoAug 2, 2016
  158. Johannes SchindelinAug 1, 2016
  159. 15/16 Ensure that the output buffer is released after calling merge_trees()Johannes Schindelin, Jul 26, 2016
  160. Junio C HamanoJul 27, 2016
  161. Johannes SchindelinAug 1, 2016
  162. 16/16 merge-recursive: flush output buffer even when erroring outJohannes Schindelin, Jul 26, 2016
  163. Junio C HamanoJul 27, 2016
  164. Johannes SchindelinAug 1, 2016
  165. Junio C HamanoAug 1, 2016
  166. 00/16 Use merge_recursive() directly in the builtin amJohannes Schindelin, Aug 1, 2016
  167. 01/16 t5520: verify that `pull --rebase` shows the helpful advice when failingJohannes Schindelin, Aug 1, 2016
  168. 02/16 Report bugs consistentlyJohannes Schindelin, Aug 1, 2016
  169. 05/16 Prepare the builtins for a libified merge_recursive()Johannes Schindelin, Aug 1, 2016
  170. Junio C HamanoAug 1, 2016
  171. Johannes SchindelinAug 2, 2016
  172. 04/16 merge-recursive: clarify code in was_tracked()Johannes Schindelin, Aug 1, 2016
  173. 03/16 Avoid translating bug messagesJohannes Schindelin, Aug 1, 2016
  174. 11/16 am -3: use merge_recursive() directly againJohannes Schindelin, Aug 1, 2016
  175. 09/16 merge-recursive: handle return values indicating errorsJohannes Schindelin, Aug 1, 2016
  176. 14/16 merge-recursive: offer an option to retain the output in 'obuf'Johannes Schindelin, Aug 1, 2016
  177. 10/16 merge-recursive: switch to returning errors instead of dyingJohannes Schindelin, Aug 1, 2016
  178. 12/16 merge-recursive: flush output buffer before printing error messagesJohannes Schindelin, Aug 1, 2016
  179. 07/16 merge-recursive: avoid returning a wholesale structJohannes Schindelin, Aug 1, 2016
  180. Junio C HamanoAug 4, 2016
  181. 15/16 Ensure that the output buffer is released after calling merge_trees()Johannes Schindelin, Aug 1, 2016
  182. Junio C HamanoAug 4, 2016
  183. 08/16 merge-recursive: allow write_tree_from_memory() to error outJohannes Schindelin, Aug 1, 2016
  184. Junio C HamanoAug 4, 2016
  185. 06/16 merge_recursive: abort properly upon errorsJohannes Schindelin, Aug 1, 2016
  186. Junio C HamanoAug 1, 2016
  187. Johannes SchindelinAug 2, 2016
  188. Junio C HamanoAug 2, 2016
  189. patch submission process, was Re: [PATCH v6 06/16] merge_recursive: abort properly upon errorsJohannes Schindelin, Aug 3, 2016
  190. Junio C HamanoAug 3, 2016
  191. Jeff KingAug 3, 2016
  192. Junio C HamanoAug 3, 2016
  193. Jeff KingAug 3, 2016
  194. Johannes SchindelinAug 4, 2016
  195. Jeff KingAug 4, 2016
  196. Junio C HamanoAug 4, 2016
  197. Jeff KingAug 5, 2016
  198. Johannes SchindelinAug 5, 2016
  199. Johannes SchindelinAug 3, 2016
  200. Stefan BellerAug 3, 2016
  201. Johannes SchindelinAug 4, 2016
  202. Stefan BellerAug 4, 2016
  203. Eric WongAug 4, 2016
  204. Johannes SchindelinAug 5, 2016
  205. Eric WongAug 5, 2016
  206. Johannes SchindelinAug 5, 2016
  207. Stefan BellerAug 5, 2016
  208. Josh TriplettAug 5, 2016
  209. Eric WongAug 5, 2016
  210. Johannes SchindelinAug 6, 2016
  211. Junio C HamanoAug 6, 2016
  212. Eric WongAug 6, 2016
  213. Johannes SchindelinAug 7, 2016
  214. Junio C HamanoAug 8, 2016
  215. Johannes SchindelinAug 9, 2016
  216. Lars SchneiderAug 7, 2016
  217. Junio C HamanoAug 8, 2016
  218. Johannes SchindelinAug 9, 2016
  219. Junio C HamanoAug 9, 2016
  220. Eric WongAug 5, 2016
  221. Johannes SchindelinAug 6, 2016
  222. Richard IpsumAug 5, 2016
  223. Johannes SchindelinAug 5, 2016
  224. Richard IpsumAug 6, 2016
  225. Michael HaggertyAug 8, 2016
  226. Junio C HamanoAug 8, 2016
  227. Michael HaggertyAug 8, 2016
  228. Michael J GruberAug 9, 2016
  229. Jeff KingAug 9, 2016
  230. Josh TriplettAug 10, 2016
  231. Jeff KingAug 9, 2016
  232. Junio C HamanoAug 9, 2016
  233. Jeff KingAug 9, 2016
  234. Junio C HamanoAug 9, 2016
  235. Duy NguyenAug 9, 2016
  236. Stefan BellerAug 9, 2016
  237. Jeff KingAug 9, 2016
  238. Jeff KingAug 9, 2016
  239. Duy NguyenAug 9, 2016
  240. Duy NguyenAug 9, 2016
  241. Duy NguyenAug 9, 2016
  242. Richard IpsumAug 9, 2016
  243. Jeff KingAug 9, 2016
  244. Michael HaggertyAug 9, 2016
  245. Johannes SchindelinAug 9, 2016
  246. Eric WongAug 9, 2016
  247. Josh TriplettAug 10, 2016
  248. Eric WongAug 10, 2016
  249. Jakub NarębskiAug 10, 2016
  250. Josh TriplettAug 10, 2016
  251. Junio C HamanoAug 10, 2016
  252. Duy NguyenAug 5, 2016
  253. Johannes SchindelinAug 5, 2016
  254. Philip OakleyAug 5, 2016
  255. Johannes SchindelinAug 6, 2016
  256. Philip OakleyAug 6, 2016
  257. Junio C HamanoAug 2, 2016
  258. 13/16 merge-recursive: write the commit title in one goJohannes Schindelin, Aug 1, 2016
  259. 16/16 merge-recursive: flush output buffer even when erroring outJohannes Schindelin, Aug 1, 2016
  260. Junio C HamanoAug 4, 2016
  261. Johannes SchindelinAug 5, 2016
  262. Junio C HamanoAug 6, 2016

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.