diff options
author | Junio C Hamano <junkio@cox.net> | 2006-04-21 13:19:58 -0700 |
---|---|---|
committer | Junio C Hamano <junkio@cox.net> | 2006-04-21 13:25:47 -0700 |
commit | 91efcf60653b2538b05625807293b97c07cb04f4 (patch) | |
tree | 0240b448657063bc251be1c79596377ea8b91542 | |
parent | 43885c2a557871aedcbb1a412fc18e98c3dd1dc4 (diff) | |
parent | 70827b15bfb11f7aea52c6995956be9d149233e1 (diff) | |
download | git-91efcf60653b2538b05625807293b97c07cb04f4.tar.gz |
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.txt | 21 | ||||
-rw-r--r-- | Makefile | 11 | ||||
-rw-r--r-- | builtin-help.c | 241 | ||||
-rw-r--r-- | builtin-log.c | 108 | ||||
-rw-r--r-- | builtin.h | 24 | ||||
-rw-r--r-- | diff-lib.c (renamed from diff.c) | 7 | ||||
-rwxr-xr-x | git-commit.sh | 21 | ||||
-rwxr-xr-x | git-merge.sh | 2 | ||||
-rwxr-xr-x | git-repack.sh | 8 | ||||
-rwxr-xr-x | git-svnimport.perl | 4 | ||||
-rw-r--r-- | git.c | 344 | ||||
-rw-r--r-- | mailinfo.c | 12 | ||||
-rw-r--r-- | pack-objects.c | 4 | ||||
-rw-r--r-- | pager.c | 2 | ||||
-rw-r--r-- | revision.c | 1 | ||||
-rw-r--r-- | sha1_name.c | 16 | ||||
-rwxr-xr-x | t/t1200-tutorial.sh | 2 | ||||
-rw-r--r-- | templates/hooks--pre-commit | 3 | ||||
-rw-r--r-- | tree-walk.c | 50 | ||||
-rw-r--r-- | tree-walk.h | 2 |
20 files changed, 514 insertions, 369 deletions
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt index 9ac54c282c..131e445747 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:: + ------------ @@ -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 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..a39aed6d86 --- /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 0000000000..94dc0732f9 --- /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 @@ -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 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-merge.sh b/git-merge.sh index 78ab422e4e..b834e79c98 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 a5d349fd09..e0c9f323c3 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 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,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 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/revision.c b/revision.c index dbd54da5ba..113dd5a89f 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 4f92e12a8d..345935bb2b 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 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. diff --git a/templates/hooks--pre-commit b/templates/hooks--pre-commit index 43d3b6ef4a..723a9ef210 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 bf8bfdfdf8..9f7abb7cb3 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 76893e36c3..47438fe1c0 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 |