From 62476c8e331a22e224d87c18830913129f5f303b Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 31 Oct 2006 14:22:34 -0800 Subject: [PATCH] Introduce a new revision set operator ^! This is a shorthand for " --not ^@", i.e. "include this commit but exclude any of its parents". When a new file $F is introduced by revision $R, this notation can be used to find a copy-and-paste from existing file in the parents of that revision without annotating the ancestry of the lines that were copied from: git pickaxe -f -C $R^! -- $F Signed-off-by: Junio C Hamano --- Documentation/git-pickaxe.txt | 38 +++++++++++++++++++++++++++++++++ Documentation/git-rev-parse.txt | 13 ++++++++--- revision.c | 7 ++++++ 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/Documentation/git-pickaxe.txt b/Documentation/git-pickaxe.txt index 6d22fd9e9..c08fdec19 100644 --- a/Documentation/git-pickaxe.txt +++ b/Documentation/git-pickaxe.txt @@ -111,6 +111,44 @@ The contents of the actual line is output after the above header, prefixed by a TAB. This is to allow adding more header elements later. + +SPECIFIYING RANGES +------------------ + +Unlike `git-blame` and `git-annotate` in older git, the extent +of annotation can be limited to both line ranges and revision +ranges. When you are interested in finding the origin for +ll. 40-60 for file `foo`, you can use `-L` option like this: + + git pickaxe -L 40,60 foo + +When you are not interested in changes older than the version +v2.6.18, or changes older than 3 weeks, you can use revision +range specifiers similar to `git-rev-list`: + + git pickaxe v2.6.18.. -- foo + git pickaxe --since=3.weeks -- foo + +When revision range specifiers are used to limit the annotation, +lines that have not changed since the range boundary (either the +commit v2.6.18 or the most recent commit that is more than 3 +weeks old in the above example) are blamed for that range +boundary commit. + +A particularly useful way is to see if an added file have lines +created by copy-and-paste from existing files. Sometimes this +indicates that the developer was being sloppy and did not +refactor the code properly. You can first find the commit that +introduced the file with: + + git log --diff-filter=A --pretty=short -- foo + +and then annotate the change between the commit and its +parents, using `commit{caret}!` notation: + + git pickaxe -C -C -f $commit^! -- foo + + SEE ALSO -------- gitlink:git-blame[1] diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt index 5d4257062..cda80b18f 100644 --- a/Documentation/git-rev-parse.txt +++ b/Documentation/git-rev-parse.txt @@ -222,14 +222,21 @@ of `r1` and `r2` and is defined as It it the set of commits that are reachable from either one of `r1` or `r2` but not from both. -Here are a few examples: +Two other shorthands for naming a set that is formed by a commit +and its parent commits exists. `r1{caret}@` notation means all +parents of `r1`. `r1{caret}!` includes commit `r1` but excludes +its all parents. + +Here are a handful examples: D A B D D F A B C D F - ^A G B D + ^A G B D ^A F B C F G...I C D F G I - ^B G I C D F G I + ^B G I C D F G I + F^@ A B C + F^! H D F H Author ------ diff --git a/revision.c b/revision.c index f1e0caaae..b021d3354 100644 --- a/revision.c +++ b/revision.c @@ -660,6 +660,13 @@ int handle_revision_arg(const char *arg, struct rev_info *revs, return 0; *dotdot = '^'; } + dotdot = strstr(arg, "^!"); + if (dotdot && !dotdot[2]) { + *dotdot = 0; + if (!add_parents_only(revs, arg, flags ^ UNINTERESTING)) + *dotdot = '^'; + } + local_flags = 0; if (*arg == '^') { local_flags = UNINTERESTING; -- 2.30.2