"GOT", but the "O" is a cute, smiling pufferfish. Index | Thread | Search

From:
James Cook <falsifian@falsifian.org>
Subject:
got log -b path gets confused by merge commits
To:
gameoftrees@openbsd.org
Date:
Sun, 28 Jan 2024 18:34:17 +0000

Download raw body.

Thread
I've managed to trigger the error 

	got: //d/g: no such entry found in tree

by running got log -b d/g or tog log -b d/g in a specially crafted 
repo.

I have a script (at bottom) to reproduce and am happy to turn that 
into a patch for regress/cmdline.

However, I have only partly understood the cause of the problem. 
Some notes below. Maybe someone more familiar with how advance_branch 
is supposed to work can see it more quickly.

My commit graph looks like this (starting with the most recent commit):

   o  create d/g
   |
   o  merge (does not touch the directory d at all)
  / \
o   o  unrelated changes which leave the whole directory d unchanged
  \ /
   o  initial commit, which includes directory d but without the file d/g

I noticed that when detect_changed_path is called at commit_graph:508, 
and *commit_id is the merge commit, detect_changed_path sets changed 
to 0 and returns no error. (Line number 508 is from commit d4fbd6eb.) 
This is interesting because the path "d/g" is not present in that 
commit, and the if statement immediately following seems to be 
looking for that case (comparing err->code to GOT_ERR_NO_OBJ).

The reason detect_changed_path doesn't return GOT_ERR_NO_OBJ is 
that the director d is not changed in the merge commit, so 
got_object_tree_path_changed stops walking the tree before it tries 
to look up d/g.

I don't actually know if that's where the bug is because I don't 
know how it's all supposed to work. Interestingly, the bug doesn't 
appear without the -b option to {got,tog} log.

FYI here is a backtrace from when got_error_path 
gets called (line numbers from commit d4fbd6eb):

#0  got_error_path (path=0x0, code=31040) at /home/falsifian/co/got/got/../lib/error.c:437
#1  0x000006517031869b in got_object_tree_find_path (id=0x7940d1e13d60, mode=0x0, repo=0x6544d0b1450, tree=0x654541d49c0, 
     path=0x654541fbea0 "/d/g") at /home/falsifian/co/got/got/../lib/object.c:591
#2  0x00000651703188e0 in got_object_id_by_path (id=0x7940d1e13d60, repo=0x6544d0b1450, commit=0x654541d8240, path=0x654541fbea0 "/d/g")
     at /home/falsifian/co/got/got/../lib/object.c:645
#3  0x000006517030985b in advance_branch (graph=0x654541eb440, commit_id=0x654541f60f0, commit=0x654541d8240, repo=0x6544d0b1450)
     at /home/falsifian/co/got/got/../lib/commit_graph.c:295
#4  0x0000065170308bf3 in fetch_commits_from_open_branches (graph=0x654541eb440, repo=0x6544d0b1450, 
     cancel_cb=0x651702f77d0 <check_cancelled>, cancel_arg=0x0) at /home/falsifian/co/got/got/../lib/commit_graph.c:527
#5  0x0000065170308d53 in got_commit_graph_iter_next (id=0x7940d1e14010, graph=0x654541eb440, repo=0x6544d0b1450, 
     cancel_cb=0x651702f77d0 <check_cancelled>, cancel_arg=0x0) at /home/falsifian/co/got/got/../lib/commit_graph.c:610
#6  0x00000651702f82dc in print_commits (root_id=0x654541d1d40, end_id=0x0, repo=0x6544d0b1450, path=0x6544d0cbd80 "/d/g", 
     show_changed_paths=0, show_diffstat=0, show_patch=0, search_pattern=0x0, diff_context=3, limit=0, log_branches=1, 
     reverse_display_order=0, refs_idmap=0x654541e90b0, one_line=0, tmpfile=0x0) at /home/falsifian/co/got/got/got.c:4492
#7  0x00000651702e4926 in cmd_log (argc=1, argv=0x7940d1e143a0) at /home/falsifian/co/got/got/got.c:4871
#8  0x00000651702decd7 in main (argc=5, argv=0x7940d1e14380) at /home/falsifian/co/got/got/got.c:262

-- 
James


#!/bin/sh
set -e


mkdir bug; cd bug

gotadmin init repo.git
mkdir -p init/d
echo content > init/d/f
got import -r repo.git -m init init

got co repo.git
cd repo

got br aux
echo aux > aux
got add aux
got ci -m 'change on aux'

got up -b main
echo main > main
got add main
got ci -m 'change on main'

got up
got mg aux

touch d/g
got add d/g
got ci -m 'create d/g'

got log -b d/g