Merge branch 'jc/maint-request-pull-for-tag' into maint
authorJunio C Hamano <gitster@pobox.com>
Fri, 10 Feb 2012 21:59:02 +0000 (13:59 -0800)
committerJunio C Hamano <gitster@pobox.com>
Fri, 10 Feb 2012 21:59:02 +0000 (13:59 -0800)
* jc/maint-request-pull-for-tag:
request-pull: explicitly ask tags/$name to be pulled

38 files changed:
Documentation/RelNotes/1.7.7.6.txt
Documentation/RelNotes/1.7.8.4.txt
Documentation/RelNotes/1.7.9.1.txt [new file with mode: 0644]
Documentation/RelNotes/1.7.9.txt
Documentation/git-grep.txt
Documentation/git-show-ref.txt
Documentation/git.txt
GIT-VERSION-GEN
INSTALL
RelNotes
builtin/grep.c
builtin/receive-pack.c
builtin/send-pack.c
cache.h
connect.c
contrib/completion/git-completion.bash
credential-cache.c
diff-lib.c
diff.c
git-mergetool.sh
git-submodule.sh
git.c
imap-send.c
remote-curl.c
revision.c
run-command.c
run-command.h
t/t4010-diff-pathspec.sh
t/t4034-diff-words.sh
t/t5523-push-upstream.sh
t/t5541-http-push.sh
t/t6012-rev-list-simplify.sh
t/t7406-submodule-update.sh
t/t7610-mergetool.sh
t/t7810-grep.sh
tree-walk.c
unix-socket.c
upload-pack.c
index b8b86ebc61df5b63dd69c6b74be25128a57b0668..8df606d45273573b5c0d899096ca5de798e08a13 100644 (file)
@@ -8,6 +8,10 @@ Fixes since v1.7.7.5
    directory when two paths in question are in adjacent directories and
    the name of the one directory is a prefix of the other.
 
+ * A wildcard that matches deeper hierarchy given to the "diff-index" command,
+   e.g. "git diff-index HEAD -- '*.txt'", incorrectly reported additions of
+   matching files even when there is no change.
+
  * When producing a "thin pack" (primarily used in bundles and smart
    HTTP transfers) out of a fully packed repository, we unnecessarily
    avoided sending recent objects as a delta against objects we know
index c21fc99bdb32622f619305d7945e0c3b1d66ab23..9bebdbf13d860a598c4c57ec8381e44cef257f09 100644 (file)
@@ -8,6 +8,10 @@ Fixes since v1.7.8.3
    directory when two paths in question are in adjacent directories and
    the name of the one directory is a prefix of the other.
 
+ * A wildcard that matches deeper hierarchy given to the "diff-index" command,
+   e.g. "git diff-index HEAD -- '*.txt'", incorrectly reported additions of
+   matching files even when there is no change.
+
  * When producing a "thin pack" (primarily used in bundles and smart
    HTTP transfers) out of a fully packed repository, we unnecessarily
    avoided sending recent objects as a delta against objects we know
diff --git a/Documentation/RelNotes/1.7.9.1.txt b/Documentation/RelNotes/1.7.9.1.txt
new file mode 100644 (file)
index 0000000..d8a0961
--- /dev/null
@@ -0,0 +1,19 @@
+Git v1.7.9.1 Release Notes
+==========================
+
+Fixes since v1.7.9
+------------------
+
+ * Subprocesses spawned from various git programs were often left running
+   to completion even when the top-level process was killed.
+
+ * "git log --first-parent $pathspec" did not stay on the first parent
+   chain and veered into side branch from which the whole change to the
+   specified paths came.
+
+ * "git push -q" was not sufficiently quiet.
+
+ * When "git push" fails to update any refs, the client side did not
+   report an error correctly to the end user.
+
+Also contains minor fixes and documentation updates.
index 5eb88b899a43960f5d48fd39bb3b6d9496cd543f..95320aad5dd2414efeacbc088b34e45c4ac51bbf 100644 (file)
@@ -1,4 +1,4 @@
-Git v1.7.9 Release Notes (draft)
+Git v1.7.9 Release Notes
 ========================
 
 Updates since v1.7.8
@@ -12,19 +12,20 @@ Updates since v1.7.8
 
  * Git uses gettext to translate its most common interface messages
    into the user's language if translations are available and the
-   locale is appropriately set. Distributors can drop in new PO files
+   locale is appropriately set. Distributors can drop new PO files
    in po/ to add new translations.
 
- * The code to handle username/password for HTTP transaction used in
+ * The code to handle username/password for HTTP transactions used in
    "git push" & "git fetch" learned to talk "credential API" to
    external programs to cache or store them, to allow integration with
    platform native keychain mechanisms.
 
- * The prompted input in the terminal use our own getpass() replacement
-   when possible. HTTP transactions used to ask username without echoing
-   back what was typed, but with this change you will see it as you type.
+ * The input prompts in the terminal use our own getpass() replacement
+   when possible. HTTP transactions used to ask for the username without
+   echoing back what was typed, but with this change you will see it as
+   you type.
 
- * The internal of "revert/cherry-pick" has been tweaked to prepare
+ * The internals of "revert/cherry-pick" have been tweaked to prepare
    building more generic "sequencer" on top of the implementation that
    drives them.
 
@@ -63,7 +64,7 @@ Updates since v1.7.8
    knows MATLAB.
 
  * "git log --format='<format>'" learned new %g[nNeE] specifiers to
-   show information from the reflog entries when warlking the reflog
+   show information from the reflog entries when walking the reflog
    (i.e. with "-g").
 
  * "git pull" can be used to fetch and merge an annotated/signed tag,
@@ -109,11 +110,3 @@ Fixes since v1.7.8
 Unless otherwise noted, all the fixes since v1.7.8 in the maintenance
 releases are contained in this release (see release notes to them for
 details).
-
---
-exec >/var/tmp/1
-O=v1.7.9-rc0-44-g478c446
-echo O=$(git describe master)
-git log --first-parent --oneline --reverse ^$O master
-echo
-git shortlog --no-merges ^$O ^maint master
index 15d6711d46754e9659561b4372b46ec3c6654d6b..6a8b1e3a7d06218903ce5614f51c4e7cbba73b17 100644 (file)
@@ -79,6 +79,9 @@ OPTIONS
 --max-depth <depth>::
        For each <pathspec> given on command line, descend at most <depth>
        levels of directories. A negative value means no limit.
+       This option is ignored if <pathspec> contains active wildcards.
+       In other words if "a*" matches a directory named "a*",
+       "*" is matched literally so --max-depth is still effective.
 
 -w::
 --word-regexp::
