summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <junkio@cox.net>2006-04-21 20:19:58 (GMT)
committerJunio C Hamano <junkio@cox.net>2006-04-21 20:25:47 (GMT)
commit91efcf60653b2538b05625807293b97c07cb04f4 (patch)
tree0240b448657063bc251be1c79596377ea8b91542
parent43885c2a557871aedcbb1a412fc18e98c3dd1dc4 (diff)
parent70827b15bfb11f7aea52c6995956be9d149233e1 (diff)
downloadgit-91efcf60653b2538b05625807293b97c07cb04f4.zip
git-91efcf60653b2538b05625807293b97c07cb04f4.tar.gz
git-91efcf60653b2538b05625807293b97c07cb04f4.tar.bz2
Merge branch 'master' into jc/fmt-patch
* master: Split up builtin commands into separate files from git.c git-log produces no output fix pack-object buffer size mailinfo: decode underscore used in "Q" encoding properly. Reintroduce svn pools to solve the memory leak. pack-objects: do not stop at object that is "too small" git-commit --amend: two fixes. get_tree_entry(): make it available from tree-walk sha1_name.c: no need to include diff.h; tree-walk.h will do. sha1_name.c: prepare to make get_tree_entry() reusable from others. get_sha1() shorthands for blob/tree objects pre-commit hook: complain about conflict markers. git-merge: a bit more readable user guidance. diff: move diff.c to diff-lib.c to make room. git log: don't do merge diffs by default Allow "git repack" users to specify repacking window/depth Document git-clone --reference Fix filename scaling for binary files Fix uninteresting tags in new revision parsing Conflicts: Adjusted the addition of fmt-patch to match the recent split from git.c to builtin.log.c.
-rw-r--r--Documentation/git-clone.txt21
-rw-r--r--Makefile11
-rw-r--r--builtin-help.c241
-rw-r--r--builtin-log.c108
-rw-r--r--builtin.h24
-rw-r--r--diff-lib.c (renamed from diff.c)7
-rwxr-xr-xgit-commit.sh21
-rwxr-xr-xgit-merge.sh2
-rwxr-xr-xgit-repack.sh8
-rwxr-xr-xgit-svnimport.perl4
-rw-r--r--git.c344
-rw-r--r--mailinfo.c12
-rw-r--r--pack-objects.c4
-rw-r--r--pager.c2
-rw-r--r--revision.c1
-rw-r--r--sha1_name.c16
-rwxr-xr-xt/t1200-tutorial.sh2
-rw-r--r--templates/hooks--pre-commit3
-rw-r--r--tree-walk.c50
-rw-r--r--tree-walk.h2
20 files changed, 514 insertions, 369 deletions
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index 9ac54c2..131e445 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -10,6 +10,7 @@ SYNOPSIS
--------
[verse]
'git-clone' [-l [-s]] [-q] [-n] [--bare] [-o <name>] [-u <upload-pack>]
+ [--reference <repository>]
<repository> [<directory>]
DESCRIPTION
@@ -46,10 +47,18 @@ OPTIONS
-s::
When the repository to clone is on the local machine,
instead of using hard links, automatically setup
- .git/objects/info/alternatives to share the objects
+ .git/objects/info/alternates to share the objects
with the source repository. The resulting repository
starts out without any object of its own.
+--reference <repository>::
+ If the reference repository is on the local machine
+ automatically setup .git/objects/info/alternates to
+ obtain objects from the reference repository. Using
+ an already existing repository as an alternate will
+ require less objects to be copied from the repository
+ being cloned, reducing network and local storage costs.
+
--quiet::
-q::
Operate quietly. This flag is passed to "rsync" and
@@ -112,6 +121,16 @@ $ git show-branch
------------
+Clone from upstream while borrowing from an existing local directory::
++
+------------
+$ git clone --reference my2.6 \
+ git://git.kernel.org/pub/scm/.../linux-2.7 \
+ my2.7
+$ cd my2.7
+------------
+
+
Create a bare repository to publish your changes to the public::
+
------------
diff --git a/Makefile b/Makefile
index 8aed3af..a83c502 100644
--- a/Makefile
+++ b/Makefile
@@ -199,7 +199,7 @@ LIB_H = \
tree-walk.h log-tree.h
DIFF_OBJS = \
- diff.o diffcore-break.o diffcore-order.o \
+ diff-lib.o diffcore-break.o diffcore-order.o \
diffcore-pickaxe.o diffcore-rename.o tree-diff.o combine-diff.o \
diffcore-delta.o log-tree.o
@@ -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,10 @@ 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)
$(BUILT_INS): git$X
rm -f $@ && ln git$X $@
@@ -565,7 +568,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 0000000..10a59cc
--- /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 0000000..a39aed6
--- /dev/null
+++ b/builtin-log.c
@@ -0,0 +1,108 @@
+/*
+ * 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"
+#include "builtin.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);
+}
+
+int cmd_format_patch(int argc, const char **argv, char **envp)
+{
+ struct commit *commit;
+ struct commit **list = NULL;
+ struct rev_info rev;
+ int nr = 0;
+
+ init_revisions(&rev);
+ rev.commit_format = CMIT_FMT_EMAIL;
+ rev.verbose_header = 1;
+ rev.diff = 1;
+ rev.diffopt.with_raw = 0;
+ rev.diffopt.with_stat = 1;
+ rev.combine_merges = 0;
+ rev.ignore_merges = 1;
+ rev.diffopt.output_format = DIFF_FORMAT_PATCH;
+ argc = setup_revisions(argc, argv, &rev, "HEAD");
+
+ prepare_revision_walk(&rev);
+ while ((commit = get_revision(&rev)) != NULL) {
+ nr++;
+ list = realloc(list, nr * sizeof(list[0]));
+ list[nr - 1] = commit;
+ }
+ while (0 <= --nr) {
+ int shown;
+ commit = list[nr];
+ shown = log_tree_commit(&rev, commit);
+ free(commit->buffer);
+ commit->buffer = NULL;
+ if (shown)
+ printf("-- \n%s\n\n", git_version_string);
+ }
+ free(list);
+ return 0;
+}
+
diff --git a/builtin.h b/builtin.h
new file mode 100644
index 0000000..94dc073
--- /dev/null
+++ b/builtin.h
@@ -0,0 +1,24 @@
+#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);
+extern int cmd_format_patch(int argc, const char **argv, char **envp);
+
+#endif
diff --git a/diff.c b/diff-lib.c
index d75e017..0a832c3 100644
--- a/diff.c
+++ b/diff-lib.c
@@ -250,13 +250,14 @@ static void show_stats(struct diffstat_t* data)
for (i = 0; i < data->nr; i++) {
struct diffstat_file *file = data->files[i];
+ len = strlen(file->name);
+ if (max_len < len)
+ max_len = len;
+
if (file->is_binary || file->is_unmerged)
continue;
if (max_change < file->added + file->deleted)
max_change = file->added + file->deleted;
- len = strlen(file->name);
- if (max_len < len)
- max_len = len;
}
for (i = 0; i < data->nr; i++) {
diff --git a/git-commit.sh b/git-commit.sh
index 01c73bd..26cd7ca 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-merge.sh b/git-merge.sh
index 78ab422..b834e79 100755
--- a/git-merge.sh
+++ b/git-merge.sh
@@ -335,5 +335,5 @@ Conflicts:
then
git-rerere
fi
- die "Automatic merge failed; fix up by hand"
+ die "Automatic merge failed; fix conflicts and then commit the result."
fi
diff --git a/git-repack.sh b/git-repack.sh
index a5d349f..e0c9f32 100755
--- a/git-repack.sh
+++ b/git-repack.sh
@@ -5,9 +5,9 @@
USAGE='[-a] [-d] [-f] [-l] [-n] [-q]'
. git-sh-setup
-
+
no_update_info= all_into_one= remove_redundant=
-local= quiet= no_reuse_delta=
+local= quiet= no_reuse_delta= extra=
while case "$#" in 0) break ;; esac
do
case "$1" in
@@ -17,6 +17,8 @@ do
-q) quiet=-q ;;
-f) no_reuse_delta=--no-reuse-delta ;;
-l) local=--local ;;
+ --window=*) extra="$extra $1" ;;
+ --depth=*) extra="$extra $1" ;;
*) usage ;;
esac
shift
@@ -40,7 +42,7 @@ case ",$all_into_one," in
find . -type f \( -name '*.pack' -o -name '*.idx' \) -print`
;;
esac
-pack_objects="$pack_objects $local $quiet $no_reuse_delta"
+pack_objects="$pack_objects $local $quiet $no_reuse_delta$extra"
name=$(git-rev-list --objects --all $rev_list 2>&1 |
git-pack-objects --non-empty $pack_objects .tmp-pack) ||
exit 1
diff --git a/git-svnimport.perl b/git-svnimport.perl
index 60ed7ae..61f559f0 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 d5aa41d..619c665 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,138 +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_format_patch(int argc, const char **argv, char **envp)
-{
- struct commit *commit;
- struct commit **list = NULL;
- struct rev_info rev;
- int nr = 0;
-
- init_revisions(&rev);
- rev.commit_format = CMIT_FMT_EMAIL;
- rev.verbose_header = 1;
- rev.diff = 1;
- rev.diffopt.with_raw = 0;
- rev.diffopt.with_stat = 1;
- rev.combine_merges = 0;
- rev.ignore_merges = 1;
- rev.diffopt.output_format = DIFF_FORMAT_PATCH;
- argc = setup_revisions(argc, argv, &rev, "HEAD");
-
- prepare_revision_walk(&rev);
- while ((commit = get_revision(&rev)) != NULL) {
- nr++;
- list = realloc(list, nr * sizeof(list[0]));
- list[nr - 1] = commit;
- }
- while (0 <= --nr) {
- int shown;
- commit = list[nr];
- shown = log_tree_commit(&rev, commit);
- free(commit->buffer);
- commit->buffer = NULL;
- if (shown)
- printf("-- \n%s\n\n", GIT_VERSION);
- }
- free(list);
- 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;
- rev.combine_merges = 1;
- rev.ignore_merges = 0;
- 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)
{
@@ -383,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 },
{ "fmt-patch", cmd_format_patch },
};
diff --git a/mailinfo.c b/mailinfo.c
index 3c56f8c..b276519 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 09f4f2c..c0acc46 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 b063353..9a30939 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/revision.c b/revision.c
index dbd54da..113dd5a 100644
--- a/revision.c
+++ b/revision.c
@@ -152,6 +152,7 @@ static struct commit *handle_commit(struct rev_info *revs, struct object *object
if (parse_commit(commit) < 0)
die("unable to parse commit %s", name);
if (flags & UNINTERESTING) {
+ commit->object.flags |= UNINTERESTING;
mark_parents_uninteresting(commit);
revs->limited = 1;
}
diff --git a/sha1_name.c b/sha1_name.c
index 4f92e12..345935b 100644
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -3,6 +3,7 @@
#include "commit.h"
#include "tree.h"
#include "blob.h"
+#include "tree-walk.h"
static int find_short_object_filename(int len, const char *name, unsigned char *sha1)
{
@@ -455,6 +456,19 @@ static int get_sha1_1(const char *name, int len, unsigned char *sha1)
*/
int get_sha1(const char *name, unsigned char *sha1)
{
+ int ret;
+ unsigned unused;
+
prepare_alt_odb();
- return get_sha1_1(name, strlen(name), sha1);
+ ret = get_sha1_1(name, strlen(name), sha1);
+ if (ret < 0) {
+ const char *cp = strchr(name, ':');
+ if (cp) {
+ unsigned char tree_sha1[20];
+ if (!get_sha1_1(name, cp-name, tree_sha1))
+ return get_tree_entry(tree_sha1, cp+1, sha1,
+ &unused);
+ }
+ }
+ return ret;
}
diff --git a/t/t1200-tutorial.sh b/t/t1200-tutorial.sh
index 16b3ea9..c7db20e 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.
diff --git a/templates/hooks--pre-commit b/templates/hooks--pre-commit
index 43d3b6e..723a9ef 100644
--- a/templates/hooks--pre-commit
+++ b/templates/hooks--pre-commit
@@ -61,6 +61,9 @@ perl -e '
if (/^\s* /) {
bad_line("indent SP followed by a TAB", $_);
}
+ if (/^(?:[<>=]){7}/) {
+ bad_line("unresolved merge conflict", $_);
+ }
}
}
exit($found_bad);
diff --git a/tree-walk.c b/tree-walk.c
index bf8bfdf..9f7abb7 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -115,3 +115,53 @@ void traverse_trees(int n, struct tree_desc *t, const char *base, traverse_callb
free(entry);
}
+static int find_tree_entry(struct tree_desc *t, const char *name, unsigned char *result, unsigned *mode)
+{
+ int namelen = strlen(name);
+ while (t->size) {
+ const char *entry;
+ const unsigned char *sha1;
+ int entrylen, cmp;
+
+ sha1 = tree_entry_extract(t, &entry, mode);
+ update_tree_entry(t);
+ entrylen = strlen(entry);
+ if (entrylen > namelen)
+ continue;
+ cmp = memcmp(name, entry, entrylen);
+ if (cmp > 0)
+ continue;
+ if (cmp < 0)
+ break;
+ if (entrylen == namelen) {
+ memcpy(result, sha1, 20);
+ return 0;
+ }
+ if (name[entrylen] != '/')
+ continue;
+ if (!S_ISDIR(*mode))
+ break;
+ if (++entrylen == namelen) {
+ memcpy(result, sha1, 20);
+ return 0;
+ }
+ return get_tree_entry(sha1, name + entrylen, result, mode);
+ }
+ return -1;
+}
+
+int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned char *sha1, unsigned *mode)
+{
+ int retval;
+ void *tree;
+ struct tree_desc t;
+
+ tree = read_object_with_reference(tree_sha1, tree_type, &t.size, NULL);
+ if (!tree)
+ return -1;
+ t.buf = tree;
+ retval = find_tree_entry(&t, name, sha1, mode);
+ free(tree);
+ return retval;
+}
+
diff --git a/tree-walk.h b/tree-walk.h
index 76893e3..47438fe 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -22,4 +22,6 @@ typedef void (*traverse_callback_t)(int n, unsigned long mask, struct name_entry
void traverse_trees(int n, struct tree_desc *t, const char *base, traverse_callback_t callback);
+int get_tree_entry(const unsigned char *, const char *, unsigned char *, unsigned *);
+
#endif