diff options
-rw-r--r-- | Documentation/git-cvsexportcommit.txt | 5 | ||||
-rw-r--r-- | Documentation/git-cvsserver.txt | 24 | ||||
-rw-r--r-- | Documentation/git-merge.txt | 2 | ||||
-rw-r--r-- | Documentation/merge-options.txt | 4 | ||||
-rw-r--r-- | Documentation/user-manual.txt | 2 | ||||
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | builtin-mailsplit.c | 6 | ||||
-rw-r--r-- | builtin-pack-objects.c | 60 | ||||
-rw-r--r-- | connect.c | 38 | ||||
-rwxr-xr-x | contrib/workdir/git-new-workdir | 12 | ||||
-rwxr-xr-x | git-cvsexportcommit.perl | 8 | ||||
-rwxr-xr-x | git-cvsserver.perl | 8 | ||||
-rwxr-xr-x | git-fetch.sh | 10 | ||||
-rw-r--r-- | git-gui/Makefile | 12 | ||||
-rwxr-xr-x | git-gui/git-gui.sh | 17 | ||||
-rwxr-xr-x | git-merge.sh | 18 | ||||
-rwxr-xr-x | git-pull.sh | 3 | ||||
-rwxr-xr-x | git-svn.perl | 16 | ||||
-rw-r--r-- | run-command.c | 45 | ||||
-rw-r--r-- | run-command.h | 9 | ||||
-rwxr-xr-x | t/t0021-conversion.sh | 36 | ||||
-rwxr-xr-x | t/t9400-git-cvsserver-server.sh | 31 | ||||
-rw-r--r-- | tag.c | 2 |
23 files changed, 304 insertions, 68 deletions
diff --git a/Documentation/git-cvsexportcommit.txt b/Documentation/git-cvsexportcommit.txt index fd7f54093f..da5c242241 100644 --- a/Documentation/git-cvsexportcommit.txt +++ b/Documentation/git-cvsexportcommit.txt @@ -8,7 +8,7 @@ git-cvsexportcommit - Export a single commit to a CVS checkout SYNOPSIS -------- -'git-cvsexportcommit' [-h] [-v] [-c] [-P] [-p] [-a] [-d cvsroot] [-f] [-m msgprefix] [PARENTCOMMIT] COMMITID +'git-cvsexportcommit' [-h] [-u] [-v] [-c] [-P] [-p] [-a] [-d cvsroot] [-f] [-m msgprefix] [PARENTCOMMIT] COMMITID DESCRIPTION @@ -58,6 +58,9 @@ OPTIONS Prepend the commit message with the provided prefix. Useful for patch series and the like. +-u:: + Update affected files from cvs repository before attempting export. + -v:: Verbose. diff --git a/Documentation/git-cvsserver.txt b/Documentation/git-cvsserver.txt index d22844ba49..e5005f02f9 100644 --- a/Documentation/git-cvsserver.txt +++ b/Documentation/git-cvsserver.txt @@ -46,16 +46,28 @@ INSTALLATION cvspserver stream tcp nowait nobody git-cvsserver pserver ------ -Note: In some cases, you need to pass the 'pserver' argument twice for -git-cvsserver to see it. So the line would look like +Note: Some inetd servers let you specify the name of the executable +independently of the value of argv[0] (i.e. the name the program assumes +it was executed with). In this case the correct line in /etc/inetd.conf +looks like ------ - cvspserver stream tcp nowait nobody git-cvsserver pserver pserver + cvspserver stream tcp nowait nobody /usr/bin/git-cvsserver git-cvsserver pserver ------ No special setup is needed for SSH access, other than having GIT tools in the PATH. If you have clients that do not accept the CVS_SERVER -env variable, you can rename git-cvsserver to cvs. +environment variable, you can rename git-cvsserver to cvs. + +Note: Newer cvs versions (>= 1.12.11) also support specifying +CVS_SERVER directly in CVSROOT like + +------ +cvs -d ":ext;CVS_SERVER=git-cvsserver:user@server/path/repo.git" co <HEAD_name> +------ +This has the advantage that it will be saved in your 'CVS/Root' files and +you don't need to worry about always setting the correct environment +variable. -- 2. For each repo that you want accessible from CVS you need to edit config in the repo and add the following section. @@ -74,7 +86,7 @@ write access to the log file and to the database (see SSH, the users of course also need write access to the git repository itself. [[configaccessmethod]] -All configuration variables can also be overriden for a specific method of +All configuration variables can also be overridden for a specific method of access. Valid method names are "ext" (for SSH access) and "pserver". The following example configuration would disable pserver access while still allowing access over SSH. @@ -116,7 +128,7 @@ Database Backend git-cvsserver uses one database per git head (i.e. CVS module) to store information about the repository for faster access. The -database doesn't contain any persitent data and can be completly +database doesn't contain any persistent data and can be completely regenerated from the git repository at any time. The database needs to be updated (i.e. written to) after every commit. diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt index 9c08efa53a..912ef29efc 100644 --- a/Documentation/git-merge.txt +++ b/Documentation/git-merge.txt @@ -9,7 +9,7 @@ git-merge - Join two or more development histories together SYNOPSIS -------- [verse] -'git-merge' [-n] [--no-commit] [--squash] [-s <strategy>]... +'git-merge' [-n] [--summary] [--no-commit] [--squash] [-s <strategy>]... [-m <msg>] <remote> <remote>... DESCRIPTION diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt index 182cef54be..56f1d8d69d 100644 --- a/Documentation/merge-options.txt +++ b/Documentation/merge-options.txt @@ -1,3 +1,7 @@ +--summary:: + Show a diffstat at the end of the merge. The diffstat is also + controlled by the configuration option merge.diffstat. + -n, \--no-summary:: Do not show diffstat at the end of the merge. diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt index 52247aa713..4fabb8e2a9 100644 --- a/Documentation/user-manual.txt +++ b/Documentation/user-manual.txt @@ -872,7 +872,7 @@ Obviously, endless variations are possible; for example, to see all commits reachable from some head but not from any tag in the repository: ------------------------------------------------- -$ gitk ($ git show-ref --heads ) --not $( git show-ref --tags ) +$ gitk $( git show-ref --heads ) --not $( git show-ref --tags ) ------------------------------------------------- (See gitlink:git-rev-parse[1] for explanations of commit-selecting @@ -235,7 +235,7 @@ endif # ... and all the rest that could be moved out of bindir to gitexecdir PROGRAMS = \ - git-convert-objects$X git-fetch-pack$X git-fsck$X \ + git-convert-objects$X git-fetch-pack$X \ git-hash-object$X git-index-pack$X git-local-fetch$X \ git-fast-import$X \ git-merge-base$X \ @@ -246,7 +246,7 @@ PROGRAMS = \ git-show-index$X git-ssh-fetch$X \ git-ssh-upload$X git-unpack-file$X \ git-update-server-info$X \ - git-upload-pack$X git-verify-pack$X \ + git-upload-pack$X \ git-pack-redundant$X git-var$X \ git-merge-tree$X git-imap-send$X \ git-merge-recursive$X \ diff --git a/builtin-mailsplit.c b/builtin-mailsplit.c index 97ae004ab7..c938425555 100644 --- a/builtin-mailsplit.c +++ b/builtin-mailsplit.c @@ -261,7 +261,8 @@ int cmd_mailsplit(int argc, const char **argv, const char *prefix) error("cannot split patches from stdin"); return 1; } - num += ret; + num += (ret - nr); + nr = ret; continue; } @@ -279,7 +280,8 @@ int cmd_mailsplit(int argc, const char **argv, const char *prefix) error("cannot split patches from %s", arg); return 1; } - num += ret; + num += (ret - nr); + nr = ret; } printf("%d\n", num); diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c index d165f10288..eca130f055 100644 --- a/builtin-pack-objects.c +++ b/builtin-pack-objects.c @@ -1,5 +1,6 @@ #include "builtin.h" #include "cache.h" +#include "attr.h" #include "object.h" #include "blob.h" #include "commit.h" @@ -40,9 +41,10 @@ struct object_entry { enum object_type in_pack_type; /* could be delta */ unsigned char in_pack_header_size; unsigned char preferred_base; /* we do not pack this, but is available - * to be used as the base objectto delta + * to be used as the base object to delta * objects against. */ + unsigned char no_try_delta; }; /* @@ -723,6 +725,9 @@ static unsigned name_hash(const char *name) unsigned char c; unsigned hash = 0; + if (!name) + return 0; + /* * This effectively just creates a sortable number from the * last sixteen non-whitespace characters. Last characters @@ -736,13 +741,36 @@ static unsigned name_hash(const char *name) return hash; } +static void setup_delta_attr_check(struct git_attr_check *check) +{ + static struct git_attr *attr_delta; + + if (!attr_delta) + attr_delta = git_attr("delta", 5); + + check[0].attr = attr_delta; +} + +static int no_try_delta(const char *path) +{ + struct git_attr_check check[1]; + + setup_delta_attr_check(check); + if (git_checkattr(path, ARRAY_SIZE(check), check)) + return 0; + if (ATTR_FALSE(check->value)) + return 1; + return 0; +} + static int add_object_entry(const unsigned char *sha1, enum object_type type, - unsigned hash, int exclude) + const char *name, int exclude) { struct object_entry *entry; struct packed_git *p, *found_pack = NULL; off_t found_offset = 0; int ix; + unsigned hash = name_hash(name); ix = nr_objects ? locate_object_entry_hash(sha1) : -1; if (ix >= 0) { @@ -799,6 +827,9 @@ static int add_object_entry(const unsigned char *sha1, enum object_type type, if (progress) display_progress(&progress_state, nr_objects); + if (name && no_try_delta(name)) + entry->no_try_delta = 1; + return 1; } @@ -931,10 +962,9 @@ static void add_pbase_object(struct tree_desc *tree, if (cmp < 0) return; if (name[cmplen] != '/') { - unsigned hash = name_hash(fullname); add_object_entry(entry.sha1, S_ISDIR(entry.mode) ? OBJ_TREE : OBJ_BLOB, - hash, 1); + fullname, 1); return; } if (S_ISDIR(entry.mode)) { @@ -994,10 +1024,11 @@ static int check_pbase_path(unsigned hash) return 0; } -static void add_preferred_base_object(const char *name, unsigned hash) +static void add_preferred_base_object(const char *name) { struct pbase_tree *it; int cmplen; + unsigned hash = name_hash(name); if (!num_preferred_base || check_pbase_path(hash)) return; @@ -1005,7 +1036,7 @@ static void add_preferred_base_object(const char *name, unsigned hash) cmplen = name_cmp_len(name); for (it = pbase_tree; it; it = it->next) { if (cmplen == 0) { - add_object_entry(it->pcache.sha1, OBJ_TREE, 0, 1); + add_object_entry(it->pcache.sha1, OBJ_TREE, NULL, 1); } else { struct tree_desc tree; @@ -1347,6 +1378,10 @@ static void find_deltas(struct object_entry **list, int window, int depth) if (entry->size < 50) continue; + + if (entry->no_try_delta) + continue; + free_delta_index(n->index); n->index = NULL; free(n->data); @@ -1446,7 +1481,6 @@ static void read_object_list_from_stdin(void) { char line[40 + 1 + PATH_MAX + 2]; unsigned char sha1[20]; - unsigned hash; for (;;) { if (!fgets(line, sizeof(line), stdin)) { @@ -1469,22 +1503,20 @@ static void read_object_list_from_stdin(void) if (get_sha1_hex(line, sha1)) die("expected sha1, got garbage:\n %s", line); - hash = name_hash(line+41); - add_preferred_base_object(line+41, hash); - add_object_entry(sha1, 0, hash, 0); + add_preferred_base_object(line+41); + add_object_entry(sha1, 0, line+41, 0); } } static void show_commit(struct commit *commit) { - add_object_entry(commit->object.sha1, OBJ_COMMIT, 0, 0); + add_object_entry(commit->object.sha1, OBJ_COMMIT, NULL, 0); } static void show_object(struct object_array_entry *p) { - unsigned hash = name_hash(p->name); - add_preferred_base_object(p->name, hash); - add_object_entry(p->item->sha1, p->item->type, hash, 0); + add_preferred_base_object(p->name); + add_object_entry(p->item->sha1, p->item->type, p->name, 0); } static void show_edge(struct commit *commit) @@ -391,6 +391,23 @@ static enum protocol get_protocol(const char *name) #ifndef NO_IPV6 +static const char *ai_name(const struct addrinfo *ai) +{ + static char addr[INET_ADDRSTRLEN]; + if ( AF_INET == ai->ai_family ) { + struct sockaddr_in *in; + in = (struct sockaddr_in *)ai->ai_addr; + inet_ntop(ai->ai_family, &in->sin_addr, addr, sizeof(addr)); + } else if ( AF_INET6 == ai->ai_family ) { + struct sockaddr_in6 *in; + in = (struct sockaddr_in6 *)ai->ai_addr; + inet_ntop(ai->ai_family, &in->sin6_addr, addr, sizeof(addr)); + } else { + strcpy(addr, "(unknown)"); + } + return addr; +} + /* * Returns a connected socket() fd, or else die()s. */ @@ -401,6 +418,7 @@ static int git_tcp_connect_sock(char *host, int flags) const char *port = STR(DEFAULT_GIT_PORT); struct addrinfo hints, *ai0, *ai; int gai; + int cnt = 0; if (host[0] == '[') { end = strchr(host + 1, ']'); @@ -444,10 +462,18 @@ static int git_tcp_connect_sock(char *host, int flags) } if (connect(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) { saved_errno = errno; + fprintf(stderr, "%s[%d: %s]: net=%s, errno=%s\n", + host, + cnt, + ai_name(ai), + hstrerror(h_errno), + strerror(saved_errno)); close(sockfd); sockfd = -1; continue; } + if (flags & CONNECT_VERBOSE) + fprintf(stderr, "%s ", ai_name(ai)); break; } @@ -476,6 +502,7 @@ static int git_tcp_connect_sock(char *host, int flags) struct sockaddr_in sa; char **ap; unsigned int nport; + int cnt; if (host[0] == '[') { end = strchr(host + 1, ']'); @@ -512,7 +539,7 @@ static int git_tcp_connect_sock(char *host, int flags) if (flags & CONNECT_VERBOSE) fprintf(stderr, "done.\nConnecting to %s (port %s) ... ", host, port); - for (ap = he->h_addr_list; *ap; ap++) { + for (cnt = 0, ap = he->h_addr_list; *ap; ap++, cnt++) { sockfd = socket(he->h_addrtype, SOCK_STREAM, 0); if (sockfd < 0) { saved_errno = errno; @@ -526,10 +553,19 @@ static int git_tcp_connect_sock(char *host, int flags) if (connect(sockfd, (struct sockaddr *)&sa, sizeof sa) < 0) { saved_errno = errno; + fprintf(stderr, "%s[%d: %s]: net=%s, errno=%s\n", + host, + cnt, + inet_ntoa(*(struct in_addr *)&sa.sin_addr), + hstrerror(h_errno), + strerror(saved_errno)); close(sockfd); sockfd = -1; continue; } + if (flags & CONNECT_VERBOSE) + fprintf(stderr, "%s ", + inet_ntoa(*(struct in_addr *)&sa.sin_addr)); break; } diff --git a/contrib/workdir/git-new-workdir b/contrib/workdir/git-new-workdir index 9877b98508..f2a3615bbc 100755 --- a/contrib/workdir/git-new-workdir +++ b/contrib/workdir/git-new-workdir @@ -20,17 +20,19 @@ new_workdir=$2 branch=$3 # want to make sure that what is pointed to has a .git directory ... -test -d "$orig_git/.git" || die "\"$orig_git\" is not a git repository!" +git_dir=$(cd "$orig_git" 2>/dev/null && + git rev-parse --git-dir 2>/dev/null) || + die "\"$orig_git\" is not a git repository!" # don't link to a workdir -if test -L "$orig_git/.git/config" +if test -L "$git_dir/config" then die "\"$orig_git\" is a working directory only, please specify" \ "a complete repository." fi # make sure the the links use full paths -orig_git=$(cd "$orig_git"; pwd) +git_dir=$(cd "$git_dir"; pwd) # create the workdir mkdir -p "$new_workdir/.git" || die "unable to create \"$new_workdir\"!" @@ -45,13 +47,13 @@ do mkdir -p "$(dirname "$new_workdir/.git/$x")" ;; esac - ln -s "$orig_git/.git/$x" "$new_workdir/.git/$x" + ln -s "$git_dir/$x" "$new_workdir/.git/$x" done # now setup the workdir cd "$new_workdir" # copy the HEAD from the original repository as a default branch -cp "$orig_git/.git/HEAD" .git/HEAD +cp "$git_dir/HEAD" .git/HEAD # checkout the branch (either the same as HEAD from the original repository, or # the one that was asked for) git checkout -f $branch diff --git a/git-cvsexportcommit.perl b/git-cvsexportcommit.perl index d6ae99b8c0..42060ef6e1 100755 --- a/git-cvsexportcommit.perl +++ b/git-cvsexportcommit.perl @@ -15,9 +15,9 @@ unless ($ENV{GIT_DIR} && -r $ENV{GIT_DIR}){ die "GIT_DIR is not defined or is unreadable"; } -our ($opt_h, $opt_P, $opt_p, $opt_v, $opt_c, $opt_f, $opt_a, $opt_m, $opt_d); +our ($opt_h, $opt_P, $opt_p, $opt_v, $opt_c, $opt_f, $opt_a, $opt_m, $opt_d, $opt_u); -getopts('hPpvcfam:d:'); +getopts('uhPpvcfam:d:'); $opt_h && usage(); @@ -178,6 +178,10 @@ foreach my $f (@files) { my %cvsstat; if (@canstatusfiles) { + if ($opt_u) { + my @updated = safe_pipe_capture(@cvs, 'update', @canstatusfiles); + print @updated; + } my @cvsoutput; @cvsoutput= safe_pipe_capture(@cvs, 'status', @canstatusfiles); my $matchcount = 0; diff --git a/git-cvsserver.perl b/git-cvsserver.perl index 1de517791f..2b4825a8ee 100755 --- a/git-cvsserver.perl +++ b/git-cvsserver.perl @@ -95,9 +95,10 @@ $state->{method} = 'ext'; if (@ARGV && $ARGV[0] eq 'pserver') { $state->{method} = 'pserver'; my $line = <STDIN>; chomp $line; - unless( $line eq 'BEGIN AUTH REQUEST') { + unless( $line =~ /^BEGIN (AUTH|VERIFICATION) REQUEST$/) { die "E Do not understand $line - expecting BEGIN AUTH REQUEST\n"; } + my $request = $1; $line = <STDIN>; chomp $line; req_Root('root', $line) # reuse Root or die "E Invalid root $line \n"; @@ -109,10 +110,11 @@ if (@ARGV && $ARGV[0] eq 'pserver') { } $line = <STDIN>; chomp $line; # validate the password? $line = <STDIN>; chomp $line; - unless ($line eq 'END AUTH REQUEST') { - die "E Do not understand $line -- expecting END AUTH REQUEST\n"; + unless ($line eq "END $request REQUEST") { + die "E Do not understand $line -- expecting END $request REQUEST\n"; } print "I LOVE YOU\n"; + exit if $request eq 'VERIFICATION'; # cvs login # and now back to our regular programme... } diff --git a/git-fetch.sh b/git-fetch.sh index 0e05cf1195..6d3a3468b3 100755 --- a/git-fetch.sh +++ b/git-fetch.sh @@ -61,7 +61,7 @@ do quiet=--quiet ;; -v|--verbose) - verbose=Yes + verbose="$verbose"Yes ;; -k|--k|--ke|--kee|--keep) keep='-k -k' @@ -201,8 +201,14 @@ fetch_all_at_once () { echo "$ls_remote_result" | \ git-fetch--tool pick-rref "$rref" "-" else + flags= + case $verbose in + YesYes*) + flags="-v" + ;; + esac git-fetch-pack --thin $exec $keep $shallow_depth \ - $quiet $no_progress "$remote" $rref || + $quiet $no_progress $flags "$remote" $rref || echo failed "$remote" fi fi diff --git a/git-gui/Makefile b/git-gui/Makefile index ee564219c0..3de0de1a23 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -22,7 +22,7 @@ ifndef gitexecdir endif ifndef sharedir - sharedir := $(dir $(gitexecdir))/share + sharedir := $(dir $(gitexecdir))share endif ifndef INSTALL @@ -53,12 +53,19 @@ TCLTK_PATH_SQ = $(subst ','\'',$(TCLTK_PATH)) libdir ?= $(sharedir)/git-gui/lib libdir_SQ = $(subst ','\'',$(libdir)) +exedir = $(dir $(gitexecdir))share/git-gui/lib +exedir_SQ = $(subst ','\'',$(exedir)) + $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh $(QUIET_GEN)rm -f $@ $@+ && \ + if test '$(exedir_SQ)' = '$(libdir_SQ)'; then \ + GITGUI_RELATIVE=1; \ + fi && \ sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ -e 's|^exec wish "$$0"|exec $(subst |,'\|',$(TCLTK_PATH_SQ)) "$$0"|' \ -e 's/@@GITGUI_VERSION@@/$(GITGUI_VERSION)/g' \ - -e 's|@@GITGUI_LIBDIR@@|$(libdir_SQ)|' \ + -e 's|@@GITGUI_RELATIVE@@|'$$GITGUI_RELATIVE'|' \ + -e $$GITGUI_RELATIVE's|@@GITGUI_LIBDIR@@|$(libdir_SQ)|' \ $@.sh >$@+ && \ chmod +x $@+ && \ mv $@+ $@ @@ -88,6 +95,7 @@ TRACK_VARS = \ $(subst ','\'',SHELL_PATH='$(SHELL_PATH_SQ)') \ $(subst ','\'',TCL_PATH='$(TCL_PATH_SQ)') \ $(subst ','\'',TCLTK_PATH='$(TCLTK_PATH_SQ)') \ + $(subst ','\'',gitexecdir='$(gitexecdir_SQ)') \ $(subst ','\'',libdir='$(libdir_SQ)') \ #end TRACK_VARS diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 0a471a5c7d..dba585111c 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -25,7 +25,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA} ## configure our library set oguilib {@@GITGUI_LIBDIR@@} -if {[string match @@* $oguilib]} { +set oguirel {@@GITGUI_RELATIVE@@} +if {$oguirel eq {1}} { + set oguilib [file dirname [file dirname [file normalize $argv0]]] + set oguilib [file join $oguilib share git-gui lib] +} elseif {[string match @@* $oguirel]} { set oguilib [file join [file dirname [file normalize $argv0]] lib] } set idx [file join $oguilib tclIndex] @@ -55,7 +59,7 @@ if {$idx ne {}} { } else { set auto_path [concat [list $oguilib] $auto_path] } -unset -nocomplain fd idx +unset -nocomplain oguilib oguirel idx fd if {![catch {set _verbose $env(GITGUI_VERBOSE)}]} { unset _verbose @@ -1206,15 +1210,12 @@ foreach class {Button Checkbutton Entry Label } unset class -if {[is_Windows]} { - set M1B Control - set M1T Ctrl -} elseif {[is_MacOSX]} { +if {[is_MacOSX]} { set M1B M1 set M1T Cmd } else { - set M1B M1 - set M1T M1 + set M1B Control + set M1T Ctrl } proc apply_config {} { diff --git a/git-merge.sh b/git-merge.sh index ff92aaf3f9..981d69d35f 100755 --- a/git-merge.sh +++ b/git-merge.sh @@ -3,7 +3,7 @@ # Copyright (c) 2005 Junio C Hamano # -USAGE='[-n] [--no-commit] [--squash] [-s <strategy>] [-m=<merge-message>] <commit>+' +USAGE='[-n] [--summary] [--no-commit] [--squash] [-s <strategy>] [-m=<merge-message>] <commit>+' SUBDIRECTORY_OK=Yes . git-sh-setup @@ -88,12 +88,11 @@ finish () { '') ;; ?*) - case "$no_summary" in - '') + if test "$show_diffstat" = t + then # We want color (if set), but no pager GIT_PAGER='' git-diff --stat --summary -M "$head" "$1" - ;; - esac + fi ;; esac } @@ -126,7 +125,9 @@ do case "$1" in -n|--n|--no|--no-|--no-s|--no-su|--no-sum|--no-summ|\ --no-summa|--no-summar|--no-summary) - no_summary=t ;; + show_diffstat=false ;; + --summary) + show_diffstat=t ;; --sq|--squ|--squa|--squas|--squash) squash=t no_commit=t ;; --no-c|--no-co|--no-com|--no-comm|--no-commi|--no-commit) @@ -168,6 +169,11 @@ do shift done +if test -z "$show_diffstat"; then + test "$(git-config --bool merge.diffstat)" = false && show_diffstat=false + test -z "$show_diffstat" && show_diffstat=t +fi + # This could be traditional "merge <msg> HEAD <commit>..." and the # way we can tell it is to see if the second token is HEAD, but some # people might have misused the interface and used a committish that diff --git a/git-pull.sh b/git-pull.sh index a3665d7751..ba0ca079e2 100755 --- a/git-pull.sh +++ b/git-pull.sh @@ -22,6 +22,9 @@ do -n|--n|--no|--no-|--no-s|--no-su|--no-sum|--no-summ|\ --no-summa|--no-summar|--no-summary) no_summary=-n ;; + --summary) + no_summary=$1 + ;; --no-c|--no-co|--no-com|--no-comm|--no-commi|--no-commit) no_commit=--no-commit ;; --sq|--squ|--squa|--squas|--squash) diff --git a/git-svn.perl b/git-svn.perl index fa46236ae8..e35006142a 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -2472,12 +2472,16 @@ sub close_file { my $hash; my $path = $self->git_path($fb->{path}); if (my $fh = $fb->{fh}) { - seek($fh, 0, 0) or croak $!; - my $md5 = Digest::MD5->new; - $md5->addfile($fh); - my $got = $md5->hexdigest; - die "Checksum mismatch: $path\n", - "expected: $exp\n got: $got\n" if (defined $exp && $got ne $exp); + if (defined $exp) { + seek($fh, 0, 0) or croak $!; + my $md5 = Digest::MD5->new; + $md5->addfile($fh); + my $got = $md5->hexdigest; + if ($got ne $exp) { + die "Checksum mismatch: $path\n", + "expected: $exp\n got: $got\n"; + } + } sysseek($fh, 0, 0) or croak $!; if ($fb->{mode_b} == 120000) { sysread($fh, my $buf, 5) == 5 or croak $!; diff --git a/run-command.c b/run-command.c index eff523e191..7e779d33ee 100644 --- a/run-command.c +++ b/run-command.c @@ -73,6 +73,17 @@ int start_command(struct child_process *cmd) close(cmd->out); } + if (cmd->dir && chdir(cmd->dir)) + die("exec %s: cd to %s failed (%s)", cmd->argv[0], + cmd->dir, strerror(errno)); + if (cmd->env) { + for (; *cmd->env; cmd->env++) { + if (strchr(*cmd->env, '=')) + putenv((char*)*cmd->env); + else + unsetenv(*cmd->env); + } + } if (cmd->git_cmd) { execv_git_cmd(cmd->argv); } else { @@ -133,13 +144,37 @@ int run_command(struct child_process *cmd) return finish_command(cmd); } +static void prepare_run_command_v_opt(struct child_process *cmd, + const char **argv, + int opt) +{ + memset(cmd, 0, sizeof(*cmd)); + cmd->argv = argv; + cmd->no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0; + cmd->git_cmd = opt & RUN_GIT_CMD ? 1 : 0; + cmd->stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0; +} + int run_command_v_opt(const char **argv, int opt) { struct child_process cmd; - memset(&cmd, 0, sizeof(cmd)); - cmd.argv = argv; - cmd.no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0; - cmd.git_cmd = opt & RUN_GIT_CMD ? 1 : 0; - cmd.stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0; + prepare_run_command_v_opt(&cmd, argv, opt); + return run_command(&cmd); +} + +int run_command_v_opt_cd(const char **argv, int opt, const char *dir) +{ + struct child_process cmd; + prepare_run_command_v_opt(&cmd, argv, opt); + cmd.dir = dir; + return run_command(&cmd); +} + +int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const char *const *env) +{ + struct child_process cmd; + prepare_run_command_v_opt(&cmd, argv, opt); + cmd.dir = dir; + cmd.env = env; return run_command(&cmd); } diff --git a/run-command.h b/run-command.h index 3680ef9d45..7958eb1e0b 100644 --- a/run-command.h +++ b/run-command.h @@ -16,6 +16,8 @@ struct child_process { pid_t pid; int in; int out; + const char *dir; + const char *const *env; unsigned close_in:1; unsigned close_out:1; unsigned no_stdin:1; @@ -32,5 +34,12 @@ int run_command(struct child_process *); #define RUN_GIT_CMD 2 /*If this is to be git sub-command */ #define RUN_COMMAND_STDOUT_TO_STDERR 4 int run_command_v_opt(const char **argv, int opt); +int run_command_v_opt_cd(const char **argv, int opt, const char *dir); + +/* + * env (the environment) is to be formatted like environ: "VAR=VALUE". + * To unset an environment variable use just "VAR". + */ +int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const char *const *env); #endif diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh index 6c26fd829d..a839f4e074 100755 --- a/t/t0021-conversion.sh +++ b/t/t0021-conversion.sh @@ -45,4 +45,40 @@ test_expect_success check ' test "z$id" = "z$embedded" ' +# If an expanded ident ever gets into the repository, we want to make sure that +# it is collapsed before being expanded again on checkout +test_expect_success expanded_in_repo ' + { + echo "File with expanded keywords" + echo "\$Id\$" + echo "\$Id:\$" + echo "\$Id: 0000000000000000000000000000000000000000 \$" + echo "\$Id: NoSpaceAtEnd\$" + echo "\$Id:NoSpaceAtFront \$" + echo "\$Id:NoSpaceAtEitherEnd\$" + echo "\$Id: NoTerminatingSymbol" + } > expanded-keywords && + + { + echo "File with expanded keywords" + echo "\$Id: 4f21723e7b15065df7de95bd46c8ba6fb1818f4c \$" + echo "\$Id: 4f21723e7b15065df7de95bd46c8ba6fb1818f4c \$" + echo "\$Id: 4f21723e7b15065df7de95bd46c8ba6fb1818f4c \$" + echo "\$Id: 4f21723e7b15065df7de95bd46c8ba6fb1818f4c \$" + echo "\$Id: 4f21723e7b15065df7de95bd46c8ba6fb1818f4c \$" + echo "\$Id: 4f21723e7b15065df7de95bd46c8ba6fb1818f4c \$" + echo "\$Id: NoTerminatingSymbol" + } > expected-output && + + git add expanded-keywords && + git commit -m "File with keywords expanded" && + + echo "expanded-keywords ident" >> .gitattributes && + + rm -f expanded-keywords && + git checkout -- expanded-keywords && + cat expanded-keywords && + cmp expanded-keywords expected-output +' + test_done diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh index 7f9c6e29b2..e9ef315173 100755 --- a/t/t9400-git-cvsserver-server.sh +++ b/t/t9400-git-cvsserver-server.sh @@ -67,6 +67,22 @@ git END AUTH REQUEST EOF +cat >login-anonymous <<EOF +BEGIN VERIFICATION REQUEST +$SERVERDIR +anonymous + +END VERIFICATION REQUEST +EOF + +cat >login-git <<EOF +BEGIN VERIFICATION REQUEST +$SERVERDIR +git + +END VERIFICATION REQUEST +EOF + test_expect_success 'pserver authentication' \ 'cat request-anonymous | git-cvsserver pserver >log 2>&1 && tail -n1 log | grep -q "^I LOVE YOU$"' @@ -80,6 +96,19 @@ test_expect_success 'pserver authentication failure (non-anonymous user)' \ fi && tail -n1 log | grep -q "^I HATE YOU$"' +test_expect_success 'pserver authentication (login)' \ + 'cat login-anonymous | git-cvsserver pserver >log 2>&1 && + tail -n1 log | grep -q "^I LOVE YOU$"' + +test_expect_success 'pserver authentication failure (login/non-anonymous user)' \ + 'if cat login-git | git-cvsserver pserver >log 2>&1 + then + false + else + true + fi && + tail -n1 log | grep -q "^I HATE YOU$"' + #-------------- # CONFIG TESTS @@ -250,6 +279,7 @@ test_expect_success 'cvs update (merge)' \ git commit -q -m "Merge test (merge)" && git push gitcvs.git >/dev/null && cd cvswork && + sleep 1 && touch merge && GIT_CONFIG="$git_config" cvs -Q update && diff -q merge ../expected' @@ -292,6 +322,7 @@ test_expect_success 'cvs update (merge no-op)' \ git commit -q -m "Merge test (no-op)" && git push gitcvs.git >/dev/null && cd cvswork && + sleep 1 && touch merge && GIT_CONFIG="$git_config" cvs -Q update && diff -q merge ../merge' @@ -26,7 +26,7 @@ struct tag *lookup_tag(const unsigned char *sha1) if (!obj->type) obj->type = OBJ_TAG; if (obj->type != OBJ_TAG) { - error("Object %s is a %s, not a tree", + error("Object %s is a %s, not a tag", sha1_to_hex(sha1), typename(obj->type)); return NULL; } |