From 604cb211a9b5401b265d1c1ca3d57dad243e7260 Mon Sep 17 00:00:00 2001 From: Alan Chandler Date: Tue, 3 Oct 2006 22:48:46 +0100 Subject: [PATCH 01/15] Update the gitweb/README file to include setting the GITWEB_CONFIG environment Signed-off-by: Alan Chandler Signed-off-by: Junio C Hamano --- gitweb/README | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/gitweb/README b/gitweb/README index 61c7ab5d4bb..78e6fc05f3d 100644 --- a/gitweb/README +++ b/gitweb/README @@ -43,6 +43,7 @@ repositories, you can configure apache like this: DocumentRoot /pub/git RewriteEngine on RewriteRule ^/(.*\.git/(?!/?(info|objects|refs)).*)?$ /cgi-bin/gitweb.cgi%{REQUEST_URI} [L,PT] + SetEnv GITWEB_CONFIG /etc/gitweb.conf The above configuration expects your public repositories to live under @@ -51,6 +52,12 @@ both as cloneable GIT URL and as browseable gitweb interface. If you then start your git-daemon with --base-path=/pub/git --export-all then you can even use the git:// URL with exactly the same path. +Setting the environment variable GITWEB_CONFIG will tell gitweb to use +the named file (i.e. in this example /etc/gitweb.conf) as a +configuration for gitweb. Perl variables defined in here will +override the defaults given at the head of the gitweb.perl (or +gitweb.cgi). Look at the comments in that file for information on +which variables and what they mean. Originally written by: From 281e67d6fa8e523147792c17fbe6db03f13f72e1 Mon Sep 17 00:00:00 2001 From: Alan Chandler Date: Tue, 3 Oct 2006 21:11:25 +0100 Subject: [PATCH 02/15] Fix usage string to match that given in the man page Still not managed to understand git-send-mail sufficiently well to not accidently miss of this list when I sending it to Junio Signed-off-by: Alan Chandler Signed-off-by: Junio C Hamano --- git.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git.c b/git.c index ae80e784560..b8e8622afb8 100644 --- a/git.c +++ b/git.c @@ -16,7 +16,7 @@ #include "builtin.h" const char git_usage_string[] = - "git [--version] [--exec-path[=GIT_EXEC_PATH]] [--help] COMMAND [ ARGS ]"; + "git [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate] [--bare] [--git-dir=GIT_DIR] [--help] COMMAND [ARGS]"; static void prepend_to_path(const char *dir, int len) { From c065b6e4293f856012ec53fcff7bf4d47ac50927 Mon Sep 17 00:00:00 2001 From: Martin Waitz Date: Tue, 3 Oct 2006 18:38:25 +0200 Subject: [PATCH 03/15] git-commit: cleanup unused function. The report() function is not used anymore. Kill it. Signed-off-by: Martin Waitz Signed-off-by: Junio C Hamano --- git-commit.sh | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/git-commit.sh b/git-commit.sh index 5a4c659b6fb..6f6cbda8984 100755 --- a/git-commit.sh +++ b/git-commit.sh @@ -32,33 +32,6 @@ save_index () { cp -p "$THIS_INDEX" "$NEXT_INDEX" } -report () { - header="# -# $1: -# ($2) -# -" - trailer="" - while read status name newname - do - printf '%s' "$header" - header="" - trailer="# -" - case "$status" in - M ) echo "# modified: $name";; - D*) echo "# deleted: $name";; - T ) echo "# typechange: $name";; - C*) echo "# copied: $name -> $newname";; - R*) echo "# renamed: $name -> $newname";; - A*) echo "# new file: $name";; - U ) echo "# unmerged: $name";; - esac - done - printf '%s' "$trailer" - [ "$header" ] -} - run_status () { # If TMP_INDEX is defined, that means we are doing # "--only" partial commit, and that index file is used From 6030649591256a8bc1b504ec1e4fce86ab0ad064 Mon Sep 17 00:00:00 2001 From: Franck Bui-Huu Date: Thu, 5 Oct 2006 10:42:16 +0200 Subject: [PATCH 04/15] Add git-upload-archive to the main git man page Signed-off-by: Franck Bui-Huu Signed-off-by: Junio C Hamano --- Documentation/git.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/git.txt b/Documentation/git.txt index 2135b65516b..3af6fc63e2b 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -243,6 +243,9 @@ gitlink:git-update-server-info[1]:: Updates auxiliary information on a dumb server to help clients discover references and packs on it. +gitlink:git-upload-archive[1]:: + Invoked by 'git-archive' to send a generated archive. + gitlink:git-upload-pack[1]:: Invoked by 'git-fetch-pack' to push what are asked for. From 9ccb64c8e0791a865ad520bcfff4b02cc7c50097 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 5 Oct 2006 02:26:12 -0700 Subject: [PATCH 05/15] tar-tree deprecation: we eat our own dog food. It is silly to keep using git-tar-tree in dist target when the command gives a big deprecation warning when called. Instead, use "git-archive --format=tar" which we recommend to our users. Update gitweb's snapshot feature to use git-archive for the same reason. Signed-off-by: Junio C Hamano --- Makefile | 5 +++-- gitweb/gitweb.perl | 9 ++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 401b893bfaa..2c7c33855e3 100644 --- a/Makefile +++ b/Makefile @@ -856,8 +856,9 @@ git.spec: git.spec.in mv $@+ $@ GIT_TARNAME=git-$(GIT_VERSION) -dist: git.spec git-tar-tree - ./git-tar-tree HEAD^{tree} $(GIT_TARNAME) > $(GIT_TARNAME).tar +dist: git.spec git-archive + ./git-archive --format=tar \ + --prefix=$(GIT_TARNAME)/ HEAD^{tree} > $(GIT_TARNAME).tar @mkdir -p $(GIT_TARNAME) @cp git.spec $(GIT_TARNAME) @echo $(GIT_VERSION) > $(GIT_TARNAME)/version diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 3e9d4a00524..6e1496d6ac9 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2838,9 +2838,12 @@ sub git_snapshot { -content_disposition => 'inline; filename="' . "$filename" . '"', -status => '200 OK'); - my $git_command = git_cmd_str(); - open my $fd, "-|", "$git_command tar-tree $hash \'$project\' | $command" or - die_error(undef, "Execute git-tar-tree failed."); + my $git = git_cmd_str(); + my $name = $project; + $name =~ s/\047/\047\\\047\047/g; + open my $fd, "-|", + "$git archive --format=tar --prefix=\'$name\'/ $hash | $command" + or die_error(undef, "Execute git-tar-tree failed."); binmode STDOUT, ':raw'; print <$fd>; binmode STDOUT, ':utf8'; # as set at the beginning of gitweb.cgi From c530c5aa31f44adafd1f4ecb05223024162e689c Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Thu, 5 Oct 2006 11:29:57 +0200 Subject: [PATCH 06/15] git.el: Fixed inverted "renamed from/to" message. The deleted file should be labeled "renamed to" and the added file "renamed from", not the other way around (duh!) Signed-off-by: Alexandre Julliard Signed-off-by: Junio C Hamano --- contrib/emacs/git.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/emacs/git.el b/contrib/emacs/git.el index 68de9be0c7c..5354cd67b3d 100644 --- a/contrib/emacs/git.el +++ b/contrib/emacs/git.el @@ -422,8 +422,8 @@ and returns the process output as a string." (propertize (concat " (" (if (eq state 'copy) "copied from " - (if (eq (git-fileinfo->state info) 'added) "renamed to " - "renamed from ")) + (if (eq (git-fileinfo->state info) 'added) "renamed from " + "renamed to ")) (git-escape-file-name (git-fileinfo->orig-name info)) ")") 'face 'git-status-face) ""))) From 13f8e0b24b546c0da942ab8ebe334d6e55fe1ea6 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Thu, 5 Oct 2006 11:30:44 +0200 Subject: [PATCH 07/15] vc-git.el: Switch to using git-blame instead of git-annotate. Signed-off-by: Alexandre Julliard Signed-off-by: Junio C Hamano --- contrib/emacs/vc-git.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/emacs/vc-git.el b/contrib/emacs/vc-git.el index 4a8f79092d1..4189c4ced04 100644 --- a/contrib/emacs/vc-git.el +++ b/contrib/emacs/vc-git.el @@ -119,10 +119,10 @@ (defun vc-git-annotate-command (file buf &optional rev) ; FIXME: rev is ignored (let ((name (file-relative-name file))) - (call-process "git" nil buf nil "annotate" name))) + (call-process "git" nil buf nil "blame" name))) (defun vc-git-annotate-time () - (and (re-search-forward "[0-9a-f]+\t(.*\t\\([0-9]+\\)-\\([0-9]+\\)-\\([0-9]+\\) \\([0-9]+\\):\\([0-9]+\\):\\([0-9]+\\) \\([-+0-9]+\\)\t[0-9]+)" nil t) + (and (re-search-forward "[0-9a-f]+ (.* \\([0-9]+\\)-\\([0-9]+\\)-\\([0-9]+\\) \\([0-9]+\\):\\([0-9]+\\):\\([0-9]+\\) \\([-+0-9]+\\) +[0-9]+)" nil t) (vc-annotate-convert-time (apply #'encode-time (mapcar (lambda (match) (string-to-number (match-string match))) '(6 5 4 3 2 1 7)))))) From 6e0e92fda893311ff5af91836e5007bf6bbd4a21 Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Thu, 5 Oct 2006 12:22:57 -0700 Subject: [PATCH 08/15] gitweb: Do not print "log" and "shortlog" redundantly in commit view Do not print "log" and "shortlog" redundantly in commit view. This is passed into the $extra argument of git_print_page_nav from git_commit, but git_print_page_nav prints "log" and "shortlog" already with the same head. Noticed by Junio. Signed-off-by: Luben Tuikov Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 5 ----- 1 file changed, 5 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 6e1496d6ac9..8bf7bf4bb09 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2940,11 +2940,6 @@ sub git_commit { $cgi->a({-href => href(action=>"blame", hash_parent=>$parent, file_name=>$file_name)}, "blame"); } - if (defined $co{'parent'}) { - push @views_nav, - $cgi->a({-href => href(action=>"shortlog", hash=>$hash)}, "shortlog"), - $cgi->a({-href => href(action=>"log", hash=>$hash)}, "log"); - } git_header_html(undef, $expires); git_print_page_nav('commit', defined $co{'parent'} ? '' : 'commitdiff', $hash, $co{'tree'}, $hash, From db94b41aee0dfeae06e9c6f03d38a2aa30f8fd10 Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Thu, 5 Oct 2006 13:30:31 -0700 Subject: [PATCH 09/15] gitweb: blame: Minimize vertical table row padding Minimize vertical table row padding for blame only. I discovered this while having the browser's blame output right next to my editor's window, only to notice how much vertically stretched the blame output was. Blame most likely shows source code and is in this way more "spartan" than the rest of the tables gitweb shows. This patch makes the blame table more vertically compact, thus being closer to what you'd see in your editor's window, as well as reusing more window estate to show more information (which in turn minimizes scrolling). Signed-off-by: Luben Tuikov Signed-off-by: Junio C Hamano --- gitweb/gitweb.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/gitweb/gitweb.css b/gitweb/gitweb.css index eb9fc3804b1..668e69af1ee 100644 --- a/gitweb/gitweb.css +++ b/gitweb/gitweb.css @@ -173,6 +173,12 @@ table.blame { border-collapse: collapse; } +table.blame td { + padding: 0px 5px; + font-size: 12px; + vertical-align: top; +} + th { padding: 2px 5px; font-size: 12px; From 51a7c66a73ce74fad3b7b05109ed6ce013202fa5 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 23 Sep 2006 12:36:01 -0700 Subject: [PATCH 10/15] gitweb: Make the Git logo link target to point to the homepage It provides more useful information for causual Git users than the Git docs (especially about where to get Git and such). People can override with GITWEB_CONFIG if they want to. Signed-off-by: Petr Baudis Signed-off-by: Junio C Hamano Acked-by: Petr Baudis --- gitweb/gitweb.perl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 8bf7bf4bb09..3320069171d 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -51,6 +51,9 @@ our $logo = "++GITWEB_LOGO++"; # URI of GIT favicon, assumed to be image/png type our $favicon = "++GITWEB_FAVICON++"; +our $githelp_url = "http://git.or.cz/"; +our $githelp_label = "git homepage"; + # source of projects list our $projects_list = "++GITWEB_LIST++"; @@ -1373,7 +1376,9 @@ EOF print "\n" . "\n" . "
\n" . - "" . + "" . "\"git\"" . "\n"; print $cgi->a({-href => esc_url($home_link)}, $home_link_str) . " / "; From 506e49ff9ff2b5be34b2bdf15c88038b00d3ef66 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 5 Oct 2006 14:00:55 -0700 Subject: [PATCH 11/15] blame.c: whitespace and formatting clean-up. Signed-off-by: Junio C Hamano --- blame.c | 200 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 100 insertions(+), 100 deletions(-) diff --git a/blame.c b/blame.c index 8cfd5d94c77..394b5c3617e 100644 --- a/blame.c +++ b/blame.c @@ -20,16 +20,17 @@ #define DEBUG 0 -static const char blame_usage[] = "git-blame [-c] [-l] [-t] [-S ] [--] file [commit]\n" - " -c, --compatibility Use the same output mode as git-annotate (Default: off)\n" - " -l, --long Show long commit SHA1 (Default: off)\n" - " -t, --time Show raw timestamp (Default: off)\n" - " -S, --revs-file Use revisions from revs-file instead of calling git-rev-list\n" - " -h, --help This message"; +static const char blame_usage[] = +"git-blame [-c] [-l] [-t] [-S ] [--] file [commit]\n" +" -c, --compatibility Use the same output mode as git-annotate (Default: off)\n" +" -l, --long Show long commit SHA1 (Default: off)\n" +" -t, --time Show raw timestamp (Default: off)\n" +" -S, --revs-file Use revisions from revs-file instead of calling git-rev-list\n" +" -h, --help This message"; static struct commit **blame_lines; static int num_blame_lines; -static char* blame_contents; +static char *blame_contents; static int blame_len; struct util_info { @@ -38,9 +39,9 @@ struct util_info { char *buf; unsigned long size; int num_lines; - const char* pathname; + const char *pathname; - void* topo_data; + void *topo_data; }; struct chunk { @@ -156,11 +157,10 @@ static int get_blob_sha1_internal(const unsigned char *sha1, const char *base, unsigned mode, int stage); static unsigned char blob_sha1[20]; -static const char* blame_file; +static const char *blame_file; static int get_blob_sha1(struct tree *t, const char *pathname, unsigned char *sha1) { - int i; const char *pathspec[2]; blame_file = pathname; pathspec[0] = pathname; @@ -168,12 +168,7 @@ static int get_blob_sha1(struct tree *t, const char *pathname, hashclr(blob_sha1); read_tree_recursive(t, "", 0, 0, pathspec, get_blob_sha1_internal); - for (i = 0; i < 20; i++) { - if (blob_sha1[i] != 0) - break; - } - - if (i == 20) + if (is_null_sha1(blob_sha1)) return -1; hashcpy(sha1, blob_sha1); @@ -239,7 +234,8 @@ static void print_map(struct commit *cmit, struct commit *other) if (i < util->num_lines) { num = util->line_map[i]; printf("%d\t", num); - } else + } + else printf("\t"); if (i < util2->num_lines) { @@ -247,7 +243,8 @@ static void print_map(struct commit *cmit, struct commit *other) printf("%d\t", num2); if (num != -1 && num2 != num) printf("---"); - } else + } + else printf("\t"); printf("\n"); @@ -266,12 +263,12 @@ static void fill_line_map(struct commit *commit, struct commit *other, int cur_chunk = 0; int i1, i2; - if (p->num && DEBUG) - print_patch(p); - - if (DEBUG) + if (DEBUG) { + if (p->num) + print_patch(p); printf("num lines 1: %d num lines 2: %d\n", util->num_lines, util2->num_lines); + } for (i1 = 0, i2 = 0; i1 < util->num_lines; i1++, i2++) { struct chunk *chunk = NULL; @@ -293,7 +290,8 @@ static void fill_line_map(struct commit *commit, struct commit *other, i2 += chunk->len2; cur_chunk++; - } else { + } + else { if (i2 >= util2->num_lines) break; @@ -327,7 +325,7 @@ static int map_line(struct commit *commit, int line) return info->line_map[line]; } -static struct util_info* get_util(struct commit *commit) +static struct util_info *get_util(struct commit *commit) { struct util_info *util = commit->util; @@ -369,7 +367,7 @@ static void alloc_line_map(struct commit *commit) if (util->buf[i] == '\n') util->num_lines++; } - if(util->buf[util->size - 1] != '\n') + if (util->buf[util->size - 1] != '\n') util->num_lines++; util->line_map = xmalloc(sizeof(int) * util->num_lines); @@ -378,9 +376,9 @@ static void alloc_line_map(struct commit *commit) util->line_map[i] = -1; } -static void init_first_commit(struct commit* commit, const char* filename) +static void init_first_commit(struct commit *commit, const char *filename) { - struct util_info* util = commit->util; + struct util_info *util = commit->util; int i; util->pathname = filename; @@ -395,18 +393,17 @@ static void init_first_commit(struct commit* commit, const char* filename) util->line_map[i] = i; } - static void process_commits(struct rev_info *rev, const char *path, - struct commit** initial) + struct commit **initial) { int i; - struct util_info* util; + struct util_info *util; int lines_left; int *blame_p; int *new_lines; int new_lines_len; - struct commit* commit = get_revision(rev); + struct commit *commit = get_revision(rev); assert(commit); init_first_commit(commit, path); @@ -442,7 +439,7 @@ static void process_commits(struct rev_info *rev, const char *path, parents != NULL; parents = parents->next) num_parents++; - if(num_parents == 0) + if (num_parents == 0) *initial = commit; if (fill_util_info(commit)) @@ -503,13 +500,12 @@ static void process_commits(struct rev_info *rev, const char *path, } while ((commit = get_revision(rev)) != NULL); } - -static int compare_tree_path(struct rev_info* revs, - struct commit* c1, struct commit* c2) +static int compare_tree_path(struct rev_info *revs, + struct commit *c1, struct commit *c2) { int ret; - const char* paths[2]; - struct util_info* util = c2->util; + const char *paths[2]; + struct util_info *util = c2->util; paths[0] = util->pathname; paths[1] = NULL; @@ -520,12 +516,11 @@ static int compare_tree_path(struct rev_info* revs, return ret; } - -static int same_tree_as_empty_path(struct rev_info *revs, struct tree* t1, - const char* path) +static int same_tree_as_empty_path(struct rev_info *revs, struct tree *t1, + const char *path) { int ret; - const char* paths[2]; + const char *paths[2]; paths[0] = path; paths[1] = NULL; @@ -536,9 +531,9 @@ static int same_tree_as_empty_path(struct rev_info *revs, struct tree* t1, return ret; } -static const char* find_rename(struct commit* commit, struct commit* parent) +static const char *find_rename(struct commit *commit, struct commit *parent) { - struct util_info* cutil = commit->util; + struct util_info *cutil = commit->util; struct diff_options diff_opts; const char *paths[1]; int i; @@ -564,9 +559,11 @@ static const char* find_rename(struct commit* commit, struct commit* parent) for (i = 0; i < diff_queued_diff.nr; i++) { struct diff_filepair *p = diff_queued_diff.queue[i]; - if (p->status == 'R' && !strcmp(p->one->path, cutil->pathname)) { + if (p->status == 'R' && + !strcmp(p->one->path, cutil->pathname)) { if (DEBUG) - printf("rename %s -> %s\n", p->one->path, p->two->path); + printf("rename %s -> %s\n", + p->one->path, p->two->path); return p->two->path; } } @@ -582,7 +579,7 @@ static void simplify_commit(struct rev_info *revs, struct commit *commit) return; if (!commit->parents) { - struct util_info* util = commit->util; + struct util_info *util = commit->util; if (!same_tree_as_empty_path(revs, commit->tree, util->pathname)) commit->object.flags |= TREECHANGE; @@ -608,17 +605,17 @@ static void simplify_commit(struct rev_info *revs, struct commit *commit) case REV_TREE_NEW: { - - struct util_info* util = commit->util; + struct util_info *util = commit->util; if (revs->remove_empty_trees && same_tree_as_empty_path(revs, p->tree, util->pathname)) { - const char* new_name = find_rename(commit, p); + const char *new_name = find_rename(commit, p); if (new_name) { - struct util_info* putil = get_util(p); + struct util_info *putil = get_util(p); if (!putil->pathname) putil->pathname = xstrdup(new_name); - } else { + } + else { *pp = parent->next; continue; } @@ -639,19 +636,18 @@ static void simplify_commit(struct rev_info *revs, struct commit *commit) commit->object.flags |= TREECHANGE; } - struct commit_info { - char* author; - char* author_mail; + char *author; + char *author_mail; unsigned long author_time; - char* author_tz; + char *author_tz; }; -static void get_commit_info(struct commit* commit, struct commit_info* ret) +static void get_commit_info(struct commit *commit, struct commit_info *ret) { int len; - char* tmp; + char *tmp; static char author_buf[1024]; tmp = strstr(commit->buffer, "\nauthor ") + 8; @@ -662,24 +658,24 @@ static void get_commit_info(struct commit* commit, struct commit_info* ret) tmp = ret->author; tmp += len; *tmp = 0; - while(*tmp != ' ') + while (*tmp != ' ') tmp--; ret->author_tz = tmp+1; *tmp = 0; - while(*tmp != ' ') + while (*tmp != ' ') tmp--; ret->author_time = strtoul(tmp, NULL, 10); *tmp = 0; - while(*tmp != ' ') + while (*tmp != ' ') tmp--; ret->author_mail = tmp + 1; *tmp = 0; } -static const char* format_time(unsigned long time, const char* tz_str, +static const char *format_time(unsigned long time, const char *tz_str, int show_raw_time) { static char time_buf[128]; @@ -704,15 +700,15 @@ static const char* format_time(unsigned long time, const char* tz_str, return time_buf; } -static void topo_setter(struct commit* c, void* data) +static void topo_setter(struct commit *c, void *data) { - struct util_info* util = c->util; + struct util_info *util = c->util; util->topo_data = data; } -static void* topo_getter(struct commit* c) +static void *topo_getter(struct commit *c) { - struct util_info* util = c->util; + struct util_info *util = c->util; return util->topo_data; } @@ -747,9 +743,9 @@ int main(int argc, const char **argv) int compatibility = 0; int show_raw_time = 0; int options = 1; - struct commit* start_commit; + struct commit *start_commit; - const char* args[10]; + const char *args[10]; struct rev_info rev; struct commit_info ci; @@ -758,27 +754,30 @@ int main(int argc, const char **argv) int longest_file, longest_author; int found_rename; - const char* prefix = setup_git_directory(); + const char *prefix = setup_git_directory(); git_config(git_default_config); - for(i = 1; i < argc; i++) { - if(options) { - if(!strcmp(argv[i], "-h") || + 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")) { + if (!strcmp(argv[i], "-l") || + !strcmp(argv[i], "--long")) { sha1_len = 40; continue; - } else if(!strcmp(argv[i], "-c") || - !strcmp(argv[i], "--compatibility")) { + } + if (!strcmp(argv[i], "-c") || + !strcmp(argv[i], "--compatibility")) { compatibility = 1; continue; - } else if(!strcmp(argv[i], "-t") || - !strcmp(argv[i], "--time")) { + } + if (!strcmp(argv[i], "-t") || + !strcmp(argv[i], "--time")) { show_raw_time = 1; continue; - } else if(!strcmp(argv[i], "-S")) { + } + if (!strcmp(argv[i], "-S")) { if (i + 1 < argc && !read_ancestry(argv[i + 1], &sha1_p)) { compatibility = 1; @@ -786,33 +785,34 @@ int main(int argc, const char **argv) continue; } usage(blame_usage); - } else if(!strcmp(argv[i], "--")) { + } + if (!strcmp(argv[i], "--")) { options = 0; continue; - } else if(argv[i][0] == '-') + } + if (argv[i][0] == '-') usage(blame_usage); - else - options = 0; + options = 0; } - if(!options) { - if(!filename) + if (!options) { + if (!filename) filename = argv[i]; - else if(!commit) + else if (!commit) commit = argv[i]; else usage(blame_usage); } } - if(!filename) + if (!filename) usage(blame_usage); if (commit && sha1_p) usage(blame_usage); - else if(!commit) + else if (!commit) commit = "HEAD"; - if(prefix) + if (prefix) sprintf(filename_buf, "%s%s", prefix, filename); else strcpy(filename_buf, filename); @@ -830,7 +830,6 @@ int main(int argc, const char **argv) return 1; } - init_revisions(&rev, setup_git_directory()); rev.remove_empty_trees = 1; rev.topo_order = 1; @@ -857,7 +856,7 @@ int main(int argc, const char **argv) found_rename = 0; for (i = 0; i < num_blame_lines; i++) { struct commit *c = blame_lines[i]; - struct util_info* u; + struct util_info *u; if (!c) c = initial; u = c->util; @@ -873,20 +872,20 @@ int main(int argc, const char **argv) for (i = 0; i < num_blame_lines; i++) { struct commit *c = blame_lines[i]; - struct util_info* u; - + struct util_info *u; if (!c) c = initial; - u = c->util; + get_commit_info(c, &ci); fwrite(sha1_to_hex(c->object.sha1), sha1_len, 1, stdout); - if(compatibility) { + if (compatibility) { printf("\t(%10s\t%10s\t%d)", ci.author, format_time(ci.author_time, ci.author_tz, show_raw_time), i+1); - } else { + } + else { if (found_rename) printf(" %-*.*s", longest_file, longest_file, u->pathname); @@ -897,13 +896,14 @@ int main(int argc, const char **argv) max_digits, i+1); } - if(i == num_blame_lines - 1) { + if (i == num_blame_lines - 1) { fwrite(buf, blame_len - (buf - blame_contents), 1, stdout); - if(blame_contents[blame_len-1] != '\n') + if (blame_contents[blame_len-1] != '\n') putc('\n', stdout); - } else { - char* next_buf = strchr(buf, '\n') + 1; + } + else { + char *next_buf = strchr(buf, '\n') + 1; fwrite(buf, next_buf - buf, 1, stdout); buf = next_buf; } From eb93b7240665e35ecc0ed72098e1a5b3352bdc17 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 5 Oct 2006 14:06:22 -0700 Subject: [PATCH 12/15] git-blame: --show-name (and -f) The new option makes the command's native output format show the filename even when there were no renames in its history, to make it simpler for Porcelains to parse its output. Signed-off-by: Junio C Hamano --- blame.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/blame.c b/blame.c index 394b5c3617e..d830b293fda 100644 --- a/blame.c +++ b/blame.c @@ -752,7 +752,7 @@ int main(int argc, const char **argv) const char *buf; int max_digits; int longest_file, longest_author; - int found_rename; + int show_name = 0; const char *prefix = setup_git_directory(); git_config(git_default_config); @@ -786,6 +786,11 @@ int main(int argc, const char **argv) } usage(blame_usage); } + if (!strcmp(argv[i], "-f") || + !strcmp(argv[i], "--show-name")) { + show_name = 1; + continue; + } if (!strcmp(argv[i], "--")) { options = 0; continue; @@ -853,7 +858,6 @@ int main(int argc, const char **argv) longest_file = 0; longest_author = 0; - found_rename = 0; for (i = 0; i < num_blame_lines; i++) { struct commit *c = blame_lines[i]; struct util_info *u; @@ -861,8 +865,8 @@ int main(int argc, const char **argv) c = initial; u = c->util; - if (!found_rename && strcmp(filename, u->pathname)) - found_rename = 1; + if (!show_name && strcmp(filename, u->pathname)) + show_name = 1; if (longest_file < strlen(u->pathname)) longest_file = strlen(u->pathname); get_commit_info(c, &ci); @@ -886,7 +890,7 @@ int main(int argc, const char **argv) i+1); } else { - if (found_rename) + if (show_name) printf(" %-*.*s", longest_file, longest_file, u->pathname); printf(" (%-*.*s %10s %*d) ", From cf54a029ff82ce9b565e075bfa5d97ec82841283 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 5 Oct 2006 14:06:26 -0700 Subject: [PATCH 13/15] git-blame: --show-number (and -n) The new option makes the command's native output format show the original line number in the blamed revision. Note: the current implementation of find_orig_linenum involves linear search through the line_map array every time. It should probably build a reverse map upfront and do a simple look-up to speed things up, but I'll leave it to more clever and beautiful people ;-). Signed-off-by: Junio C Hamano --- blame.c | 42 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/blame.c b/blame.c index d830b293fda..bf4a1a1ff06 100644 --- a/blame.c +++ b/blame.c @@ -731,6 +731,25 @@ static int read_ancestry(const char *graft_file, return 0; } +static int lineno_width(int lines) +{ + int i, width; + + for (width = 1, i = 10; i <= lines + 1; width++) + i *= 10; + return width; +} + +static int find_orig_linenum(struct util_info *u, int lineno) +{ + int i; + + for (i = 0; i < u->num_lines; i++) + if (lineno == u->line_map[i]) + return i + 1; + return 0; +} + int main(int argc, const char **argv) { int i; @@ -750,9 +769,10 @@ int main(int argc, const char **argv) struct commit_info ci; const char *buf; - int max_digits; - int longest_file, longest_author; + int max_digits, max_orig_digits; + int longest_file, longest_author, longest_file_lines; int show_name = 0; + int show_number = 0; const char *prefix = setup_git_directory(); git_config(git_default_config); @@ -791,6 +811,11 @@ int main(int argc, const char **argv) show_name = 1; continue; } + if (!strcmp(argv[i], "-n") || + !strcmp(argv[i], "--show-number")) { + show_number = 1; + continue; + } if (!strcmp(argv[i], "--")) { options = 0; continue; @@ -853,11 +878,11 @@ int main(int argc, const char **argv) process_commits(&rev, filename, &initial); buf = blame_contents; - for (max_digits = 1, i = 10; i <= num_blame_lines + 1; max_digits++) - i *= 10; + max_digits = lineno_width(num_blame_lines); longest_file = 0; longest_author = 0; + longest_file_lines = 0; for (i = 0; i < num_blame_lines; i++) { struct commit *c = blame_lines[i]; struct util_info *u; @@ -869,17 +894,23 @@ int main(int argc, const char **argv) show_name = 1; if (longest_file < strlen(u->pathname)) longest_file = strlen(u->pathname); + if (longest_file_lines < u->num_lines) + longest_file_lines = u->num_lines; get_commit_info(c, &ci); if (longest_author < strlen(ci.author)) longest_author = strlen(ci.author); } + max_orig_digits = lineno_width(longest_file_lines); + for (i = 0; i < num_blame_lines; i++) { struct commit *c = blame_lines[i]; struct util_info *u; + int lineno; if (!c) c = initial; u = c->util; + lineno = find_orig_linenum(u, i); get_commit_info(c, &ci); fwrite(sha1_to_hex(c->object.sha1), sha1_len, 1, stdout); @@ -893,6 +924,9 @@ int main(int argc, const char **argv) if (show_name) printf(" %-*.*s", longest_file, longest_file, u->pathname); + if (show_number) + printf(" %*d", max_orig_digits, + lineno); printf(" (%-*.*s %10s %*d) ", longest_author, longest_author, ci.author, format_time(ci.author_time, ci.author_tz, From c137f40f8a9dfe05ee002cf5f23bf562c1f13100 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 5 Oct 2006 14:06:42 -0700 Subject: [PATCH 14/15] blame.c: move code to output metainfo into a separate function. This does not change any behaviour, but just separates out the code to emit the initial part of the output of each line into a separate function, since I'll be mucking with it further. Signed-off-by: Junio C Hamano --- blame.c | 76 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 45 insertions(+), 31 deletions(-) diff --git a/blame.c b/blame.c index bf4a1a1ff06..47471e88897 100644 --- a/blame.c +++ b/blame.c @@ -750,6 +750,42 @@ static int find_orig_linenum(struct util_info *u, int lineno) return 0; } +static void emit_meta(struct commit *c, int lno, + int sha1_len, int compatibility, + int show_name, int show_number, int show_raw_time, + int longest_file, int longest_author, + int max_digits, int max_orig_digits) +{ + struct util_info *u; + int lineno; + struct commit_info ci; + + u = c->util; + lineno = find_orig_linenum(u, lno); + + get_commit_info(c, &ci); + fwrite(sha1_to_hex(c->object.sha1), sha1_len, 1, stdout); + if (compatibility) { + printf("\t(%10s\t%10s\t%d)", ci.author, + format_time(ci.author_time, ci.author_tz, + show_raw_time), + lno + 1); + } + else { + if (show_name) + printf(" %-*.*s", longest_file, longest_file, + u->pathname); + if (show_number) + printf(" %*d", max_orig_digits, + lineno); + printf(" (%-*.*s %10s %*d) ", + longest_author, longest_author, ci.author, + format_time(ci.author_time, ci.author_tz, + show_raw_time), + max_digits, lno + 1); + } +} + int main(int argc, const char **argv) { int i; @@ -877,6 +913,10 @@ int main(int argc, const char **argv) prepare_revision_walk(&rev); process_commits(&rev, filename, &initial); + for (i = 0; i < num_blame_lines; i++) + if (!blame_lines[i]) + blame_lines[i] = initial; + buf = blame_contents; max_digits = lineno_width(num_blame_lines); @@ -886,8 +926,6 @@ int main(int argc, const char **argv) for (i = 0; i < num_blame_lines; i++) { struct commit *c = blame_lines[i]; struct util_info *u; - if (!c) - c = initial; u = c->util; if (!show_name && strcmp(filename, u->pathname)) @@ -904,35 +942,11 @@ int main(int argc, const char **argv) max_orig_digits = lineno_width(longest_file_lines); for (i = 0; i < num_blame_lines; i++) { - struct commit *c = blame_lines[i]; - struct util_info *u; - int lineno; - if (!c) - c = initial; - u = c->util; - lineno = find_orig_linenum(u, i); - - get_commit_info(c, &ci); - fwrite(sha1_to_hex(c->object.sha1), sha1_len, 1, stdout); - if (compatibility) { - printf("\t(%10s\t%10s\t%d)", ci.author, - format_time(ci.author_time, ci.author_tz, - show_raw_time), - i+1); - } - else { - if (show_name) - printf(" %-*.*s", longest_file, longest_file, - u->pathname); - if (show_number) - printf(" %*d", max_orig_digits, - lineno); - printf(" (%-*.*s %10s %*d) ", - longest_author, longest_author, ci.author, - format_time(ci.author_time, ci.author_tz, - show_raw_time), - max_digits, i+1); - } + emit_meta(blame_lines[i], i, + sha1_len, compatibility, + show_name, show_number, show_raw_time, + longest_file, longest_author, + max_digits, max_orig_digits); if (i == num_blame_lines - 1) { fwrite(buf, blame_len - (buf - blame_contents), From b5c698d947c236559e338e45c6234ece7c819338 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 5 Oct 2006 14:07:42 -0700 Subject: [PATCH 15/15] git-blame --porcelain The new option makes the command's native output format to emit output that is easier to handle by Porcelain. Each line is output after a header. The header at the minimum has the first line which has: - 40-byte SHA-1 of the commit the line is attributed to; - the line number of the line in the original file; - the line number of the line in the final file; - on a line that starts a group of line from a different commit than the previous one, the number of lines in this group. On subsequent lines this field is absent. This header line is followed by the following information once for each commit: - author name ("author"), email ("author-mail"), time ("author-time"), and timezone ("author-tz"); similarly for committer. - filename in the commit the line is attributed to. - the first line of the commit log message ("summary"). 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. Signed-off-by: Junio C Hamano --- blame.c | 147 ++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 126 insertions(+), 21 deletions(-) diff --git a/blame.c b/blame.c index 47471e88897..314f3e2f0d9 100644 --- a/blame.c +++ b/blame.c @@ -17,6 +17,7 @@ #include "diffcore.h" #include "revision.h" #include "xdiff-interface.h" +#include "quote.h" #define DEBUG 0 @@ -40,6 +41,7 @@ struct util_info { unsigned long size; int num_lines; const char *pathname; + unsigned meta_given:1; void *topo_data; }; @@ -332,12 +334,8 @@ static struct util_info *get_util(struct commit *commit) if (util) return util; - util = xmalloc(sizeof(struct util_info)); - util->buf = NULL; - util->size = 0; - util->line_map = NULL; + util = xcalloc(1, sizeof(struct util_info)); util->num_lines = -1; - util->pathname = NULL; commit->util = util; return util; } @@ -642,39 +640,99 @@ struct commit_info char *author_mail; unsigned long author_time; char *author_tz; + + /* filled only when asked for details */ + char *committer; + char *committer_mail; + unsigned long committer_time; + char *committer_tz; + + char *summary; }; -static void get_commit_info(struct commit *commit, struct commit_info *ret) +static void get_ac_line(const char *inbuf, const char *what, + int bufsz, char *person, char **mail, + unsigned long *time, char **tz) { int len; - char *tmp; - static char author_buf[1024]; + char *tmp, *endp; - tmp = strstr(commit->buffer, "\nauthor ") + 8; - len = strchr(tmp, '\n') - tmp; - ret->author = author_buf; - memcpy(ret->author, tmp, len); + tmp = strstr(inbuf, what); + if (!tmp) + goto error_out; + tmp += strlen(what); + endp = strchr(tmp, '\n'); + if (!endp) + len = strlen(tmp); + else + len = endp - tmp; + if (bufsz <= len) { + error_out: + /* Ugh */ + person = *mail = *tz = "(unknown)"; + *time = 0; + return; + } + memcpy(person, tmp, len); - tmp = ret->author; + tmp = person; tmp += len; *tmp = 0; while (*tmp != ' ') tmp--; - ret->author_tz = tmp+1; + *tz = tmp+1; *tmp = 0; while (*tmp != ' ') tmp--; - ret->author_time = strtoul(tmp, NULL, 10); + *time = strtoul(tmp, NULL, 10); *tmp = 0; while (*tmp != ' ') tmp--; - ret->author_mail = tmp + 1; - + *mail = tmp + 1; *tmp = 0; } +static void get_commit_info(struct commit *commit, struct commit_info *ret, int detailed) +{ + int len; + char *tmp, *endp; + static char author_buf[1024]; + static char committer_buf[1024]; + static char summary_buf[1024]; + + ret->author = author_buf; + get_ac_line(commit->buffer, "\nauthor ", + sizeof(author_buf), author_buf, &ret->author_mail, + &ret->author_time, &ret->author_tz); + + if (!detailed) + return; + + ret->committer = committer_buf; + get_ac_line(commit->buffer, "\ncommitter ", + sizeof(committer_buf), committer_buf, &ret->committer_mail, + &ret->committer_time, &ret->committer_tz); + + ret->summary = summary_buf; + tmp = strstr(commit->buffer, "\n\n"); + if (!tmp) { + error_out: + sprintf(summary_buf, "(%s)", sha1_to_hex(commit->object.sha1)); + return; + } + tmp += 2; + endp = strchr(tmp, '\n'); + if (!endp) + goto error_out; + len = endp - tmp; + if (len >= sizeof(summary_buf)) + goto error_out; + memcpy(summary_buf, tmp, len); + summary_buf[len] = 0; +} + static const char *format_time(unsigned long time, const char *tz_str, int show_raw_time) { @@ -751,7 +809,7 @@ static int find_orig_linenum(struct util_info *u, int lineno) } static void emit_meta(struct commit *c, int lno, - int sha1_len, int compatibility, + int sha1_len, int compatibility, int porcelain, int show_name, int show_number, int show_raw_time, int longest_file, int longest_author, int max_digits, int max_orig_digits) @@ -763,7 +821,47 @@ static void emit_meta(struct commit *c, int lno, u = c->util; lineno = find_orig_linenum(u, lno); - get_commit_info(c, &ci); + if (porcelain) { + int group_size = -1; + struct commit *cc = (lno == 0) ? NULL : blame_lines[lno-1]; + if (cc != c) { + /* This is the beginning of this group */ + int i; + for (i = lno + 1; i < num_blame_lines; i++) + if (blame_lines[i] != c) + break; + group_size = i - lno; + } + if (0 < group_size) + printf("%s %d %d %d\n", sha1_to_hex(c->object.sha1), + lineno, lno + 1, group_size); + else + printf("%s %d %d\n", sha1_to_hex(c->object.sha1), + lineno, lno + 1); + if (!u->meta_given) { + get_commit_info(c, &ci, 1); + printf("author %s\n", ci.author); + printf("author-mail %s\n", ci.author_mail); + printf("author-time %lu\n", ci.author_time); + printf("author-tz %s\n", ci.author_tz); + printf("committer %s\n", ci.committer); + printf("committer-mail %s\n", ci.committer_mail); + printf("committer-time %lu\n", ci.committer_time); + printf("committer-tz %s\n", ci.committer_tz); + printf("filename "); + if (quote_c_style(u->pathname, NULL, NULL, 0)) + quote_c_style(u->pathname, NULL, stdout, 0); + else + fputs(u->pathname, stdout); + printf("\nsummary %s\n", ci.summary); + + u->meta_given = 1; + } + putchar('\t'); + return; + } + + get_commit_info(c, &ci, 0); fwrite(sha1_to_hex(c->object.sha1), sha1_len, 1, stdout); if (compatibility) { printf("\t(%10s\t%10s\t%d)", ci.author, @@ -809,6 +907,7 @@ int main(int argc, const char **argv) int longest_file, longest_author, longest_file_lines; int show_name = 0; int show_number = 0; + int porcelain = 0; const char *prefix = setup_git_directory(); git_config(git_default_config); @@ -852,6 +951,12 @@ int main(int argc, const char **argv) show_number = 1; continue; } + if (!strcmp(argv[i], "--porcelain")) { + porcelain = 1; + sha1_len = 40; + show_raw_time = 1; + continue; + } if (!strcmp(argv[i], "--")) { options = 0; continue; @@ -934,7 +1039,7 @@ int main(int argc, const char **argv) longest_file = strlen(u->pathname); if (longest_file_lines < u->num_lines) longest_file_lines = u->num_lines; - get_commit_info(c, &ci); + get_commit_info(c, &ci, 0); if (longest_author < strlen(ci.author)) longest_author = strlen(ci.author); } @@ -943,7 +1048,7 @@ int main(int argc, const char **argv) for (i = 0; i < num_blame_lines; i++) { emit_meta(blame_lines[i], i, - sha1_len, compatibility, + sha1_len, compatibility, porcelain, show_name, show_number, show_raw_time, longest_file, longest_author, max_digits, max_orig_digits);