index 3c4589529960e013df364c68e4480caa09b744c6..fcee0008a9d868bb27c9eacbcfe72a3a3f8ed60f 100644 (file)
@@ -44,7 +44,7 @@ OPTIONS
 -d::
 --dereference::
 
-       Dereference tags into object IDs as well. They will be shown with "^{}"
+       Dereference tags into object IDs as well. They will be shown with "{caret}{}"
        appended.
 
 -s::
@@ -73,9 +73,9 @@ OPTIONS
 --exclude-existing[=<pattern>]::
 
        Make 'git show-ref' act as a filter that reads refs from stdin of the
-       form "^(?:<anything>\s)?<refname>(?:{backslash}{caret}\{\})?$"
+       form "`{caret}(?:<anything>\s)?<refname>(?:{backslash}{caret}{})?$`"
        and performs the following actions on each:
-       (1) strip "^{}" at the end of line if any;
+       (1) strip "{caret}{}" at the end of line if any;
        (2) ignore if pattern is provided and does not head-match refname;
        (3) warn if refname is not a well-formed refname and skip;
        (4) ignore if refname is a ref that exists in the local repository;
index 8a77fa47adf1ddc96a942e190b1227b638017346..f7e201fae30940ac00d1685bfd9411de9d81ca28 100644 (file)
@@ -44,17 +44,24 @@ unreleased) version of git, that is available from 'master'
 branch of the `git.git` repository.
 Documentation for older releases are available here:
 
-* link:v1.7.8.3/git.html[documentation for release 1.7.8.3]
+* link:v1.7.9/git.html[documentation for release 1.7.9]
 
 * release notes for
+  link:RelNotes/1.7.9.txt[1.7.9].
+
+* link:v1.7.8.4/git.html[documentation for release 1.7.8.4]
+
+* release notes for
+  link:RelNotes/1.7.8.4.txt[1.7.8.4],
   link:RelNotes/1.7.8.3.txt[1.7.8.3],
   link:RelNotes/1.7.8.2.txt[1.7.8.2],
   link:RelNotes/1.7.8.1.txt[1.7.8.1],
   link:RelNotes/1.7.8.txt[1.7.8].
 
-* link:v1.7.7.5/git.html[documentation for release 1.7.7.5]
+* link:v1.7.7.6/git.html[documentation for release 1.7.7.6]
 
 * release notes for
+  link:RelNotes/1.7.7.6.txt[1.7.7.6],
   link:RelNotes/1.7.7.5.txt[1.7.7.5],
   link:RelNotes/1.7.7.4.txt[1.7.7.4],
   link:RelNotes/1.7.7.3.txt[1.7.7.3],
@@ -62,9 +69,10 @@ Documentation for older releases are available here:
   link:RelNotes/1.7.7.1.txt[1.7.7.1],
   link:RelNotes/1.7.7.txt[1.7.7].
 
-* link:v1.7.6.5/git.html[documentation for release 1.7.6.5]
+* link:v1.7.6.6/git.html[documentation for release 1.7.6.6]
 
 * release notes for
+  link:RelNotes/1.7.6.6.txt[1.7.6.6],
   link:RelNotes/1.7.6.5.txt[1.7.6.5],
   link:RelNotes/1.7.6.4.txt[1.7.6.4],
   link:RelNotes/1.7.6.3.txt[1.7.6.3],
index 15d06cfaab509b9a358dadad1f77cd02e5232c7a..70204f87f90c733db7043b3111b5c18226ab64ac 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v1.7.9-rc1
+DEF_VER=v1.7.9
 
 LF='
 '
diff --git a/INSTALL b/INSTALL
index 8120641a513f1528b7e8f312b1ba8f496b936539..6fa83fe2b85f2611fc0253a90b7b238bf74745b7 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -83,7 +83,11 @@ Issues of note:
        - "Perl" version 5.8 or later is needed to use some of the
          features (e.g. preparing a partial commit using "git add -i/-p",
          interacting with svn repositories with "git svn").  If you can
-         live without these, use NO_PERL.
+         live without these, use NO_PERL.  Note that recent releases of
+         Redhat/Fedora are reported to ship Perl binary package with some
+         core modules stripped away (see http://lwn.net/Articles/477234/),
+         so you might need to install additional packages other than Perl
+         itself, e.g. Time::HiRes.
 
        - "openssl" library is used by git-imap-send to use IMAP over SSL.
          If you don't need it, use NO_OPENSSL.
index 766bbaf8f5a90759645200e1fc61e11d9836de49..d69b2c37acc38f4916d4daa8387abb567a8b9834 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/1.7.9.txt
\ No newline at end of file
+Documentation/RelNotes/1.7.9.1.txt
\ No newline at end of file
index 9ce064ac1131e9a93383f568bb6f567791740b77..5c2ae94e5576f2e8af1f8509b789a67851db2598 100644 (file)
@@ -1034,8 +1034,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 
 #ifndef NO_PTHREADS
        if (use_threads) {
-               if (opt.pre_context || opt.post_context || opt.file_break ||
-                   opt.funcbody)
+               if (!(opt.name_only || opt.unmatch_name_only || opt.count)
+                   && (opt.pre_context || opt.post_context ||
+                       opt.file_break || opt.funcbody))
                        skip_first_line = 1;
                start_threads(&opt);
        }
index 8c9e91e78c95a4a3d581aae59d0f00bc95b2c942..fa7448be5aaf9d2830168b77f9a555e9b6740993 100644 (file)
@@ -33,6 +33,7 @@ static int transfer_unpack_limit = -1;
 static int unpack_limit = 100;
 static int report_status;
 static int use_sideband;
+static int quiet;
 static int prefer_ofs_delta = 1;
 static int auto_update_server_info;
 static int auto_gc = 1;
@@ -122,7 +123,7 @@ static void show_ref(const char *path, const unsigned char *sha1)
        else
                packet_write(1, "%s %s%c%s%s\n",
                             sha1_to_hex(sha1), path, 0,
-                            " report-status delete-refs side-band-64k",
+                            " report-status delete-refs side-band-64k quiet",
                             prefer_ofs_delta ? " ofs-delta" : "");
        sent_capabilities = 1;
 }
@@ -748,10 +749,13 @@ static struct command *read_head_info(void)
                refname = line + 82;
                reflen = strlen(refname);
                if (reflen + 82 < len) {
-                       if (strstr(refname + reflen + 1, "report-status"))
+                       const char *feature_list = refname + reflen + 1;
+                       if (parse_feature_request(feature_list, "report-status"))
                                report_status = 1;
-                       if (strstr(refname + reflen + 1, "side-band-64k"))
+                       if (parse_feature_request(feature_list, "side-band-64k"))
                                use_sideband = LARGE_PACKET_MAX;
+                       if (parse_feature_request(feature_list, "quiet"))
+                               quiet = 1;
                }
                cmd = xcalloc(1, sizeof(struct command) + len - 80);
                hashcpy(cmd->old_sha1, old_sha1);
