Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.kernel.org/pub/scm/git/git.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/blame-options.txt10
-rw-r--r--Documentation/git-blame.txt2
-rw-r--r--blame.c40
-rw-r--r--t/annotate-tests.sh14
4 files changed, 46 insertions, 20 deletions
diff --git a/Documentation/blame-options.txt b/Documentation/blame-options.txt
index 9a663535f4..95599bd6e5 100644
--- a/Documentation/blame-options.txt
+++ b/Documentation/blame-options.txt
@@ -64,11 +64,11 @@ include::line-range-format.txt[]
manual page.
--contents <file>::
- When <rev> is not specified, the command annotates the
- changes starting backwards from the working tree copy.
- This flag makes the command pretend as if the working
- tree copy has the contents of the named file (specify
- `-` to make the command read from the standard input).
+ Pretend the file being annotated has a commit with the
+ contents from the named file and a parent of <rev>,
+ defaulting to HEAD when no <rev> is specified. You may
+ specify '-' to make the command read from the standard
+ input for the file contents.
--date <format>::
Specifies the format used to output dates. If --date is not
diff --git a/Documentation/git-blame.txt b/Documentation/git-blame.txt
index 4400a17330..f69a871a96 100644
--- a/Documentation/git-blame.txt
+++ b/Documentation/git-blame.txt
@@ -12,7 +12,7 @@ SYNOPSIS
[-L <range>] [-S <revs-file>] [-M] [-C] [-C] [-C] [--since=<date>]
[--ignore-rev <rev>] [--ignore-revs-file <file>]
[--color-lines] [--color-by-age] [--progress] [--abbrev=<n>]
- [<rev> | --contents <file> | --reverse <rev>..<rev>] [--] <file>
+ [ --contents <file> ] [<rev> | --reverse <rev>..<rev>] [--] <file>
DESCRIPTION
-----------
diff --git a/blame.c b/blame.c
index e45d8a3bf9..63ce7eb630 100644
--- a/blame.c
+++ b/blame.c
@@ -177,12 +177,12 @@ static void set_commit_buffer_from_strbuf(struct repository *r,
static struct commit *fake_working_tree_commit(struct repository *r,
struct diff_options *opt,
const char *path,
- const char *contents_from)
+ const char *contents_from,
+ struct object_id *oid)
{
struct commit *commit;
struct blame_origin *origin;
struct commit_list **parent_tail, *parent;
- struct object_id head_oid;
struct strbuf buf = STRBUF_INIT;
const char *ident;
time_t now;
@@ -198,10 +198,7 @@ static struct commit *fake_working_tree_commit(struct repository *r,
commit->date = now;
parent_tail = &commit->parents;
- if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL))
- die("no such ref: HEAD");
-
- parent_tail = append_parent(r, parent_tail, &head_oid);
+ parent_tail = append_parent(r, parent_tail, oid);
append_merge_parents(r, parent_tail);
verify_working_tree_path(r, commit, path);
@@ -2772,22 +2769,37 @@ void setup_scoreboard(struct blame_scoreboard *sb,
sb->commits.compare = compare_commits_by_reverse_commit_date;
}
- if (sb->final && sb->contents_from)
- die(_("cannot use --contents with final commit object name"));
-
if (sb->reverse && sb->revs->first_parent_only)
sb->revs->children.name = NULL;
- if (!sb->final) {
+ if (sb->contents_from || !sb->final) {
+ struct object_id head_oid, *parent_oid;
+
/*
- * "--not A B -- path" without anything positive;
- * do not default to HEAD, but use the working tree
- * or "--contents".
+ * Build a fake commit at the top of the history, when
+ * (1) "git blame [^A] --path", i.e. with no positive end
+ * of the history range, in which case we build such
+ * a fake commit on top of the HEAD to blame in-tree
+ * modifications.
+ * (2) "git blame --contents=file [A] -- path", with or
+ * without positive end of the history range but with
+ * --contents, in which case we pretend that there is
+ * a fake commit on top of the positive end (defaulting to
+ * HEAD) that has the given contents in the path.
*/
+ if (sb->final) {
+ parent_oid = &sb->final->object.oid;
+ } else {
+ if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL))
+ die("no such ref: HEAD");
+ parent_oid = &head_oid;
+ }
+
setup_work_tree();
sb->final = fake_working_tree_commit(sb->repo,
&sb->revs->diffopt,
- sb->path, sb->contents_from);
+ sb->path, sb->contents_from,
+ parent_oid);
add_pending_object(sb->revs, &(sb->final->object), ":");
}
diff --git a/t/annotate-tests.sh b/t/annotate-tests.sh
index f1b9a6ce4d..b35be20cf3 100644
--- a/t/annotate-tests.sh
+++ b/t/annotate-tests.sh
@@ -72,6 +72,16 @@ test_expect_success 'blame 1 author' '
check_count A 2
'
+test_expect_success 'blame with --contents' '
+ check_count --contents=file A 2
+'
+
+test_expect_success 'blame with --contents changed' '
+ echo "1A quick brown fox jumps over the" >contents &&
+ echo "another lazy dog" >>contents &&
+ check_count --contents=contents A 1 "Not Committed Yet" 1
+'
+
test_expect_success 'blame in a bare repo without starting commit' '
git clone --bare . bare.git &&
(
@@ -98,6 +108,10 @@ test_expect_success 'blame 2 authors' '
check_count A 2 B 2
'
+test_expect_success 'blame with --contents and revision' '
+ check_count -h testTag --contents=file A 2 "Not Committed Yet" 2
+'
+
test_expect_success 'setup B1 lines (branch1)' '
git checkout -b branch1 main &&
echo "3A slow green fox jumps into the" >>file &&