commit - 14ed98fdf951d01d640d17b7ef18d4a9a3b761a7
commit + 8d725ae11ecc53e7d7f7bc3b576f7e949d08b980
blob - d7a5a560a572e11ce47c89a95d7c14bc30483ee8
blob + a1b4bd57e86473bd5bd845a4ee2c6601b8df3430
--- lib/blame.c
+++ lib/blame.c
struct got_blame_line {
int annotated;
struct got_object_id id;
- off_t offset;
};
struct got_blame_diff_offsets {
static const struct got_error *
blame_commit(struct got_blame *blame, struct got_object_id *id,
- struct got_object_id *pid, const char *path, struct got_repository *repo,
+ const char *path, struct got_repository *repo,
const struct got_error *(*cb)(void *, int, int, struct got_object_id *),
void *arg)
{
const struct got_error *err = NULL;
struct got_object *obj = NULL, *pobj = NULL;
struct got_object_id *obj_id = NULL, *pobj_id = NULL;
+ struct got_commit_object *commit = NULL;
struct got_blob_object *blob = NULL, *pblob = NULL;
struct got_diff_changes *changes = NULL;
+ struct got_object_qid *pid = NULL;
+ err = got_object_open_as_commit(&commit, repo, id);
+ if (err)
+ return err;
+
err = got_object_id_by_path(&obj_id, repo, id, path);
if (err)
goto done;
goto done;
}
+ pid = SIMPLEQ_FIRST(got_object_commit_get_parent_ids(commit));
if (pid) {
- err = got_object_id_by_path(&pobj_id, repo, pid, path);
+ err = got_object_id_by_path(&pobj_id, repo, pid->id, path);
if (err) {
if (err->code == GOT_ERR_NO_TREE_ENTRY) {
/* Blob's history began in previous commit. */
} else if (cb)
err = cb(arg, blame->nlines, -1, id);
done:
+ if (commit)
+ got_object_commit_close(commit);
free(obj_id);
free(pobj_id);
if (obj)
struct got_object_id *obj_id = NULL;
struct got_blob_object *blob = NULL;
struct got_blame *blame = NULL;
- struct got_object_id *id = NULL, *parent_id = NULL;
+ struct got_object_id *id = NULL, *next_id = NULL;
int lineno;
struct got_commit_graph *graph = NULL;
goto done;
}
- err = got_commit_graph_open(&graph, start_commit_id, path, 0, repo);
+ err = got_commit_graph_open(&graph, start_commit_id, path, 1, repo);
if (err)
return err;
err = got_commit_graph_iter_start(graph, start_commit_id, repo);
id = NULL;
for (;;) {
- err = got_commit_graph_iter_next(&parent_id, graph);
+ err = got_commit_graph_iter_next(&next_id, graph);
if (err) {
if (err->code == GOT_ERR_ITER_COMPLETED) {
if (id)
err = blame_commit(blame, id,
- parent_id, path, repo, cb, arg);
+ path, repo, cb, arg);
else
err = NULL;
break;
continue;
}
if (id) {
- err = blame_commit(blame, id, parent_id, path, repo,
+ err = blame_commit(blame, id, path, repo,
cb, arg);
if (err) {
if (err->code == GOT_ERR_ITER_COMPLETED)
if (blame->nannotated == blame->nlines)
break;
}
- id = parent_id;
+ id = next_id;
}
if (id && blame->nannotated < blame->nlines) {
blob - 60ecdd0c932486f6f73a0a6a29d9048339d48eae
blob + 66015530063440d784e2152767420965b157b0de
--- regress/cmdline/blame.sh
+++ regress/cmdline/blame.sh
test_done "$testroot" "$ret"
}
+function test_blame_all_lines_replaced {
+ local testroot=`test_init blame_all_lines_replaced`
+
+ got checkout $testroot/repo $testroot/wt > /dev/null
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ jot 8 > $testroot/wt/alpha
+ (cd $testroot/wt && got commit -m "change 1" > /dev/null)
+ local commit1=`git_show_head $testroot/repo`
+ local short_commit1=`trim_obj_id 32 $commit1`
+ local author_time=`git_show_author_time $testroot/repo`
+
+ (cd $testroot/wt && got blame alpha > $testroot/stdout)
+
+ d=`date -r $author_time +"%g/%m/%d"`
+ echo "1) $short_commit1 $d $GOT_AUTHOR_8 1" > $testroot/stdout.expected
+ echo "2) $short_commit1 $d $GOT_AUTHOR_8 2" >> $testroot/stdout.expected
+ echo "3) $short_commit1 $d $GOT_AUTHOR_8 3" >> $testroot/stdout.expected
+ echo "4) $short_commit1 $d $GOT_AUTHOR_8 4" >> $testroot/stdout.expected
+ echo "5) $short_commit1 $d $GOT_AUTHOR_8 5" >> $testroot/stdout.expected
+ echo "6) $short_commit1 $d $GOT_AUTHOR_8 6" >> $testroot/stdout.expected
+ echo "7) $short_commit1 $d $GOT_AUTHOR_8 7" >> $testroot/stdout.expected
+ echo "8) $short_commit1 $d $GOT_AUTHOR_8 8" >> $testroot/stdout.expected
+
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ fi
+ test_done "$testroot" "$ret"
+
+}
+
+function test_blame_lines_shifted_up {
+ local testroot=`test_init blame_lines_shifted_up`
+
+ got checkout $testroot/repo $testroot/wt > /dev/null
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ jot 8 > $testroot/wt/alpha
+ (cd $testroot/wt && got commit -m "change 1" > /dev/null)
+ local commit1=`git_show_head $testroot/repo`
+ local short_commit1=`trim_obj_id 32 $commit1`
+ local author_time=`git_show_author_time $testroot/repo`
+
+ sed -i -e '/^[345]$/d' $testroot/wt/alpha
+ (cd $testroot/wt && got commit -m "change 2" > /dev/null)
+ local commit2=`git_show_head $testroot/repo`
+ local short_commit2=`trim_obj_id 32 $commit2`
+
+ jot 2 > $testroot/wt/alpha
+ echo foo >> $testroot/wt/alpha
+ echo bar >> $testroot/wt/alpha
+ echo baz >> $testroot/wt/alpha
+ jot 8 6 8 1 >> $testroot/wt/alpha
+ (cd $testroot/wt && got commit -m "change 3" > /dev/null)
+ local commit3=`git_show_head $testroot/repo`
+ local short_commit3=`trim_obj_id 32 $commit3`
+ local author_time=`git_show_author_time $testroot/repo`
+
+ (cd $testroot/wt && got blame alpha > $testroot/stdout)
+
+ d=`date -r $author_time +"%g/%m/%d"`
+ echo "1) $short_commit1 $d $GOT_AUTHOR_8 1" > $testroot/stdout.expected
+ echo "2) $short_commit1 $d $GOT_AUTHOR_8 2" >> $testroot/stdout.expected
+ echo "3) $short_commit3 $d $GOT_AUTHOR_8 foo" >> $testroot/stdout.expected
+ echo "4) $short_commit3 $d $GOT_AUTHOR_8 bar" >> $testroot/stdout.expected
+ echo "5) $short_commit3 $d $GOT_AUTHOR_8 baz" >> $testroot/stdout.expected
+ echo "6) $short_commit1 $d $GOT_AUTHOR_8 6" >> $testroot/stdout.expected
+ echo "7) $short_commit1 $d $GOT_AUTHOR_8 7" >> $testroot/stdout.expected
+ echo "8) $short_commit1 $d $GOT_AUTHOR_8 8" >> $testroot/stdout.expected
+
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ fi
+
+ test_done "$testroot" "$ret"
+}
+
+function test_blame_lines_shifted_down {
+ local testroot=`test_init blame_lines_shifted_down`
+
+ got checkout $testroot/repo $testroot/wt > /dev/null
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ jot 8 > $testroot/wt/alpha
+ (cd $testroot/wt && got commit -m "change 1" > /dev/null)
+ local commit1=`git_show_head $testroot/repo`
+ local short_commit1=`trim_obj_id 32 $commit1`
+ local author_time=`git_show_author_time $testroot/repo`
+
+ sed -i -e '/^8$/d' $testroot/wt/alpha
+ (cd $testroot/wt && got commit -m "change 2" > /dev/null)
+ local commit2=`git_show_head $testroot/repo`
+ local short_commit2=`trim_obj_id 32 $commit2`
+
+ jot 2 > $testroot/wt/alpha
+ echo foo >> $testroot/wt/alpha
+ echo bar >> $testroot/wt/alpha
+ echo baz >> $testroot/wt/alpha
+ jot 8 3 8 1 >> $testroot/wt/alpha
+ (cd $testroot/wt && got commit -m "change 3" > /dev/null)
+ local commit3=`git_show_head $testroot/repo`
+ local short_commit3=`trim_obj_id 32 $commit3`
+ local author_time=`git_show_author_time $testroot/repo`
+
+ (cd $testroot/wt && got blame alpha > $testroot/stdout)
+
+ d=`date -r $author_time +"%g/%m/%d"`
+ echo "01) $short_commit1 $d $GOT_AUTHOR_8 1" \
+ > $testroot/stdout.expected
+ echo "02) $short_commit1 $d $GOT_AUTHOR_8 2" \
+ >> $testroot/stdout.expected
+ echo "03) $short_commit3 $d $GOT_AUTHOR_8 foo" \
+ >> $testroot/stdout.expected
+ echo "04) $short_commit3 $d $GOT_AUTHOR_8 bar" \
+ >> $testroot/stdout.expected
+ echo "05) $short_commit3 $d $GOT_AUTHOR_8 baz" \
+ >> $testroot/stdout.expected
+ echo "06) $short_commit1 $d $GOT_AUTHOR_8 3" \
+ >> $testroot/stdout.expected
+ echo "07) $short_commit1 $d $GOT_AUTHOR_8 4" \
+ >> $testroot/stdout.expected
+ echo "08) $short_commit1 $d $GOT_AUTHOR_8 5" \
+ >> $testroot/stdout.expected
+ echo "09) $short_commit1 $d $GOT_AUTHOR_8 6" \
+ >> $testroot/stdout.expected
+ echo "10) $short_commit1 $d $GOT_AUTHOR_8 7" \
+ >> $testroot/stdout.expected
+ echo "11) $short_commit3 $d $GOT_AUTHOR_8 8" \
+ >> $testroot/stdout.expected
+
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ fi
+
+ test_done "$testroot" "$ret"
+}
+
+function test_blame_commit_subsumed {
+ local testroot=`test_init blame_commit_subsumed`
+
+ got checkout $testroot/repo $testroot/wt > /dev/null
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ cat > $testroot/wt/alpha <<EOF
+SUBDIRS = ext modules codedocs docs
+
+if WITH_PDNS_SERVER
+ SUBDIRS += pdns
+endif
+
+EXTRA_DIST =
+ INSTALL
+ NOTICE
+ README
+ .version
+ build-aux/gen-version
+ codedocs/doxygen.conf
+ contrib/powerdns.solaris.init.d
+ pdns/named.conf.parsertest
+ regression-tests/zones/unit.test
+
+ACLOCAL_AMFLAGS = -I m4
+
+dvi: # do nothing to build dvi
+EOF
+ (cd $testroot/wt && got commit -m "change 1" > /dev/null)
+ local commit1=`git_show_head $testroot/repo`
+ local short_commit1=`trim_obj_id 32 $commit1`
+ local author_time1=`git_show_author_time $testroot/repo`
+ local d1=`date -r $author_time1 +"%g/%m/%d"`
+
+ cat > $testroot/wt/alpha <<EOF
+SUBDIRS = ext modules codedocs docs
+
+SUBDIRS += pdns
+
+EXTRA_DIST =
+ INSTALL
+ NOTICE
+ README
+ .version
+ build-aux/gen-version
+ codedocs/doxygen.conf
+ contrib/powerdns.solaris.init.d
+ pdns/named.conf.parsertest
+ regression-tests/zones/unit.test
+
+ACLOCAL_AMFLAGS = -I m4
+
+dvi: # do nothing to build dvi
+EOF
+ # all changes in this commit will be subsumed by later commits
+ (cd $testroot/wt && got commit -m "change 2" > /dev/null)
+ local commit2=`git_show_head $testroot/repo`
+ local short_commit2=`trim_obj_id 32 $commit2`
+ local author_time2=`git_show_author_time $testroot/repo`
+ local d2=`date -r $author_time2 +"%g/%m/%d"`
+
+ cat > $testroot/wt/alpha <<EOF
+SUBDIRS = ext modules pdns codedocs docs
+
+EXTRA_DIST =
+ INSTALL
+ NOTICE
+ README
+ .version
+ build-aux/gen-version
+ codedocs/doxygen.conf
+ contrib/powerdns.solaris.init.d
+ pdns/named.conf.parsertest
+ regression-tests/zones/unit.test
+
+ACLOCAL_AMFLAGS = -I m4
+
+dvi: # do nothing to build dvi
+EOF
+ (cd $testroot/wt && got commit -m "change 3" > /dev/null)
+ local commit3=`git_show_head $testroot/repo`
+ local short_commit3=`trim_obj_id 32 $commit3`
+ local author_time3=`git_show_author_time $testroot/repo`
+ local d3=`date -r $author_time3 +"%g/%m/%d"`
+
+ cat > $testroot/wt/alpha <<EOF
+SUBDIRS = ext modules pdns codedocs docs
+
+EXTRA_DIST =
+ INSTALL
+ NOTICE
+ README
+ COPYING
+ codedocs/doxygen.conf
+ contrib/powerdns.solaris.init.d
+ pdns/named.conf.parsertest
+ regression-tests/zones/unit.test
+ builder-support/gen-version
+
+ACLOCAL_AMFLAGS = -I m4
+
+dvi: # do nothing to build dvi
+EOF
+ (cd $testroot/wt && got commit -m "change 4" > /dev/null)
+ local commit4=`git_show_head $testroot/repo`
+ local short_commit4=`trim_obj_id 32 $commit4`
+ local author_time4=`git_show_author_time $testroot/repo`
+ local d4=`date -r $author_time4 +"%g/%m/%d"`
+
+ (cd $testroot/wt && got blame alpha > $testroot/stdout)
+
+ echo -n "01) $short_commit3 $d3 $GOT_AUTHOR_8 " \
+ > $testroot/stdout.expected
+ echo "SUBDIRS = ext modules pdns codedocs docs" \
+ >> $testroot/stdout.expected
+ echo "02) $short_commit1 $d1 $GOT_AUTHOR_8 " \
+ >> $testroot/stdout.expected
+ echo -n "03) $short_commit1 $d1 $GOT_AUTHOR_8 " \
+ >> $testroot/stdout.expected
+ echo 'EXTRA_DIST =' >> $testroot/stdout.expected
+ echo -n "04) $short_commit1 $d1 $GOT_AUTHOR_8 " \
+ >> $testroot/stdout.expected
+ printf "\tINSTALL\n" >> $testroot/stdout.expected
+ echo -n "05) $short_commit1 $d1 $GOT_AUTHOR_8 " \
+ >> $testroot/stdout.expected
+ printf "\tNOTICE\n" >> $testroot/stdout.expected
+ echo -n "06) $short_commit1 $d1 $GOT_AUTHOR_8 " \
+ >> $testroot/stdout.expected
+ printf "\tREADME\n" >> $testroot/stdout.expected
+ echo -n "07) $short_commit4 $d4 $GOT_AUTHOR_8 " \
+ >> $testroot/stdout.expected
+ printf "\tCOPYING\n" >> $testroot/stdout.expected
+ echo -n "08) $short_commit1 $d1 $GOT_AUTHOR_8 " \
+ >> $testroot/stdout.expected
+ printf "\tcodedocs/doxygen.conf\n" >> $testroot/stdout.expected
+ echo -n "09) $short_commit1 $d1 $GOT_AUTHOR_8 " \
+ >> $testroot/stdout.expected
+ printf "\tcontrib/powerdns.solaris.init.d\n" \
+ >> $testroot/stdout.expected
+ echo -n "10) $short_commit1 $d1 $GOT_AUTHOR_8 " \
+ >> $testroot/stdout.expected
+ printf "\tpdns/named.conf.parsertest\n" >> $testroot/stdout.expected
+ echo -n "11) $short_commit1 $d1 $GOT_AUTHOR_8 " \
+ >> $testroot/stdout.expected
+ printf "\tregression-tests/zones/unit.test\n" \
+ >> $testroot/stdout.expected
+ echo -n "12) $short_commit4 $d4 $GOT_AUTHOR_8 " \
+ >> $testroot/stdout.expected
+ printf "\tbuilder-support/gen-version\n" >> $testroot/stdout.expected
+ echo "13) $short_commit1 $d1 $GOT_AUTHOR_8 " \
+ >> $testroot/stdout.expected
+ echo -n "14) $short_commit1 $d1 $GOT_AUTHOR_8 " \
+ >> $testroot/stdout.expected
+ echo "ACLOCAL_AMFLAGS = -I m4" \
+ >> $testroot/stdout.expected
+ echo "15) $short_commit1 $d1 $GOT_AUTHOR_8 " \
+ >> $testroot/stdout.expected
+ echo -n "16) $short_commit1 $d1 $GOT_AUTHOR_8 " \
+ >> $testroot/stdout.expected
+ echo "dvi: # do nothing to build dvi" \
+ >> $testroot/stdout.expected
+
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ #diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "xfail: line 3 has wrong annotation"
+ return 1
+ fi
+ test_done "$testroot" "$ret"
+}
+
run_test test_blame_basic
run_test test_blame_tag
run_test test_blame_file_single_line
run_test test_blame_file_single_line_no_newline
+run_test test_blame_all_lines_replaced
+run_test test_blame_lines_shifted_up
+run_test test_blame_lines_shifted_down
+run_test test_blame_commit_subsumed