Skip to content

Commit

Permalink
[PATCH] Introducing software archaeologist's tool "pickaxe".
Browse files Browse the repository at this point in the history
This steals the "pickaxe" feature from JIT and make it available
to the bare Plumbing layer.  From the command line, the user
gives a string he is intersted in.

Using the diff-core infrastructure previously introduced, it
filters the differences to limit the output only to the diffs
between <src> and <dst> where the string appears only in one but
not in the other.  For example:

 $ ./git-rev-list HEAD | ./git-diff-tree -Sdiff-tree-helper --stdin -M

would show the diffs that touch the string "diff-tree-helper".

In real software-archaeologist application, you would typically
look for a few to several lines of code and see where that code
came from.

The "pickaxe" module runs after "rename/copy detection" module,
so it even crosses the file rename boundary, as the above
example demonstrates.

Signed-off-by: Junio C Hamano <junkio@cox.net>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
  • Loading branch information
Junio C Hamano authored and Linus Torvalds committed May 21, 2005
1 parent 427dcb4 commit 52e9578
Show file tree
Hide file tree
Showing 14 changed files with 140 additions and 51 deletions.
6 changes: 5 additions & 1 deletion Documentation/git-diff-cache.txt
Expand Up @@ -9,7 +9,7 @@ git-diff-cache - Compares content and mode of blobs between the cache and reposi

SYNOPSIS
--------
'git-diff-cache' [-p] [-r] [-z] [-m] [-M] [-R] [-C] [--cached] <tree-ish>
'git-diff-cache' [-p] [-r] [-z] [-m] [-M] [-R] [-C] [-S<string>] [--cached] <tree-ish>

DESCRIPTION
-----------
Expand Down Expand Up @@ -39,6 +39,10 @@ OPTIONS
-C::
Detect copies as well as renames; implies -p.

-S<string>::
Look for differences that contains the change in <string>.


-R::
Output diff in reverse.

Expand Down
6 changes: 5 additions & 1 deletion Documentation/git-diff-files.txt
Expand Up @@ -9,7 +9,7 @@ git-diff-files - Compares files in the working tree and the cache

SYNOPSIS
--------
'git-diff-files' [-p] [-q] [-r] [-z] [-M] [-C] [-R] [<pattern>...]
'git-diff-files' [-p] [-q] [-r] [-z] [-M] [-C] [-R] [-S<string>] [<pattern>...]

DESCRIPTION
-----------
Expand All @@ -35,6 +35,10 @@ OPTIONS
-C::
Detect copies as well as renames; implies -p.

-S<string>::
Look for differences that contains the change in <string>.


-r::
This flag does not mean anything. It is there only to match
git-diff-tree. Unlike git-diff-tree, git-diff-files always looks
Expand Down
6 changes: 5 additions & 1 deletion Documentation/git-diff-helper.txt
Expand Up @@ -9,7 +9,7 @@ git-diff-helper - Generates patch format output for git-diff-*

SYNOPSIS
--------
'git-diff-helper' [-z] [-R] [-M] [-C]
'git-diff-helper' [-z] [-R] [-M] [-C] [-S<string>]

DESCRIPTION
-----------
Expand Down Expand Up @@ -37,6 +37,10 @@ OPTIONS
-C::
Detect copies as well as renames.

-S<string>::
Look for differences that contains the change in <string>.


See Also
--------
The section on generating patches in link:git-diff-cache.html[git-diff-cache]
Expand Down
5 changes: 4 additions & 1 deletion Documentation/git-diff-tree.txt
Expand Up @@ -9,7 +9,7 @@ git-diff-tree - Compares the content and mode of blobs found via two tree object

SYNOPSIS
--------
'git-diff-tree' [-p] [-r] [-z] [--stdin] [-M] [-R] [-C] [-m] [-s] [-v] <tree-ish> <tree-ish> [<pattern>]\*
'git-diff-tree' [-p] [-r] [-z] [--stdin] [-M] [-R] [-C] [-S<string>] [-m] [-s] [-v] <tree-ish> <tree-ish> [<pattern>]\*

