1
0
Fork 0
mirror of https://github.com/git/git.git synced 2024-11-06 01:03:02 +01:00

Merge branch 'fd/asciidoc' into next

* fd/asciidoc:
  Tweak asciidoc output to work with broken docbook-xsl
  annotate-blame test: add evil merge.
  annotate-blame test: don't "source", but say "."
  annotate/blame tests updates.
  annotate: Support annotation of files on other revisions.
  git/Documentation: fix SYNOPSIS style bugs
  blame: avoid "diff -u0".
  git-blame: Use the same tests for git-blame as for git-annotate
  blame and annotate: show localtime with timezone.
  blame: avoid -lm by not using log().
  git-blame: Make the output human readable
  get_revision(): do not dig deeper when we know we are at the end.
  documentation: add 'see also' sections to git-rm and git-add
  contrib/emacs/Makefile: Provide tool for byte-compiling files.
  gitignore: Ignore some more boring things.
This commit is contained in:
Junio C Hamano 2006-03-05 22:38:22 -08:00
commit 3bcd59a546
21 changed files with 340 additions and 122 deletions

1
.gitignore vendored
View file

@ -130,3 +130,4 @@ libgit.a
*.o
*.py[co]
config.mak
git-blame

View file

@ -18,6 +18,16 @@ ifdef::backend-docbook[]
{0#</citerefentry>}
endif::backend-docbook[]
ifdef::backend-docbook[]
# "unbreak" docbook-xsl v1.68 for manpages. v1.69 works with or without this.
[listingblock]
<example><title>{title}</title>
<literallayout>
|
</literallayout>
{title#}</example>
endif::backend-docbook[]
ifdef::backend-xhtml11[]
[gitlink-inlinemacro]
<a href="{target}.html">{target}{0?({0})}</a>

View file

@ -65,6 +65,9 @@ git-add git-*.sh::
(i.e. you are listing the files explicitly), it does not
add `subdir/git-foo.sh` to the index.
See Also
--------
gitlink:git-rm[1]
Author
------

View file

@ -9,7 +9,7 @@ git-archimport - Import an Arch repository into git
SYNOPSIS
--------
[verse]
`git-archimport` [-h] [-v] [-o] [-a] [-f] [-T] [-D depth] [-t tempdir]
'git-archimport' [-h] [-v] [-o] [-a] [-f] [-T] [-D depth] [-t tempdir]
<archive/branch> [ <archive/branch> ]
DESCRIPTION

View file

@ -8,7 +8,7 @@ git-fetch-pack - Receive missing objects from another repository.
SYNOPSIS
--------
git-fetch-pack [-q] [-k] [--exec=<git-upload-pack>] [<host>:]<directory> [<refs>...]
'git-fetch-pack' [-q] [-k] [--exec=<git-upload-pack>] [<host>:]<directory> [<refs>...]
DESCRIPTION
-----------

View file

@ -8,7 +8,7 @@ git-pack-redundant - Program used to find redundant pack files.
SYNOPSIS
--------
'git-pack-redundant [ --verbose ] [ --alt-odb ] < --all | .pack filename ... >'
'git-pack-redundant' [ --verbose ] [ --alt-odb ] < --all | .pack filename ... >
DESCRIPTION
-----------

View file

@ -74,6 +74,9 @@ git-rm -f git-*.sh::
shell expand the asterisk (i.e. you are listing the files
explicitly), it does not remove `subdir/git-foo.sh`.
See Also
--------
gitlink:git-add[1]
Author
------

View file

@ -8,7 +8,7 @@ git-shell - Restricted login shell for GIT over SSH only
SYNOPSIS
--------
'git-shell -c <command> <argument>'
'git-shell' -c <command> <argument>
DESCRIPTION
-----------

View file

@ -8,7 +8,7 @@ git-shortlog - Summarize 'git log' output.
SYNOPSIS
--------
'git-log --pretty=short | git shortlog'
git-log --pretty=short | 'git-shortlog'
DESCRIPTION
-----------

View file

@ -8,9 +8,9 @@ git-show-branch - Show branches and their commits.
SYNOPSIS
--------
[verse]
git-show-branch [--all] [--heads] [--tags] [--topo-order] [--current]
[--more=<n> | --list | --independent | --merge-base]
[--no-name | --sha1-name] [<rev> | <glob>]...
'git-show-branch' [--all] [--heads] [--tags] [--topo-order] [--current]
[--more=<n> | --list | --independent | --merge-base]
[--no-name | --sha1-name] [<rev> | <glob>]...
DESCRIPTION
-----------

View file

@ -7,7 +7,7 @@ git-update-ref - update the object name stored in a ref safely
SYNOPSIS
--------
`git-update-ref` <ref> <newvalue> [<oldvalue>]
'git-update-ref' <ref> <newvalue> [<oldvalue>]
DESCRIPTION
-----------

View file

@ -8,7 +8,7 @@ git-var - Print the git users identity
SYNOPSIS
--------
git-var [ -l | <variable> ]
'git-var' [ -l | <variable> ]
DESCRIPTION
-----------

175
blame.c
View file

@ -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;
@ -84,7 +92,7 @@ static struct patch *get_patch(struct commit *commit, struct commit *other)
die("write failed: %s", strerror(errno));
close(fd);
sprintf(diff_cmd, "diff -u0 %s %s", tmp_path1, tmp_path2);
sprintf(diff_cmd, "diff -u -U 0 %s %s", tmp_path1, tmp_path2);
fin = popen(diff_cmd, "r");
if (!fin)
die("popen failed: %s", strerror(errno));
@ -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,137 @@ 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;
}
static const char* format_time(unsigned long time, const char* tz_str)
{
static char time_buf[128];
time_t t = time;
int minutes, tz;
struct tm *tm;
tz = atoi(tz_str);
minutes = tz < 0 ? -tz : tz;
minutes = (minutes / 100)*60 + (minutes % 100);
minutes = tz < 0 ? -minutes : minutes;
t = time + minutes * 60;
tm = gmtime(&t);
strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S ", tm);
strcat(time_buf, tz_str);
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 = 40;
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 +650,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 +659,35 @@ int main(int argc, const char **argv)
prepare_revision_walk(&rev);
process_commits(&rev, filename, &initial);
buf = blame_contents;
for (max_digits = 1, i = 10; i <= num_blame_lines + 1; max_digits++)
i *= 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) {

1
contrib/emacs/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
*.elc

20
contrib/emacs/Makefile Normal file
View file

@ -0,0 +1,20 @@
## Build and install stuff
EMACS = emacs
ELC = git.elc vc-git.elc
INSTALL = install
INSTALL_ELC = $(INSTALL) -m 644
prefix = $(HOME)
emacsdir = $(prefix)/share/emacs/site-lisp
all: $(ELC)
install: all
$(INSTALL) -d $(emacsdir)
$(INSTALL_ELC) $(ELC) $(emacsdir)
%.elc: %.el
$(EMACS) --batch --eval '(byte-compile-file "$<")'
clean:; rm -f $(ELC)

View file

@ -99,7 +99,7 @@ ()
}
}
push @revqueue, $head;
init_claim( defined $starting_rev ? $starting_rev : 'dirty');
init_claim( defined $starting_rev ? $head : 'dirty');
unless (defined $starting_rev) {
my $diff = open_pipe("git","diff","-R", "HEAD", "--",$filename)
or die "Failed to call git diff to check for dirty state: $!";
@ -345,6 +345,7 @@ sub git_cat_file {
return () unless defined $rev && defined $filename;
my $blob = git_ls_tree($rev, $filename);
die "Failed to find a blob for $filename in rev $rev\n" if !defined $blob;
my $catfile = open_pipe("git","cat-file", "blob", $blob)
or die "Failed to git-cat-file blob $blob (rev $rev, file $filename): " . $!;
@ -367,12 +368,13 @@ sub git_ls_tree {
my ($mode, $type, $blob, $tfilename);
while(<$lstree>) {
chomp;
($mode, $type, $blob, $tfilename) = split(/\s+/, $_, 4);
last if ($tfilename eq $filename);
}
close($lstree);
return $blob if $filename eq $filename;
return $blob if ($tfilename eq $filename);
die "git-ls-tree failed to find blob for $filename";
}
@ -418,7 +420,13 @@ sub format_date {
return $_[0];
}
my ($timestamp, $timezone) = split(' ', $_[0]);
return strftime("%Y-%m-%d %H:%M:%S " . $timezone, gmtime($timestamp));
my $minutes = abs($timezone);
$minutes = int($minutes / 100) * 60 + ($minutes % 100);
if ($timezone < 0) {
$minutes = -$minutes;
}
my $t = $timestamp + $minutes * 60;
return strftime("%Y-%m-%d %H:%M:%S " . $timezone, gmtime($t));
}
# Copied from git-send-email.perl - We need a Git.pm module..

View file

@ -684,13 +684,11 @@ static void rewrite_parents(struct commit *commit)
struct commit *get_revision(struct rev_info *revs)
{
struct commit_list *list = revs->commits;
struct commit *commit;
if (!list)
return NULL;
/* Check the max_count ... */
commit = list->item;
switch (revs->max_count) {
case -1:
break;
@ -701,22 +699,28 @@ struct commit *get_revision(struct rev_info *revs)
}
do {
commit = pop_most_recent_commit(&revs->commits, SEEN);
struct commit *commit = revs->commits->item;
if (commit->object.flags & (UNINTERESTING|SHOWN))
continue;
goto next;
if (revs->min_age != -1 && (commit->date > revs->min_age))
continue;
goto next;
if (revs->max_age != -1 && (commit->date < revs->max_age))
return NULL;
if (revs->no_merges && commit->parents && commit->parents->next)
continue;
goto next;
if (revs->paths && revs->dense) {
if (!(commit->object.flags & TREECHANGE))
continue;
goto next;
rewrite_parents(commit);
}
/* More to go? */
if (revs->max_count)
pop_most_recent_commit(&revs->commits, SEEN);
commit->object.flags |= SHOWN;
return commit;
next:
pop_most_recent_commit(&revs->commits, SEEN);
} while (revs->commits);
return NULL;
}

1
t/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
trash

102
t/annotate-tests.sh Normal file
View file

@ -0,0 +1,102 @@
# This file isn't used as a test script directly, instead it is
# sourced from t8001-annotate.sh and t8001-blame.sh.
check_count () {
head=
case "$1" in -h) head="$2"; shift; shift ;; esac
$PROG file $head | perl -e '
my %expect = (@ARGV);
my %count = ();
while (<STDIN>) {
if (/^[0-9a-f]+\t\(([^\t]+)\t/) {
my $author = $1;
for ($author) { s/^\s*//; s/\s*$//; }
if (exists $expect{$author}) {
$count{$author}++;
}
}
}
my $bad = 0;
while (my ($author, $count) = each %count) {
my $ok;
if ($expect{$author} != $count) {
$bad = 1;
$ok = "bad";
}
else {
$ok = "good";
}
print STDERR "Author $author (expected $expect{$author}, attributed $count) $ok\n";
}
exit($bad);
' "$@"
}
test_expect_success \
'prepare reference tree' \
'echo "1A quick brown fox jumps over the" >file &&
echo "lazy dog" >>file &&
git add file
GIT_AUTHOR_NAME="A" git commit -a -m "Initial."'
test_expect_success \
'check all lines blamed on A' \
'check_count A 2'
test_expect_success \
'Setup new lines blamed on B' \
'echo "2A quick brown fox jumps over the" >>file &&
echo "lazy dog" >> file &&
GIT_AUTHOR_NAME="B" git commit -a -m "Second."'
test_expect_success \
'Two lines blamed on A, two on B' \
'check_count A 2 B 2'
test_expect_success \
'merge-setup part 1' \
'git checkout -b branch1 master &&
echo "3A slow green fox jumps into the" >> file &&
echo "well." >> file &&
GIT_AUTHOR_NAME="B1" git commit -a -m "Branch1-1"'
test_expect_success \
'Two lines blamed on A, two on B, two on B1' \
'check_count A 2 B 2 B1 2'
test_expect_success \
'merge-setup part 2' \
'git checkout -b branch2 master &&
sed -e "s/2A quick brown/4A quick brown lazy dog/" < file > file.new &&
mv file.new file &&
GIT_AUTHOR_NAME="B2" git commit -a -m "Branch2-1"'
test_expect_success \
'Two lines blamed on A, one on B, one on B2' \
'check_count A 2 B 1 B2 1'
test_expect_success \
'merge-setup part 3' \
'git pull . branch1'
test_expect_success \
'Two lines blamed on A, one on B, two on B1, one on B2' \
'check_count A 2 B 1 B1 2 B2 1'
test_expect_success \
'Annotating an old revision works' \
'check_count -h master A 2 B 2'
test_expect_success \
'Annotating an old revision works' \
'check_count -h master^ A 2'
test_expect_success \
'merge-setup part 4' \
'echo "evil merge." >>file &&
EDITOR=: git commit -a --amend'
test_expect_success \
'Two lines blamed on A, one on B, two on B1, one on B2, one on A U Thor' \
'check_count A 2 B 1 B1 2 B2 1 "A U Thor" 1'

View file

@ -3,88 +3,7 @@
test_description='git-annotate'
. ./test-lib.sh
test_expect_success \
'prepare reference tree' \
'echo "1A quick brown fox jumps over the" >file &&
echo "lazy dog" >>file &&
git add file
GIT_AUTHOR_NAME="A" git commit -a -m "Initial."'
test_expect_success \
'check all lines blamed on A' \
'[ $(git annotate file | awk "{print \$3}" | grep -c "A") == 2 ]'
test_expect_success \
'Setup new lines blamed on B' \
'echo "2A quick brown fox jumps over the" >>file &&
echo "lazy dog" >> file &&
GIT_AUTHOR_NAME="B" git commit -a -m "Second."'
test_expect_success \
'Two lines blamed on A' \
'[ $(git annotate file | awk "{print \$3}" | grep -c "A") == 2 ]'
test_expect_success \
'Two lines blamed on B' \
'[ $(git annotate file | awk "{print \$3}" | grep -c "B") == 2 ]'
test_expect_success \
'merge-setup part 1' \
'git checkout -b branch1 master &&
echo "3A slow green fox jumps into the" >> file &&
echo "well." >> file &&
GIT_AUTHOR_NAME="B1" git commit -a -m "Branch1-1"'
test_expect_success \
'Two lines blamed on A' \
'[ $(git annotate file | awk "{print \$3}" | grep -c "^A$") == 2 ]'
test_expect_success \
'Two lines blamed on B' \
'[ $(git annotate file | awk "{print \$3}" | grep -c "^B$") == 2 ]'
test_expect_success \
'Two lines blamed on B1' \
'[ $(git annotate file | awk "{print \$3}" | grep -c "^B1$") == 2 ]'
test_expect_success \
'merge-setup part 2' \
'git checkout -b branch2 master &&
sed -e "s/2A quick brown/4A quick brown lazy dog/" < file > file.new &&
mv file.new file &&
GIT_AUTHOR_NAME="B2" git commit -a -m "Branch2-1"'
test_expect_success \
'Two lines blamed on A' \
'[ $(git annotate file | awk "{print \$3}" | grep -c "^A$") == 2 ]'
test_expect_success \
'One line blamed on B' \
'[ $(git annotate file | awk "{print \$3}" | grep -c "^B$") == 1 ]'
test_expect_success \
'One line blamed on B2' \
'[ $(git annotate file | awk "{print \$3}" | grep -c "^B2$") == 1 ]'
test_expect_success \
'merge-setup part 3' \
'git pull . branch1'
test_expect_success \
'Two lines blamed on A' \
'[ $(git annotate file | awk "{print \$3}" | grep -c "^A$") == 2 ]'
test_expect_success \
'One line blamed on B' \
'[ $(git annotate file | awk "{print \$3}" | grep -c "^B$") == 1 ]'
test_expect_success \
'Two lines blamed on B1' \
'[ $(git annotate file | awk "{print \$3}" | grep -c "^B1$") == 2 ]'
test_expect_success \
'One line blamed on B2' \
'[ $(git annotate file | awk "{print \$3}" | grep -c "^B2$") == 1 ]'
PROG='git annotate'
. ../annotate-tests.sh
test_done

9
t/t8002-blame.sh Executable file
View file

@ -0,0 +1,9 @@
#!/bin/sh
test_description='git-blame'
. ./test-lib.sh
PROG='git blame -c'
. ../annotate-tests.sh
test_done