Commit Diff


commit - 75b7a700d9d14ef8eb902961255212acbedef164
commit + d68a0a7de13af722c55099582019c03240e13320
blob - c787aadf05e2afab61bd34976f7349912252e6da
blob + 5255d076c915accf159940978b821d06803ff2f8
--- include/got_blame.h
+++ include/got_blame.h
@@ -28,6 +28,15 @@ const struct got_error *got_blame(const char *, struct
  * The callback receives the provided void * argument, the total number
  * of lines of the annotated file, a line number, and the ID of the commit
  * which last changed this line.
+ *
+ * The callback is invoked for each commit as history is traversed.
+ * If no changes to the file were made in a commit, line number -1 and
+ * commit ID NULL will be reported.
+ *
+ * If the callback returns GOT_ERR_ITER_COMPLETED, the blame operation
+ * will be aborted and this function returns NULL.
+ * If the callback returns any other error, the blame operation will be
+ * aborted and the callback's error is returned from this function.
  */
 const struct got_error *got_blame_incremental(const char *,
     struct got_object_id *, struct got_repository *,
blob - c57eaabaef3b116c178390d76ee554ebbb2e16e9
blob + a6ac4fec63e6c9041d7c5cc75a0c8df7a3cf86d2
--- lib/blame.c
+++ lib/blame.c
@@ -132,7 +132,8 @@ blame_commit(struct got_blame *blame, struct got_objec
 					goto done;
 			}
 		}
-	}
+	} else if (cb)
+		err = cb(arg, blame->nlines, -1, NULL);
 done:
 	if (obj)
 		got_object_close(obj);
blob - 581999675170afab7819c5cb96bad859a29b2545
blob + 400eda3f35aa381e3cfb172ace64f7974e8ed066
--- tog/tog.c
+++ tog/tog.c
@@ -1135,17 +1135,26 @@ blame_cb(void *arg, int nlines, int lineno, struct got
 	struct tog_blame_cb_args *a = arg;
 	struct tog_blame_line *line;
 	int eof;
-
-	if (*a->done)
-		return got_error(GOT_ERR_ITER_COMPLETED);
 
-	if (nlines != a->nlines || lineno < 1 || lineno > a->nlines)
+	if (nlines != a->nlines ||
+	    (lineno != -1 && lineno < 1) || lineno > a->nlines)
 		return got_error(GOT_ERR_RANGE);
 
 	if (pthread_mutex_lock(a->mutex) != 0)
 		return got_error_from_errno();
 
+	if (*a->done) {	/* user has quit the blame view */
+		err = got_error(GOT_ERR_ITER_COMPLETED);
+		goto done;
+	}
+
+	if (lineno == -1)
+		goto done; /* no change in this commit */
+
 	line = &a->lines[lineno - 1];
+	if (line->annotated)
+		goto done;
+
 	line->id = got_object_id_dup(id);
 	if (line->id == NULL) {
 		err = got_error_from_errno();