summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile11
-rw-r--r--builtin-help.c241
-rw-r--r--builtin-log.c69
-rw-r--r--builtin.h23
-rw-r--r--contrib/colordiff/README2
-rwxr-xr-xcontrib/colordiff/colordiff.perl196
-rw-r--r--diff-lib.c77
-rwxr-xr-xgit-commit.sh21
-rwxr-xr-xgit-svnimport.perl4
-rw-r--r--git.c305
-rwxr-xr-xgitk20
-rw-r--r--mailinfo.c12
-rw-r--r--pack-objects.c4
-rw-r--r--pager.c2
-rwxr-xr-xt/t1200-tutorial.sh2
15 files changed, 642 insertions, 347 deletions
diff --git a/Makefile b/Makefile
index 3ecd674c14..d9a3a82fe2 100644
--- a/Makefile
+++ b/Makefile
@@ -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 $@;
diff --git a/git.c b/git.c
index 40b7e42ae9..aa2b814d93 100644
--- a/git.c
+++ b/git.c
@@ -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;
diff --git a/gitk b/gitk
index 87e71629af..5362b76bee 100755
--- a/gitk
+++ b/gitk
@@ -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;
diff --git a/pager.c b/pager.c
index b063353d96..9a30939016 100644
--- a/pager.c
+++ b/pager.c
@@ -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.