diff options
-rw-r--r-- | Makefile | 11 | ||||
-rw-r--r-- | builtin-help.c | 241 | ||||
-rw-r--r-- | builtin-log.c | 69 | ||||
-rw-r--r-- | builtin.h | 23 | ||||
-rw-r--r-- | contrib/colordiff/README | 2 | ||||
-rwxr-xr-x | contrib/colordiff/colordiff.perl | 196 | ||||
-rw-r--r-- | diff-lib.c | 77 | ||||
-rwxr-xr-x | git-commit.sh | 21 | ||||
-rwxr-xr-x | git-svnimport.perl | 4 | ||||
-rw-r--r-- | git.c | 305 | ||||
-rwxr-xr-x | gitk | 20 | ||||
-rw-r--r-- | mailinfo.c | 12 | ||||
-rw-r--r-- | pack-objects.c | 4 | ||||
-rw-r--r-- | pager.c | 2 | ||||
-rwxr-xr-x | t/t1200-tutorial.sh | 2 |
15 files changed, 642 insertions, 347 deletions
@@ -213,6 +213,9 @@ LIB_OBJS = \ fetch-clone.o revision.o pager.o tree-walk.o xdiff-interface.o \ $(DIFF_OBJS) +BUILTIN_OBJS = \ + builtin-log.o builtin-help.o + GITLIBS = $(LIB_FILE) $(XDIFF_LIB) LIBS = $(GITLIBS) -lz @@ -462,10 +465,12 @@ all: strip: $(PROGRAMS) git$X $(STRIP) $(STRIP_OPTS) $(PROGRAMS) git$X -git$X: git.c common-cmds.h $(GITLIBS) +git$X: git.c common-cmds.h $(BUILTIN_OBJS) $(GITLIBS) $(CC) -DGIT_VERSION='"$(GIT_VERSION)"' \ $(ALL_CFLAGS) -o $@ $(filter %.c,$^) \ - $(ALL_LDFLAGS) $(LIBS) + $(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS) + +builtin-help.o: common-cmds.h $(BUILT_INS): git$X rm -f $@ && ln git$X $@ @@ -565,7 +570,7 @@ init-db.o: init-db.c $(CC) -c $(ALL_CFLAGS) \ -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"' $*.c -$(LIB_OBJS): $(LIB_H) +$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H) $(patsubst git-%$X,%.o,$(PROGRAMS)): $(GITLIBS) $(DIFF_OBJS): diffcore.h diff --git a/builtin-help.c b/builtin-help.c new file mode 100644 index 0000000000..10a59cc403 --- /dev/null +++ b/builtin-help.c @@ -0,0 +1,241 @@ +/* + * builtin-help.c + * + * Builtin help-related commands (help, usage, version) + */ +#include "cache.h" +#include "builtin.h" +#include "exec_cmd.h" +#include "common-cmds.h" + +static const char git_usage[] = + "Usage: git [--version] [--exec-path[=GIT_EXEC_PATH]] [--help] COMMAND [ ARGS ]"; + +/* most gui terms set COLUMNS (although some don't export it) */ +static int term_columns(void) +{ + char *col_string = getenv("COLUMNS"); + int n_cols = 0; + + if (col_string && (n_cols = atoi(col_string)) > 0) + return n_cols; + +#ifdef TIOCGWINSZ + { + struct winsize ws; + if (!ioctl(1, TIOCGWINSZ, &ws)) { + if (ws.ws_col) + return ws.ws_col; + } + } +#endif + + return 80; +} + +static void oom(void) +{ + fprintf(stderr, "git: out of memory\n"); + exit(1); +} + +static inline void mput_char(char c, unsigned int num) +{ + while(num--) + putchar(c); +} + +static struct cmdname { + size_t len; + char name[1]; +} **cmdname; +static int cmdname_alloc, cmdname_cnt; + +static void add_cmdname(const char *name, int len) +{ + struct cmdname *ent; + if (cmdname_alloc <= cmdname_cnt) { + cmdname_alloc = cmdname_alloc + 200; + cmdname = realloc(cmdname, cmdname_alloc * sizeof(*cmdname)); + if (!cmdname) + oom(); + } + ent = malloc(sizeof(*ent) + len); + if (!ent) + oom(); + ent->len = len; + memcpy(ent->name, name, len); + ent->name[len] = 0; + cmdname[cmdname_cnt++] = ent; +} + +static int cmdname_compare(const void *a_, const void *b_) +{ + struct cmdname *a = *(struct cmdname **)a_; + struct cmdname *b = *(struct cmdname **)b_; + return strcmp(a->name, b->name); +} + +static void pretty_print_string_list(struct cmdname **cmdname, int longest) +{ + int cols = 1, rows; + int space = longest + 1; /* min 1 SP between words */ + int max_cols = term_columns() - 1; /* don't print *on* the edge */ + int i, j; + + if (space < max_cols) + cols = max_cols / space; + rows = (cmdname_cnt + cols - 1) / cols; + + qsort(cmdname, cmdname_cnt, sizeof(*cmdname), cmdname_compare); + + for (i = 0; i < rows; i++) { + printf(" "); + + for (j = 0; j < cols; j++) { + int n = j * rows + i; + int size = space; + if (n >= cmdname_cnt) + break; + if (j == cols-1 || n + rows >= cmdname_cnt) + size = 1; + printf("%-*s", size, cmdname[n]->name); + } + putchar('\n'); + } +} + +static void list_commands(const char *exec_path, const char *pattern) +{ + unsigned int longest = 0; + char path[PATH_MAX]; + int dirlen; + DIR *dir = opendir(exec_path); + struct dirent *de; + + if (!dir) { + fprintf(stderr, "git: '%s': %s\n", exec_path, strerror(errno)); + exit(1); + } + + dirlen = strlen(exec_path); + if (PATH_MAX - 20 < dirlen) { + fprintf(stderr, "git: insanely long exec-path '%s'\n", + exec_path); + exit(1); + } + + memcpy(path, exec_path, dirlen); + path[dirlen++] = '/'; + + while ((de = readdir(dir)) != NULL) { + struct stat st; + int entlen; + + if (strncmp(de->d_name, "git-", 4)) + continue; + strcpy(path+dirlen, de->d_name); + if (stat(path, &st) || /* stat, not lstat */ + !S_ISREG(st.st_mode) || + !(st.st_mode & S_IXUSR)) + continue; + + entlen = strlen(de->d_name); + if (4 < entlen && !strcmp(de->d_name + entlen - 4, ".exe")) + entlen -= 4; + + if (longest < entlen) + longest = entlen; + + add_cmdname(de->d_name + 4, entlen-4); + } + closedir(dir); + + printf("git commands available in '%s'\n", exec_path); + printf("----------------------------"); + mput_char('-', strlen(exec_path)); + putchar('\n'); + pretty_print_string_list(cmdname, longest - 4); + putchar('\n'); +} + +static void list_common_cmds_help(void) +{ + int i, longest = 0; + + for (i = 0; i < ARRAY_SIZE(common_cmds); i++) { + if (longest < strlen(common_cmds[i].name)) + longest = strlen(common_cmds[i].name); + } + + puts("The most commonly used git commands are:"); + for (i = 0; i < ARRAY_SIZE(common_cmds); i++) { + printf(" %s", common_cmds[i].name); + mput_char(' ', longest - strlen(common_cmds[i].name) + 4); + puts(common_cmds[i].help); + } + puts("(use 'git help -a' to get a list of all installed git commands)"); +} + +void cmd_usage(int show_all, const char *exec_path, const char *fmt, ...) +{ + if (fmt) { + va_list ap; + + va_start(ap, fmt); + printf("git: "); + vprintf(fmt, ap); + va_end(ap); + putchar('\n'); + } + else + puts(git_usage); + + if (exec_path) { + putchar('\n'); + if (show_all) + list_commands(exec_path, "git-*"); + else + list_common_cmds_help(); + } + + exit(1); +} + +static void show_man_page(const char *git_cmd) +{ + const char *page; + + if (!strncmp(git_cmd, "git", 3)) + page = git_cmd; + else { + int page_len = strlen(git_cmd) + 4; + char *p = malloc(page_len + 1); + strcpy(p, "git-"); + strcpy(p + 4, git_cmd); + p[page_len] = 0; + page = p; + } + + execlp("man", "man", page, NULL); +} + +int cmd_version(int argc, const char **argv, char **envp) +{ + printf("git version %s\n", git_version_string); + return 0; +} + +int cmd_help(int argc, const char **argv, char **envp) +{ + const char *help_cmd = argv[1]; + if (!help_cmd) + cmd_usage(0, git_exec_path(), NULL); + else if (!strcmp(help_cmd, "--all") || !strcmp(help_cmd, "-a")) + cmd_usage(1, git_exec_path(), NULL); + else + show_man_page(help_cmd); + return 0; +} + + diff --git a/builtin-log.c b/builtin-log.c new file mode 100644 index 0000000000..69f2911cb4 --- /dev/null +++ b/builtin-log.c @@ -0,0 +1,69 @@ +/* + * Builtin "git log" and related commands (show, whatchanged) + * + * (C) Copyright 2006 Linus Torvalds + * 2006 Junio Hamano + */ +#include "cache.h" +#include "commit.h" +#include "diff.h" +#include "revision.h" +#include "log-tree.h" + +static int cmd_log_wc(int argc, const char **argv, char **envp, + struct rev_info *rev) +{ + struct commit *commit; + + rev->abbrev = DEFAULT_ABBREV; + rev->commit_format = CMIT_FMT_DEFAULT; + rev->verbose_header = 1; + argc = setup_revisions(argc, argv, rev, "HEAD"); + + if (argc > 1) + die("unrecognized argument: %s", argv[1]); + + prepare_revision_walk(rev); + setup_pager(); + while ((commit = get_revision(rev)) != NULL) { + log_tree_commit(rev, commit); + free(commit->buffer); + commit->buffer = NULL; + } + return 0; +} + +int cmd_whatchanged(int argc, const char **argv, char **envp) +{ + struct rev_info rev; + + init_revisions(&rev); + rev.diff = 1; + rev.diffopt.recursive = 1; + return cmd_log_wc(argc, argv, envp, &rev); +} + +int cmd_show(int argc, const char **argv, char **envp) +{ + struct rev_info rev; + + init_revisions(&rev); + rev.diff = 1; + rev.diffopt.recursive = 1; + rev.combine_merges = 1; + rev.dense_combined_merges = 1; + rev.always_show_header = 1; + rev.ignore_merges = 0; + rev.no_walk = 1; + return cmd_log_wc(argc, argv, envp, &rev); +} + +int cmd_log(int argc, const char **argv, char **envp) +{ + struct rev_info rev; + + init_revisions(&rev); + rev.always_show_header = 1; + rev.diffopt.recursive = 1; + return cmd_log_wc(argc, argv, envp, &rev); +} diff --git a/builtin.h b/builtin.h new file mode 100644 index 0000000000..47408a0585 --- /dev/null +++ b/builtin.h @@ -0,0 +1,23 @@ +#ifndef BUILTIN_H +#define BUILTIN_H + +#ifndef PATH_MAX +# define PATH_MAX 4096 +#endif + +extern const char git_version_string[]; + +void cmd_usage(int show_all, const char *exec_path, const char *fmt, ...) +#ifdef __GNUC__ + __attribute__((__format__(__printf__, 3, 4), __noreturn__)) +#endif + ; + +extern int cmd_help(int argc, const char **argv, char **envp); +extern int cmd_version(int argc, const char **argv, char **envp); + +extern int cmd_whatchanged(int argc, const char **argv, char **envp); +extern int cmd_show(int argc, const char **argv, char **envp); +extern int cmd_log(int argc, const char **argv, char **envp); + +#endif diff --git a/contrib/colordiff/README b/contrib/colordiff/README new file mode 100644 index 0000000000..2678fdf9c2 --- /dev/null +++ b/contrib/colordiff/README @@ -0,0 +1,2 @@ +This is "colordiff" (http://colordiff.sourceforge.net/) by Dave +Ewart <davee@sungate.co.uk>, modified specifically for git. diff --git a/contrib/colordiff/colordiff.perl b/contrib/colordiff/colordiff.perl new file mode 100755 index 0000000000..5789cfb265 --- /dev/null +++ b/contrib/colordiff/colordiff.perl @@ -0,0 +1,196 @@ +#!/usr/bin/perl -w +# +# $Id: colordiff.pl,v 1.4.2.10 2004/01/04 15:02:59 daveewart Exp $ + +######################################################################## +# # +# ColorDiff - a wrapper/replacment for 'diff' producing # +# colourful output # +# # +# Copyright (C)2002-2004 Dave Ewart (davee@sungate.co.uk) # +# # +######################################################################## +# # +# This program is free software; you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation; either version 2 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program; if not, write to the Free Software # +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # +# # +######################################################################## + +use strict; +use Getopt::Long qw(:config pass_through); +use IPC::Open2; + +my $app_name = 'colordiff'; +my $version = '1.0.4'; +my $author = 'Dave Ewart'; +my $author_email = 'davee@sungate.co.uk'; +my $app_www = 'http://colordiff.sourceforge.net/'; +my $copyright = '(C)2002-2004'; +my $show_banner = 1; + +# ANSI sequences for colours +my %colour; +$colour{white} = "\033[1;37m"; +$colour{yellow} = "\033[1;33m"; +$colour{green} = "\033[1;32m"; +$colour{blue} = "\033[1;34m"; +$colour{cyan} = "\033[1;36m"; +$colour{red} = "\033[1;31m"; +$colour{magenta} = "\033[1;35m"; +$colour{black} = "\033[1;30m"; +$colour{darkwhite} = "\033[0;37m"; +$colour{darkyellow} = "\033[0;33m"; +$colour{darkgreen} = "\033[0;32m"; +$colour{darkblue} = "\033[0;34m"; +$colour{darkcyan} = "\033[0;36m"; +$colour{darkred} = "\033[0;31m"; +$colour{darkmagenta} = "\033[0;35m"; +$colour{darkblack} = "\033[0;30m"; +$colour{OFF} = "\033[0;0m"; + +# Default colours if /etc/colordiffrc or ~/.colordiffrc do not exist +my $plain_text = $colour{OFF}; +my $file_old = $colour{red}; +my $file_new = $colour{blue}; +my $diff_stuff = $colour{magenta}; + +# Locations for personal and system-wide colour configurations +my $HOME = $ENV{HOME}; +my $etcdir = '/etc'; + +my ($setting, $value); +my @config_files = ("$etcdir/colordiffrc", "$HOME/.colordiffrc"); +my $config_file; + +foreach $config_file (@config_files) { + if (open(COLORDIFFRC, "<$config_file")) { + while (<COLORDIFFRC>) { + chop; + next if (/^#/ || /^$/); + s/\s+//g; + ($setting, $value) = split ('='); + if ($setting eq 'banner') { + if ($value eq 'no') { + $show_banner = 0; + } + next; + } + if (!defined $colour{$value}) { + print "Invalid colour specification ($value) in $config_file\n"; + next; + } + if ($setting eq 'plain') { + $plain_text = $colour{$value}; + } + elsif ($setting eq 'oldtext') { + $file_old = $colour{$value}; + } + elsif ($setting eq 'newtext') { + $file_new = $colour{$value}; + } + elsif ($setting eq 'diffstuff') { + $diff_stuff = $colour{$value}; + } + else { + print "Unknown option in $etcdir/colordiffrc: $setting\n"; + } + } + close COLORDIFFRC; + } +} + +# colordiff specfic options here. Need to pre-declare if using variables +GetOptions( + "no-banner" => sub { $show_banner = 0 }, + "plain-text=s" => \&set_color, + "file-old=s" => \&set_color, + "file-new=s" => \&set_color, + "diff-stuff=s" => \&set_color +); + +if ($show_banner == 1) { + print STDERR "$app_name $version ($app_www)\n"; + print STDERR "$copyright $author, $author_email\n\n"; +} + +if (defined $ARGV[0]) { + # More reliable way of pulling in arguments + open2(\*INPUTSTREAM, undef, "git", "diff", @ARGV); +} +else { + *INPUTSTREAM = \*STDIN; +} + +my $record; +my $nrecs = 0; +my $inside_file_old = 1; +my $nparents = undef; + +while (<INPUTSTREAM>) { + $nrecs++; + if (/^(\@\@+) -[-+0-9, ]+ \1/) { + print "$diff_stuff"; + $nparents = length($1) - 1; + } + elsif (/^diff -/ || /^index / || + /^old mode / || /^new mode / || + /^deleted file mode / || /^new file mode / || + /^similarity index / || /^dissimilarity index / || + /^copy from / || /^copy to / || + /^rename from / || /^rename to /) { + $nparents = undef; + print "$diff_stuff"; + } + elsif (defined $nparents) { + if ($nparents == 1) { + if (/^\+/) { + print $file_new; + } + elsif (/^-/) { + print $file_old; + } + else { + print $plain_text; + } + } + elsif (/^ {$nparents}/) { + print "$plain_text"; + } + elsif (/^[+ ]{$nparents}/) { + print "$file_new"; + } + elsif (/^[- ]{$nparents}/) { + print "$file_old"; + } + else { + print $plain_text; + } + } + elsif (/^--- / || /^\+\+\+ /) { + print $diff_stuff; + } + else { + print "$plain_text"; + } + s/$/$colour{OFF}/; + print "$_"; +} +close INPUTSTREAM; + +sub set_color { + my ($type, $color) = @_; + + $type =~ s/-/_/; + eval "\$$type = \$colour{$color}"; +} diff --git a/diff-lib.c b/diff-lib.c index 0a832c3585..13b216f273 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -195,6 +195,56 @@ static int fn_out(void *priv, mmbuffer_t *mb, int nbuf) return 0; } +static char *pprint_rename(const char *a, const char *b) +{ + const char *old = a; + const char *new = b; + char *name = NULL; + int pfx_length, sfx_length; + int len_a = strlen(a); + int len_b = strlen(b); + + /* Find common prefix */ + pfx_length = 0; + while (*old && *new && *old == *new) { + if (*old == '/') + pfx_length = old - a + 1; + old++; + new++; + } + + /* Find common suffix */ + old = a + len_a; + new = b + len_b; + sfx_length = 0; + while (a <= old && b <= new && *old == *new) { + if (*old == '/') + sfx_length = len_a - (old - a); + old--; + new--; + } + + /* + * pfx{mid-a => mid-b}sfx + * {pfx-a => pfx-b}sfx + * pfx{sfx-a => sfx-b} + * name-a => name-b + */ + if (pfx_length + sfx_length) { + name = xmalloc(len_a + len_b - pfx_length - sfx_length + 7); + sprintf(name, "%.*s{%.*s => %.*s}%s", + pfx_length, a, + len_a - pfx_length - sfx_length, a + pfx_length, + len_b - pfx_length - sfx_length, b + pfx_length, + a + len_a - sfx_length); + } + else { + name = xmalloc(len_a + len_b + 5); + sprintf(name, "%s => %s", a, b); + } + return name; +} + struct diffstat_t { struct xdiff_emit_state xm; @@ -204,12 +254,14 @@ struct diffstat_t { char *name; unsigned is_unmerged:1; unsigned is_binary:1; + unsigned is_renamed:1; unsigned int added, deleted; } **files; }; static struct diffstat_file *diffstat_add(struct diffstat_t *diffstat, - const char *name) + const char *name_a, + const char *name_b) { struct diffstat_file *x; x = xcalloc(sizeof (*x), 1); @@ -219,7 +271,12 @@ static struct diffstat_file *diffstat_add(struct diffstat_t *diffstat, diffstat->alloc * sizeof(x)); } diffstat->files[diffstat->nr++] = x; - x->name = strdup(name); + if (name_b) { + x->name = pprint_rename(name_a, name_b); + x->is_renamed = 1; + } + else + x->name = strdup(name_a); return x; } @@ -305,7 +362,8 @@ static void show_stats(struct diffstat_t* data) printf(" %s%-*s | Unmerged\n", prefix, len, name); goto free_diffstat_file; } - else if (added + deleted == 0) { + else if (!data->files[i]->is_renamed && + (added + deleted == 0)) { total_files--; goto free_diffstat_file; } @@ -425,13 +483,14 @@ static void builtin_diff(const char *name_a, } static void builtin_diffstat(const char *name_a, const char *name_b, - struct diff_filespec *one, struct diff_filespec *two, - struct diffstat_t *diffstat) + struct diff_filespec *one, + struct diff_filespec *two, + struct diffstat_t *diffstat) { mmfile_t mf1, mf2; struct diffstat_file *data; - data = diffstat_add(diffstat, name_a ? name_a : name_b); + data = diffstat_add(diffstat, name_a, name_b); if (!one || !two) { data->is_unmerged = 1; @@ -992,7 +1051,7 @@ static void run_diff(struct diff_filepair *p, struct diff_options *o) } static void run_diffstat(struct diff_filepair *p, struct diff_options *o, - struct diffstat_t *diffstat) + struct diffstat_t *diffstat) { const char *name; const char *other; @@ -1374,7 +1433,7 @@ static void diff_flush_patch(struct diff_filepair *p, struct diff_options *o) } static void diff_flush_stat(struct diff_filepair *p, struct diff_options *o, - struct diffstat_t *diffstat) + struct diffstat_t *diffstat) { if (diff_unmodified_pair(p)) return; @@ -1559,7 +1618,7 @@ void diff_flush(struct diff_options *options) for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; flush_one_pair(p, DIFF_FORMAT_DIFFSTAT, options, - diffstat); + diffstat); } show_stats(diffstat); free(diffstat); diff --git a/git-commit.sh b/git-commit.sh index 01c73bdd08..26cd7ca54d 100755 --- a/git-commit.sh +++ b/git-commit.sh @@ -167,8 +167,13 @@ run_status () { fi case "$committable" in 0) - echo "nothing to commit" - exit 1 + case "$amend" in + t) + echo "# No changes" ;; + *) + echo "nothing to commit" ;; + esac + exit 1 ;; esac exit 0 ) @@ -365,14 +370,16 @@ tt*) die "Only one of -c/-C/-F/-m can be used." ;; esac -case "$#,$also$only" in -*,tt) +case "$#,$also,$only,$amend" in +*,t,t,*) die "Only one of --include/--only can be used." ;; -0,t) +0,t,,* | 0,,t,) die "No paths with --include/--only does not make sense." ;; -0,) +0,,t,t) + only_include_assumed="# Clever... amending the last one with dirty index." ;; +0,,,*) ;; -*,) +*,,,*) only_include_assumed="# Explicit paths specified without -i nor -o; assuming --only paths..." also= ;; diff --git a/git-svnimport.perl b/git-svnimport.perl index 60ed7ae3ee..61f559f0a8 100755 --- a/git-svnimport.perl +++ b/git-svnimport.perl @@ -136,8 +136,10 @@ sub file { print "... $rev $path ...\n" if $opt_v; my (undef, $properties); + my $pool = SVN::Pool->new(); eval { (undef, $properties) - = $self->{'svn'}->get_file($path,$rev,$fh); }; + = $self->{'svn'}->get_file($path,$rev,$fh,$pool); }; + $pool->clear; if($@) { return undef if $@ =~ /Attempted to get checksum/; die $@; @@ -11,215 +11,8 @@ #include <sys/ioctl.h> #include "git-compat-util.h" #include "exec_cmd.h" -#include "common-cmds.h" -#include "cache.h" -#include "commit.h" -#include "diff.h" -#include "revision.h" -#include "log-tree.h" - -#ifndef PATH_MAX -# define PATH_MAX 4096 -#endif - -static const char git_usage[] = - "Usage: git [--version] [--exec-path[=GIT_EXEC_PATH]] [--help] COMMAND [ ARGS ]"; - -/* most gui terms set COLUMNS (although some don't export it) */ -static int term_columns(void) -{ - char *col_string = getenv("COLUMNS"); - int n_cols = 0; - - if (col_string && (n_cols = atoi(col_string)) > 0) - return n_cols; - -#ifdef TIOCGWINSZ - { - struct winsize ws; - if (!ioctl(1, TIOCGWINSZ, &ws)) { - if (ws.ws_col) - return ws.ws_col; - } - } -#endif - - return 80; -} - -static void oom(void) -{ - fprintf(stderr, "git: out of memory\n"); - exit(1); -} - -static inline void mput_char(char c, unsigned int num) -{ - while(num--) - putchar(c); -} - -static struct cmdname { - size_t len; - char name[1]; -} **cmdname; -static int cmdname_alloc, cmdname_cnt; - -static void add_cmdname(const char *name, int len) -{ - struct cmdname *ent; - if (cmdname_alloc <= cmdname_cnt) { - cmdname_alloc = cmdname_alloc + 200; - cmdname = realloc(cmdname, cmdname_alloc * sizeof(*cmdname)); - if (!cmdname) - oom(); - } - ent = malloc(sizeof(*ent) + len); - if (!ent) - oom(); - ent->len = len; - memcpy(ent->name, name, len); - ent->name[len] = 0; - cmdname[cmdname_cnt++] = ent; -} - -static int cmdname_compare(const void *a_, const void *b_) -{ - struct cmdname *a = *(struct cmdname **)a_; - struct cmdname *b = *(struct cmdname **)b_; - return strcmp(a->name, b->name); -} - -static void pretty_print_string_list(struct cmdname **cmdname, int longest) -{ - int cols = 1, rows; - int space = longest + 1; /* min 1 SP between words */ - int max_cols = term_columns() - 1; /* don't print *on* the edge */ - int i, j; - - if (space < max_cols) - cols = max_cols / space; - rows = (cmdname_cnt + cols - 1) / cols; - - qsort(cmdname, cmdname_cnt, sizeof(*cmdname), cmdname_compare); - - for (i = 0; i < rows; i++) { - printf(" "); - - for (j = 0; j < cols; j++) { - int n = j * rows + i; - int size = space; - if (n >= cmdname_cnt) - break; - if (j == cols-1 || n + rows >= cmdname_cnt) - size = 1; - printf("%-*s", size, cmdname[n]->name); - } - putchar('\n'); - } -} - -static void list_commands(const char *exec_path, const char *pattern) -{ - unsigned int longest = 0; - char path[PATH_MAX]; - int dirlen; - DIR *dir = opendir(exec_path); - struct dirent *de; - - if (!dir) { - fprintf(stderr, "git: '%s': %s\n", exec_path, strerror(errno)); - exit(1); - } - - dirlen = strlen(exec_path); - if (PATH_MAX - 20 < dirlen) { - fprintf(stderr, "git: insanely long exec-path '%s'\n", - exec_path); - exit(1); - } - - memcpy(path, exec_path, dirlen); - path[dirlen++] = '/'; - - while ((de = readdir(dir)) != NULL) { - struct stat st; - int entlen; - - if (strncmp(de->d_name, "git-", 4)) - continue; - strcpy(path+dirlen, de->d_name); - if (stat(path, &st) || /* stat, not lstat */ - !S_ISREG(st.st_mode) || - !(st.st_mode & S_IXUSR)) - continue; - - entlen = strlen(de->d_name); - if (4 < entlen && !strcmp(de->d_name + entlen - 4, ".exe")) - entlen -= 4; - - if (longest < entlen) - longest = entlen; - - add_cmdname(de->d_name + 4, entlen-4); - } - closedir(dir); - - printf("git commands available in '%s'\n", exec_path); - printf("----------------------------"); - mput_char('-', strlen(exec_path)); - putchar('\n'); - pretty_print_string_list(cmdname, longest - 4); - putchar('\n'); -} - -static void list_common_cmds_help(void) -{ - int i, longest = 0; - - for (i = 0; i < ARRAY_SIZE(common_cmds); i++) { - if (longest < strlen(common_cmds[i].name)) - longest = strlen(common_cmds[i].name); - } - - puts("The most commonly used git commands are:"); - for (i = 0; i < ARRAY_SIZE(common_cmds); i++) { - printf(" %s", common_cmds[i].name); - mput_char(' ', longest - strlen(common_cmds[i].name) + 4); - puts(common_cmds[i].help); - } - puts("(use 'git help -a' to get a list of all installed git commands)"); -} - -#ifdef __GNUC__ -static void cmd_usage(int show_all, const char *exec_path, const char *fmt, ...) - __attribute__((__format__(__printf__, 3, 4), __noreturn__)); -#endif -static void cmd_usage(int show_all, const char *exec_path, const char *fmt, ...) -{ - if (fmt) { - va_list ap; - - va_start(ap, fmt); - printf("git: "); - vprintf(fmt, ap); - va_end(ap); - putchar('\n'); - } - else - puts(git_usage); - - if (exec_path) { - putchar('\n'); - if (show_all) - list_commands(exec_path, "git-*"); - else - list_common_cmds_help(); - } - - exit(1); -} +#include "builtin.h" static void prepend_to_path(const char *dir, int len) { @@ -240,99 +33,7 @@ static void prepend_to_path(const char *dir, int len) setenv("PATH", path, 1); } -static void show_man_page(const char *git_cmd) -{ - const char *page; - - if (!strncmp(git_cmd, "git", 3)) - page = git_cmd; - else { - int page_len = strlen(git_cmd) + 4; - char *p = malloc(page_len + 1); - strcpy(p, "git-"); - strcpy(p + 4, git_cmd); - p[page_len] = 0; - page = p; - } - - execlp("man", "man", page, NULL); -} - -static int cmd_version(int argc, const char **argv, char **envp) -{ - printf("git version %s\n", GIT_VERSION); - return 0; -} - -static int cmd_help(int argc, const char **argv, char **envp) -{ - const char *help_cmd = argv[1]; - if (!help_cmd) - cmd_usage(0, git_exec_path(), NULL); - else if (!strcmp(help_cmd, "--all") || !strcmp(help_cmd, "-a")) - cmd_usage(1, git_exec_path(), NULL); - else - show_man_page(help_cmd); - return 0; -} - -static int cmd_log_wc(int argc, const char **argv, char **envp, - struct rev_info *rev) -{ - struct commit *commit; - - rev->abbrev = DEFAULT_ABBREV; - rev->commit_format = CMIT_FMT_DEFAULT; - rev->verbose_header = 1; - argc = setup_revisions(argc, argv, rev, "HEAD"); - - if (argc > 1) - die("unrecognized argument: %s", argv[1]); - - prepare_revision_walk(rev); - setup_pager(); - while ((commit = get_revision(rev)) != NULL) { - log_tree_commit(rev, commit); - free(commit->buffer); - commit->buffer = NULL; - } - return 0; -} - -static int cmd_wc(int argc, const char **argv, char **envp) -{ - struct rev_info rev; - - init_revisions(&rev); - rev.diff = 1; - rev.diffopt.recursive = 1; - return cmd_log_wc(argc, argv, envp, &rev); -} - -static int cmd_show(int argc, const char **argv, char **envp) -{ - struct rev_info rev; - - init_revisions(&rev); - rev.diff = 1; - rev.diffopt.recursive = 1; - rev.combine_merges = 1; - rev.dense_combined_merges = 1; - rev.always_show_header = 1; - rev.ignore_merges = 0; - rev.no_walk = 1; - return cmd_log_wc(argc, argv, envp, &rev); -} - -static int cmd_log(int argc, const char **argv, char **envp) -{ - struct rev_info rev; - - init_revisions(&rev); - rev.always_show_header = 1; - rev.diffopt.recursive = 1; - return cmd_log_wc(argc, argv, envp, &rev); -} +const char git_version_string[] = GIT_VERSION; static void handle_internal_command(int argc, const char **argv, char **envp) { @@ -344,7 +45,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp) { "version", cmd_version }, { "help", cmd_help }, { "log", cmd_log }, - { "whatchanged", cmd_wc }, + { "whatchanged", cmd_whatchanged }, { "show", cmd_show }, }; int i; @@ -16,22 +16,6 @@ proc gitdir {} { } } -proc parse_args {rargs} { - global parsed_args - - if {[catch { - set parse_args [concat --default HEAD $rargs] - set parsed_args [split [eval exec git-rev-parse $parse_args] "\n"] - }]} { - # if git-rev-parse failed for some reason... - if {$rargs == {}} { - set rargs HEAD - } - set parsed_args $rargs - } - return $parsed_args -} - proc start_rev_list {rlargs} { global startmsecs nextupdate ncmupdate global commfd leftover tclencoding datemode @@ -46,7 +30,7 @@ proc start_rev_list {rlargs} { } if {[catch { set commfd [open [concat | git-rev-list --header $order \ - --parents --boundary $rlargs] r] + --parents --boundary --default HEAD $rlargs] r] } err]} { puts stderr "Error executing git-rev-list: $err" exit 1 @@ -65,7 +49,7 @@ proc getcommits {rargs} { global phase canv mainfont set phase getcommits - start_rev_list [parse_args $rargs] + start_rev_list $rargs $canv delete all $canv create text 3 3 -anchor nw -text "Reading commits..." \ -font $mainfont -tags textitems diff --git a/mailinfo.c b/mailinfo.c index 3c56f8c108..b27651935d 100644 --- a/mailinfo.c +++ b/mailinfo.c @@ -405,7 +405,7 @@ static unsigned hexval(int c) return ~0; } -static int decode_q_segment(char *in, char *ot, char *ep) +static int decode_q_segment(char *in, char *ot, char *ep, int rfc2047) { int c; while ((c = *in++) != 0 && (in <= ep)) { @@ -414,9 +414,11 @@ static int decode_q_segment(char *in, char *ot, char *ep) if (d == '\n' || !d) break; /* drop trailing newline */ *ot++ = ((hexval(d) << 4) | hexval(*in++)); + continue; } - else - *ot++ = c; + if (rfc2047 && c == '_') /* rfc2047 4.2 (2) */ + c = 0x20; + *ot++ = c; } *ot = 0; return 0; @@ -547,7 +549,7 @@ static void decode_header_bq(char *it) sz = decode_b_segment(cp + 3, piecebuf, ep); break; case 'q': - sz = decode_q_segment(cp + 3, piecebuf, ep); + sz = decode_q_segment(cp + 3, piecebuf, ep, 1); break; } if (sz < 0) @@ -569,7 +571,7 @@ static void decode_transfer_encoding(char *line) switch (transfer_encoding) { case TE_QP: ep = line + strlen(line); - decode_q_segment(line, line, ep); + decode_q_segment(line, line, ep, 0); break; case TE_BASE64: ep = line + strlen(line); diff --git a/pack-objects.c b/pack-objects.c index 09f4f2c944..c0acc460bb 100644 --- a/pack-objects.c +++ b/pack-objects.c @@ -1052,7 +1052,7 @@ static int try_delta(struct unpacked *cur, struct unpacked *old, unsigned max_de if (cur_entry->delta) max_size = cur_entry->delta_size-1; if (sizediff >= max_size) - return -1; + return 0; delta_buf = diff_delta(old->data, oldsize, cur->data, size, &delta_size, max_size); if (!delta_buf) @@ -1231,7 +1231,7 @@ static void setup_progress_signal(void) int main(int argc, char **argv) { SHA_CTX ctx; - char line[PATH_MAX + 20]; + char line[40 + 1 + PATH_MAX + 2]; int window = 10, depth = 10, pack_to_stdout = 0; struct object_entry **list; int num_preferred_base = 0; @@ -8,6 +8,7 @@ static void run_pager(const char *pager) { execlp(pager, pager, NULL); + execl("/bin/sh", "sh", "-c", pager, NULL); } void setup_pager(void) @@ -47,5 +48,6 @@ void setup_pager(void) setenv("LESS", "-S", 0); run_pager(pager); + die("unable to execute pager '%s'", pager); exit(255); } diff --git a/t/t1200-tutorial.sh b/t/t1200-tutorial.sh index 16b3ea9157..c7db20e7f3 100755 --- a/t/t1200-tutorial.sh +++ b/t/t1200-tutorial.sh @@ -114,6 +114,8 @@ EOF git commit -m 'Merged "mybranch" changes.' -i hello +test_done + cat > show-branch.expect << EOF * [master] Merged "mybranch" changes. ! [mybranch] Some work. |