mirror of
https://github.com/git/git.git
synced 2026-03-14 10:53:25 +01:00
Merge branch 'jc/pickaxe' into next
* jc/pickaxe: Introduce a new revision set operator <rev>^! git-pickaxe: cache one already found path per commit.
This commit is contained in:
@@ -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]
|
||||
|
||||
@@ -239,14 +239,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
|
||||
------
|
||||
|
||||
@@ -141,6 +141,8 @@ static int cmp_suspect(struct origin *a, struct origin *b)
|
||||
return strcmp(a->path, b->path);
|
||||
}
|
||||
|
||||
#define cmp_suspect(a, b) ( ((a)==(b)) ? 0 : cmp_suspect(a,b) )
|
||||
|
||||
static void sanity_check_refcnt(struct scoreboard *);
|
||||
|
||||
static void coalesce(struct scoreboard *sb)
|
||||
@@ -213,6 +215,12 @@ static struct origin *find_origin(struct scoreboard *sb,
|
||||
struct diff_options diff_opts;
|
||||
const char *paths[2];
|
||||
|
||||
if (parent->util) {
|
||||
struct origin *cached = parent->util;
|
||||
if (!strcmp(cached->path, origin->path))
|
||||
return origin_incref(cached);
|
||||
}
|
||||
|
||||
/* See if the origin->path is different between parent
|
||||
* and origin first. Most of the time they are the
|
||||
* same and diff-tree is fairly efficient about this.
|
||||
@@ -259,6 +267,12 @@ static struct origin *find_origin(struct scoreboard *sb,
|
||||
}
|
||||
}
|
||||
diff_flush(&diff_opts);
|
||||
if (porigin) {
|
||||
origin_incref(porigin);
|
||||
if (parent->util)
|
||||
origin_decref(parent->util);
|
||||
parent->util = porigin;
|
||||
}
|
||||
return porigin;
|
||||
}
|
||||
|
||||
@@ -905,7 +919,7 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)
|
||||
continue;
|
||||
if (parse_commit(p))
|
||||
continue;
|
||||
porigin = find(sb, parent->item, origin);
|
||||
porigin = find(sb, p, origin);
|
||||
if (!porigin)
|
||||
continue;
|
||||
if (!hashcmp(porigin->blob_sha1, origin->blob_sha1)) {
|
||||
@@ -1371,8 +1385,10 @@ static void sanity_check_refcnt(struct scoreboard *sb)
|
||||
ent->suspect->refcnt = -ent->suspect->refcnt;
|
||||
}
|
||||
for (ent = sb->ent; ent; ent = ent->next) {
|
||||
/* then pick each and see if they have the the
|
||||
* correct refcnt
|
||||
/* then pick each and see if they have the the correct
|
||||
* refcnt; note that ->util caching means origin's refcnt
|
||||
* may well be greater than the number of blame entries
|
||||
* that use it.
|
||||
*/
|
||||
int found;
|
||||
struct blame_entry *e;
|
||||
@@ -1386,7 +1402,7 @@ static void sanity_check_refcnt(struct scoreboard *sb)
|
||||
continue;
|
||||
found++;
|
||||
}
|
||||
if (suspect->refcnt != found)
|
||||
if (suspect->refcnt < found)
|
||||
baa = 1;
|
||||
}
|
||||
if (baa) {
|
||||
|
||||
@@ -657,6 +657,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;
|
||||
|
||||
Reference in New Issue
Block a user