DESCRIPTION
-----------
Expand Down Expand Up @@ -43,6 +43,9 @@ OPTIONS
-R::
Output diff in reverse.

-S<string>::
Look for differences that contains the change in <string>.

-r::
recurse

Expand Down
3 changes: 2 additions & 1 deletion Makefile
Expand Up @@ -45,7 +45,7 @@ LIB_H += strbuf.h
LIB_OBJS += strbuf.o

LIB_H += diff.h
LIB_OBJS += diff.o diffcore-rename.o
LIB_OBJS += diff.o diffcore-rename.o diffcore-pickaxe.o

LIB_OBJS += gitenv.o

Expand Down Expand Up @@ -125,6 +125,7 @@ strbuf.o: $(LIB_H)
gitenv.o: $(LIB_H)
diff.o: $(LIB_H)
diffcore-rename.o : $(LIB_H)
diffcore-pickaxe.o : $(LIB_H)

test: all
make -C t/ all
Expand Down
11 changes: 8 additions & 3 deletions diff-cache.c
Expand Up @@ -8,6 +8,7 @@ static int line_termination = '\n';
static int detect_rename = 0;
static int reverse_diff = 0;
static int diff_score_opt = 0;
static char *pickaxe = 0;

/* A file entry went away or appeared */
static void show_file(const char *prefix, struct cache_entry *ce, unsigned char *sha1, unsigned int mode)
Expand Down Expand Up @@ -153,7 +154,7 @@ static void mark_merge_entries(void)
}

static char *diff_cache_usage =
"git-diff-cache [-p] [-r] [-z] [-m] [-M] [-C] [-R] [--cached] <tree-ish>";
"git-diff-cache [-p] [-r] [-z] [-m] [-M] [-C] [-R] [-S<string>] [--cached] <tree-ish>";

