From: Junio C Hamano Date: Tue, 8 Aug 2006 00:02:07 +0000 (-0700) Subject: Merge branch 'master' into pb/gitpm X-Git-Tag: v1.4.3-rc1~2^2~8 X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=9673198ee867cea4ed70d2cf54c1a2eb8f27bb46;p=git.git Merge branch 'master' into pb/gitpm This is to resolve the conflicts with Ryan's annotate updates early. --- 9673198ee867cea4ed70d2cf54c1a2eb8f27bb46 diff --cc Makefile index 01b9a9482,0761d6c6e..2ab112bbd --- a/Makefile +++ b/Makefile @@@ -239,10 -254,11 +264,11 @@@ BUILTIN_OBJS = builtin-apply.o builtin-show-branch.o builtin-diff-files.o \ builtin-diff-index.o builtin-diff-stages.o builtin-diff-tree.o \ builtin-cat-file.o builtin-mailsplit.o builtin-stripspace.o \ - builtin-update-ref.o + builtin-update-ref.o builtin-fmt-merge-msg.o builtin-prune.o \ + builtin-mv.o builtin-prune-packed.o builtin-repo-config.o GITLIBS = $(LIB_FILE) $(XDIFF_LIB) -LIBS = $(GITLIBS) -lz +EXTLIBS = -lz # # Platform specific tweaks @@@ -259,15 -278,17 +288,17 @@@ ifeq ($(uname_S),Darwin NEEDS_SSL_WITH_CRYPTO = YesPlease NEEDS_LIBICONV = YesPlease NO_STRLCPY = YesPlease - ## fink - ifeq ($(shell test -d /sw/lib && echo y),y) - BASIC_CFLAGS += -I/sw/include - BASIC_LDFLAGS += -L/sw/lib + ifndef NO_FINK + ifeq ($(shell test -d /sw/lib && echo y),y) - ALL_CFLAGS += -I/sw/include - ALL_LDFLAGS += -L/sw/lib ++ BASIC_CFLAGS += -I/sw/include ++ BASIC_LDFLAGS += -L/sw/lib + endif endif - ## darwinports - ifeq ($(shell test -d /opt/local/lib && echo y),y) - BASIC_CFLAGS += -I/opt/local/include - BASIC_LDFLAGS += -L/opt/local/lib + ifndef NO_DARWIN_PORTS + ifeq ($(shell test -d /opt/local/lib && echo y),y) - ALL_CFLAGS += -I/opt/local/include - ALL_LDFLAGS += -L/opt/local/lib ++ BASIC_CFLAGS += -I/opt/local/include ++ BASIC_LDFLAGS += -L/opt/local/lib + endif endif endif ifeq ($(uname_S),SunOS) @@@ -341,10 -361,8 +372,11 @@@ endi ifneq (,$(findstring arm,$(uname_M))) ARM_SHA1 = YesPlease endif +ifeq ($(uname_M),x86_64) + USE_PIC = YesPlease +endif + -include config.mak.autogen -include config.mak ifdef WITH_OWN_SUBPROCESS_PY @@@ -415,13 -433,16 +447,16 @@@ ifdef NEEDS_NS SIMPLE_LIB += -lnsl endif ifdef NO_D_TYPE_IN_DIRENT - ALL_CFLAGS += -DNO_D_TYPE_IN_DIRENT + BASIC_CFLAGS += -DNO_D_TYPE_IN_DIRENT endif ifdef NO_D_INO_IN_DIRENT - ALL_CFLAGS += -DNO_D_INO_IN_DIRENT + BASIC_CFLAGS += -DNO_D_INO_IN_DIRENT endif + ifdef NO_C99_FORMAT + ALL_CFLAGS += -DNO_C99_FORMAT + endif ifdef NO_SYMLINK_HEAD - ALL_CFLAGS += -DNO_SYMLINK_HEAD + BASIC_CFLAGS += -DNO_SYMLINK_HEAD endif ifdef NO_STRCASESTR COMPAT_CFLAGS += -DNO_STRCASESTR @@@ -474,18 -495,15 +509,18 @@@ ifdef MOZILLA_SHA LIB_OBJS += mozilla-sha1/sha1.o else SHA1_HEADER = - LIBS += $(LIB_4_CRYPTO) + EXTLIBS += $(LIB_4_CRYPTO) +endif endif endif +ifdef USE_PIC + ALL_CFLAGS += -fPIC endif ifdef NO_ACCURATE_DIFF - ALL_CFLAGS += -DNO_ACCURATE_DIFF + BASIC_CFLAGS += -DNO_ACCURATE_DIFF endif - # Shell quote (do not use $(call) to accomodate ancient setups); + # Shell quote (do not use $(call) to accommodate ancient setups); SHA1_HEADER_SQ = $(subst ','\'',$(SHA1_HEADER)) @@@ -707,8 -721,7 +766,8 @@@ install: al $(INSTALL) -d -m755 '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL) git$X gitk '$(DESTDIR_SQ)$(bindir_SQ)' - $(MAKE) -C templates install + $(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install + $(MAKE) -C perl install $(INSTALL) -d -m755 '$(DESTDIR_SQ)$(GIT_PYTHON_DIR_SQ)' $(INSTALL) $(PYMODULES) '$(DESTDIR_SQ)$(GIT_PYTHON_DIR_SQ)' if test 'z$(bindir_SQ)' != 'z$(gitexecdir_SQ)'; \ diff --cc builtin-repo-config.c index 000000000,c821e2271..1d9373977 mode 000000,100644..100644 --- a/builtin-repo-config.c +++ b/builtin-repo-config.c @@@ -1,0 -1,200 +1,200 @@@ + #include "builtin.h" + #include "cache.h" + #include + + static const char git_config_set_usage[] = + "git-repo-config [ --bool | --int ] [--get | --get-all | --get-regexp | --replace-all | --unset | --unset-all] name [value [value_regex]] | --list"; + + static char* key = NULL; + static regex_t* key_regexp = NULL; + static regex_t* regexp = NULL; + static int show_keys = 0; + static int use_key_regexp = 0; + static int do_all = 0; + static int do_not_match = 0; + static int seen = 0; + static enum { T_RAW, T_INT, T_BOOL } type = T_RAW; + + static int show_all_config(const char *key_, const char *value_) + { + if (value_) + printf("%s=%s\n", key_, value_); + else + printf("%s\n", key_); + return 0; + } + + static int show_config(const char* key_, const char* value_) + { + char value[256]; + const char *vptr = value; + int dup_error = 0; + + if (!use_key_regexp && strcmp(key_, key)) + return 0; + if (use_key_regexp && regexec(key_regexp, key_, 0, NULL, 0)) + return 0; + if (regexp != NULL && + (do_not_match ^ + regexec(regexp, (value_?value_:""), 0, NULL, 0))) + return 0; + + if (show_keys) + printf("%s ", key_); + if (seen && !do_all) + dup_error = 1; + if (type == T_INT) + sprintf(value, "%d", git_config_int(key_, value_?value_:"")); + else if (type == T_BOOL) + vptr = git_config_bool(key_, value_) ? "true" : "false"; + else + vptr = value_?value_:""; + seen++; + if (dup_error) { + error("More than one value for the key %s: %s", + key_, vptr); + } + else + printf("%s\n", vptr); + + return 0; + } + + static int get_value(const char* key_, const char* regex_) + { + int ret = -1; + char *tl; + char *global = NULL, *repo_config = NULL; + const char *local; + + local = getenv("GIT_CONFIG"); + if (!local) { + const char *home = getenv("HOME"); + local = getenv("GIT_CONFIG_LOCAL"); + if (!local) + local = repo_config = strdup(git_path("config")); + if (home) + global = strdup(mkpath("%s/.gitconfig", home)); + } + + key = strdup(key_); + for (tl=key+strlen(key)-1; tl >= key && *tl != '.'; --tl) + *tl = tolower(*tl); + for (tl=key; *tl && *tl != '.'; ++tl) + *tl = tolower(*tl); + + if (use_key_regexp) { + key_regexp = (regex_t*)malloc(sizeof(regex_t)); + if (regcomp(key_regexp, key, REG_EXTENDED)) { + fprintf(stderr, "Invalid key pattern: %s\n", key_); + goto free_strings; + } + } + + if (regex_) { + if (regex_[0] == '!') { + do_not_match = 1; + regex_++; + } + + regexp = (regex_t*)malloc(sizeof(regex_t)); + if (regcomp(regexp, regex_, REG_EXTENDED)) { + fprintf(stderr, "Invalid pattern: %s\n", regex_); + goto free_strings; + } + } + + if (do_all && global) + git_config_from_file(show_config, global); + git_config_from_file(show_config, local); + if (!do_all && !seen && global) + git_config_from_file(show_config, global); + + free(key); + if (regexp) { + regfree(regexp); + free(regexp); + } + + if (do_all) + ret = !seen; + else - ret = (seen == 1) ? 0 : 1; ++ ret = (seen == 1) ? 0 : seen > 1 ? 2 : 1; + + free_strings: + if (repo_config) + free(repo_config); + if (global) + free(global); + return ret; + } + + int cmd_repo_config(int argc, const char **argv, const char *prefix) + { + int nongit = 0; + setup_git_directory_gently(&nongit); + + while (1 < argc) { + if (!strcmp(argv[1], "--int")) + type = T_INT; + else if (!strcmp(argv[1], "--bool")) + type = T_BOOL; + else if (!strcmp(argv[1], "--list") || !strcmp(argv[1], "-l")) + return git_config(show_all_config); + else + break; + argc--; + argv++; + } + + switch (argc) { + case 2: + return get_value(argv[1], NULL); + case 3: + if (!strcmp(argv[1], "--unset")) + return git_config_set(argv[2], NULL); + else if (!strcmp(argv[1], "--unset-all")) + return git_config_set_multivar(argv[2], NULL, NULL, 1); + else if (!strcmp(argv[1], "--get")) + return get_value(argv[2], NULL); + else if (!strcmp(argv[1], "--get-all")) { + do_all = 1; + return get_value(argv[2], NULL); + } else if (!strcmp(argv[1], "--get-regexp")) { + show_keys = 1; + use_key_regexp = 1; + do_all = 1; + return get_value(argv[2], NULL); + } else + + return git_config_set(argv[1], argv[2]); + case 4: + if (!strcmp(argv[1], "--unset")) + return git_config_set_multivar(argv[2], NULL, argv[3], 0); + else if (!strcmp(argv[1], "--unset-all")) + return git_config_set_multivar(argv[2], NULL, argv[3], 1); + else if (!strcmp(argv[1], "--get")) + return get_value(argv[2], argv[3]); + else if (!strcmp(argv[1], "--get-all")) { + do_all = 1; + return get_value(argv[2], argv[3]); + } else if (!strcmp(argv[1], "--get-regexp")) { + show_keys = 1; + use_key_regexp = 1; + do_all = 1; + return get_value(argv[2], argv[3]); + } else if (!strcmp(argv[1], "--replace-all")) + + return git_config_set_multivar(argv[2], argv[3], NULL, 1); + else + + return git_config_set_multivar(argv[1], argv[2], argv[3], 0); + case 5: + if (!strcmp(argv[1], "--replace-all")) + return git_config_set_multivar(argv[2], argv[3], argv[4], 1); + case 1: + default: + usage(git_config_set_usage); + } + return 0; + } diff --cc cache.h index 962f2fc34,b8c21e07b..ed26b4785 --- a/cache.h +++ b/cache.h @@@ -115,10 -115,8 +115,11 @@@ static inline unsigned int create_ce_mo extern struct cache_entry **active_cache; extern unsigned int active_nr, active_alloc, active_cache_changed; extern struct cache_tree *active_cache_tree; + extern int cache_errno; +extern void setup_git(char *new_git_dir, char *new_git_object_dir, + char *new_git_index_file, char *new_git_graft_file); + #define GIT_DIR_ENVIRONMENT "GIT_DIR" #define DEFAULT_GIT_DIR_ENVIRONMENT ".git" #define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY" diff --cc environment.c index 6b64d111f,87162b257..1ce34118d --- a/environment.c +++ b/environment.c @@@ -20,21 -21,18 +21,24 @@@ int repository_format_version = 0 char git_commit_encoding[MAX_ENCODING_LENGTH] = "utf-8"; int shared_repository = PERM_UMASK; const char *apply_default_whitespace = NULL; + int zlib_compression_level = Z_DEFAULT_COMPRESSION; + int pager_in_use; + int pager_use_color = 1; +static int dyn_git_object_dir, dyn_git_index_file, dyn_git_graft_file; static char *git_dir, *git_object_dir, *git_index_file, *git_refs_dir, *git_graft_file; -static void setup_git_env(void) + +void setup_git(char *new_git_dir, char *new_git_object_dir, + char *new_git_index_file, char *new_git_graft_file) { - git_dir = getenv(GIT_DIR_ENVIRONMENT); + git_dir = new_git_dir; if (!git_dir) git_dir = DEFAULT_GIT_DIR_ENVIRONMENT; - git_object_dir = getenv(DB_ENVIRONMENT); + + if (dyn_git_object_dir) + free(git_object_dir); + git_object_dir = new_git_object_dir; if (!git_object_dir) { git_object_dir = xmalloc(strlen(git_dir) + 9); sprintf(git_object_dir, "%s/objects", git_dir); diff --cc git-annotate.perl index d924e8771,215ed26f3..742a51c50 --- a/git-annotate.perl +++ b/git-annotate.perl @@@ -105,11 -102,15 +105,11 @@@ while (my $bound = pop @stack) push @revqueue, $head; init_claim( defined $starting_rev ? $head : 'dirty'); unless (defined $starting_rev) { - my $diff = open_pipe("git","diff","HEAD", "--",$filename) - or die "Failed to call git diff to check for dirty state: $!"; - - _git_diff_parse($diff, [$head], "dirty", ( - 'author' => gitvar_name("GIT_AUTHOR_IDENT"), - 'author_date' => sprintf("%s +0000",time()), - ) - ); - close($diff); + my %ident; + @ident{'author', 'author_email', 'author_date'} = $repo->ident('author'); + my $diff = $repo->command_output_pipe('diff', '-R', 'HEAD', '--', $filename); - _git_diff_parse($diff, $head, "dirty", %ident); ++ _git_diff_parse($diff, [$head], "dirty", %ident); + $repo->command_close_pipe($diff); } handle_rev(); @@@ -240,19 -247,131 +239,117 @@@ sub git_find_parent return $parent; } + sub git_find_all_parents { + my ($rev) = @_; + - my $revparent = open_pipe("git-rev-list","--remove-empty", "--parents","--max-count=1","$rev") - or die "Failed to open git-rev-list to find a single parent: $!"; - - my $parentline = <$revparent>; - chomp $parentline; ++ my $parentline = $repo->command_oneline("rev-list","--remove-empty", "--parents","--max-count=1","$rev"); + my ($origrev, @parents) = split m/\s+/, $parentline; + - close($revparent); - + return @parents; + } + + sub git_merge_base { + my ($rev1, $rev2) = @_; + - my $mb = open_pipe("git-merge-base", $rev1, $rev2) - or die "Failed to open git-merge-base: $!"; - - my $base = <$mb>; - chomp $base; - - close($mb); - ++ my $base = $repo->command_oneline("merge-base", $rev1, $rev2); + return $base; + } + + # Construct a set of pseudo parents that are in the same order, + # and the same quantity as the real parents, + # but whose SHA1s are as similar to the logical parents + # as possible. + sub get_pseudo_parents { + my ($all, $fake) = @_; + + my @all = @$all; + my @fake = @$fake; + + my @pseudo; + + my %fake = map {$_ => 1} @fake; + my %seenfake; + + my $fakeidx = 0; + foreach my $p (@all) { + if (exists $fake{$p}) { + if ($fake[$fakeidx] ne $p) { + die sprintf("parent mismatch: %s != %s\nall:%s\nfake:%s\n", + $fake[$fakeidx], $p, + join(", ", @all), + join(", ", @fake), + ); + } + + push @pseudo, $p; + $fakeidx++; + $seenfake{$p}++; + + } else { + my $base = git_merge_base($fake[$fakeidx], $p); + if ($base ne $fake[$fakeidx]) { + die sprintf("Result of merge-base doesn't match fake: %s,%s != %s\n", + $fake[$fakeidx], $p, $base); + } + + # The details of how we parse the diffs + # mean that we cannot have a duplicate + # revision in the list, so if we've already + # seen the revision we would normally add, just use + # the actual revision. + if ($seenfake{$base}) { + push @pseudo, $p; + } else { + push @pseudo, $base; + $seenfake{$base}++; + } + } + } + + return @pseudo; + } + # Get a diff between the current revision and a parent. # Record the commit information that results. sub git_diff_parse { - my ($parent, $rev, %revinfo) = @_; + my ($parents, $rev, %revinfo) = @_; - my $diff = $repo->command_output_pipe('diff-tree', '-M', '-p', - $rev, $parent, '--', - $revs{$rev}{'filename'}, $revs{$parent}{'filename'}); + my @pseudo_parents; - my @command = ("git-diff-tree"); ++ my @command = ("diff-tree"); + my $revision_spec; + + if (scalar @$parents == 1) { + + $revision_spec = join("..", $parents->[0], $rev); + @pseudo_parents = @$parents; + } else { + my @all_parents = git_find_all_parents($rev); + + if (@all_parents != @$parents) { + @pseudo_parents = get_pseudo_parents(\@all_parents, $parents); + } else { + @pseudo_parents = @$parents; + } + + $revision_spec = $rev; + push @command, "-c"; + } - _git_diff_parse($diff, $parent, $rev, %revinfo); + my @filenames = ( $revs{$rev}{'filename'} ); + + foreach my $parent (@$parents) { + push @filenames, $revs{$parent}{'filename'}; + } + + push @command, "-p", "-M", $revision_spec, "--", @filenames; + + - my $diff = open_pipe( @command ) - or die "Failed to call git-diff for annotation: $!"; ++ my $diff = $repo->command_output_pipe(@command); + + _git_diff_parse($diff, \@pseudo_parents, $rev, %revinfo); - close($diff); + $repo->command_close_pipe($diff); } sub _git_diff_parse { diff --cc git-send-email.perl index 79e82f5a8,a83c7e909..1e2777c8e --- a/git-send-email.perl +++ b/git-send-email.perl @@@ -21,11 -21,56 +21,57 @@@ use warnings use Term::ReadLine; use Getopt::Long; use Data::Dumper; +use Git; + package FakeTerm; + sub new { + my ($class, $reason) = @_; + return bless \$reason, shift; + } + sub readline { + my $self = shift; + die "Cannot use readline on FakeTerm: $$self"; + } + package main; + # most mail servers generate the Date: header, but not all... - $ENV{LC_ALL} = 'C'; - use POSIX qw/strftime/; + sub format_2822_time { + my ($time) = @_; + my @localtm = localtime($time); + my @gmttm = gmtime($time); + my $localmin = $localtm[1] + $localtm[2] * 60; + my $gmtmin = $gmttm[1] + $gmttm[2] * 60; + if ($localtm[0] != $gmttm[0]) { + die "local zone differs from GMT by a non-minute interval\n"; + } + if ((($gmttm[6] + 1) % 7) == $localtm[6]) { + $localmin += 1440; + } elsif ((($gmttm[6] - 1) % 7) == $localtm[6]) { + $localmin -= 1440; + } elsif ($gmttm[6] != $localtm[6]) { + die "local time offset greater than or equal to 24 hours\n"; + } + my $offset = $localmin - $gmtmin; + my $offhour = $offset / 60; + my $offmin = abs($offset % 60); + if (abs($offhour) >= 24) { + die ("local time offset greater than or equal to 24 hours\n"); + } + + return sprintf("%s, %2d %s %d %02d:%02d:%02d %s%02d%02d", + qw(Sun Mon Tue Wed Thu Fri Sat)[$localtm[6]], + $localtm[3], + qw(Jan Feb Mar Apr May Jun + Jul Aug Sep Oct Nov Dec)[$localtm[4]], + $localtm[5]+1900, + $localtm[2], + $localtm[1], + $localtm[0], + ($offset >= 0) ? '+' : '-', + abs($offhour), + $offmin, + ); + } my $have_email_valid = eval { require Email::Valid; 1 }; my $smtp; @@@ -47,9 -92,12 +93,13 @@@ my $smtp_server # Example reply to: #$initial_reply_to = ''; #<20050203173208.GA23964@foobar.com>'; +my $repo = Git->repository(); - - my $term = new Term::ReadLine 'git-send-email'; + my $term = eval { + new Term::ReadLine 'git-send-email'; + }; + if ($@) { + $term = new FakeTerm "$@: going non-interactive"; + } # Begin by accumulating all the variables (defined above), that we will end up # needing, first, from the command line: @@@ -353,10 -422,13 +403,10 @@@ sub send_messag my @recipients = unique_email_list(@to); my $to = join (",\n\t", @recipients); @recipients = unique_email_list(@recipients,@cc,@bcclist); - my $date = strftime('%a, %d %b %Y %H:%M:%S %z', localtime($time++)); + my $date = format_2822_time($time++); my $gitversion = '@@GIT_VERSION@@'; if ($gitversion =~ m/..GIT_VERSION../) { - $gitversion = `git --version`; - chomp $gitversion; - # keep only what's after the last space - $gitversion =~ s/^.* //; + $gitversion = Git::version(); } my $header = "From: $from