mirror of
https://github.com/git/git.git
synced 2025-03-14 21:13:01 +00:00
git-blame: Make the output human readable
The default output mode is slightly different from git-annotate's. However, git-annotate's output mode can be obtained by using the '-c' flag. Signed-off-by: Fredrik Kuivinen <freku045@student.liu.se> Signed-off-by: Junio C Hamano <junkio@cox.net>
This commit is contained in:
parent
ea5ed3abce
commit
ea4c7f9bf6
4
Makefile
4
Makefile
@ -534,6 +534,10 @@ git-rev-list$X: rev-list.o $(LIB_FILE)
|
||||
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
|
||||
$(LIBS) $(OPENSSL_LIBSSL)
|
||||
|
||||
git-blame$X: blame.o $(LIB_FILE)
|
||||
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
|
||||
$(LIBS) -lm
|
||||
|
||||
init-db.o: init-db.c
|
||||
$(CC) -c $(ALL_CFLAGS) \
|
||||
-DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"' $*.c
|
||||
|
162
blame.c
162
blame.c
@ -5,6 +5,7 @@
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "cache.h"
|
||||
#include "refs.h"
|
||||
@ -17,8 +18,15 @@
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
struct commit **blame_lines;
|
||||
int num_blame_lines;
|
||||
static const char blame_usage[] = "[-c] [-l] [--] file [commit]\n"
|
||||
" -c, --compability Use the same output mode as git-annotate (Default: off)\n"
|
||||
" -l, --long Show long commit SHA1 (Default: off)\n"
|
||||
" -h, --help This message";
|
||||
|
||||
static struct commit **blame_lines;
|
||||
static int num_blame_lines;
|
||||
static char* blame_contents;
|
||||
static int blame_len;
|
||||
|
||||
struct util_info {
|
||||
int *line_map;
|
||||
@ -390,9 +398,8 @@ static void init_first_commit(struct commit* commit, const char* filename)
|
||||
alloc_line_map(commit);
|
||||
|
||||
util = commit->object.util;
|
||||
num_blame_lines = util->num_lines;
|
||||
|
||||
for (i = 0; i < num_blame_lines; i++)
|
||||
for (i = 0; i < util->num_lines; i++)
|
||||
util->line_map[i] = i;
|
||||
}
|
||||
|
||||
@ -414,6 +421,9 @@ static void process_commits(struct rev_info *rev, const char *path,
|
||||
util = commit->object.util;
|
||||
num_blame_lines = util->num_lines;
|
||||
blame_lines = xmalloc(sizeof(struct commit *) * num_blame_lines);
|
||||
blame_contents = util->buf;
|
||||
blame_len = util->size;
|
||||
|
||||
for (i = 0; i < num_blame_lines; i++)
|
||||
blame_lines[i] = NULL;
|
||||
|
||||
@ -501,32 +511,128 @@ static void process_commits(struct rev_info *rev, const char *path,
|
||||
} while ((commit = get_revision(rev)) != NULL);
|
||||
}
|
||||
|
||||
struct commit_info
|
||||
{
|
||||
char* author;
|
||||
char* author_mail;
|
||||
unsigned long author_time;
|
||||
char* author_tz;
|
||||
};
|
||||
|
||||
static void get_commit_info(struct commit* commit, struct commit_info* ret)
|
||||
{
|
||||
int len;
|
||||
char* tmp;
|
||||
static char author_buf[1024];
|
||||
|
||||
tmp = strstr(commit->buffer, "\nauthor ") + 8;
|
||||
len = index(tmp, '\n') - tmp;
|
||||
ret->author = author_buf;
|
||||
memcpy(ret->author, tmp, len);
|
||||
|
||||
tmp = ret->author;
|
||||
tmp += len;
|
||||
*tmp = 0;
|
||||
while(*tmp != ' ')
|
||||
tmp--;
|
||||
ret->author_tz = tmp+1;
|
||||
|
||||
*tmp = 0;
|
||||
while(*tmp != ' ')
|
||||
tmp--;
|
||||
ret->author_time = strtoul(tmp, NULL, 10);
|
||||
|
||||
*tmp = 0;
|
||||
while(*tmp != ' ')
|
||||
tmp--;
|
||||
ret->author_mail = tmp + 1;
|
||||
|
||||
*tmp = 0;
|
||||
}
|
||||
|
||||
char* format_time(unsigned long time, const char* tz)
|
||||
{
|
||||
static char time_buf[128];
|
||||
time_t t = time;
|
||||
|
||||
strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S ", gmtime(&t));
|
||||
strcat(time_buf, tz);
|
||||
return time_buf;
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
int i;
|
||||
struct commit *initial = NULL;
|
||||
unsigned char sha1[20];
|
||||
const char* filename;
|
||||
|
||||
const char *filename = NULL, *commit = NULL;
|
||||
char filename_buf[256];
|
||||
int sha1_len = 8;
|
||||
int compability = 0;
|
||||
int options = 1;
|
||||
|
||||
int num_args;
|
||||
const char* args[10];
|
||||
struct rev_info rev;
|
||||
|
||||
setup_git_directory();
|
||||
struct commit_info ci;
|
||||
const char *buf;
|
||||
int max_digits;
|
||||
|
||||
if (argc != 3)
|
||||
die("Usage: blame commit-ish file");
|
||||
const char* prefix = setup_git_directory();
|
||||
|
||||
for(i = 1; i < argc; i++) {
|
||||
if(options) {
|
||||
if(!strcmp(argv[i], "-h") ||
|
||||
!strcmp(argv[i], "--help"))
|
||||
usage(blame_usage);
|
||||
else if(!strcmp(argv[i], "-l") ||
|
||||
!strcmp(argv[i], "--long")) {
|
||||
sha1_len = 20;
|
||||
continue;
|
||||
} else if(!strcmp(argv[i], "-c") ||
|
||||
!strcmp(argv[i], "--compability")) {
|
||||
compability = 1;
|
||||
continue;
|
||||
} else if(!strcmp(argv[i], "--")) {
|
||||
options = 0;
|
||||
continue;
|
||||
} else if(argv[i][0] == '-')
|
||||
usage(blame_usage);
|
||||
else
|
||||
options = 0;
|
||||
}
|
||||
|
||||
filename = argv[2];
|
||||
if(!options) {
|
||||
if(!filename)
|
||||
filename = argv[i];
|
||||
else if(!commit)
|
||||
commit = argv[i];
|
||||
else
|
||||
usage(blame_usage);
|
||||
}
|
||||
}
|
||||
|
||||
if(!filename)
|
||||
usage(blame_usage);
|
||||
if(!commit)
|
||||
commit = "HEAD";
|
||||
|
||||
if(prefix)
|
||||
sprintf(filename_buf, "%s%s", prefix, filename);
|
||||
else
|
||||
strcpy(filename_buf, filename);
|
||||
filename = filename_buf;
|
||||
|
||||
{
|
||||
struct commit* commit;
|
||||
if (get_sha1(argv[1], sha1))
|
||||
die("get_sha1 failed");
|
||||
commit = lookup_commit_reference(sha1);
|
||||
struct commit* c;
|
||||
if (get_sha1(commit, sha1))
|
||||
die("get_sha1 failed, commit '%s' not found", commit);
|
||||
c = lookup_commit_reference(sha1);
|
||||
|
||||
if (fill_util_info(commit, filename)) {
|
||||
printf("%s not found in %s\n", filename, argv[1]);
|
||||
if (fill_util_info(c, filename)) {
|
||||
printf("%s not found in %s\n", filename, commit);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@ -535,7 +641,7 @@ int main(int argc, const char **argv)
|
||||
args[num_args++] = NULL;
|
||||
args[num_args++] = "--topo-order";
|
||||
args[num_args++] = "--remove-empty";
|
||||
args[num_args++] = argv[1];
|
||||
args[num_args++] = commit;
|
||||
args[num_args++] = "--";
|
||||
args[num_args++] = filename;
|
||||
args[num_args] = NULL;
|
||||
@ -544,13 +650,33 @@ int main(int argc, const char **argv)
|
||||
prepare_revision_walk(&rev);
|
||||
process_commits(&rev, filename, &initial);
|
||||
|
||||
buf = blame_contents;
|
||||
max_digits = 1 + log(num_blame_lines+1)/log(10);
|
||||
for (i = 0; i < num_blame_lines; i++) {
|
||||
struct commit *c = blame_lines[i];
|
||||
if (!c)
|
||||
c = initial;
|
||||
|
||||
printf("%d %.8s\n", i, sha1_to_hex(c->object.sha1));
|
||||
// printf("%d %s\n", i, find_unique_abbrev(blame_lines[i]->object.sha1, 6));
|
||||
get_commit_info(c, &ci);
|
||||
fwrite(sha1_to_hex(c->object.sha1), sha1_len, 1, stdout);
|
||||
if(compability)
|
||||
printf("\t(%10s\t%10s\t%d)", ci.author,
|
||||
format_time(ci.author_time, ci.author_tz), i+1);
|
||||
else
|
||||
printf(" (%-15.15s %10s %*d) ", ci.author,
|
||||
format_time(ci.author_time, ci.author_tz),
|
||||
max_digits, i+1);
|
||||
|
||||
if(i == num_blame_lines - 1) {
|
||||
fwrite(buf, blame_len - (buf - blame_contents),
|
||||
1, stdout);
|
||||
if(blame_contents[blame_len-1] != '\n')
|
||||
putc('\n', stdout);
|
||||
} else {
|
||||
char* next_buf = index(buf, '\n') + 1;
|
||||
fwrite(buf, next_buf - buf, 1, stdout);
|
||||
buf = next_buf;
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user