@@ -805,8 +809,10 @@ static const char *unpack(void)
 
        if (ntohl(hdr.hdr_entries) < unpack_limit) {
                int code, i = 0;
-               const char *unpacker[4];
+               const char *unpacker[5];
                unpacker[i++] = "unpack-objects";
+               if (quiet)
+                       unpacker[i++] = "-q";
                if (fsck_objects)
                        unpacker[i++] = "--strict";
                unpacker[i++] = hdr_arg;
@@ -901,6 +907,11 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
                const char *arg = *argv++;
 
                if (*arg == '-') {
+                       if (!strcmp(arg, "--quiet")) {
+                               quiet = 1;
+                               continue;
+                       }
+
                        if (!strcmp(arg, "--advertise-refs")) {
                                advertise_refs = 1;
                                continue;
index cd1115ffc687c642acd4bda09b1ea7976e1e0478..71f258ef6e620979a9dbeaa87d2501a304b3a0fa 100644 (file)
@@ -263,6 +263,8 @@ int send_pack(struct send_pack_args *args,
                args->use_ofs_delta = 1;
        if (server_supports("side-band-64k"))
                use_sideband = 1;
+       if (!server_supports("quiet"))
+               args->quiet = 0;
 
        if (!remote_refs) {
                fprintf(stderr, "No refs in common and none specified; doing nothing.\n"
@@ -301,11 +303,12 @@ int send_pack(struct send_pack_args *args,
                        char *old_hex = sha1_to_hex(ref->old_sha1);
                        char *new_hex = sha1_to_hex(ref->new_sha1);
 
-                       if (!cmds_sent && (status_report || use_sideband)) {
-                               packet_buf_write(&req_buf, "%s %s %s%c%s%s",
+                       if (!cmds_sent && (status_report || use_sideband || args->quiet)) {
+                               packet_buf_write(&req_buf, "%s %s %s%c%s%s%s",
                                        old_hex, new_hex, ref->name, 0,
                                        status_report ? " report-status" : "",
-                                       use_sideband ? " side-band-64k" : "");
+                                       use_sideband ? " side-band-64k" : "",
+                                       args->quiet ? " quiet" : "");
                        }
                        else
                                packet_buf_write(&req_buf, "%s %s %s",
@@ -439,6 +442,10 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
                                args.force_update = 1;
                                continue;
                        }
+                       if (!strcmp(arg, "--quiet")) {
+                               args.quiet = 1;
+                               continue;
+                       }
                        if (!strcmp(arg, "--verbose")) {
                                args.verbose = 1;
                                continue;
diff --git a/cache.h b/cache.h
index 10afd71d435920a3cc2152208a06058791ea7a04..9bd8c2d06c80c958b5f654fe16e7294883e49a30 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -1037,6 +1037,7 @@ struct extra_have_objects {
 };
 extern struct ref **get_remote_heads(int in, struct ref **list, unsigned int flags, struct extra_have_objects *);
 extern int server_supports(const char *feature);
+extern const char *parse_feature_request(const char *features, const char *feature);
 
 extern struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path);
 
index 2ea5c3c0fbedb89e4189d32a455f289398ce106b..912cddeea8c4f09ec523ce19e677358c84eda9b7 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -101,8 +101,27 @@ struct ref **get_remote_heads(int in, struct ref **list,
 
 int server_supports(const char *feature)
 {
-       return server_capabilities &&
-               strstr(server_capabilities, feature) != NULL;
+       return !!parse_feature_request(server_capabilities, feature);
+}
+
+const char *parse_feature_request(const char *feature_list, const char *feature)
+{
+       int len;
+
+       if (!feature_list)
+               return NULL;
+
+       len = strlen(feature);
+       while (*feature_list) {
+               const char *found = strstr(feature_list, feature);
+               if (!found)
+                       return NULL;
+               if ((feature_list == found || isspace(found[-1])) &&
+                   (!found[len] || isspace(found[len]) || found[len] == '='))
+                       return found;
+               feature_list = found + 1;
+       }
+       return NULL;
 }
 
 enum protocol {
index b0062bac22347e42dd64047c51dfb2bff92243ef..78be1958383da7cc2fd1ec22e3cd02e972874eb1 100755 (executable)
@@ -1622,7 +1622,7 @@ _git_log ()
 
 __git_merge_options="
        --no-commit --no-stat --log --no-log --squash --strategy
-       --commit --stat --no-squash --ff --no-ff --ff-only
+       --commit --stat --no-squash --ff --no-ff --ff-only --edit --no-edit
 "
 
 _git_merge ()
@@ -2631,6 +2631,10 @@ _git ()
                # workaround zsh's bug that leaves 'words' as a special
                # variable in versions < 4.3.12
                typeset -h words
+
+               # workaround zsh's bug that quotes spaces in the COMPREPLY
+               # array if IFS doesn't contain spaces.
+               typeset -h IFS
        fi
 
        local cur words cword prev
@@ -2687,6 +2691,10 @@ _gitk ()
                # workaround zsh's bug that leaves 'words' as a special
                # variable in versions < 4.3.12
                typeset -h words
+
+               # workaround zsh's bug that quotes spaces in the COMPREPLY
+               # array if IFS doesn't contain spaces.
+               typeset -h IFS
        fi
 
        local cur words cword prev
index b15a9a74494c746d6f1e70b7658769c343c66576..9a03792c7de109e957a1f01924c4f66ba87b5c87 100644 (file)
@@ -71,10 +71,14 @@ static void do_cache(const char *socket, const char *action, int timeout,
                        die_errno("unable to relay credential");
        }
 
-       if (send_request(socket, &buf) < 0 && (flags & FLAG_SPAWN)) {
-               spawn_daemon(socket);
-               if (send_request(socket, &buf) < 0)
+       if (send_request(socket, &buf) < 0) {
+               if (errno != ENOENT && errno != ECONNREFUSED)
                        die_errno("unable to connect to cache daemon");
+               if (flags & FLAG_SPAWN) {
+                       spawn_daemon(socket);
+                       if (send_request(socket, &buf) < 0)
+                               die_errno("unable to connect to cache daemon");
+               }
        }
        strbuf_release(&buf);
 }
index 62f4cd94cfbc4d3fe9e46c84f318af6624349a48..fc0dff31b58c8bd6668de5c6396a93b31cc5729d 100644 (file)
@@ -469,6 +469,8 @@ static int diff_cache(struct rev_info *revs,
        opts.src_index = &the_index;
        opts.dst_index = NULL;
        opts.pathspec = &revs->diffopt.pathspec;
+       opts.pathspec->recursive = 1;
+       opts.pathspec->max_depth = -1;
 
        init_tree_desc(&t, tree->buffer, tree->size);
        return unpack_trees(1, &t, &opts);
diff --git a/diff.c b/diff.c
index 374ecf3b486e218c52f94ba14481a715c19b80db..7e154265f778c645192cbf17c65b9bea2a507402 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -1113,6 +1113,15 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
                        diff_words_append(line, len,
                                          &ecbdata->diff_words->plus);
                        return;
+               } else if (!prefixcmp(line, "\\ ")) {
+                       /*
+                        * Eat the "no newline at eof" marker as if we
+                        * saw a "+" or "-" line with nothing on it,
+                        * and return without diff_words_flush() to
+                        * defer processing. If this is the end of
+                        * preimage, more "+" lines may come after it.
+                        */
+                       return;
                }
                diff_words_flush(ecbdata);
                if (ecbdata->diff_words->type == DIFF_WORDS_PORCELAIN) {
index 085e213a126e5864befc8e3436832ae3c587a624..a9f23f7fcdff610f2b206bc121db7c9217bbf0c7 100755 (executable)
@@ -181,10 +181,14 @@ stage_submodule () {
 }
 
 checkout_staged_file () {
-    tmpfile=$(expr "$(git checkout-index --temp --stage="$1" "$2")" : '\([^    ]*\)    ')
+    tmpfile=$(expr \
+           "$(git checkout-index --temp --stage="$1" "$2" 2>/dev/null)" \
+           : '\([^     ]*\)    ')
 
     if test $? -eq 0 -a -n "$tmpfile" ; then
        mv -- "$(git rev-parse --show-cdup)$tmpfile" "$3"
+    else
+       >"$3"
     fi
 }
 
@@ -224,9 +228,9 @@ merge_file () {
     mv -- "$MERGED" "$BACKUP"
     cp -- "$BACKUP" "$MERGED"
 
-    base_present   && checkout_staged_file 1 "$MERGED" "$BASE"
-    local_present  && checkout_staged_file 2 "$MERGED" "$LOCAL"
-    remote_present && checkout_staged_file 3 "$MERGED" "$REMOTE"
+    checkout_staged_file 1 "$MERGED" "$BASE"
+    checkout_staged_file 2 "$MERGED" "$LOCAL"
+    checkout_staged_file 3 "$MERGED" "$REMOTE"
 
     if test -z "$local_mode" -o -z "$remote_mode"; then
        echo "Deleted merge conflict for '$MERGED':"
index 3adab9363563e80e4ceb2c7fb5c3ab91ac1ef505..9bb2e13e929c824a75c648966aaaa61672b9c445 100755 (executable)
@@ -131,6 +131,7 @@ module_clone()
        gitdir=
        gitdir_base=
        name=$(module_name "$path" 2>/dev/null)
+       test -n "$name" || name="$path"
        base_path=$(dirname "$path")
 
        gitdir=$(git rev-parse --git-dir)
diff --git a/git.c b/git.c
index fb9029cbf17bdad1d52ea6eae0c8f4ddf6a13979..380561663061f011189de883a865fbd59a922190 100644 (file)
--- a/git.c
+++ b/git.c
@@ -495,7 +495,7 @@ static void execv_dashed_external(const char **argv)
         * if we fail because the command is not found, it is
         * OK to return. Otherwise, we just pass along the status code.
         */
-       status = run_command_v_opt(argv, RUN_SILENT_EXEC_FAILURE);
+       status = run_command_v_opt(argv, RUN_SILENT_EXEC_FAILURE | RUN_CLEAN_ON_EXIT);
        if (status >= 0 || errno != ENOENT)
                exit(status);
 
index e40125a22b72544c107e365d4f09eaa3b1ce53de..972ad62cd92ff2b09fb5caa21b24f471009ef19b 100644 (file)
@@ -42,28 +42,6 @@ struct store_conf {
        unsigned trash_remote_new:1, trash_only_new:1;
 };
 
-struct string_list {
-       struct string_list *next;
-       char string[1];
-};
-
-struct channel_conf {
-       struct channel_conf *next;
-       char *name;
-       struct store_conf *master, *slave;
-       char *master_name, *slave_name;
-       char *sync_state;
-       struct string_list *patterns;
-       int mops, sops;
-       unsigned max_messages; /* for slave only */
-};
-
-struct group_conf {
-       struct group_conf *next;
-       char *name;
-       struct string_list *channels;
-};
-
 /* For message->status */
 #define M_RECENT       (1<<0) /* unsyncable flag; maildir_* depend on this being 1<<0 */
 #define M_DEAD         (1<<1) /* expunged */
@@ -71,7 +49,6 @@ struct group_conf {
 
 struct message {
        struct message *next;
-       /* struct string_list *keywords; */
        size_t size; /* zero implies "not fetched" */
        int uid;
        unsigned char flags, status;
index 48c20b86f3cfc6c189972718046a6890aaefacf3..d159fe7f3433ccf6e8c8908961736951e42b9c35 100644 (file)
@@ -770,7 +770,9 @@ static int push_git(struct discovery *heads, int nr_spec, char **specs)
                argv[argc++] = "--thin";
        if (options.dry_run)
                argv[argc++] = "--dry-run";
-       if (options.verbosity > 1)
+       if (options.verbosity == 0)
+               argv[argc++] = "--quiet";
+       else if (options.verbosity > 1)
                argv[argc++] = "--verbose";
        argv[argc++] = url;
        for (i = 0; i < nr_spec; i++)
@@ -805,7 +807,7 @@ static int push(int nr_spec, char **specs)
 static void parse_push(struct strbuf *buf)
 {
        char **specs = NULL;
-       int alloc_spec = 0, nr_spec = 0, i;
+       int alloc_spec = 0, nr_spec = 0, i, ret;
 
        do {
                if (!prefixcmp(buf->buf, "push ")) {
@@ -822,12 +824,13 @@ static void parse_push(struct strbuf *buf)
                        break;
        } while (1);
 
-       if (push(nr_spec, specs))
-               exit(128); /* error already reported */
-
+       ret = push(nr_spec, specs);
        printf("\n");
        fflush(stdout);
 
+       if (ret)
+               exit(128); /* error already reported */
+
  free_specs:
        for (i = 0; i < nr_spec; i++)
                free(specs[i]);
index 064e35108478431e82ec08464203fe119f24c1d6..eb0be4206d2772e4d8eb11bfd164725529f915e7 100644 (file)
@@ -416,7 +416,7 @@ static int rev_same_tree_as_empty(struct rev_info *revs, struct commit *commit)
 static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
 {
        struct commit_list **pp, *parent;
-       int tree_changed = 0, tree_same = 0;
+       int tree_changed = 0, tree_same = 0, nth_parent = 0;
 
        /*
         * If we don't do pruning, everything is interesting
@@ -444,6 +444,14 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
        while ((parent = *pp) != NULL) {
                struct commit *p = parent->item;
 
+               /*
+                * Do not compare with later parents when we care only about
+                * the first parent chain, in order to avoid derailing the
+                * traversal to follow a side branch that brought everything
+                * in the path we are limited to by the pathspec.
+                */
+               if (revs->first_parent_only && nth_parent++)
+                       break;
                if (parse_commit(p) < 0)
                        die("cannot simplify commit %s (because of %s)",
                            sha1_to_hex(commit->object.sha1),
index 1c5104388429e50722769358d5d89948c55bb3aa..1db8abf9843516576f30f8105bbfdd66487db6e1 100644 (file)
@@ -1,8 +1,66 @@
 #include "cache.h"
 #include "run-command.h"
 #include "exec_cmd.h"
+#include "sigchain.h"
 #include "argv-array.h"
 
+struct child_to_clean {
+       pid_t pid;
+       struct child_to_clean *next;
+};
+static struct child_to_clean *children_to_clean;
+static int installed_child_cleanup_handler;
+
+static void cleanup_children(int sig)
+{
+       while (children_to_clean) {
+               struct child_to_clean *p = children_to_clean;
+               children_to_clean = p->next;
+               kill(p->pid, sig);
+               free(p);
+       }
+}
+
+static void cleanup_children_on_signal(int sig)
+{
+       cleanup_children(sig);
+       sigchain_pop(sig);
+       raise(sig);
+}
+
+static void cleanup_children_on_exit(void)
+{
+       cleanup_children(SIGTERM);
+}
+
+static void mark_child_for_cleanup(pid_t pid)
+{
+       struct child_to_clean *p = xmalloc(sizeof(*p));
+       p->pid = pid;
+       p->next = children_to_clean;
+       children_to_clean = p;
+
+       if (!installed_child_cleanup_handler) {
+               atexit(cleanup_children_on_exit);
+               sigchain_push_common(cleanup_children_on_signal);
+               installed_child_cleanup_handler = 1;
+       }
+}
+
+static void clear_child_for_cleanup(pid_t pid)
+{
+       struct child_to_clean **last, *p;
+
+       last = &children_to_clean;
+       for (p = children_to_clean; p; p = p->next) {
+               if (p->pid == pid) {
+                       *last = p->next;
+                       free(p);
+                       return;
+               }
+       }
+}
+
 static inline void close_pair(int fd[2])
 {
        close(fd[0]);
@@ -130,6 +188,9 @@ static int wait_or_whine(pid_t pid, const char *argv0, int silent_exec_failure)
        } else {
                error("waitpid is confused (%s)", argv0);
        }
+
+       clear_child_for_cleanup(pid);
+
        errno = failed_errno;
        return code;
 }
@@ -292,6 +353,8 @@ int start_command(struct child_process *cmd)
        if (cmd->pid < 0)
                error("cannot fork() for %s: %s", cmd->argv[0],
                        strerror(failed_errno = errno));
+       else if (cmd->clean_on_exit)
+               mark_child_for_cleanup(cmd->pid);
 
        /*
         * Wait for child's execvp. If the execvp succeeds (or if fork()
@@ -312,6 +375,7 @@ int start_command(struct child_process *cmd)
                cmd->pid = -1;
        }
        close(notify_pipe[0]);
+
 }
 #else
 {
@@ -356,6 +420,8 @@ int start_command(struct child_process *cmd)
        failed_errno = errno;
        if (cmd->pid < 0 && (!cmd->silent_exec_failure || errno != ENOENT))
                error("cannot spawn %s: %s", cmd->argv[0], strerror(errno));
+       if (cmd->clean_on_exit && cmd->pid >= 0)
+               mark_child_for_cleanup(cmd->pid);
 
        if (cmd->env)
                free_environ(env);
@@ -431,6 +497,7 @@ static void prepare_run_command_v_opt(struct child_process *cmd,
        cmd->stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0;
        cmd->silent_exec_failure = opt & RUN_SILENT_EXEC_FAILURE ? 1 : 0;
        cmd->use_shell = opt & RUN_USING_SHELL ? 1 : 0;
+       cmd->clean_on_exit = opt & RUN_CLEAN_ON_EXIT ? 1 : 0;
 }
 
 int run_command_v_opt(const char **argv, int opt)
@@ -540,6 +607,8 @@ int start_async(struct async *async)
                exit(!!async->proc(proc_in, proc_out, async->data));
        }
 
+       mark_child_for_cleanup(async->pid);
+
        if (need_in)
                close(fdin[0]);
        else if (async->in)
index 56491b9f2344541c02bd0da2928a535f11193bd8..44f7d2bd42ddcf2d65722b7e54bea69645d167a2 100644 (file)
@@ -38,6 +38,7 @@ struct child_process {
        unsigned silent_exec_failure:1;
        unsigned stdout_to_stderr:1;
        unsigned use_shell:1;
+       unsigned clean_on_exit:1;
        void (*preexec_cb)(void);
 };
 
@@ -52,6 +53,7 @@ extern int run_hook(const char *index_file, const char *name, ...);
 #define RUN_COMMAND_STDOUT_TO_STDERR 4
 #define RUN_SILENT_EXEC_FAILURE 8
 #define RUN_USING_SHELL 16
+#define RUN_CLEAN_ON_EXIT 32
 int run_command_v_opt(const char **argv, int opt);
 
 /*
index fbc8cd8f05f4debeb30b935c1b1db86e94e49f0e..af5134b70c6b4898aa652907d58191d45aa30ac4 100755 (executable)
@@ -47,6 +47,14 @@ test_expect_success \
     'git diff-index --cached $tree -- path1/ >current &&
      compare_diff_raw current expected'
 
+cat >expected <<\EOF
+:100644 100644 766498d93a4b06057a8e49d23f4068f1170ff38f 0a41e115ab61be0328a19b29f18cdcb49338d516 M     path1/file1
+EOF
+test_expect_success \
+    '"*file1" should show path1/file1' \
+    'git diff-index --cached $tree -- "*file1" >current &&
+     compare_diff_raw current expected'
+
 cat >expected <<\EOF
 :100644 100644 766498d93a4b06057a8e49d23f4068f1170ff38f 0a41e115ab61be0328a19b29f18cdcb49338d516 M     file0
 EOF
index 6f1e5a2a15f0215e4ed7c19437f5d000edbbd255..5c2012111c28d338ad979fb7bcca871e744184fe 100755 (executable)
@@ -334,4 +334,18 @@ test_expect_success 'word-diff with diff.sbe' '
        word_diff --word-diff=plain
 '
 
+test_expect_success 'word-diff with no newline at EOF' '
+       cat >expect <<-\EOF &&
+       diff --git a/pre b/post
+       index 7bf316e..3dd0303 100644
+       --- a/pre
+       +++ b/post
+       @@ -1 +1 @@
+       a a [-a-]{+ab+} a a
+       EOF
+       printf "%s" "a a a a a" >pre &&
+       printf "%s" "a a ab a a" >post &&
+       word_diff --word-diff=plain
+'
+
 test_done
index c229fe68f11007fbb96d7b3837c18fd2f306a0bf..9ee52cfc458b2914ee82da6ac1117a2b1ae45a64 100755 (executable)
@@ -108,4 +108,11 @@ test_expect_failure TTY 'push --no-progress suppresses progress' '
        ! grep "Writing objects" err
 '
 
+test_expect_success TTY 'quiet push' '
+       ensure_fresh_upstream &&
+
+       test_terminal git push --quiet --no-progress upstream master 2>&1 | tee output &&
+       test_cmp /dev/null output
+'
+
 test_done
index 9b85d420c39a0f2192b6b829a6c7912ae28d8e92..d66ed2450854c3091105a43bb2aa0f831140ed1f 100755 (executable)
@@ -14,6 +14,7 @@ fi
 ROOT_PATH="$PWD"
 LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'5541'}
 . "$TEST_DIRECTORY"/lib-httpd.sh
+. "$TEST_DIRECTORY"/lib-terminal.sh
 start_httpd
 
 test_expect_success 'setup remote repository' '
@@ -95,6 +96,32 @@ test_expect_success 'create and delete remote branch' '
        test_must_fail git show-ref --verify refs/remotes/origin/dev
 '
 
+cat >"$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git/hooks/update" <<EOF
+#!/bin/sh
+exit 1
+EOF
+chmod a+x "$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git/hooks/update"
+
+cat >exp <<EOF
+remote: error: hook declined to update refs/heads/dev2
+To http://127.0.0.1:$LIB_HTTPD_PORT/smart/test_repo.git
+ ! [remote rejected] dev2 -> dev2 (hook declined)
+error: failed to push some refs to 'http://127.0.0.1:5541/smart/test_repo.git'
+EOF
+
+test_expect_success 'rejected update prints status' '
+       cd "$ROOT_PATH"/test_repo_clone &&
+       git checkout -b dev2 &&
+       : >path4 &&
+       git add path4 &&
+       test_tick &&
+       git commit -m dev2 &&
+       test_must_fail git push origin dev2 2>act &&
+       sed -e "/^remote: /s/ *$//" <act >cmp &&
+       test_cmp exp cmp
+'
+rm -f "$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git/hooks/update"
+
 cat >exp <<EOF
 
 GET  /smart/test_repo.git/info/refs?service=git-upload-pack HTTP/1.1 200
@@ -106,6 +133,8 @@ GET  /smart/test_repo.git/info/refs?service=git-receive-pack HTTP/1.1 200
 POST /smart/test_repo.git/git-receive-pack HTTP/1.1 200
 GET  /smart/test_repo.git/info/refs?service=git-receive-pack HTTP/1.1 200
 POST /smart/test_repo.git/git-receive-pack HTTP/1.1 200
+GET  /smart/test_repo.git/info/refs?service=git-receive-pack HTTP/1.1 200
+POST /smart/test_repo.git/git-receive-pack HTTP/1.1 200
 EOF
 test_expect_success 'used receive-pack service' '
        sed -e "
@@ -186,5 +215,12 @@ test_expect_success 'push --mirror to repo with alternates' '
        git push --mirror "$HTTPD_URL"/smart/alternates-mirror.git
 '
 
+test_expect_success TTY 'quiet push' '
+       cd "$ROOT_PATH"/test_repo_clone &&
+       test_commit quiet &&
+       test_terminal git push --quiet --no-progress 2>&1 | tee output &&
+       test_cmp /dev/null output
+'
+
 stop_httpd
 test_done
index af34a1e81711ca183680c9882353bd786b55e79f..839ad97b791c6aa757d0b82eea7fc16369ad4586 100755 (executable)
@@ -86,5 +86,6 @@ check_result 'I H E C B A' --full-history --date-order -- file
 check_result 'I E C B A' --simplify-merges -- file
 check_result 'I B A' -- file
 check_result 'I B A' --topo-order -- file
+check_result 'H' --first-parent -- another-file
 
 test_done
index 33b292b8a8e992c98774ad6e51270a9babc7e6de..5b97222c48a15dff018cb814ca14c59ed0ee91a2 100755 (executable)
@@ -611,4 +611,12 @@ test_expect_success 'submodule update places git-dir in superprojects git-dir re
        )
 '
 
+test_expect_success 'submodule add properly re-creates deeper level submodules' '
+       (cd super &&
+        git reset --hard master &&
+        rm -rf deeper/ &&
+        git submodule add ../submodule deeper/submodule
+       )
+'
+
 test_done
index 4aab2a75b8ef5836a58f30b6c27a8eec4a733afc..f5e16fc7db3f1dd84aff6d86261d10b3b3d00826 100755 (executable)
@@ -39,6 +39,7 @@ test_expect_success 'setup' '
     echo branch1 change >file1 &&
     echo branch1 newfile >file2 &&
     echo branch1 spaced >"spaced name" &&
+    echo branch1 both added >both &&
     echo branch1 change file11 >file11 &&
     echo branch1 change file13 >file13 &&
     echo branch1 sub >subdir/file3 &&
@@ -50,6 +51,7 @@ test_expect_success 'setup' '
        git checkout -b submod-branch1
     ) &&
     git add file1 "spaced name" file11 file13 file2 subdir/file3 submod &&
+    git add both &&
     git rm file12 &&
     git commit -m "branch1 changes" &&
 
@@ -58,6 +60,7 @@ test_expect_success 'setup' '
     echo master updated >file1 &&
     echo master new >file2 &&
     echo master updated spaced >"spaced name" &&
+    echo master both added >both &&
     echo master updated file12 >file12 &&
     echo master updated file14 >file14 &&
     echo master new sub >subdir/file3 &&
@@ -69,18 +72,22 @@ test_expect_success 'setup' '
        git checkout -b submod-master
     ) &&
     git add file1 "spaced name" file12 file14 file2 subdir/file3 submod &&
+    git add both &&
     git rm file11 &&
     git commit -m "master updates" &&
 
     git config merge.tool mytool &&
     git config mergetool.mytool.cmd "cat \"\$REMOTE\" >\"\$MERGED\"" &&
-    git config mergetool.mytool.trustExitCode true
+    git config mergetool.mytool.trustExitCode true &&
+    git config mergetool.mybase.cmd "cat \"\$BASE\" >\"\$MERGED\"" &&
+    git config mergetool.mybase.trustExitCode true
 '
 
 test_expect_success 'custom mergetool' '
     git checkout -b test1 branch1 &&
     git submodule update -N &&
     test_must_fail git merge master >/dev/null 2>&1 &&
+    ( yes "" | git mergetool both >/dev/null 2>&1 ) &&
     ( yes "" | git mergetool file1 file1 ) &&
     ( yes "" | git mergetool file2 "spaced name" >/dev/null 2>&1 ) &&
     ( yes "" | git mergetool subdir/file3 >/dev/null 2>&1 ) &&
@@ -101,6 +108,7 @@ test_expect_success 'mergetool crlf' '
     ( yes "" | git mergetool file1 >/dev/null 2>&1 ) &&
     ( yes "" | git mergetool file2 >/dev/null 2>&1 ) &&
     ( yes "" | git mergetool "spaced name" >/dev/null 2>&1 ) &&
+    ( yes "" | git mergetool both >/dev/null 2>&1 ) &&
     ( yes "" | git mergetool subdir/file3 >/dev/null 2>&1 ) &&
     ( yes "d" | git mergetool file11 >/dev/null 2>&1 ) &&
     ( yes "d" | git mergetool file12 >/dev/null 2>&1 ) &&
@@ -131,6 +139,7 @@ test_expect_success 'mergetool on file in parent dir' '
        cd subdir &&
        ( yes "" | git mergetool ../file1 >/dev/null 2>&1 ) &&
        ( yes "" | git mergetool ../file2 ../spaced\ name >/dev/null 2>&1 ) &&
+       ( yes "" | git mergetool ../both >/dev/null 2>&1 ) &&
        ( yes "d" | git mergetool ../file11 >/dev/null 2>&1 ) &&
        ( yes "d" | git mergetool ../file12 >/dev/null 2>&1 ) &&
        ( yes "l" | git mergetool ../submod >/dev/null 2>&1 ) &&
@@ -212,6 +221,7 @@ test_expect_success 'deleted vs modified submodule' '
     test_must_fail git merge master &&
     test -n "$(git ls-files -u)" &&
     ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) &&
+    ( yes "" | git mergetool both >/dev/null 2>&1 ) &&
     ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) &&
     ( yes "r" | git mergetool submod ) &&
     rmdir submod && mv submod-movedaside submod &&
@@ -228,6 +238,7 @@ test_expect_success 'deleted vs modified submodule' '
     test_must_fail git merge master &&
     test -n "$(git ls-files -u)" &&
     ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) &&
+    ( yes "" | git mergetool both >/dev/null 2>&1 ) &&
     ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) &&
     ( yes "l" | git mergetool submod ) &&
     test ! -e submod &&
@@ -241,6 +252,7 @@ test_expect_success 'deleted vs modified submodule' '
     test_must_fail git merge test6 &&
     test -n "$(git ls-files -u)" &&
     ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) &&
+    ( yes "" | git mergetool both >/dev/null 2>&1 ) &&
     ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) &&
     ( yes "r" | git mergetool submod ) &&
     test ! -e submod &&
@@ -256,6 +268,7 @@ test_expect_success 'deleted vs modified submodule' '
     test_must_fail git merge test6 &&
     test -n "$(git ls-files -u)" &&
     ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) &&
+    ( yes "" | git mergetool both >/dev/null 2>&1 ) &&
     ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) &&
     ( yes "l" | git mergetool submod ) &&
     test "$(cat submod/bar)" = "master submodule" &&
@@ -279,6 +292,7 @@ test_expect_success 'file vs modified submodule' '
     test_must_fail git merge master &&
     test -n "$(git ls-files -u)" &&
     ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) &&
+    ( yes "" | git mergetool both >/dev/null 2>&1 ) &&
     ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) &&
     ( yes "r" | git mergetool submod ) &&
     rmdir submod && mv submod-movedaside submod &&
@@ -294,6 +308,7 @@ test_expect_success 'file vs modified submodule' '
     test_must_fail git merge master &&
     test -n "$(git ls-files -u)" &&
     ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) &&
+    ( yes "" | git mergetool both >/dev/null 2>&1 ) &&
     ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) &&
     ( yes "l" | git mergetool submod ) &&
     git submodule update -N &&
@@ -309,6 +324,7 @@ test_expect_success 'file vs modified submodule' '
     test_must_fail git merge test7 &&
     test -n "$(git ls-files -u)" &&
     ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) &&
+    ( yes "" | git mergetool both >/dev/null 2>&1 ) &&
     ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) &&
     ( yes "r" | git mergetool submod ) &&
     test -d submod.orig &&
@@ -324,6 +340,7 @@ test_expect_success 'file vs modified submodule' '
     test_must_fail git merge test7 &&
     test -n "$(git ls-files -u)" &&
     ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) &&
+    ( yes "" | git mergetool both>/dev/null 2>&1 ) &&
     ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) &&
     ( yes "l" | git mergetool submod ) &&
     test "$(cat submod/bar)" = "master submodule" &&
@@ -445,4 +462,13 @@ test_expect_success 'directory vs modified submodule' '
     git submodule update -N
 '
 
+test_expect_success 'file with no base' '
+    git checkout -b test13 branch1 &&
+    test_must_fail git merge master &&
+    git mergetool --no-prompt --tool mybase -- both &&
+    >expected &&
+    test_cmp both expected &&
+    git reset --hard master >/dev/null 2>&1
+'
+
 test_done
index 7ba5b16f99443c0dc5aaff8fbb4ce4ad8874a27c..75f4716d8cbca0c295668e181a557b186cb37432 100755 (executable)
@@ -245,6 +245,28 @@ do
        '
 done
 
+cat >expected <<EOF
+file
+EOF
+test_expect_success 'grep -l -C' '
+       git grep -l -C1 foo >actual &&
+       test_cmp expected actual
+'
+
+cat >expected <<EOF
+file:5
+EOF
+test_expect_success 'grep -l -C' '
+       git grep -c -C1 foo >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'grep -L -C' '
+       git ls-files >expected &&
+       git grep -L -C1 nonexistent_string >actual &&
+       test_cmp expected actual
+'
+
 cat >expected <<EOF
 file:foo mmap bar_mmap
 EOF
index f82dba6a1f43bf2a259952a4fd6db94d6335deb7..492c7cd744d5f0739c8393ab67705c0be1254783 100644 (file)
@@ -661,6 +661,9 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,
                /*
                 * Match all directories. We'll try to match files
                 * later on.
+                * max_depth is ignored but we may consider support it
+                * in future, see
+                * http://thread.gmane.org/gmane.comp.version-control.git/163757/focus=163840
                 */
                if (ps->recursive && S_ISDIR(entry->mode))
                        return entry_interesting;
index 84b15099f2fbf89dedf5241a6176b39abd4b1723..01f119f9700791ddc59a81cdc80fd365e678622a 100644 (file)
@@ -9,48 +9,114 @@ static int unix_stream_socket(void)
        return fd;
 }
 
-static void unix_sockaddr_init(struct sockaddr_un *sa, const char *path)
+static int chdir_len(const char *orig, int len)
+{
+       char *path = xmemdupz(orig, len);
+       int r = chdir(path);
+       free(path);
+       return r;
+}
+
+struct unix_sockaddr_context {
+       char orig_dir[PATH_MAX];
+};
+
+static void unix_sockaddr_cleanup(struct unix_sockaddr_context *ctx)
+{
+       if (!ctx->orig_dir[0])
+               return;
+       /*
+        * If we fail, we can't just return an error, since we have
+        * moved the cwd of the whole process, which could confuse calling
+        * code.  We are better off to just die.
+        */
+       if (chdir(ctx->orig_dir) < 0)
+               die("unable to restore original working directory");
+}
+
+static int unix_sockaddr_init(struct sockaddr_un *sa, const char *path,
+                             struct unix_sockaddr_context *ctx)
 {
        int size = strlen(path) + 1;
-       if (size > sizeof(sa->sun_path))
-               die("socket path is too long to fit in sockaddr");
+
+       ctx->orig_dir[0] = '\0';
+       if (size > sizeof(sa->sun_path)) {
+               const char *slash = find_last_dir_sep(path);
+               const char *dir;
+
+               if (!slash) {
+                       errno = ENAMETOOLONG;
+                       return -1;
+               }
+
+               dir = path;
+               path = slash + 1;
+               size = strlen(path) + 1;
+               if (size > sizeof(sa->sun_path)) {
+                       errno = ENAMETOOLONG;
+                       return -1;
+               }
+
+               if (!getcwd(ctx->orig_dir, sizeof(ctx->orig_dir))) {
+                       errno = ENAMETOOLONG;
+                       return -1;
+               }
+               if (chdir_len(dir, slash - dir) < 0)
+                       return -1;
+       }
+
        memset(sa, 0, sizeof(*sa));
        sa->sun_family = AF_UNIX;
        memcpy(sa->sun_path, path, size);
+       return 0;
 }
 
 int unix_stream_connect(const char *path)
 {
-       int fd;
+       int fd, saved_errno;
        struct sockaddr_un sa;
+       struct unix_sockaddr_context ctx;
 
-       unix_sockaddr_init(&sa, path);
-       fd = unix_stream_socket();
-       if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
-               close(fd);
+       if (unix_sockaddr_init(&sa, path, &ctx) < 0)
                return -1;
-       }
+       fd = unix_stream_socket();
+       if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0)
+               goto fail;
+       unix_sockaddr_cleanup(&ctx);
        return fd;
+
+fail:
+       saved_errno = errno;
+       unix_sockaddr_cleanup(&ctx);
+       close(fd);
+       errno = saved_errno;
+       return -1;
 }
 
 int unix_stream_listen(const char *path)
 {
-       int fd;
+       int fd, saved_errno;
        struct sockaddr_un sa;
+       struct unix_sockaddr_context ctx;
 
-       unix_sockaddr_init(&sa, path);
+       if (unix_sockaddr_init(&sa, path, &ctx) < 0)
+               return -1;
        fd = unix_stream_socket();
 
        unlink(path);
-       if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
-               close(fd);
-               return -1;
-       }
+       if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0)
+               goto fail;
 
-       if (listen(fd, 5) < 0) {
-               close(fd);
-               return -1;
-       }
+       if (listen(fd, 5) < 0)
+               goto fail;
 
+       unix_sockaddr_cleanup(&ctx);
        return fd;
+
+fail:
+       saved_errno = errno;
+       unix_sockaddr_cleanup(&ctx);
+       close(fd);
+       errno = saved_errno;
+       return -1;
 }
index 6f36f6255c3f4e3db4cdc7ca9b9dcca56846c72d..0d11e21a68b227101d6c7f6f4d7b305d08f77d95 100644 (file)
@@ -585,6 +585,7 @@ static void receive_needs(void)
                write_str_in_full(debug_fd, "#S\n");
        for (;;) {
                struct object *o;
+               const char *features;
                unsigned char sha1_buf[20];
                len = packet_read_line(0, line, sizeof(line));
                reset_timeout();
@@ -616,23 +617,26 @@ static void receive_needs(void)
                    get_sha1_hex(line+5, sha1_buf))
                        die("git upload-pack: protocol error, "
                            "expected to get sha, not '%s'", line);
-               if (strstr(line+45, "multi_ack_detailed"))
+
+               features = line + 45;
+
+               if (parse_feature_request(features, "multi_ack_detailed"))
                        multi_ack = 2;
-               else if (strstr(line+45, "multi_ack"))
+               else if (parse_feature_request(features, "multi_ack"))
                        multi_ack = 1;
-               if (strstr(line+45, "no-done"))
+               if (parse_feature_request(features, "no-done"))
                        no_done = 1;
-               if (strstr(line+45, "thin-pack"))
+               if (parse_feature_request(features, "thin-pack"))
                        use_thin_pack = 1;
-               if (strstr(line+45, "ofs-delta"))
+               if (parse_feature_request(features, "ofs-delta"))
                        use_ofs_delta = 1;
-               if (strstr(line+45, "side-band-64k"))
+               if (parse_feature_request(features, "side-band-64k"))
                        use_sideband = LARGE_PACKET_MAX;
-               else if (strstr(line+45, "side-band"))
+               else if (parse_feature_request(features, "side-band"))
                        use_sideband = DEFAULT_PACKET_MAX;
-               if (strstr(line+45, "no-progress"))
+               if (parse_feature_request(features, "no-progress"))
                        no_progress = 1;
-               if (strstr(line+45, "include-tag"))
+               if (parse_feature_request(features, "include-tag"))
                        use_include_tag = 1;
 
                o = lookup_object(sha1_buf);