int main(int argc, char **argv)
{
Expand Down Expand Up @@ -194,6 +195,10 @@ int main(int argc, char **argv)
reverse_diff = 1;
continue;
}
if (!strcmp(arg, "-S")) {
pickaxe = arg + 2;
continue;
}
if (!strcmp(arg, "-m")) {
match_nonexisting = 1;
continue;
Expand All @@ -208,8 +213,8 @@ int main(int argc, char **argv)
if (argc != 2 || get_sha1(argv[1], tree_sha1))
usage(diff_cache_usage);

diff_setup(detect_rename, diff_score_opt, reverse_diff,
(generate_patch ? -1 : line_termination),
diff_setup(detect_rename, diff_score_opt, pickaxe,
reverse_diff, (generate_patch ? -1 : line_termination),
NULL, 0);

mark_merge_entries();
Expand Down
9 changes: 6 additions & 3 deletions diff-files.c
Expand Up @@ -7,13 +7,14 @@
#include "diff.h"

static const char *diff_files_usage =
"git-diff-files [-p] [-q] [-r] [-z] [-M] [-C] [-R] [paths...]";
"git-diff-files [-p] [-q] [-r] [-z] [-M] [-C] [-R] [-S<string>] [paths...]";

static int generate_patch = 0;
static int line_termination = '\n';
static int detect_rename = 0;
static int reverse_diff = 0;
static int diff_score_opt = 0;
static char *pickaxe = 0;
static int silent = 0;

static int matches_pathspec(struct cache_entry *ce, char **spec, int cnt)
Expand Down Expand Up @@ -67,6 +68,8 @@ int main(int argc, char **argv)
line_termination = 0;
else if (!strcmp(argv[1], "-R"))
reverse_diff = 1;
else if (!strcmp(argv[1], "-S"))
pickaxe = argv[1] + 2;
else if (!strncmp(argv[1], "-M", 2)) {
diff_score_opt = diff_scoreopt_parse(argv[1]);
detect_rename = generate_patch = 1;
Expand All @@ -89,8 +92,8 @@ int main(int argc, char **argv)
exit(1);
}

diff_setup(detect_rename, diff_score_opt, reverse_diff,
(generate_patch ? -1 : line_termination),
diff_setup(detect_rename, diff_score_opt, pickaxe,
reverse_diff, (generate_patch ? -1 : line_termination),
NULL, 0);

for (i = 0; i < entries; i++) {
Expand Down
10 changes: 7 additions & 3 deletions diff-helper.c
Expand Up @@ -9,6 +9,7 @@
static int detect_rename = 0;
static int diff_score_opt = 0;
static int generate_patch = 1;
static char *pickaxe = 0;

static int parse_oneside_change(const char *cp, int *mode,
unsigned char *sha1, char *path)
Expand Down Expand Up @@ -93,7 +94,7 @@ static int parse_diff_raw_output(const char *buf)
}

static const char *diff_helper_usage =
"git-diff-helper [-z] [-R] [-M] [-C] paths...";
"git-diff-helper [-z] [-R] [-M] [-C] [-S<string>] paths...";

int main(int ac, const char **av) {
struct strbuf sb;
Expand All @@ -117,14 +118,17 @@ int main(int ac, const char **av) {
detect_rename = 2;
diff_score_opt = diff_scoreopt_parse(av[1]);
}
else if (av[1][1] == 'S') {
pickaxe = av[1] + 2;
}
else
usage(diff_helper_usage);
ac--; av++;
}
/* the remaining parameters are paths patterns */

diff_setup(detect_rename, diff_score_opt, reverse,
(generate_patch ? -1 : line_termination),
diff_setup(detect_rename, diff_score_opt, pickaxe,
reverse, (generate_patch ? -1 : line_termination),
av+1, ac-1);

while (1) {
Expand Down
15 changes: 10 additions & 5 deletions diff-tree.c
Expand Up @@ -13,6 +13,7 @@ static int generate_patch = 0;
static int detect_rename = 0;
static int reverse_diff = 0;
static int diff_score_opt = 0;
static char *pickaxe = 0;
static const char *header = NULL;
static const char *header_prefix = "";

Expand Down Expand Up @@ -271,8 +272,8 @@ static int diff_tree_sha1_top(const unsigned char *old,
{
int ret;

diff_setup(detect_rename, diff_score_opt, reverse_diff,
(generate_patch ? -1 : line_termination),
diff_setup(detect_rename, diff_score_opt, pickaxe,
reverse_diff, (generate_patch ? -1 : line_termination),
NULL, 0);
ret = diff_tree_sha1(old, new, base);
diff_flush();
Expand All @@ -285,8 +286,8 @@ static int diff_root_tree(const unsigned char *new, const char *base)
void *tree;
unsigned long size;

diff_setup(detect_rename, diff_score_opt, reverse_diff,
(generate_patch ? -1 : line_termination),
diff_setup(detect_rename, diff_score_opt, pickaxe,
reverse_diff, (generate_patch ? -1 : line_termination),
NULL, 0);
tree = read_object_with_reference(new, "tree", &size, NULL);
if (!tree)
Expand Down Expand Up @@ -430,7 +431,7 @@ static int diff_tree_stdin(char *line)
}

static char *diff_tree_usage =
"git-diff-tree [-p] [-r] [-z] [--stdin] [-M] [-C] [-R] [-m] [-s] [-v] <tree-ish> <tree-ish>";
"git-diff-tree [-p] [-r] [-z] [--stdin] [-M] [-C] [-R] [-S<string>] [-m] [-s] [-v] <tree-ish> <tree-ish>";

int main(int argc, char **argv)
{
Expand Down Expand Up @@ -473,6 +474,10 @@ int main(int argc, char **argv)
recursive = generate_patch = 1;
continue;
}
if (!strncmp(arg, "-S", 2)) {
pickaxe = arg + 2;
continue;
}
if (!strncmp(arg, "-M", 2)) {
detect_rename = recursive = generate_patch = 1;
diff_score_opt = diff_scoreopt_parse(arg);
Expand Down
23 changes: 14 additions & 9 deletions diff.c
Expand Up @@ -17,6 +17,7 @@ static int reverse_diff;
static int diff_raw_output = -1;
static const char **pathspec;
static int speccnt;
static const char *pickaxe;
static int minimum_score;

static const char *external_diff(void)
Expand Down Expand Up @@ -511,8 +512,9 @@ int diff_scoreopt_parse(const char *opt)
return MAX_SCORE * num / scale;
}

void diff_setup(int detect_rename_, int minimum_score_, int reverse_diff_,
int diff_raw_output_,
void diff_setup(int detect_rename_, int minimum_score_,
char *pickaxe_,
int reverse_diff_, int diff_raw_output_,
const char **pathspec_, int speccnt_)
{
detect_rename = detect_rename_;
Expand All @@ -521,15 +523,16 @@ void diff_setup(int detect_rename_, int minimum_score_, int reverse_diff_,
diff_raw_output = diff_raw_output_;
speccnt = speccnt_;
minimum_score = minimum_score_ ? : DEFAULT_MINIMUM_SCORE;
pickaxe = pickaxe_;
}

static struct diff_queue_struct queued_diff;

struct diff_file_pair *diff_queue(struct diff_queue_struct *queue,
struct diff_filepair *diff_queue(struct diff_queue_struct *queue,
struct diff_filespec *one,
struct diff_filespec *two)
{
struct diff_file_pair *dp = xmalloc(sizeof(*dp));
struct diff_filepair *dp = xmalloc(sizeof(*dp));
dp->one = one;
dp->two = two;
dp->xfrm_msg = 0;
Expand All @@ -549,7 +552,7 @@ static const char *git_object_type(unsigned mode)
return S_ISDIR(mode) ? "tree" : "blob";
}

static void diff_flush_raw(struct diff_file_pair *p)
static void diff_flush_raw(struct diff_filepair *p)
{
struct diff_filespec *it;
int addremove;
Expand Down Expand Up @@ -583,7 +586,7 @@ static void diff_flush_raw(struct diff_file_pair *p)
sha1_to_hex(it->sha1), it->path, diff_raw_output);
}

static void diff_flush_patch(struct diff_file_pair *p)
static void diff_flush_patch(struct diff_filepair *p)
{
const char *name, *other;

Expand All @@ -600,7 +603,7 @@ static int identical(struct diff_filespec *one, struct diff_filespec *two)
{
/* This function is written stricter than necessary to support
* the currently implemented transformers, but the idea is to
* let transformers to produce diff_file_pairs any way they want,
* let transformers to produce diff_filepairs any way they want,
* and filter and clean them up here before producing the output.
*/

Expand All @@ -623,7 +626,7 @@ static int identical(struct diff_filespec *one, struct diff_filespec *two)
return 0;
}

static void diff_flush_one(struct diff_file_pair *p)
static void diff_flush_one(struct diff_filepair *p)
{
if (identical(p->one, p->two))
return;
Expand All @@ -640,11 +643,13 @@ void diff_flush(void)

if (detect_rename)
diff_detect_rename(q, detect_rename, minimum_score);
if (pickaxe)
diff_pickaxe(q, pickaxe);
for (i = 0; i < q->nr; i++)
diff_flush_one(q->queue[i]);

for (i = 0; i < q->nr; i++) {
struct diff_file_pair *p = q->queue[i];
struct diff_filepair *p = q->queue[i];
diff_free_filespec_data(p->one);
diff_free_filespec_data(p->two);
free(p->xfrm_msg);
Expand Down
1 change: 1 addition & 0 deletions diff.h
Expand Up @@ -20,6 +20,7 @@ extern void diff_unmerge(const char *path);
extern int diff_scoreopt_parse(const char *opt);

extern void diff_setup(int detect_rename, int minimum_score,
char *pickaxe,
int reverse, int raw_output,
const char **spec, int cnt);

Expand Down

0 comments on commit 52e9578

Please sign in to comment.