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

[PATCH v4] rerere: fix overeager gc

From
SZEDER Gábor <szeder@ira.uka.de>
Date
Jul 8, 2010, 14:35 UTC
Message-ID
<1278599758-18962-1-git-send-email-szeder@ira.uka.de>
In-Reply-To
<4C31757A.1000207@viscovery.net>

'rerere gc' prunes resolutions of conflicted merges that occurred long time ago, and when doing so it takes the creation time of the conflicted automerge results into account. This can cause the loss of frequently used merge resolutions (e.g. long-living topic branches are merged into a regularly rebuilt integration branch (think of git's pu)) when they become old enough to exceed 'rerere gc's threshold.

To prevent the loss of valuable merge resolutions 'rerere' will (1) write 'thisimage' into a temporary file and then rename it into its final destination, thereby updating the directory timestamp each time when encountering the same merge conflict, and (2) take the directory timestamp, i.e. the time of the last usage into account when gc'ing.

Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
---
On Mon, Jul 05, 2010 at 08:02:34AM +0200, Johannes Sixt wrote:
Show 7 quoted lines
> Am 7/2/2010 19:25, schrieb Junio C Hamano:
> > If we for whatever reason trust placing an extra timestamp on a regular
> > file more than using directory timestamp (which I think may be a valid
> > concern from portability point of view),
> 
> Windows behaves well in this regard. Writing of thisimage must be
> converted to lockfile infrastructure, of course.

So, here is the next take with the tmpfile-rename stuff to update the directory timestamp. If there are any portability issues wrt directory timestamp updating, the new test should catch them early.

 builtin/rerere.c  |    6 +++---
 rerere.c          |   19 +++++++++++++++++--
 t/t4200-rerere.sh |   16 ++++++++++++----
 3 files changed, 32 insertions(+), 9 deletions(-)
diff --git a/builtin/rerere.c b/builtin/rerere.c
index 980d542..bede3eb 100644
--- a/builtin/rerere.c
+++ b/builtin/rerere.c
@@ -13,10 +13,10 @@ static const char git_rerere_usage[] =
 static int cutoff_noresolve = 15;
 static int cutoff_resolve = 60;
 
-static time_t rerere_created_at(const char *name)
+static time_t rerere_last_used_at(const char *name)
 {
 	struct stat st;
-	return stat(rerere_path(name, "preimage"), &st) ? (time_t) 0 : st.st_mtime;
+	return stat(rerere_path(name, "."), &st) ? (time_t) 0 : st.st_mtime;
 }
 
 static void unlink_rr_item(const char *name)
@@ -53,7 +53,7 @@ static void garbage_collect(struct string_list *rr)
 	while ((e = readdir(dir))) {
 		if (is_dot_or_dotdot(e->d_name))
 			continue;
-		then = rerere_created_at(e->d_name);
+		then = rerere_last_used_at(e->d_name);
 		if (!then)
 			continue;
 		cutoff = (has_rerere_resolution(e->d_name)
diff --git a/rerere.c b/rerere.c
index d03a696..e415f54 100644
--- a/rerere.c
+++ b/rerere.c
@@ -363,13 +363,28 @@ static int find_conflict(struct string_list *conflict)
 
 static int merge(const char *name, const char *path)
 {
-	int ret;
+	int fd, ret;
 	mmfile_t cur = {NULL, 0}, base = {NULL, 0}, other = {NULL, 0};
 	mmbuffer_t result = {NULL, 0};
+	char *tmpfile;
+
+	tmpfile = xstrdup(rerere_path(name, "tmp_thisimage_XXXXXX"));
+	fd = git_mkstemp_mode(tmpfile, 0600);
+	if (fd < 0) {
+		error("unable to create temporary file %s for rerere: %s\n",
+				tmpfile, strerror(errno));
+		return 1;
+	}
+	close(fd);
 
-	if (handle_file(path, NULL, rerere_path(name, "thisimage")) < 0)
+	if (handle_file(path, NULL, tmpfile) < 0)
 		return 1;
 
+	if (move_temp_to_file(tmpfile, rerere_path(name, "thisimage")) < 0)
+		return 1;
+
+	free(tmpfile);
+
 	if (read_mmfile(&cur, rerere_path(name, "thisimage")) ||
 			read_mmfile(&base, rerere_path(name, "preimage")) ||
 			read_mmfile(&other, rerere_path(name, "postimage"))) {
diff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh
index 70856d0..a425329 100755
--- a/t/t4200-rerere.sh
+++ b/t/t4200-rerere.sh
@@ -144,6 +144,14 @@ test_expect_success 'rerere kicked in' "! grep ^=======$ a1"
 
 test_expect_success 'rerere prefers first change' 'test_cmp a1 expect'
 
+test_expect_success 'rerere updates directory timestamp' '
+	git reset --hard &&
+	oldmtime=$(test-chmtime -v -42 $rr |cut -f 1) &&
+	test_must_fail git pull . first &&
+	newmtime=$(test-chmtime -v +0 $rr |cut -f 1) &&
+	test $oldmtime -lt $newmtime
+'
+
 rm $rr/postimage
 echo "$sha1	a1" | perl -pe 'y/\012/\000/' > .git/MERGE_RR
 
@@ -165,16 +173,16 @@ just_over_15_days_ago=$((-1-15*86400))
 almost_60_days_ago=$((60-60*86400))
 just_over_60_days_ago=$((-1-60*86400))
 
-test-chmtime =$almost_60_days_ago $rr/preimage
-test-chmtime =$almost_15_days_ago $rr2/preimage
+test-chmtime =$almost_60_days_ago $rr
+test-chmtime =$almost_15_days_ago $rr2
 
 test_expect_success 'garbage collection (part1)' 'git rerere gc'
 
 test_expect_success 'young records still live' \
 	"test -f $rr/preimage && test -f $rr2/preimage"
 
-test-chmtime =$just_over_60_days_ago $rr/preimage
-test-chmtime =$just_over_15_days_ago $rr2/preimage
+test-chmtime =$just_over_60_days_ago $rr
+test-chmtime =$just_over_15_days_ago $rr2
 
 test_expect_success 'garbage collection (part2)' 'git rerere gc'
 
-- 
1.7.2.rc2.42.gfe876
Previous: Johannes SixtNext: Junio C Hamano
Message 16 of 24 in “rerere: fix overeager gc”
  1. rerere: fix overeager gcSZEDER Gábor, Jun 29, 2010
  2. Junio C HamanoJun 29, 2010
  3. Johannes SixtJun 30, 2010
  4. SZEDER GáborJun 30, 2010
  5. Junio C HamanoJun 30, 2010
  6. Johannes SixtJun 30, 2010
  7. rerere: fix overeager gcSZEDER Gábor, Jul 1, 2010
  8. Johannes SixtJul 1, 2010
  9. 1/2 mingw: utime() handles NULL times parameterSZEDER Gábor, Jul 1, 2010
  10. 1/2 mingw_utime(): handle NULL times parameterJohannes Sixt, Jul 1, 2010
  11. 2/2 rerere: fix overeager gcSZEDER Gábor, Jul 1, 2010
  12. Junio C HamanoJul 1, 2010
  13. Johannes SixtJul 2, 2010
  14. Junio C HamanoJul 2, 2010
  15. Johannes SixtJul 5, 2010
  16. rerere: fix overeager gcSZEDER Gábor, Jul 8, 2010
  17. Junio C HamanoJul 9, 2010
  18. 1/2 mingw_utime(): handle NULL times parameterSZEDER Gábor, Jul 12, 2010
  19. 2/2 rerere: fix overeager gcSZEDER Gábor, Jul 12, 2010
  20. Junio C HamanoJul 13, 2010
  21. SZEDER GáborJul 14, 2010
  22. Junio C HamanoJul 14, 2010
  23. SZEDER GáborJul 14, 2010
  24. Johannes SixtJul 8, 2010

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.