Merge branch 'tr/bash-read-unescaped'
authorJunio C Hamano <gitster@pobox.com>
Thu, 22 Dec 2011 23:30:38 +0000 (15:30 -0800)
committerJunio C Hamano <gitster@pobox.com>
Thu, 22 Dec 2011 23:30:38 +0000 (15:30 -0800)
* tr/bash-read-unescaped:
bash completion: use read -r everywhere

63 files changed:
Documentation/RelNotes/1.7.8.1.txt
Documentation/RelNotes/1.7.9.txt
Documentation/git-fsck.txt
Documentation/git-sh-setup.txt
Documentation/pretty-formats.txt
Makefile
builtin/clone.c
builtin/commit-tree.c
builtin/commit.c
builtin/diff.c
builtin/fast-export.c
builtin/grep.c
builtin/index-pack.c
builtin/log.c
builtin/merge.c
builtin/notes.c
builtin/revert.c
cache.h
combine-diff.c
commit.c
commit.h
compat/setenv.c
compat/terminal.c [new file with mode: 0644]
compat/terminal.h [new file with mode: 0644]
connect.c
contrib/credential/osxkeychain/.gitignore [new file with mode: 0644]
contrib/credential/osxkeychain/Makefile [new file with mode: 0644]
contrib/credential/osxkeychain/git-credential-osxkeychain.c [new file with mode: 0644]
convert.c
credential.c
diff.h
fast-import.c
gitweb/gitweb.perl
grep.c
grep.h
imap-send.c
log-tree.c
notes-cache.c
notes-merge.c
notes-merge.h
pack-write.c
pretty.c
prompt.c [new file with mode: 0644]
prompt.h [new file with mode: 0644]
reflog-walk.c
reflog-walk.h
remote-curl.c
sha1_file.c
submodule.c
t/t3502-cherry-pick-merge.sh
t/t3510-cherry-pick-sequence.sh
t/t3900-i18n-commit.sh
t/t5541-http-push.sh
t/t6006-rev-list-format.sh
t/t7006-pager.sh
t/t7810-grep.sh
t/test-lib.sh
t/test-terminal.perl
test-treap.c
transport.c
tree-diff.c
vcs-svn/repo_tree.c
vcs-svn/string_pool.c
index 0e8bd9f5eeba1be4971e6d81df943c9d9a5f74f9..33dc948b94492652e4ee5e80ae39288098cff99b 100644 (file)
@@ -1,17 +1,38 @@
 Git v1.7.8.1 Release Notes
 ==========================
 
-Fixes since v1.7.8.1
---------------------
+Fixes since v1.7.8
+------------------
 
  * In some codepaths (notably, checkout and merge), the ignore patterns
    recorded in $GIT_DIR/info/exclude were not honored. They now are.
 
- * After fetching from a remote that has very long refname, the reporting
-   output could have corrupted by overrunning a static buffer.
+ * "git apply --check" did not error out when given an empty input
+   without any patch.
+
+ * "git archive" mistakenly allowed remote clients to ask for commits
+   that are not at the tip of any ref.
 
  * "git checkout" and "git merge" treated in-tree .gitignore and exclude
    file in $GIT_DIR/info/ directory inconsistently when deciding which
    untracked files are ignored and expendable.
 
+ * LF-to-CRLF streaming filter used when checking out a large-ish blob
+   fell into an infinite loop with a rare input.
+
+ * The function header pattern for files with "diff=cpp" attribute did
+   not consider "type *funcname(type param1,..." as the beginning of a
+   function.
+
+ * The error message from "git diff" and "git status" when they fail
+   to inspect changes in submodules did not report which submodule they
+   had trouble with.
+
+ * After fetching from a remote that has very long refname, the reporting
+   output could have corrupted by overrunning a static buffer.
+
+ * "git pack-objects" avoids creating cyclic dependencies among deltas
+   when seeing a broken packfile that records the same object in both
+   the deflated form and as a delta.
+
 Also contains minor fixes and documentation updates.
index 70ff0602315109a665a66d68f5803fda71a92a9d..3ddd75be638cdef02c99d8f2a3e8da4b9bac958d 100644 (file)
@@ -10,8 +10,10 @@ Updates since v1.7.8
 
  * git-p4 (in contrib/) updates.
 
- * i18n effort is going forward and Git uses localized messages if
-   available.
+ * 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
+   in po/ to add new translations.
 
  * Porcelain commands like "git reset" did not distinguish deletions
    and type-changes from ordinary modification, and reported them with
@@ -23,9 +25,9 @@ Updates since v1.7.8
    external programs to cache or store them, to allow integration with
    platform native keychain mechanisms.
 
- * "git commit" and "git reset" re-learned the optimization to prime
-   the cache-tree information in the index, which makes it faster to
-   write a tree object out after the index entries are updated.
+ * 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.
 
  * "git add" learned to stream large files directly into a packfile
    instead of writing them into individual loose object files.
@@ -43,6 +45,13 @@ Updates since v1.7.8
    user is amending the tree being recorded, without updating the
    commit log message.
 
+ * "git commit" and "git reset" re-learned the optimization to prime
+   the cache-tree information in the index, which makes it faster to
+   write a tree object out after the index entries are updated.
+
+ * "git commit" detects and rejects an attempt to stuff NUL byte in
+   the commit log message.
+
  * fsck and prune are relatively lengthy operations that still go
    silent while making the end-user wait. They learned to give progress
    output like other slow operations.
@@ -50,6 +59,13 @@ Updates since v1.7.8
  * The set of built-in function-header patterns for various languages
    knows MATLAB.
 
+ * "git log --follow" honors the rename threshold score given with the
+   -M option (e.g. "-M50%").
+
+ * "git log --format='<format>'" learned new %g[nNeE] specifiers to
+   show information from the reflog entries when warlking the reflog
+   (i.e. with "-g").
+
  * "git pull" can be used to fetch and merge an annotated/signed tag,
    instead of the tip of a topic branch. The GPG signature from the
    signed tag is recorded in the resulting merge commit for later
@@ -86,45 +102,34 @@ Also contains minor documentation updates and code clean-ups.
 Fixes since v1.7.8
 ------------------
 
- * The function header pattern for files with "diff=cpp" attribute did
-   not consider "type *funcname(type param1,..." as the beginning of a
-   function.
-   (merge 37e7793 tr/userdiff-c-returns-pointer later to maint).
-
  * The replacement implemention for snprintf used on platforms with
    native snprintf that is broken did not use va_copy correctly.
    (merge a9bfbc5 jk/maint-snprintf-va-copy later to maint).
 
- * LF-to-CRLF streaming filter used when checking out a large-ish blob
-   fell into an infinite loop with a rare input.
-   (merge 284e3d2 cn/maint-lf-to-crlf-filter later to maint).
-
  * git native connection going over TCP (not over SSH) did not set
    SO_KEEPALIVE option which failed to receive link layer errors.
    (merge e47a858 ew/keepalive later to maint).
 
- * "git archive" mistakenly allowed remote clients to ask for commits
-   that are not at the tip of any ref.
-   (merge 7b51c33 jk/maint-upload-archive later to maint).
-
- * "git apply --check" did not error out when given an empty input
-   without any patch.
-   (merge cc64b31 bc/maint-apply-check-no-patch later to maint).
+ * LF-to-CRLF streaming filter replaced all LF with CRLF, which might
+   be techinically correct but not friendly to people who are trying
+   to recover from earlier mistakes of using CRLF in the repository
+   data in the first place. It now refrains from doing so for LF that
+   follows a CR.
+   (merge 8496f56 jc/maint-lf-to-crlf-keep-crlf later to maint).
 
  * "git checkout -m" did not recreate the conflicted state in a "both
    sides added, without any common ancestor version" conflict
    situation.
-   (merge 335c6e4 jc/checkout-m-twoway later to maint).
+   (merge 5cd7fadc jc/checkout-m-twoway later to maint).
 
  * "git cherry-pick $commit" (not a range) created an unnecessary
    sequencer state and interfered with valid workflow to use the
    command during a session to cherry-pick multiple commits.
    (merge d596118 jn/maint-sequencer-fixes later to maint).
 
- * The error message from "git diff" and "git status" when they fail
-   to inspect changes in submodules did not report which submodule they
-   had trouble with.
-   (merge 6a5ceda jl/submodule-status-failure-report later to maint).
+ * You could make "git commit" segfault by giving the "--no-message"
+   option.
+   (merge 03f94ae jk/maint-strbuf-missing-init later to maint).
 
  * "fast-import" did not correctly update an existing notes tree,
    possibly corrupting the fan-out.
@@ -151,9 +156,16 @@ Fixes since v1.7.8
    given.
    (merge a4ddbc3 jk/maint-push-over-dav later to maint).
 
+ * "git push" to an empty repository over HTTP were broken with a
+   recent change to the ref handling.
+   (merge 02f7914 jk/http-push-to-empty later to maint).
+
+ * "git push -v" forgot how to be verbose by mistake. It now properly is.
+   (merge bd2c86e jk/maint-push-v-is-verbose later to maint).
+
 --
 exec >/var/tmp/1
-O=v1.7.8-351-g2dccad3
+O=v1.7.8.1-361-g1aea303
 echo O=$(git describe master)
 git log --first-parent --oneline --reverse ^$O master
 echo
index 0a17b4258e2a69a1d2a5e931dd14ac1869876f33..6c47395ad2d22f54ed76dda914efbc28b0dca083 100644 (file)
@@ -81,30 +81,20 @@ index file, all SHA1 references in .git/refs/*, and all reflogs (unless
        progress status even if the standard error stream is not
        directed to a terminal.
 
-It tests SHA1 and general object sanity, and it does full tracking of
-the resulting reachability and everything else. It prints out any
-corruption it finds (missing or bad objects), and if you use the
-'--unreachable' flag it will also print out objects that exist but
-that aren't reachable from any of the specified head nodes.
-
-So for example
-
-       git fsck --unreachable HEAD \
-               $(git for-each-ref --format="%(objectname)" refs/heads)
+DISCUSSION
+----------
 
-will do quite a _lot_ of verification on the tree. There are a few
-extra validity tests to be added (make sure that tree objects are
-sorted properly etc), but on the whole if 'git fsck' is happy, you
-do have a valid tree.
+git-fsck tests SHA1 and general object sanity, and it does full tracking
+of the resulting reachability and everything else. It prints out any
+corruption it finds (missing or bad objects), and if you use the
+'--unreachable' flag it will also print out objects that exist but that
+aren't reachable from any of the specified head nodes (or the default
+set, as mentioned above).
 
 Any corrupt objects you will have to find in backups or other archives
 (i.e., you can just remove them and do an 'rsync' with some other site in
 the hopes that somebody else has the object you have corrupted).
 
-Of course, "valid tree" doesn't mean that it wasn't generated by some
-evil person, and the end result might be crap. git is a revision
-tracking system, not a quality assurance system ;)
-
 Extracted Diagnostics
 ---------------------
 
index a2f346ca710e03a7f5c65574659ac578ab8bf615..5e5f1c89646cf4389bfd30ba8e90eb0552e80aab 100644 (file)
@@ -68,6 +68,16 @@ require_work_tree_exists::
        cd_to_toplevel, which is impossible to do if there is no
        working tree.
 
+require_clean_work_tree <action> [<hint>]::
+       checks that the working tree and index associated with the
+       repository have no uncommitted changes to tracked files.
+       Otherwise it emits an error message of the form `Cannot
+       <action>: <reason>. <hint>`, and dies.  Example:
++
+----------------
+require_clean_work_tree rebase "Please commit or stash them."
+----------------
+
 get_author_ident_from_commit::
        outputs code for use with eval to set the GIT_AUTHOR_NAME,
        GIT_AUTHOR_EMAIL and GIT_AUTHOR_DATE variables for a given commit.
index 561cc9f7d7ef1a2502d608e59e2eae345bffd685..880b6f2e6f946ab6fc0ff4850759908364d50854 100644 (file)
@@ -132,6 +132,10 @@ The placeholders are:
 - '%N': commit notes
 - '%gD': reflog selector, e.g., `refs/stash@\{1\}`
 - '%gd': shortened reflog selector, e.g., `stash@\{1\}`
+- '%gn': reflog identity name
+- '%gN': reflog identity name (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
+- '%ge': reflog identity email
+- '%gE': reflog identity email (respecting .mailmap, see linkgit:git-shortlog[1] or linkgit:git-blame[1])
 - '%gs': reflog subject
 - '%Cred': switch color to red
 - '%Cgreen': switch color to green
index 9470a1034396a5f3ee36c5d0e6ffc54e21bb3820..a782409306df85985e1f465eab4bd3cd7fa2cc83 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -245,6 +245,9 @@ all::
 #
 # Define NO_REGEX if you have no or inferior regex support in your C library.
 #
+# Define HAVE_DEV_TTY if your system can open /dev/tty to interact with the
+# user.
+#
 # Define GETTEXT_POISON if you are debugging the choice of strings marked
 # for translation.  In a GETTEXT_POISON build, you can turn all strings marked
 # for translation into gibberish by setting the GIT_GETTEXT_POISON variable
@@ -543,6 +546,7 @@ LIB_H += compat/bswap.h
 LIB_H += compat/cygwin.h
 LIB_H += compat/mingw.h
 LIB_H += compat/obstack.h
+LIB_H += compat/terminal.h
 LIB_H += compat/win32/pthread.h
 LIB_H += compat/win32/syslog.h
 LIB_H += compat/win32/poll.h
@@ -585,6 +589,7 @@ LIB_H += parse-options.h
 LIB_H += patch-ids.h
 LIB_H += pkt-line.h
 LIB_H += progress.h
+LIB_H += prompt.h
 LIB_H += quote.h
 LIB_H += reflog-walk.h
 LIB_H += refs.h
@@ -632,6 +637,7 @@ LIB_OBJS += color.o
 LIB_OBJS += combine-diff.o
 LIB_OBJS += commit.o
 LIB_OBJS += compat/obstack.o
+LIB_OBJS += compat/terminal.o
 LIB_OBJS += config.o
 LIB_OBJS += connect.o
 LIB_OBJS += connected.o
@@ -694,6 +700,7 @@ LIB_OBJS += pkt-line.o
 LIB_OBJS += preload-index.o
 LIB_OBJS += pretty.o
 LIB_OBJS += progress.o
+LIB_OBJS += prompt.o
 LIB_OBJS += quote.o
 LIB_OBJS += reachable.o
 LIB_OBJS += read-cache.o
@@ -856,6 +863,7 @@ ifeq ($(uname_S),Linux)
        NO_MKSTEMPS = YesPlease
        HAVE_PATHS_H = YesPlease
        LIBC_CONTAINS_LIBINTL = YesPlease
+       HAVE_DEV_TTY = YesPlease
 endif
 ifeq ($(uname_S),GNU/kFreeBSD)
        NO_STRLCPY = YesPlease
@@ -917,6 +925,7 @@ ifeq ($(uname_S),Darwin)
        endif
        NO_MEMMEM = YesPlease
        USE_ST_TIMESPEC = YesPlease
+       HAVE_DEV_TTY = YesPlease
 endif
 ifeq ($(uname_S),SunOS)
        NEEDS_SOCKET = YesPlease
@@ -1685,6 +1694,10 @@ ifdef HAVE_LIBCHARSET_H
        BASIC_CFLAGS += -DHAVE_LIBCHARSET_H
 endif
 
+ifdef HAVE_DEV_TTY
+       BASIC_CFLAGS += -DHAVE_DEV_TTY
+endif
+
 ifdef DIR_HAS_BSD_GROUP_SEMANTICS
        COMPAT_CFLAGS += -DDIR_HAS_BSD_GROUP_SEMANTICS
 endif
index efe8b6cce5a9f2ae40c6f69755debecfb6b501ca..86db95473021bc8d0b1cc8850185e1660fd9c776 100644 (file)
@@ -84,8 +84,8 @@ static struct option builtin_clone_options[] = {
                   "directory from which templates will be used"),
        OPT_CALLBACK(0 , "reference", &option_reference, "repo",
                     "reference repository", &opt_parse_reference),
-       OPT_STRING('o', "origin", &option_origin, "branch",
-                  "use <branch> instead of 'origin' to track upstream"),
+       OPT_STRING('o', "origin", &option_origin, "name",
+                  "use <name> instead of 'origin' to track upstream"),
        OPT_STRING('b', "branch", &option_branch, "branch",
                   "checkout <branch> instead of the remote's HEAD"),
        OPT_STRING('u', "upload-pack", &option_upload_pack, "path",
index b9c331225f0d5c960e9e03f2c92d498f8f01f74c..05353c30f292684b44b42f7f744d8eb1b7062f69 100644 (file)
@@ -98,7 +98,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
                        die_errno("git commit-tree: failed to read");
        }
 
-       if (commit_tree(buffer.buf, tree_sha1, parents, commit_sha1, NULL)) {
+       if (commit_tree(&buffer, tree_sha1, parents, commit_sha1, NULL)) {
                strbuf_release(&buffer);
                return 1;
        }
index 626036a179e1476ee28a9f2ff32fedc5b97dc5d0..5891e95758a0d2530b325bd5fd346e15702e3017 100644 (file)
@@ -104,7 +104,7 @@ static enum commit_whence whence;
 static int use_editor = 1, include_status = 1;
 static int show_ignored_in_status;
 static const char *only_include_assumed;
-static struct strbuf message;
+static struct strbuf message = STRBUF_INIT;
 
 static int null_termination;
 static enum {
@@ -139,7 +139,7 @@ static struct option builtin_commit_options[] = {
        OPT_STRING('C', "reuse-message", &use_message, "commit", "reuse message from specified commit"),
        OPT_STRING(0, "fixup", &fixup_message, "commit", "use autosquash formatted message to fixup specified commit"),
        OPT_STRING(0, "squash", &squash_message, "commit", "use autosquash formatted message to squash specified commit"),
-       OPT_BOOLEAN(0, "reset-author", &renew_authorship, "the commit is authored by me now (used with -C-c/--amend)"),
+       OPT_BOOLEAN(0, "reset-author", &renew_authorship, "the commit is authored by me now (used with -C/-c/--amend)"),
        OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by:"),
        OPT_FILENAME('t', "template", &template_file, "use specified template file"),
        OPT_BOOL('e', "edit", &edit_flag, "force edit of commit"),
@@ -1492,7 +1492,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
                append_merge_tag_headers(parents, &tail);
        }
 
-       if (commit_tree_extended(sb.buf, active_cache_tree->sha1, parents, sha1,
+       if (commit_tree_extended(&sb, active_cache_tree->sha1, parents, sha1,
                                 author_ident.buf, extra)) {
                rollback_index_files();
                die(_("failed to write commit object"));
index 0fe638fc45c780e53901b8be22d3b4d715be3c30..387afa75680d813bccd5493e5946600c08679890 100644 (file)
@@ -14,6 +14,7 @@
 #include "log-tree.h"
 #include "builtin.h"
 #include "submodule.h"
+#include "sha1-array.h"
 
 struct blobinfo {
        unsigned char sha1[20];
@@ -169,7 +170,7 @@ static int builtin_diff_combined(struct rev_info *revs,
                                 struct object_array_entry *ent,
                                 int ents)
 {
-       const unsigned char (*parent)[20];
+       struct sha1_array parents = SHA1_ARRAY_INIT;
        int i;
 
        if (argc > 1)
@@ -177,12 +178,11 @@ static int builtin_diff_combined(struct rev_info *revs,
 
        if (!revs->dense_combined_merges && !revs->combine_merges)
                revs->dense_combined_merges = revs->combine_merges = 1;
-       parent = xmalloc(ents * sizeof(*parent));
-       for (i = 0; i < ents; i++)
-               hashcpy((unsigned char *)(parent + i), ent[i].item->sha1);
-       diff_tree_combined(parent[0], parent + 1, ents - 1,
+       for (i = 1; i < ents; i++)
+               sha1_array_append(&parents, ent[i].item->sha1);
+       diff_tree_combined(ent[0].item->sha1, &parents,
                           revs->dense_combined_merges, revs);
-       free((void *)parent);
+       sha1_array_clear(&parents);
        return 0;
 }
 
index 9836e6b7ca22e254c06d8d766d510ef43a8cbe90..08fed989a4a611def523aa69a642bc8559bd3f2f 100644 (file)
@@ -25,7 +25,7 @@ static const char *fast_export_usage[] = {
 
 static int progress;
 static enum { ABORT, VERBATIM, WARN, STRIP } signed_tag_mode = ABORT;
-static enum { ERROR, DROP, REWRITE } tag_of_filtered_mode = ABORT;
+static enum { ERROR, DROP, REWRITE } tag_of_filtered_mode = ERROR;
 static int fake_missing_tagger;
 static int use_done_feature;
 static int no_data;
@@ -51,7 +51,7 @@ static int parse_opt_tag_of_filtered_mode(const struct option *opt,
                                          const char *arg, int unset)
 {
        if (unset || !strcmp(arg, "abort"))
-               tag_of_filtered_mode = ABORT;
+               tag_of_filtered_mode = ERROR;
        else if (!strcmp(arg, "drop"))
                tag_of_filtered_mode = DROP;
        else if (!strcmp(arg, "rewrite"))
index 988ea1d3324d6e32fcfd3b97da0fad5ae41b592c..9ce064ac1131e9a93383f568bb6f567791740b77 100644 (file)
@@ -17,7 +17,6 @@
 #include "grep.h"
 #include "quote.h"
 #include "dir.h"
-#include "thread-utils.h"
 
 static char const * const grep_usage[] = {
        "git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]",
@@ -256,6 +255,7 @@ static void start_threads(struct grep_opt *opt)
 
        pthread_mutex_init(&grep_mutex, NULL);
        pthread_mutex_init(&read_sha1_mutex, NULL);
+       pthread_mutex_init(&grep_attr_mutex, NULL);
        pthread_cond_init(&cond_add, NULL);
        pthread_cond_init(&cond_write, NULL);
        pthread_cond_init(&cond_result, NULL);
@@ -303,6 +303,7 @@ static int wait_all(void)
 
        pthread_mutex_destroy(&grep_mutex);
        pthread_mutex_destroy(&read_sha1_mutex);
+       pthread_mutex_destroy(&grep_attr_mutex);
        pthread_cond_destroy(&cond_add);
        pthread_cond_destroy(&cond_write);
        pthread_cond_destroy(&cond_result);
@@ -1001,20 +1002,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
        if (!opt.fixed && opt.ignore_case)
                opt.regflags |= REG_ICASE;
 
-#ifndef NO_PTHREADS
-       if (online_cpus() == 1 || !grep_threads_ok(&opt))
-               use_threads = 0;
-
-       if (use_threads) {
-               if (opt.pre_context || opt.post_context || opt.file_break ||
-                   opt.funcbody)
-                       skip_first_line = 1;
-               start_threads(&opt);
-       }
-#else
-       use_threads = 0;
-#endif
-
        compile_grep_patterns(&opt);
 
        /* Check revs and then paths */
@@ -1036,6 +1023,24 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                break;
        }
 
+#ifndef NO_PTHREADS
+       if (list.nr || cached || online_cpus() == 1)
+               use_threads = 0;
+#else
+       use_threads = 0;
+#endif
+
+       opt.use_threads = use_threads;
+
+#ifndef NO_PTHREADS
+       if (use_threads) {
+               if (opt.pre_context || opt.post_context || opt.file_break ||
+                   opt.funcbody)
+                       skip_first_line = 1;
+               start_threads(&opt);
+       }
+#endif
+
        /* The rest are paths */
        if (!seen_dashdash) {
                int j;
index 98025da7670aaa9f79bfc7faa3a26c4079682fbb..af7dc37a441d12bc4283ac730524e07a582d014f 100644 (file)
@@ -172,10 +172,10 @@ static const char *open_pack_file(const char *pack_name)
        if (from_stdin) {
                input_fd = 0;
                if (!pack_name) {
-                       static char tmpfile[PATH_MAX];
-                       output_fd = odb_mkstemp(tmpfile, sizeof(tmpfile),
+                       static char tmp_file[PATH_MAX];
+                       output_fd = odb_mkstemp(tmp_file, sizeof(tmp_file),
                                                "pack/tmp_pack_XXXXXX");
-                       pack_name = xstrdup(tmpfile);
+                       pack_name = xstrdup(tmp_file);
                } else
                        output_fd = open(pack_name, O_CREAT|O_EXCL|O_RDWR, 0600);
                if (output_fd < 0)
index 89d0cc0132ca459d622827f5dd11a361fc6a138c..7d1f6f88a0e0f76bc8ee35155a532b641c14a845 100644 (file)
@@ -73,8 +73,6 @@ static int decorate_callback(const struct option *opt, const char *arg, int unse
 
 static void cmd_log_init_defaults(struct rev_info *rev)
 {
-       rev->abbrev = DEFAULT_ABBREV;
-       rev->commit_format = CMIT_FMT_DEFAULT;
        if (fmt_pretty)
                get_commit_format(fmt_pretty, rev);
        rev->verbose_header = 1;
index 24579409c08f2e24ef3e5f2599a6af1aab8d28cd..4b0ca6550c130dc8efbf248c56503018b8bcb604 100644 (file)
@@ -50,7 +50,7 @@ static int option_commit = 1, allow_fast_forward = 1;
 static int fast_forward_only, option_edit;
 static int allow_trivial = 1, have_message;
 static int overwrite_ignore = 1;
-static struct strbuf merge_msg;
+static struct strbuf merge_msg = STRBUF_INIT;
 static struct commit_list *remoteheads;
 static struct strategy **use_strategies;
 static size_t use_strategies_nr, use_strategies_alloc;
@@ -910,7 +910,8 @@ static int merge_trivial(struct commit *head)
        parent->next->item = remoteheads->item;
        parent->next->next = NULL;
        prepare_to_commit();
-       commit_tree(merge_msg.buf, result_tree, parent, result_commit, NULL);
+       if (commit_tree(&merge_msg, result_tree, parent, result_commit, NULL))
+               die(_("failed to write commit object"));
        finish(head, result_commit, "In-index merge");
        drop_save();
        return 0;
@@ -941,7 +942,8 @@ static int finish_automerge(struct commit *head,
        strbuf_addch(&merge_msg, '\n');
        prepare_to_commit();
        free_commit_list(remoteheads);
-       commit_tree(merge_msg.buf, result_tree, parents, result_commit, NULL);
+       if (commit_tree(&merge_msg, result_tree, parents, result_commit, NULL))
+               die(_("failed to write commit object"));
        strbuf_addf(&buf, "Merge made by the '%s' strategy.", wt_strategy);
        finish(head, result_commit, buf.buf);
        strbuf_release(&buf);
index 667e20a1e13770b845c0774e754043fae514a4b1..3644d140ece9f2cfc6381e1a60c5b4fc8f645e2a 100644 (file)
@@ -301,12 +301,12 @@ void commit_notes(struct notes_tree *t, const char *msg)
                return; /* don't have to commit an unchanged tree */
 
        /* Prepare commit message and reflog message */
-       strbuf_addstr(&buf, "notes: "); /* commit message starts at index 7 */
        strbuf_addstr(&buf, msg);
        if (buf.buf[buf.len - 1] != '\n')
                strbuf_addch(&buf, '\n'); /* Make sure msg ends with newline */
 
-       create_notes_commit(t, NULL, buf.buf + 7, commit_sha1);
+       create_notes_commit(t, NULL, &buf, commit_sha1);
+       strbuf_insert(&buf, 0, "notes: ", 7); /* commit message starts at index 7 */
        update_ref(buf.buf, t->ref, commit_sha1, NULL, 0, DIE_ON_ERR);
 
        strbuf_release(&buf);
index fce3f929818d6a7faac5933d585a5217e564f6ba..0d8020cf640e1abe6898308a1656446b327c83f4 100644 (file)
@@ -700,44 +700,47 @@ static int format_todo(struct strbuf *buf, struct commit_list *todo_list,
                struct replay_opts *opts)
 {
        struct commit_list *cur = NULL;
-       struct commit_message msg = { NULL, NULL, NULL, NULL, NULL };
        const char *sha1_abbrev = NULL;
        const char *action_str = opts->action == REVERT ? "revert" : "pick";
+       const char *subject;
+       int subject_len;
 
        for (cur = todo_list; cur; cur = cur->next) {
                sha1_abbrev = find_unique_abbrev(cur->item->object.sha1, DEFAULT_ABBREV);
-               if (get_message(cur->item, &msg))
-                       return error(_("Cannot get commit message for %s"), sha1_abbrev);
-               strbuf_addf(buf, "%s %s %s\n", action_str, sha1_abbrev, msg.subject);
+               subject_len = find_commit_subject(cur->item->buffer, &subject);
+               strbuf_addf(buf, "%s %s %.*s\n", action_str, sha1_abbrev,
+                       subject_len, subject);
        }
        return 0;
 }
 
-static struct commit *parse_insn_line(char *start, struct replay_opts *opts)
+static struct commit *parse_insn_line(char *bol, char *eol, struct replay_opts *opts)
 {
        unsigned char commit_sha1[20];
-       char sha1_abbrev[40];
        enum replay_action action;
-       int insn_len = 0;
-       char *p, *q;
+       char *end_of_object_name;
+       int saved, status, padding;
 
-       if (!prefixcmp(start, "pick ")) {
+       if (!prefixcmp(bol, "pick")) {
                action = CHERRY_PICK;
-               insn_len = strlen("pick");
-               p = start + insn_len + 1;
-       } else if (!prefixcmp(start, "revert ")) {
+               bol += strlen("pick");
+       } else if (!prefixcmp(bol, "revert")) {
                action = REVERT;
-               insn_len = strlen("revert");
-               p = start + insn_len + 1;
+               bol += strlen("revert");
        } else
                return NULL;
 
-       q = strchr(p, ' ');
-       if (!q)
+       /* Eat up extra spaces/ tabs before object name */
+       padding = strspn(bol, " \t");
+       if (!padding)
                return NULL;
-       q++;
+       bol += padding;
 
-       strlcpy(sha1_abbrev, p, q - p);
+       end_of_object_name = bol + strcspn(bol, " \t\n");
+       saved = *end_of_object_name;
+       *end_of_object_name = '\0';
+       status = get_sha1(bol, commit_sha1);
+       *end_of_object_name = saved;
 
        /*
         * Verify that the action matches up with the one in
@@ -750,7 +753,7 @@ static struct commit *parse_insn_line(char *start, struct replay_opts *opts)
                return NULL;
        }
 
-       if (get_sha1(sha1_abbrev, commit_sha1) < 0)
+       if (status < 0)
                return NULL;
 
        return lookup_commit_reference(commit_sha1);
@@ -765,13 +768,12 @@ static int parse_insn_buffer(char *buf, struct commit_list **todo_list,
        int i;
 
        for (i = 1; *p; i++) {
-               commit = parse_insn_line(p, opts);
+               char *eol = strchrnul(p, '\n');
+               commit = parse_insn_line(p, eol, opts);
                if (!commit)
                        return error(_("Could not parse line %d."), i);
                next = commit_list_append(commit, next);
-               p = strchrnul(p, '\n');
-               if (*p)
-                       p++;
+               p = *eol ? eol + 1 : eol;
        }
        if (!*todo_list)
                return error(_("No commits parsed."));
diff --git a/cache.h b/cache.h
index 270dfdb8aebcade3071156de8b170461d3273b5c..10afd71d435920a3cc2152208a06058791ea7a04 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -1028,7 +1028,6 @@ struct ref {
 extern struct ref *find_ref_by_name(const struct ref *list, const char *name);
 
 #define CONNECT_VERBOSE       (1u << 0)
-extern char *git_getpass(const char *prompt);
 extern struct child_process *git_connect(int fd[2], const char *url, const char *prog, int flags);
 extern int finish_connect(struct child_process *conn);
 extern int git_connection_is_socket(struct child_process *conn);
index 214014dc645e43ae257e46f1046c8ca0d21d3472..a2e8dcf8553ff15d7cfed8f8ec4735185ec162bb 100644 (file)
@@ -8,6 +8,7 @@
 #include "log-tree.h"
 #include "refs.h"
 #include "userdiff.h"
+#include "sha1-array.h"
 
 static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr, int n, int num_parent)
 {
@@ -1116,15 +1117,14 @@ static void handle_combined_callback(struct diff_options *opt,
 }
 
 void diff_tree_combined(const unsigned char *sha1,
-                       const unsigned char parent[][20],
-                       int num_parent,
+                       const struct sha1_array *parents,
                        int dense,
                        struct rev_info *rev)
 {
        struct diff_options *opt = &rev->diffopt;
        struct diff_options diffopts;
        struct combine_diff_path *p, *paths = NULL;
-       int i, num_paths, needsep, show_log_first;
+       int i, num_paths, needsep, show_log_first, num_parent = parents->nr;
 
        diffopts = *opt;
        diffopts.output_format = DIFF_FORMAT_NO_OUTPUT;
@@ -1144,7 +1144,7 @@ void diff_tree_combined(const unsigned char *sha1,
                        diffopts.output_format = stat_opt;
                else
                        diffopts.output_format = DIFF_FORMAT_NO_OUTPUT;
-               diff_tree_sha1(parent[i], sha1, "", &diffopts);
+               diff_tree_sha1(parents->sha1[i], sha1, "", &diffopts);
                diffcore_std(&diffopts);
                paths = intersect_paths(paths, i, num_parent);
 
@@ -1196,25 +1196,16 @@ void diff_tree_combined(const unsigned char *sha1,
        }
 }
 
-void diff_tree_combined_merge(const unsigned char *sha1,
-                            int dense, struct rev_info *rev)
+void diff_tree_combined_merge(const struct commit *commit, int dense,
+                             struct rev_info *rev)
 {
-       int num_parent;
-       const unsigned char (*parent)[20];
-       struct commit *commit = lookup_commit(sha1);
-       struct commit_list *parents;
-
-       /* count parents */
-       for (parents = commit->parents, num_parent = 0;
-            parents;
-            parents = parents->next, num_parent++)
-               ; /* nothing */
-
-       parent = xmalloc(num_parent * sizeof(*parent));
-       for (parents = commit->parents, num_parent = 0;
-            parents;
-            parents = parents->next, num_parent++)
-               hashcpy((unsigned char *)(parent + num_parent),
-                       parents->item->object.sha1);
-       diff_tree_combined(sha1, parent, num_parent, dense, rev);
+       struct commit_list *parent = commit->parents;
+       struct sha1_array parents = SHA1_ARRAY_INIT;
+
+       while (parent) {
+               sha1_array_append(&parents, parent->item->object.sha1);
+               parent = parent->next;
+       }
+       diff_tree_combined(commit->object.sha1, &parents, dense, rev);
+       sha1_array_clear(&parents);
 }
index b78127403be65f5c26e35e53a59b91860396194a..44bc96d44d391209d3a60e9e8c1b98ed209e6b4a 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -973,7 +973,7 @@ void free_commit_extra_headers(struct commit_extra_header *extra)
        }
 }
 
-int commit_tree(const char *msg, unsigned char *tree,
+int commit_tree(const struct strbuf *msg, unsigned char *tree,
                struct commit_list *parents, unsigned char *ret,
                const char *author)
 {
@@ -991,7 +991,7 @@ static const char commit_utf8_warn[] =
 "You may want to amend it after fixing the message, or set the config\n"
 "variable i18n.commitencoding to the encoding your project uses.\n";
 
-int commit_tree_extended(const char *msg, unsigned char *tree,
+int commit_tree_extended(const struct strbuf *msg, unsigned char *tree,
                         struct commit_list *parents, unsigned char *ret,
                         const char *author, struct commit_extra_header *extra)
 {
@@ -1001,6 +1001,9 @@ int commit_tree_extended(const char *msg, unsigned char *tree,
 
        assert_sha1_type(tree, OBJ_TREE);
 
+       if (memchr(msg->buf, '\0', msg->len))
+               return error("a NUL byte in commit log message not allowed.");
+
        /* Not having i18n.commitencoding is the same as having utf-8 */
        encoding_is_utf8 = is_encoding_utf8(git_commit_encoding);
 
@@ -1037,7 +1040,7 @@ int commit_tree_extended(const char *msg, unsigned char *tree,
        strbuf_addch(&buffer, '\n');
 
        /* And add the comment */
-       strbuf_addstr(&buffer, msg);
+       strbuf_addbuf(&buffer, msg);
 
        /* And check the encoding */
        if (encoding_is_utf8 && !is_utf8(buffer.buf))
index 3745f120994cb6876e1ccc1bfc5e07c6cc3fc5c9..4df397865abe7161a9f16e3177e3b486bf8434ca 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -191,11 +191,11 @@ struct commit_extra_header {
 extern void append_merge_tag_headers(struct commit_list *parents,
                                     struct commit_extra_header ***tail);
 
-extern int commit_tree(const char *msg, unsigned char *tree,
+extern int commit_tree(const struct strbuf *msg, unsigned char *tree,
                       struct commit_list *parents, unsigned char *ret,
                       const char *author);
 
-extern int commit_tree_extended(const char *msg, unsigned char *tree,
+extern int commit_tree_extended(const struct strbuf *msg, unsigned char *tree,
                                struct commit_list *parents, unsigned char *ret,
                                const char *author,
                                struct commit_extra_header *);
index 3a22ea7b751efb768d72afa2f97fd963e10eec7e..fc1439a6439393ff5224e98ab126607ceaa4994d 100644 (file)
@@ -6,7 +6,10 @@ int gitsetenv(const char *name, const char *value, int replace)
        size_t namelen, valuelen;
        char *envstr;
 
-       if (!name || !value) return -1;
+       if (!name || strchr(name, '=') || !value) {
+               errno = EINVAL;
+               return -1;
+       }
        if (!replace) {
                char *oldval = NULL;
                oldval = getenv(name);
@@ -16,7 +19,10 @@ int gitsetenv(const char *name, const char *value, int replace)
        namelen = strlen(name);
        valuelen = strlen(value);
        envstr = malloc((namelen + valuelen + 2));
-       if (!envstr) return -1;
+       if (!envstr) {
+               errno = ENOMEM;
+               return -1;
+       }
 
        memcpy(envstr, name, namelen);
        envstr[namelen] = '=';
diff --git a/compat/terminal.c b/compat/terminal.c
new file mode 100644 (file)
index 0000000..6d16c8f
--- /dev/null
@@ -0,0 +1,81 @@
+#include "git-compat-util.h"
+#include "compat/terminal.h"
+#include "sigchain.h"
+#include "strbuf.h"
+
+#ifdef HAVE_DEV_TTY
+
+static int term_fd = -1;
+static struct termios old_term;
+
+static void restore_term(void)
+{
+       if (term_fd < 0)
+               return;
+
+       tcsetattr(term_fd, TCSAFLUSH, &old_term);
+       term_fd = -1;
+}
+
+static void restore_term_on_signal(int sig)
+{
+       restore_term();
+       sigchain_pop(sig);
+       raise(sig);
+}
+
+char *git_terminal_prompt(const char *prompt, int echo)
+{
+       static struct strbuf buf = STRBUF_INIT;
+       int r;
+       FILE *fh;
+
+       fh = fopen("/dev/tty", "w+");
+       if (!fh)
+               return NULL;
+
+       if (!echo) {
+               struct termios t;
+
+               if (tcgetattr(fileno(fh), &t) < 0) {
+                       fclose(fh);
+                       return NULL;
+               }
+
+               old_term = t;
+               term_fd = fileno(fh);
+               sigchain_push_common(restore_term_on_signal);
+
+               t.c_lflag &= ~ECHO;
+               if (tcsetattr(fileno(fh), TCSAFLUSH, &t) < 0) {
+                       term_fd = -1;
+                       fclose(fh);
+                       return NULL;
+               }
+       }
+
+       fputs(prompt, fh);
+       fflush(fh);
+
+       r = strbuf_getline(&buf, fh, '\n');
+       if (!echo) {
+               putc('\n', fh);
+               fflush(fh);
+       }
+
+       restore_term();
+       fclose(fh);
+
+       if (r == EOF)
+               return NULL;
+       return buf.buf;
+}
+
+#else
+
+char *git_terminal_prompt(const char *prompt, int echo)
+{
+       return getpass(prompt);
+}
+
+#endif
diff --git a/compat/terminal.h b/compat/terminal.h
new file mode 100644 (file)
index 0000000..97db7cd
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef COMPAT_TERMINAL_H
+#define COMPAT_TERMINAL_H
+
+char *git_terminal_prompt(const char *prompt, int echo);
+
+#endif /* COMPAT_TERMINAL_H */
index c8d0ea5d75e89a6b15b62e7057e97947036e11ea..2ea5c3c0fbedb89e4189d32a455f289398ce106b 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -608,47 +608,3 @@ int finish_connect(struct child_process *conn)
        free(conn);
        return code;
 }
-
-char *git_getpass(const char *prompt)
-{
-       const char *askpass;
-       struct child_process pass;
-       const char *args[3];
-       static struct strbuf buffer = STRBUF_INIT;
-
-       askpass = getenv("GIT_ASKPASS");
-       if (!askpass)
-               askpass = askpass_program;
-       if (!askpass)
-               askpass = getenv("SSH_ASKPASS");
-       if (!askpass || !(*askpass)) {
-               char *result = getpass(prompt);
-               if (!result)
-                       die_errno("Could not read password");
-               return result;
-       }
-
-       args[0] = askpass;
-       args[1] = prompt;
-       args[2] = NULL;
-
-       memset(&pass, 0, sizeof(pass));
-       pass.argv = args;
-       pass.out = -1;
-
-       if (start_command(&pass))
-               exit(1);
-
-       strbuf_reset(&buffer);
-       if (strbuf_read(&buffer, pass.out, 20) < 0)
-               die("failed to read password from %s\n", askpass);
-
-       close(pass.out);
-
-       if (finish_command(&pass))
-               exit(1);
-
-       strbuf_setlen(&buffer, strcspn(buffer.buf, "\r\n"));
-
-       return buffer.buf;
-}
diff --git a/contrib/credential/osxkeychain/.gitignore b/contrib/credential/osxkeychain/.gitignore
new file mode 100644 (file)
index 0000000..6c5b702
--- /dev/null
@@ -0,0 +1 @@
+git-credential-osxkeychain
diff --git a/contrib/credential/osxkeychain/Makefile b/contrib/credential/osxkeychain/Makefile
new file mode 100644 (file)
index 0000000..75c07f8
--- /dev/null
@@ -0,0 +1,14 @@
+all:: git-credential-osxkeychain
+
+CC = gcc
+RM = rm -f
+CFLAGS = -g -Wall
+
+git-credential-osxkeychain: git-credential-osxkeychain.o
+       $(CC) -o $@ $< -Wl,-framework -Wl,Security
+
+git-credential-osxkeychain.o: git-credential-osxkeychain.c
+       $(CC) -c $(CFLAGS) $<
+
+clean:
+       $(RM) git-credential-osxkeychain git-credential-osxkeychain.o
diff --git a/contrib/credential/osxkeychain/git-credential-osxkeychain.c b/contrib/credential/osxkeychain/git-credential-osxkeychain.c
new file mode 100644 (file)
index 0000000..6beed12
--- /dev/null
@@ -0,0 +1,173 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <Security/Security.h>
+
+static SecProtocolType protocol;
+static char *host;
+static char *path;
+static char *username;
+static char *password;
+static UInt16 port;
+
+static void die(const char *err, ...)
+{
+       char msg[4096];
+       va_list params;
+       va_start(params, err);
+       vsnprintf(msg, sizeof(msg), err, params);
+       fprintf(stderr, "%s\n", msg);
+       va_end(params);
+       exit(1);
+}
+
+static void *xstrdup(const char *s1)
+{
+       void *ret = strdup(s1);
+       if (!ret)
+               die("Out of memory");
+       return ret;
+}
+
+#define KEYCHAIN_ITEM(x) (x ? strlen(x) : 0), x
+#define KEYCHAIN_ARGS \
+       NULL, /* default keychain */ \
+       KEYCHAIN_ITEM(host), \
+       0, NULL, /* account domain */ \
+       KEYCHAIN_ITEM(username), \
+       KEYCHAIN_ITEM(path), \
+       port, \
+       protocol, \
+       kSecAuthenticationTypeDefault
+
+static void write_item(const char *what, const char *buf, int len)
+{
+       printf("%s=", what);
+       fwrite(buf, 1, len, stdout);
+       putchar('\n');
+}
+
+static void find_username_in_item(SecKeychainItemRef item)
+{
+       SecKeychainAttributeList list;
+       SecKeychainAttribute attr;
+
+       list.count = 1;
+       list.attr = &attr;
+       attr.tag = kSecAccountItemAttr;
+
+       if (SecKeychainItemCopyContent(item, NULL, &list, NULL, NULL))
+               return;
+
+       write_item("username", attr.data, attr.length);
+       SecKeychainItemFreeContent(&list, NULL);
+}
+
+static void find_internet_password(void)
+{
+       void *buf;
+       UInt32 len;
+       SecKeychainItemRef item;
+
+       if (SecKeychainFindInternetPassword(KEYCHAIN_ARGS, &len, &buf, &item))
+               return;
+
+       write_item("password", buf, len);
+       if (!username)
+               find_username_in_item(item);
+
+       SecKeychainItemFreeContent(NULL, buf);
+}
+
+static void delete_internet_password(void)
+{
+       SecKeychainItemRef item;
+
+       /*
+        * Require at least a protocol and host for removal, which is what git
+        * will give us; if you want to do something more fancy, use the
+        * Keychain manager.
+        */
+       if (!protocol || !host)
+               return;
+
+       if (SecKeychainFindInternetPassword(KEYCHAIN_ARGS, 0, NULL, &item))
+               return;
+
+       SecKeychainItemDelete(item);
+}
+
+static void add_internet_password(void)
+{
+       /* Only store complete credentials */
+       if (!protocol || !host || !username || !password)
+               return;
+
+       if (SecKeychainAddInternetPassword(
+             KEYCHAIN_ARGS,
+             KEYCHAIN_ITEM(password),
+             NULL))
+               return;
+}
+
+static void read_credential(void)
+{
+       char buf[1024];
+
+       while (fgets(buf, sizeof(buf), stdin)) {
+               char *v;
+
+               if (!strcmp(buf, "\n"))
+                       break;
+               buf[strlen(buf)-1] = '\0';
+
+               v = strchr(buf, '=');
+               if (!v)
+                       die("bad input: %s", buf);
+               *v++ = '\0';
+
+               if (!strcmp(buf, "protocol")) {
+                       if (!strcmp(v, "https"))
+                               protocol = kSecProtocolTypeHTTPS;
+                       else if (!strcmp(v, "http"))
+                               protocol = kSecProtocolTypeHTTP;
+                       else /* we don't yet handle other protocols */
+                               exit(0);
+               }
+               else if (!strcmp(buf, "host")) {
+                       char *colon = strchr(v, ':');
+                       if (colon) {
+                               *colon++ = '\0';
+                               port = atoi(colon);
+                       }
+                       host = xstrdup(v);
+               }
+               else if (!strcmp(buf, "path"))
+                       path = xstrdup(v);
+               else if (!strcmp(buf, "username"))
+                       username = xstrdup(v);
+               else if (!strcmp(buf, "password"))
+                       password = xstrdup(v);
+       }
+}
+
+int main(int argc, const char **argv)
+{
+       const char *usage =
+               "Usage: git credential-osxkeychain <get|store|erase>";
+
+       if (!argv[1])
+               die(usage);
+
+       read_credential();
+
+       if (!strcmp(argv[1], "get"))
+               find_internet_password();
+       else if (!strcmp(argv[1], "store"))
+               add_internet_password();
+       else if (!strcmp(argv[1], "erase"))
+               delete_internet_password();
+       /* otherwise, ignore unknown action */
+
+       return 0;
+}
index 346f9d45e0f48048603d779f909e6c29bdd60b5b..12868ed7bda11648704ffe4e5d3415067764a6e2 100644 (file)
--- a/convert.c
+++ b/convert.c
@@ -879,7 +879,8 @@ int is_null_stream_filter(struct stream_filter *filter)
 
 struct lf_to_crlf_filter {
        struct stream_filter filter;
-       int want_lf;
+       unsigned has_held:1;
+       char held;
 };
 
 static int lf_to_crlf_filter_fn(struct stream_filter *filter,
@@ -889,32 +890,74 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter,
        size_t count, o = 0;
        struct lf_to_crlf_filter *lf_to_crlf = (struct lf_to_crlf_filter *)filter;
 
-       /* Output a pending LF if we need to */
-       if (lf_to_crlf->want_lf) {
-               output[o++] = '\n';
-               lf_to_crlf->want_lf = 0;
+       /*
+        * We may be holding onto the CR to see if it is followed by a
+        * LF, in which case we would need to go to the main loop.
+        * Otherwise, just emit it to the output stream.
+        */
+       if (lf_to_crlf->has_held && (lf_to_crlf->held != '\r' || !input)) {
+               output[o++] = lf_to_crlf->held;
+               lf_to_crlf->has_held = 0;
        }
 
-       if (!input)
-               return 0; /* We've already dealt with the state */
+       /* We are told to drain */
+       if (!input) {
+               *osize_p -= o;
+               return 0;
+       }
 
        count = *isize_p;
-       if (count) {
+       if (count || lf_to_crlf->has_held) {
                size_t i;
+               int was_cr = 0;
+
+               if (lf_to_crlf->has_held) {
+                       was_cr = 1;
+                       lf_to_crlf->has_held = 0;
+               }
+
                for (i = 0; o < *osize_p && i < count; i++) {
                        char ch = input[i];
+
                        if (ch == '\n') {
                                output[o++] = '\r';
-                               if (o >= *osize_p) {
-                                       lf_to_crlf->want_lf = 1;
-                                       continue; /* We need to increase i */
-                               }
+                       } else if (was_cr) {
+                               /*
+                                * Previous round saw CR and it is not followed
+                                * by a LF; emit the CR before processing the
+                                * current character.
+                                */
+                               output[o++] = '\r';
+                       }
+
+                       /*
+                        * We may have consumed the last output slot,
+                        * in which case we need to break out of this
+                        * loop; hold the current character before
+                        * returning.
+                        */
+                       if (*osize_p <= o) {
+                               lf_to_crlf->has_held = 1;
+                               lf_to_crlf->held = ch;
+                               continue; /* break but increment i */
                        }
+
+                       if (ch == '\r') {
+                               was_cr = 1;
+                               continue;
+                       }
+
+                       was_cr = 0;
                        output[o++] = ch;
                }
 
                *osize_p -= o;
                *isize_p -= i;
+
+               if (!lf_to_crlf->has_held && was_cr) {
+                       lf_to_crlf->has_held = 1;
+                       lf_to_crlf->held = '\r';
+               }
        }
        return 0;
 }
@@ -931,10 +974,9 @@ static struct stream_filter_vtbl lf_to_crlf_vtbl = {
 
 static struct stream_filter *lf_to_crlf_filter(void)
 {
-       struct lf_to_crlf_filter *lf_to_crlf = xmalloc(sizeof(*lf_to_crlf));
+       struct lf_to_crlf_filter *lf_to_crlf = xcalloc(1, sizeof(*lf_to_crlf));
 
        lf_to_crlf->filter.vtbl = &lf_to_crlf_vtbl;
-       lf_to_crlf->want_lf = 0;
        return (struct stream_filter *)lf_to_crlf;
 }
 
index a17eafea582638e3d77f2e37b9d82fe5069798c0..62d1c56819e5351e5697dab7ff13d33ac806c398 100644 (file)
@@ -3,6 +3,7 @@
 #include "string-list.h"
 #include "run-command.h"
 #include "url.h"
+#include "prompt.h"
 
 void credential_init(struct credential *c)
 {
@@ -108,7 +109,8 @@ static void credential_describe(struct credential *c, struct strbuf *out)
                strbuf_addf(out, "/%s", c->path);
 }
 
-static char *credential_ask_one(const char *what, struct credential *c)
+static char *credential_ask_one(const char *what, struct credential *c,
+                               int flags)
 {
        struct strbuf desc = STRBUF_INIT;
        struct strbuf prompt = STRBUF_INIT;
@@ -120,11 +122,7 @@ static char *credential_ask_one(const char *what, struct credential *c)
        else
                strbuf_addf(&prompt, "%s: ", what);
 
-       /* FIXME: for usernames, we should do something less magical that
-        * actually echoes the characters. However, we need to read from
-        * /dev/tty and not stdio, which is not portable (but getpass will do
-        * it for us). http.c uses the same workaround. */
-       r = git_getpass(prompt.buf);
+       r = git_prompt(prompt.buf, flags);
 
        strbuf_release(&desc);
        strbuf_release(&prompt);
@@ -134,9 +132,11 @@ static char *credential_ask_one(const char *what, struct credential *c)
 static void credential_getpass(struct credential *c)
 {
        if (!c->username)
-               c->username = credential_ask_one("Username", c);
+               c->username = credential_ask_one("Username", c,
+                                                PROMPT_ASKPASS|PROMPT_ECHO);
        if (!c->password)
-               c->password = credential_ask_one("Password", c);
+               c->password = credential_ask_one("Password", c,
+                                                PROMPT_ASKPASS);
 }
 
 int credential_read(struct credential *c, FILE *fp)
diff --git a/diff.h b/diff.h
index 0c51724493f76461b67d6ef8f5556852819ad809..ae71f4ccf94369b31b1a77373861b02d478d705a 100644 (file)
--- a/diff.h
+++ b/diff.h
@@ -12,6 +12,8 @@ struct diff_queue_struct;
 struct strbuf;
 struct diff_filespec;
 struct userdiff_driver;
+struct sha1_array;
+struct commit;
 
 typedef void (*change_fn_t)(struct diff_options *options,
                 unsigned old_mode, unsigned new_mode,
@@ -195,9 +197,9 @@ struct combine_diff_path {
 extern void show_combined_diff(struct combine_diff_path *elem, int num_parent,
                              int dense, struct rev_info *);
 
-extern void diff_tree_combined(const unsigned char *sha1, const unsigned char parent[][20], int num_parent, int dense, struct rev_info *rev);
+extern void diff_tree_combined(const unsigned char *sha1, const struct sha1_array *parents, int dense, struct rev_info *rev);
 
-extern void diff_tree_combined_merge(const unsigned char *sha1, int, struct rev_info *);
+extern void diff_tree_combined_merge(const struct commit *commit, int dense, struct rev_info *rev);
 
 void diff_set_mnemonic_prefix(struct diff_options *options, const char *a, const char *b);
 
index 4b9c4b73a020e9eefa4caf0bd6ec833df424c9a0..6cd19e580ba710d03682fcaff997fa7e0e555691 100644 (file)
@@ -855,15 +855,15 @@ static struct tree_content *dup_tree_content(struct tree_content *s)
 
 static void start_packfile(void)
 {
-       static char tmpfile[PATH_MAX];
+       static char tmp_file[PATH_MAX];
        struct packed_git *p;
        struct pack_header hdr;
        int pack_fd;
 
-       pack_fd = odb_mkstemp(tmpfile, sizeof(tmpfile),
+       pack_fd = odb_mkstemp(tmp_file, sizeof(tmp_file),
                              "pack/tmp_pack_XXXXXX");
-       p = xcalloc(1, sizeof(*p) + strlen(tmpfile) + 2);
-       strcpy(p->pack_name, tmpfile);
+       p = xcalloc(1, sizeof(*p) + strlen(tmp_file) + 2);
+       strcpy(p->pack_name, tmp_file);
        p->pack_fd = pack_fd;
        p->do_not_close = 1;
        pack_file = sha1fd(pack_fd, p->pack_name);
index f80f2594cb2e498fa788d38f5b06c88e2fef95ca..fc41b07bcb4a7493d255150b3a3fa75ca7412352 100755 (executable)
@@ -1443,8 +1443,8 @@ sub validate_refname {
 sub to_utf8 {
        my $str = shift;
        return undef unless defined $str;
-       if (utf8::valid($str)) {
-               utf8::decode($str);
+
+       if (utf8::is_utf8($str) || utf8::decode($str)) {
                return $str;
        } else {
                return decode($fallback_encoding, $str, Encode::FB_DEFAULT);
@@ -1696,6 +1696,7 @@ sub chop_and_escape_str {
        my ($str) = @_;
 
        my $chopped = chop_str(@_);
+       $str = to_utf8($str);
        if ($chopped eq $str) {
                return esc_html($chopped);
        } else {
@@ -6243,7 +6244,9 @@ sub git_blame_common {
                        -type=>"text/plain", -charset => "utf-8",
                        -status=> "200 OK");
                local $| = 1; # output autoflush
-               print while <$fd>;
+               while (my $line = <$fd>) {
+                       print to_utf8($line);
+               }
                close $fd
                        or print "ERROR $!\n";
 
@@ -7862,11 +7865,12 @@ sub git_opml {
                -charset => 'utf-8',
                -content_disposition => 'inline; filename="opml.xml"');
 
+       my $title = esc_html($site_name);
        print <<XML;
 <?xml version="1.0" encoding="utf-8"?>
 <opml version="1.0">
 <head>
-  <title>$site_name OPML Export</title>
+  <title>$title OPML Export</title>
 </head>
 <body>
 <outline text="git RSS feeds">
diff --git a/grep.c b/grep.c
index b29d09c7f6a5a7f9621fb5287eb07e72ece7f484..486230b511952dcf975199c82a5265d1906999cd 100644 (file)
--- a/grep.c
+++ b/grep.c
@@ -806,10 +806,46 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,
        opt->output(opt, "\n", 1);
 }
 
-static int match_funcname(struct grep_opt *opt, char *bol, char *eol)
+#ifndef NO_PTHREADS
+/*
+ * This lock protects access to the gitattributes machinery, which is
+ * not thread-safe.
+ */
+pthread_mutex_t grep_attr_mutex;
+
+static inline void grep_attr_lock(struct grep_opt *opt)
+{
+       if (opt->use_threads)
+               pthread_mutex_lock(&grep_attr_mutex);
+}
+
+static inline void grep_attr_unlock(struct grep_opt *opt)
+{
+       if (opt->use_threads)
+               pthread_mutex_unlock(&grep_attr_mutex);
+}
+#else
+#define grep_attr_lock(opt)
+#define grep_attr_unlock(opt)
+#endif
+
+static int match_funcname(struct grep_opt *opt, const char *name, char *bol, char *eol)
 {
        xdemitconf_t *xecfg = opt->priv;
-       if (xecfg && xecfg->find_func) {
+       if (xecfg && !xecfg->find_func) {
+               struct userdiff_driver *drv;
+               grep_attr_lock(opt);
+               drv = userdiff_find_by_path(name);
+               grep_attr_unlock(opt);
+               if (drv && drv->funcname.pattern) {
+                       const struct userdiff_funcname *pe = &drv->funcname;
+                       xdiff_set_find_func(xecfg, pe->pattern, pe->cflags);
+               } else {
+                       xecfg = opt->priv = NULL;
+               }
+       }
+
+       if (xecfg) {
                char buf[1];
                return xecfg->find_func(bol, eol - bol, buf, 1,
                                        xecfg->find_func_priv) >= 0;
@@ -835,7 +871,7 @@ static void show_funcname_line(struct grep_opt *opt, const char *name,
                if (lno <= opt->last_shown)
                        break;
 
-               if (match_funcname(opt, bol, eol)) {
+               if (match_funcname(opt, name, bol, eol)) {
                        show_line(opt, bol, eol, name, lno, '=');
                        break;
                }
@@ -848,7 +884,7 @@ static void show_pre_context(struct grep_opt *opt, const char *name, char *buf,
        unsigned cur = lno, from = 1, funcname_lno = 0;
        int funcname_needed = !!opt->funcname;
 
-       if (opt->funcbody && !match_funcname(opt, bol, end))
+       if (opt->funcbody && !match_funcname(opt, name, bol, end))
                funcname_needed = 2;
 
        if (opt->pre_context < lno)
@@ -864,7 +900,7 @@ static void show_pre_context(struct grep_opt *opt, const char *name, char *buf,
                while (bol > buf && bol[-1] != '\n')
                        bol--;
                cur--;
-               if (funcname_needed && match_funcname(opt, bol, eol)) {
+               if (funcname_needed && match_funcname(opt, name, bol, eol)) {
                        funcname_lno = cur;
                        funcname_needed = 0;
                }
@@ -942,19 +978,6 @@ static int look_ahead(struct grep_opt *opt,
        return 0;
 }
 
-int grep_threads_ok(const struct grep_opt *opt)
-{
-       /* If this condition is true, then we may use the attribute
-        * machinery in grep_buffer_1. The attribute code is not
-        * thread safe, so we disable the use of threads.
-        */
-       if (opt->funcname && !opt->unmatch_name_only && !opt->status_only &&
-           !opt->name_only)
-               return 0;
-
-       return 1;
-}
-
 static void std_output(struct grep_opt *opt, const void *buf, size_t size)
 {
        fwrite(buf, size, 1, stdout);
@@ -1008,15 +1031,8 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
        }
 
        memset(&xecfg, 0, sizeof(xecfg));
-       if (opt->funcname && !opt->unmatch_name_only && !opt->status_only &&
-           !opt->name_only && !binary_match_only && !collect_hits) {
-               struct userdiff_driver *drv = userdiff_find_by_path(name);
-               if (drv && drv->funcname.pattern) {
-                       const struct userdiff_funcname *pe = &drv->funcname;
-                       xdiff_set_find_func(&xecfg, pe->pattern, pe->cflags);
-                       opt->priv = &xecfg;
-               }
-       }
+       opt->priv = &xecfg;
+
        try_lookahead = should_lookahead(opt);
 
        while (left) {
@@ -1092,7 +1108,7 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
                                show_function = 1;
                        goto next_line;
                }
-               if (show_function && match_funcname(opt, bol, eol))
+               if (show_function && match_funcname(opt, name, bol, eol))
                        show_function = 0;
                if (show_function ||
                    (last_hit && lno <= last_hit + opt->post_context)) {
diff --git a/grep.h b/grep.h
index a65280026d5dee8ab059bead79f05d6a1111147a..fb205f354231c0e50026c6e7fbfae5e288620611 100644 (file)
--- a/grep.h
+++ b/grep.h
@@ -8,6 +8,7 @@ typedef int pcre;
 typedef int pcre_extra;
 #endif
 #include "kwset.h"
+#include "thread-utils.h"
 
 enum grep_pat_token {
        GREP_PATTERN,
@@ -115,6 +116,7 @@ struct grep_opt {
        int show_hunk_mark;
        int file_break;
        int heading;
+       int use_threads;
        void *priv;
 
        void (*output)(struct grep_opt *opt, const void *data, size_t size);
@@ -131,4 +133,12 @@ extern int grep_buffer(struct grep_opt *opt, const char *name, char *buf, unsign
 extern struct grep_opt *grep_opt_dup(const struct grep_opt *opt);
 extern int grep_threads_ok(const struct grep_opt *opt);
 
+#ifndef NO_PTHREADS
+/*
+ * Mutex used around access to the attributes machinery if
+ * opt->use_threads.  Must be initialized/destroyed by callers!
+ */
+extern pthread_mutex_t grep_attr_mutex;
+#endif
+
 #endif
index 91763d30181bed9bc6a3bf1cbc8d495d5b88f288..e40125a22b72544c107e365d4f09eaa3b1ce53de 100644 (file)
@@ -25,6 +25,7 @@
 #include "cache.h"
 #include "exec_cmd.h"
 #include "run-command.h"
+#include "prompt.h"
 #ifdef NO_OPENSSL
 typedef void *SSL;
 #else
@@ -1208,13 +1209,10 @@ static struct store *imap_open_store(struct imap_server_conf *srvc)
                        goto bail;
                }
                if (!srvc->pass) {
-                       char prompt[80];
-                       sprintf(prompt, "Password (%s@%s): ", srvc->user, srvc->host);
-                       arg = git_getpass(prompt);
-                       if (!arg) {
-                               perror("getpass");
-                               exit(1);
-                       }
+                       struct strbuf prompt = STRBUF_INIT;
+                       strbuf_addf(&prompt, "Password (%s@%s): ", srvc->user, srvc->host);
+                       arg = git_getpass(prompt.buf);
+                       strbuf_release(&prompt);
                        if (!*arg) {
                                fprintf(stderr, "Skipping account %s@%s, no password\n", srvc->user, srvc->host);
                                goto bail;
index e7694a3a4ca2e6de7fe8f3b5458eb2b65591373a..319bd31e2bd67f5ee38d6b887da2ca1b8e9ac742 100644 (file)
@@ -599,9 +599,7 @@ int log_tree_diff_flush(struct rev_info *opt)
 
 static int do_diff_combined(struct rev_info *opt, struct commit *commit)
 {
-       unsigned const char *sha1 = commit->object.sha1;
-
-       diff_tree_combined_merge(sha1, opt->dense_combined_merges, opt);
+       diff_tree_combined_merge(commit, opt->dense_combined_merges, opt);
        return !opt->loginfo;
 }
 
index 4c8984ede1e218d3e0aaadb6d8c72bfcafddeee9..bea013eeae70f360e12af01345058b1b217848c4 100644 (file)
@@ -48,6 +48,7 @@ int notes_cache_write(struct notes_cache *c)
 {
        unsigned char tree_sha1[20];
        unsigned char commit_sha1[20];
+       struct strbuf msg = STRBUF_INIT;
 
        if (!c || !c->tree.initialized || !c->tree.ref || !*c->tree.ref)
                return -1;
@@ -56,7 +57,9 @@ int notes_cache_write(struct notes_cache *c)
 
        if (write_notes_tree(&c->tree, tree_sha1))
                return -1;
-       if (commit_tree(c->validity, tree_sha1, NULL, commit_sha1, NULL) < 0)
+       strbuf_attach(&msg, c->validity,
+                     strlen(c->validity), strlen(c->validity) + 1);
+       if (commit_tree(&msg, tree_sha1, NULL, commit_sha1, NULL) < 0)
                return -1;
        if (update_ref("update notes cache", c->tree.ref, commit_sha1, NULL,
                       0, QUIET_ON_ERR) < 0)
index 2de27af751476a62dc9b0afe48eb360f83a0702b..0d38a1b17d8399c7acf6355d598f0a50d0ec1d3b 100644 (file)
@@ -530,7 +530,7 @@ static int merge_from_diffs(struct notes_merge_options *o,
 }
 
 void create_notes_commit(struct notes_tree *t, struct commit_list *parents,
-                        const char *msg, unsigned char *result_sha1)
+                        const struct strbuf *msg, unsigned char *result_sha1)
 {
        unsigned char tree_sha1[20];
 
@@ -668,7 +668,7 @@ int notes_merge(struct notes_merge_options *o,
                struct commit_list *parents = NULL;
                commit_list_insert(remote, &parents); /* LIFO order */
                commit_list_insert(local, &parents);
-               create_notes_commit(local_tree, parents, o->commit_msg.buf,
+               create_notes_commit(local_tree, parents, &o->commit_msg,
                                    result_sha1);
        }
 
@@ -695,7 +695,8 @@ int notes_merge_commit(struct notes_merge_options *o,
        struct dir_struct dir;
        char *path = xstrdup(git_path(NOTES_MERGE_WORKTREE "/"));
        int path_len = strlen(path), i;
-       const char *msg = strstr(partial_commit->buffer, "\n\n");
+       char *msg = strstr(partial_commit->buffer, "\n\n");
+       struct strbuf sb_msg = STRBUF_INIT;
 
        if (o->verbosity >= 3)
                printf("Committing notes in notes merge worktree at %.*s\n",
@@ -733,7 +734,8 @@ int notes_merge_commit(struct notes_merge_options *o,
                                sha1_to_hex(obj_sha1), sha1_to_hex(blob_sha1));
        }
 
-       create_notes_commit(partial_tree, partial_commit->parents, msg,
+       strbuf_attach(&sb_msg, msg, strlen(msg), strlen(msg) + 1);
+       create_notes_commit(partial_tree, partial_commit->parents, &sb_msg,
                            result_sha1);
        if (o->verbosity >= 4)
                printf("Finalized notes merge commit: %s\n",
index 168a6724cd873602e3da1ff3b7e2cc67a5b240ae..0c11b173a1e38ddeb702e022ebdd571ed2ad12f3 100644 (file)
@@ -37,7 +37,7 @@ void init_notes_merge_options(struct notes_merge_options *o);
  * The resulting commit SHA1 is stored in result_sha1.
  */
 void create_notes_commit(struct notes_tree *t, struct commit_list *parents,
-                        const char *msg, unsigned char *result_sha1);
+                        const struct strbuf *msg, unsigned char *result_sha1);
 
 /*
  * Merge notes from o->remote_ref into o->local_ref
index de2bd01414f07cb2d3fb9d212895ad0f1ea1ba26..ca9e63be18f9333bf0f603ddb9ddd923588be0aa 100644 (file)
@@ -73,9 +73,9 @@ const char *write_idx_file(const char *index_name, struct pack_idx_entry **objec
                f = sha1fd_check(index_name);
        } else {
                if (!index_name) {
-                       static char tmpfile[PATH_MAX];
-                       fd = odb_mkstemp(tmpfile, sizeof(tmpfile), "pack/tmp_idx_XXXXXX");
-                       index_name = xstrdup(tmpfile);
+                       static char tmp_file[PATH_MAX];
+                       fd = odb_mkstemp(tmp_file, sizeof(tmp_file), "pack/tmp_idx_XXXXXX");
+                       index_name = xstrdup(tmp_file);
                } else {
                        unlink(index_name);
                        fd = open(index_name, O_CREAT|O_EXCL|O_WRONLY, 0600);
index 230fe1cc82e3a3bf7c0fef604350868d917acef4..1580299d4037ada9e1f0e3c11c6c5578f44f52dd 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -822,6 +822,23 @@ static void rewrap_message_tail(struct strbuf *sb,
        c->indent2 = new_indent2;
 }
 
+static int format_reflog_person(struct strbuf *sb,
+                               char part,
+                               struct reflog_walk_info *log,
+                               enum date_mode dmode)
+{
+       const char *ident;
+
+       if (!log)
+               return 2;
+
+       ident = get_reflog_ident(log);
+       if (!ident)
+               return 2;
+
+       return format_person_part(sb, part, ident, strlen(ident), dmode);
+}
+
 static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
                                void *context)
 {
@@ -963,6 +980,14 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
                        if (c->pretty_ctx->reflog_info)
                                get_reflog_message(sb, c->pretty_ctx->reflog_info);
                        return 2;
+               case 'n':
+               case 'N':
+               case 'e':
+               case 'E':
+                       return format_reflog_person(sb,
+                                                   placeholder[1],
+                                                   c->pretty_ctx->reflog_info,
+                                                   c->pretty_ctx->date_mode);
                }
                return 0;       /* unknown %g placeholder */
        case 'N':
diff --git a/prompt.c b/prompt.c
new file mode 100644 (file)
index 0000000..72ab9de
--- /dev/null
+++ b/prompt.c
@@ -0,0 +1,63 @@
+#include "cache.h"
+#include "run-command.h"
+#include "strbuf.h"
+#include "prompt.h"
+#include "compat/terminal.h"
+
+static char *do_askpass(const char *cmd, const char *prompt)
+{
+       struct child_process pass;
+       const char *args[3];
+       static struct strbuf buffer = STRBUF_INIT;
+
+       args[0] = cmd;
+       args[1] = prompt;
+       args[2] = NULL;
+
+       memset(&pass, 0, sizeof(pass));
+       pass.argv = args;
+       pass.out = -1;
+
+       if (start_command(&pass))
+               exit(1);
+
+       strbuf_reset(&buffer);
+       if (strbuf_read(&buffer, pass.out, 20) < 0)
+               die("failed to get '%s' from %s\n", prompt, cmd);
+
+       close(pass.out);
+
+       if (finish_command(&pass))
+               exit(1);
+
+       strbuf_setlen(&buffer, strcspn(buffer.buf, "\r\n"));
+
+       return buffer.buf;
+}
+
+char *git_prompt(const char *prompt, int flags)
+{
+       char *r;
+
+       if (flags & PROMPT_ASKPASS) {
+               const char *askpass;
+
+               askpass = getenv("GIT_ASKPASS");
+               if (!askpass)
+                       askpass = askpass_program;
+               if (!askpass)
+                       askpass = getenv("SSH_ASKPASS");
+               if (askpass && *askpass)
+                       return do_askpass(askpass, prompt);
+       }
+
+       r = git_terminal_prompt(prompt, flags & PROMPT_ECHO);
+       if (!r)
+               die_errno("could not read '%s'", prompt);
+       return r;
+}
+
+char *git_getpass(const char *prompt)
+{
+       return git_prompt(prompt, PROMPT_ASKPASS);
+}
diff --git a/prompt.h b/prompt.h
new file mode 100644 (file)
index 0000000..04f321a
--- /dev/null
+++ b/prompt.h
@@ -0,0 +1,10 @@
+#ifndef PROMPT_H
+#define PROMPT_H
+
+#define PROMPT_ASKPASS (1<<0)
+#define PROMPT_ECHO    (1<<1)
+
+char *git_prompt(const char *prompt, int flags);
+char *git_getpass(const char *prompt);
+
+#endif /* PROMPT_H */
index 64c677fc49d7874736221b1828f96d8652cb1fb3..86d18843f52046d87741bffa9f865ec973a2ae73 100644 (file)
@@ -295,6 +295,18 @@ void get_reflog_message(struct strbuf *sb,
        strbuf_add(sb, info->message, len);
 }
 
+const char *get_reflog_ident(struct reflog_walk_info *reflog_info)
+{
+       struct commit_reflog *commit_reflog = reflog_info->last_commit_reflog;
+       struct reflog_info *info;
+
+       if (!commit_reflog)
+               return NULL;
+
+       info = &commit_reflog->reflogs->items[commit_reflog->recno+1];
+       return info->email;
+}
+
 void show_reflog_message(struct reflog_walk_info *reflog_info, int oneline,
        enum date_mode dmode)
 {
index 7bd2cd4c4e5cd9d51e645509eeacc49a83a44ba7..afb1ae3fde93a5c61def211be56b0554a25dd45e 100644 (file)
@@ -14,6 +14,7 @@ extern void show_reflog_message(struct reflog_walk_info *info, int,
                enum date_mode);
 extern void get_reflog_message(struct strbuf *sb,
                struct reflog_walk_info *reflog_info);
+extern const char *get_reflog_ident(struct reflog_walk_info *reflog_info);
 extern void get_reflog_selector(struct strbuf *sb,
                struct reflog_walk_info *reflog_info,
                enum date_mode dmode,
index 6a352de7be33c48134842a8ffbb86883b5d69812..48c20b86f3cfc6c189972718046a6890aaefacf3 100644 (file)
@@ -188,7 +188,7 @@ static int write_discovery(int in, int out, void *data)
        return err;
 }
 
-static struct ref *parse_git_refs(struct discovery *heads)
+static struct ref *parse_git_refs(struct discovery *heads, int for_push)
 {
        struct ref *list = NULL;
        struct async async;
@@ -200,7 +200,8 @@ static struct ref *parse_git_refs(struct discovery *heads)
 
        if (start_async(&async))
                die("cannot start thread to parse advertised refs");
-       get_remote_heads(async.out, &list, 0, NULL);
+       get_remote_heads(async.out, &list,
+                       for_push ? REF_NORMAL : 0, NULL);
        close(async.out);
        if (finish_async(&async))
                die("ref parsing thread failed");
@@ -268,7 +269,7 @@ static struct ref *get_refs(int for_push)
                heads = discover_refs("git-upload-pack");
 
        if (heads->proto_git)
-               return parse_git_refs(heads);
+               return parse_git_refs(heads, for_push);
        return parse_info_refs(heads);
 }
 
index f291f3f0f7d919c7d59b8b7dc3c3f2450a5a9f09..88f2151ff31870138a53e40f99f5ae9928b09545 100644 (file)
@@ -2452,15 +2452,15 @@ static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen,
        git_SHA_CTX c;
        unsigned char parano_sha1[20];
        char *filename;
-       static char tmpfile[PATH_MAX];
+       static char tmp_file[PATH_MAX];
 
        filename = sha1_file_name(sha1);
-       fd = create_tmpfile(tmpfile, sizeof(tmpfile), filename);
+       fd = create_tmpfile(tmp_file, sizeof(tmp_file), filename);
        if (fd < 0) {
                if (errno == EACCES)
                        return error("insufficient permission for adding an object to repository database %s\n", get_object_directory());
                else
-                       return error("unable to create temporary sha1 filename %s: %s\n", tmpfile, strerror(errno));
+                       return error("unable to create temporary sha1 filename %s: %s\n", tmp_file, strerror(errno));
        }
 
        /* Set it up */
@@ -2505,12 +2505,12 @@ static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen,
                struct utimbuf utb;
                utb.actime = mtime;
                utb.modtime = mtime;
-               if (utime(tmpfile, &utb) < 0)
+               if (utime(tmp_file, &utb) < 0)
                        warning("failed utime() on %s: %s",
-                               tmpfile, strerror(errno));
+                               tmp_file, strerror(errno));
        }
 
-       return move_temp_to_file(tmpfile, filename);
+       return move_temp_to_file(tmp_file, filename);
 }
 
 int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *returnsha1)
index 68c1ba90b9e746b869830ec66a6f23437a4d7d08..9a2806067954c55a27c068706b5bfe67a1189fd5 100644 (file)
@@ -371,27 +371,15 @@ static void collect_submodules_from_diff(struct diff_queue_struct *q,
 }
 
 
-static void commit_need_pushing(struct commit *commit, struct commit_list *parent, int *needs_pushing)
+static void commit_need_pushing(struct commit *commit, int *needs_pushing)
 {
-       const unsigned char (*parents)[20];
-       unsigned int i, n;
        struct rev_info rev;
 
-       n = commit_list_count(parent);
-       parents = xmalloc(n * sizeof(*parents));
-
-       for (i = 0; i < n; i++) {
-               hashcpy((unsigned char *)(parents + i), parent->item->object.sha1);
-               parent = parent->next;
-       }
-
        init_revisions(&rev, NULL);
        rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
        rev.diffopt.format_callback = collect_submodules_from_diff;
        rev.diffopt.format_callback_data = needs_pushing;
-       diff_tree_combined(commit->object.sha1, parents, n, 1, &rev);
-
-       free((void *)parents);
+       diff_tree_combined_merge(commit, 1, &rev);
 }
 
 int check_submodule_needs_pushing(unsigned char new_sha1[20], const char *remotes_name)
@@ -414,7 +402,7 @@ int check_submodule_needs_pushing(unsigned char new_sha1[20], const char *remote
                die("revision walk setup failed");
 
        while ((commit = get_revision(&rev)) && !needs_pushing)
-               commit_need_pushing(commit, commit->parents, &needs_pushing);
+               commit_need_pushing(commit, &needs_pushing);
 
        free(sha1_copy);
        strbuf_release(&remotes_arg);
index 0ab52da902c8d602e9c4d64660aa4a7e8e35544f..e37547f41a21ebda150aad6797012c9df3742382 100755 (executable)
@@ -35,7 +35,7 @@ test_expect_success 'cherry-pick a non-merge with -m should fail' '
 
        git reset --hard &&
        git checkout a^0 &&
-       test_must_fail git cherry-pick -m 1 b &&
+       test_expect_code 128 git cherry-pick -m 1 b &&
        git diff --exit-code a --
 
 '
index e80050e1fef9c7c2d83a34aaa671415ea168e8c4..97f371070011e2023552d9fe941dc0a406f6d09f 100755 (executable)
@@ -14,6 +14,9 @@ test_description='Test cherry-pick continuation features
 
 . ./test-lib.sh
 
+# Repeat first match 10 times
+_r10='\1\1\1\1\1\1\1\1\1\1'
+
 pristine_detach () {
        git cherry-pick --quit &&
        git checkout -f "$1^0" &&
@@ -43,7 +46,7 @@ test_expect_success setup '
 
 test_expect_success 'cherry-pick persists data on failure' '
        pristine_detach initial &&
-       test_must_fail git cherry-pick -s base..anotherpick &&
+       test_expect_code 1 git cherry-pick -s base..anotherpick &&
        test_path_is_dir .git/sequencer &&
        test_path_is_file .git/sequencer/head &&
        test_path_is_file .git/sequencer/todo &&
@@ -64,7 +67,7 @@ test_expect_success 'cherry-pick mid-cherry-pick-sequence' '
 
 test_expect_success 'cherry-pick persists opts correctly' '
        pristine_detach initial &&
-       test_must_fail git cherry-pick -s -m 1 --strategy=recursive -X patience -X ours base..anotherpick &&
+       test_expect_code 128 git cherry-pick -s -m 1 --strategy=recursive -X patience -X ours initial..anotherpick &&
        test_path_is_dir .git/sequencer &&
        test_path_is_file .git/sequencer/head &&
        test_path_is_file .git/sequencer/todo &&
@@ -104,7 +107,7 @@ test_expect_success '--abort requires cherry-pick in progress' '
 
 test_expect_success '--quit cleans up sequencer state' '
        pristine_detach initial &&
-       test_must_fail git cherry-pick base..picked &&
+       test_expect_code 1 git cherry-pick base..picked &&
        git cherry-pick --quit &&
        test_path_is_missing .git/sequencer
 '
@@ -118,7 +121,7 @@ test_expect_success '--quit keeps HEAD and conflicted index intact' '
        :000000 100644 OBJID OBJID A    foo
        :000000 100644 OBJID OBJID A    unrelated
        EOF
-       test_must_fail git cherry-pick base..picked &&
+       test_expect_code 1 git cherry-pick base..picked &&
        git cherry-pick --quit &&
        test_path_is_missing .git/sequencer &&
        test_must_fail git update-index --refresh &&
@@ -132,7 +135,7 @@ test_expect_success '--quit keeps HEAD and conflicted index intact' '
 
 test_expect_success '--abort to cancel multiple cherry-pick' '
        pristine_detach initial &&
-       test_must_fail git cherry-pick base..anotherpick &&
+       test_expect_code 1 git cherry-pick base..anotherpick &&
        git cherry-pick --abort &&
        test_path_is_missing .git/sequencer &&
        test_cmp_rev initial HEAD &&
@@ -142,7 +145,7 @@ test_expect_success '--abort to cancel multiple cherry-pick' '
 
 test_expect_success '--abort to cancel single cherry-pick' '
        pristine_detach initial &&
-       test_must_fail git cherry-pick picked &&
+       test_expect_code 1 git cherry-pick picked &&
        git cherry-pick --abort &&
        test_path_is_missing .git/sequencer &&
        test_cmp_rev initial HEAD &&
@@ -152,7 +155,7 @@ test_expect_success '--abort to cancel single cherry-pick' '
 
 test_expect_success 'cherry-pick --abort to cancel multiple revert' '
        pristine_detach anotherpick &&
-       test_must_fail git revert base..picked &&
+       test_expect_code 1 git revert base..picked &&
        git cherry-pick --abort &&
        test_path_is_missing .git/sequencer &&
        test_cmp_rev anotherpick HEAD &&
@@ -162,7 +165,7 @@ test_expect_success 'cherry-pick --abort to cancel multiple revert' '
 
 test_expect_success 'revert --abort works, too' '
        pristine_detach anotherpick &&
-       test_must_fail git revert base..picked &&
+       test_expect_code 1 git revert base..picked &&
        git revert --abort &&
        test_path_is_missing .git/sequencer &&
        test_cmp_rev anotherpick HEAD
@@ -170,7 +173,7 @@ test_expect_success 'revert --abort works, too' '
 
 test_expect_success '--abort to cancel single revert' '
        pristine_detach anotherpick &&
-       test_must_fail git revert picked &&
+       test_expect_code 1 git revert picked &&
        git revert --abort &&
        test_path_is_missing .git/sequencer &&
        test_cmp_rev anotherpick HEAD &&
@@ -181,7 +184,7 @@ test_expect_success '--abort to cancel single revert' '
 test_expect_success '--abort keeps unrelated change, easy case' '
        pristine_detach unrelatedpick &&
        echo changed >expect &&
-       test_must_fail git cherry-pick picked..yetanotherpick &&
+       test_expect_code 1 git cherry-pick picked..yetanotherpick &&
        echo changed >unrelated &&
        git cherry-pick --abort &&
        test_cmp expect unrelated
@@ -190,7 +193,7 @@ test_expect_success '--abort keeps unrelated change, easy case' '
 test_expect_success '--abort refuses to clobber unrelated change, harder case' '
        pristine_detach initial &&
        echo changed >expect &&
-       test_must_fail git cherry-pick base..anotherpick &&
+       test_expect_code 1 git cherry-pick base..anotherpick &&
        echo changed >unrelated &&
        test_must_fail git cherry-pick --abort &&
        test_cmp expect unrelated &&
@@ -205,7 +208,7 @@ test_expect_success '--abort refuses to clobber unrelated change, harder case' '
 
 test_expect_success 'cherry-pick still writes sequencer state when one commit is left' '
        pristine_detach initial &&
-       test_must_fail git cherry-pick base..picked &&
+       test_expect_code 1 git cherry-pick base..picked &&
        test_path_is_dir .git/sequencer &&
        echo "resolved" >foo &&
        git add foo &&
@@ -229,7 +232,7 @@ test_expect_success 'cherry-pick still writes sequencer state when one commit is
 
 test_expect_success '--abort after last commit in sequence' '
        pristine_detach initial &&
-       test_must_fail git cherry-pick base..picked &&
+       test_expect_code 1 git cherry-pick base..picked &&
        git cherry-pick --abort &&
        test_path_is_missing .git/sequencer &&
        test_cmp_rev initial HEAD &&
@@ -239,22 +242,22 @@ test_expect_success '--abort after last commit in sequence' '
 
 test_expect_success 'cherry-pick does not implicitly stomp an existing operation' '
        pristine_detach initial &&
-       test_must_fail git cherry-pick base..anotherpick &&
+       test_expect_code 1 git cherry-pick base..anotherpick &&
        test-chmtime -v +0 .git/sequencer >expect &&
-       test_must_fail git cherry-pick unrelatedpick &&
+       test_expect_code 128 git cherry-pick unrelatedpick &&
        test-chmtime -v +0 .git/sequencer >actual &&
        test_cmp expect actual
 '
 
 test_expect_success '--continue complains when no cherry-pick is in progress' '
        pristine_detach initial &&
-       test_must_fail git cherry-pick --continue
+       test_expect_code 128 git cherry-pick --continue
 '
 
 test_expect_success '--continue complains when there are unresolved conflicts' '
        pristine_detach initial &&
-       test_must_fail git cherry-pick base..anotherpick &&
-       test_must_fail git cherry-pick --continue
+       test_expect_code 1 git cherry-pick base..anotherpick &&
+       test_expect_code 128 git cherry-pick --continue
 '
 
 test_expect_success '--continue of single cherry-pick' '
@@ -318,7 +321,7 @@ test_expect_success '--continue after resolving conflicts' '
 
 test_expect_success '--continue after resolving conflicts and committing' '
        pristine_detach initial &&
-       test_must_fail git cherry-pick base..anotherpick &&
+       test_expect_code 1 git cherry-pick base..anotherpick &&
        echo "c" >foo &&
        git add foo &&
        git commit &&
@@ -368,7 +371,7 @@ test_expect_success 'follow advice and skip nil patch' '
 
 test_expect_success '--continue respects opts' '
        pristine_detach initial &&
-       test_must_fail git cherry-pick -x base..anotherpick &&
+       test_expect_code 1 git cherry-pick -x base..anotherpick &&
        echo "c" >foo &&
        git add foo &&
        git commit &&
@@ -409,7 +412,7 @@ test_expect_success '--continue respects -x in first commit in multi-pick' '
 
 test_expect_success '--signoff is not automatically propagated to resolved conflict' '
        pristine_detach initial &&
-       test_must_fail git cherry-pick --signoff base..anotherpick &&
+       test_expect_code 1 git cherry-pick --signoff base..anotherpick &&
        echo "c" >foo &&
        git add foo &&
        git commit &&
@@ -453,24 +456,24 @@ test_expect_success 'sign-off needs to be reaffirmed after conflict resolution,
 
 test_expect_success 'malformed instruction sheet 1' '
        pristine_detach initial &&
-       test_must_fail git cherry-pick base..anotherpick &&
+       test_expect_code 1 git cherry-pick base..anotherpick &&
        echo "resolved" >foo &&
        git add foo &&
        git commit &&
        sed "s/pick /pick/" .git/sequencer/todo >new_sheet &&
        cp new_sheet .git/sequencer/todo &&
-       test_must_fail git cherry-pick --continue
+       test_expect_code 128 git cherry-pick --continue
 '
 
 test_expect_success 'malformed instruction sheet 2' '
        pristine_detach initial &&
-       test_must_fail git cherry-pick base..anotherpick &&
+       test_expect_code 1 git cherry-pick base..anotherpick &&
        echo "resolved" >foo &&
        git add foo &&
        git commit &&
        sed "s/pick/revert/" .git/sequencer/todo >new_sheet &&
        cp new_sheet .git/sequencer/todo &&
-       test_must_fail git cherry-pick --continue
+       test_expect_code 128 git cherry-pick --continue
 '
 
 test_expect_success 'empty commit set' '
@@ -478,4 +481,40 @@ test_expect_success 'empty commit set' '
        test_expect_code 128 git cherry-pick base..base
 '
 
+test_expect_success 'malformed instruction sheet 3' '
+       pristine_detach initial &&
+       test_expect_code 1 git cherry-pick base..anotherpick &&
+       echo "resolved" >foo &&
+       git add foo &&
+       git commit &&
+       sed "s/pick \([0-9a-f]*\)/pick $_r10/" .git/sequencer/todo >new_sheet &&
+       cp new_sheet .git/sequencer/todo &&
+       test_expect_code 128 git cherry-pick --continue
+'
+
+test_expect_success 'instruction sheet, fat-fingers version' '
+       pristine_detach initial &&
+       test_expect_code 1 git cherry-pick base..anotherpick &&
+       echo "c" >foo &&
+       git add foo &&
+       git commit &&
+       sed "s/pick \([0-9a-f]*\)/pick   \1     /" .git/sequencer/todo >new_sheet &&
+       cp new_sheet .git/sequencer/todo &&
+       git cherry-pick --continue
+'
+
+test_expect_success 'commit descriptions in insn sheet are optional' '
+       pristine_detach initial &&
+       test_expect_code 1 git cherry-pick base..anotherpick &&
+       echo "c" >foo &&
+       git add foo &&
+       git commit &&
+       cut -d" " -f1,2 .git/sequencer/todo >new_sheet &&
+       cp new_sheet .git/sequencer/todo &&
+       git cherry-pick --continue &&
+       test_path_is_missing .git/sequencer &&
+       git rev-list HEAD >commits &&
+       test_line_count = 4 commits
+'
+
 test_done
index 1f62c151b0aa63b4c85f9bc76f501d53967b0260..d48a7c002d622ffac5087be9a7998f781a242731 100755 (executable)
@@ -34,6 +34,12 @@ test_expect_success 'no encoding header for base case' '
        test z = "z$E"
 '
 
+test_expect_failure 'UTF-16 refused because of NULs' '
+       echo UTF-16 >F &&
+       git commit -a -F "$TEST_DIRECTORY"/t3900/UTF-16.txt
+'
+
+
 for H in ISO8859-1 eucJP ISO-2022-JP
 do
        test_expect_success "$H setup" '
index a73c82635ff6fba6fcef4f139ff09205c1b9b6de..9b85d420c39a0f2192b6b829a6c7912ae28d8e92 100755 (executable)
@@ -154,5 +154,37 @@ test_expect_success 'push (chunked)' '
         test $HEAD = $(git rev-parse --verify HEAD))
 '
 
+test_expect_success 'push --all can push to empty repo' '
+       d=$HTTPD_DOCUMENT_ROOT_PATH/empty-all.git &&
+       git init --bare "$d" &&
+       git --git-dir="$d" config http.receivepack true &&
+       git push --all "$HTTPD_URL"/smart/empty-all.git
+'
+
+test_expect_success 'push --mirror can push to empty repo' '
+       d=$HTTPD_DOCUMENT_ROOT_PATH/empty-mirror.git &&
+       git init --bare "$d" &&
+       git --git-dir="$d" config http.receivepack true &&
+       git push --mirror "$HTTPD_URL"/smart/empty-mirror.git
+'
+
+test_expect_success 'push --all to repo with alternates' '
+       s=$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git &&
+       d=$HTTPD_DOCUMENT_ROOT_PATH/alternates-all.git &&
+       git clone --bare --shared "$s" "$d" &&
+       git --git-dir="$d" config http.receivepack true &&
+       git --git-dir="$d" repack -adl &&
+       git push --all "$HTTPD_URL"/smart/alternates-all.git
+'
+
+test_expect_success 'push --mirror to repo with alternates' '
+       s=$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git &&
+       d=$HTTPD_DOCUMENT_ROOT_PATH/alternates-mirror.git &&
+       git clone --bare --shared "$s" "$d" &&
+       git --git-dir="$d" config http.receivepack true &&
+       git --git-dir="$d" repack -adl &&
+       git push --mirror "$HTTPD_URL"/smart/alternates-mirror.git
+'
+
 stop_httpd
 test_done
index d918cc02d090157485d404d34d49005e50cd9f1a..444279077e803ca96e48281ae956ea6536317608 100755 (executable)
@@ -267,6 +267,12 @@ test_expect_success '%gd shortens ref name' '
        test_cmp expect.gd-short actual.gd-short
 '
 
+test_expect_success 'reflog identity' '
+       echo "C O Mitter:committer@example.com" >expect &&
+       git log -g -1 --format="%gn:%ge" >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'oneline with empty message' '
        git commit -m "dummy" --allow-empty &&
        git commit -m "dummy" --allow-empty &&
index 320e1d1dbe62c81e29186d7a32b73447d2f998b8..ff2590849de960cf6ec751f83904f1792862f626 100755 (executable)
@@ -6,11 +6,6 @@ test_description='Test automatic use of a pager.'
 . "$TEST_DIRECTORY"/lib-pager.sh
 . "$TEST_DIRECTORY"/lib-terminal.sh
 
-cleanup_fail() {
-       echo >&2 cleanup failed
-       (exit 1)
-}
-
 test_expect_success 'setup' '
        sane_unset GIT_PAGER GIT_PAGER_IN_USE &&
        test_unconfig core.pager &&
@@ -22,9 +17,7 @@ test_expect_success 'setup' '
 '
 
 test_expect_success TTY 'some commands use a pager' '
-       rm -f paginated.out ||
-       cleanup_fail &&
-
+       rm -f paginated.out &&
        test_terminal git log &&
        test -e paginated.out
 '
@@ -45,49 +38,37 @@ test_expect_failure TTY 'pager runs from subdir' '
 '
 
 test_expect_success TTY 'some commands do not use a pager' '
-       rm -f paginated.out ||
-       cleanup_fail &&
-
+       rm -f paginated.out &&
        test_terminal git rev-list HEAD &&
        ! test -e paginated.out
 '
 
 test_expect_success 'no pager when stdout is a pipe' '
-       rm -f paginated.out ||
-       cleanup_fail &&
-
+       rm -f paginated.out &&
        git log | cat &&
        ! test -e paginated.out
 '
 
 test_expect_success 'no pager when stdout is a regular file' '
-       rm -f paginated.out ||
-       cleanup_fail &&
-
+       rm -f paginated.out &&
        git log >file &&
        ! test -e paginated.out
 '
 
 test_expect_success TTY 'git --paginate rev-list uses a pager' '
-       rm -f paginated.out ||
-       cleanup_fail &&
-
+       rm -f paginated.out &&
        test_terminal git --paginate rev-list HEAD &&
        test -e paginated.out
 '
 
 test_expect_success 'no pager even with --paginate when stdout is a pipe' '
-       rm -f file paginated.out ||
-       cleanup_fail &&
-
+       rm -f file paginated.out &&
        git --paginate log | cat &&
        ! test -e paginated.out
 '
 
 test_expect_success TTY 'no pager with --no-pager' '
-       rm -f paginated.out ||
-       cleanup_fail &&
-
+       rm -f paginated.out &&
        test_terminal git --no-pager log &&
        ! test -e paginated.out
 '
@@ -136,9 +117,7 @@ colorful() {
 }
 
 test_expect_success 'tests can detect color' '
-       rm -f colorful.log colorless.log ||
-       cleanup_fail &&
-
+       rm -f colorful.log colorless.log &&
        git log --no-color >colorless.log &&
        git log --color >colorful.log &&
        ! colorful colorless.log &&
@@ -147,18 +126,14 @@ test_expect_success 'tests can detect color' '
 
 test_expect_success 'no color when stdout is a regular file' '
        rm -f colorless.log &&
-       test_config color.ui auto ||
-       cleanup_fail &&
-
+       test_config color.ui auto &&
        git log >colorless.log &&
        ! colorful colorless.log
 '
 
 test_expect_success TTY 'color when writing to a pager' '
        rm -f paginated.out &&
-       test_config color.ui auto ||
-       cleanup_fail &&
-
+       test_config color.ui auto &&
        (
                TERM=vt100 &&
                export TERM &&
@@ -181,9 +156,7 @@ test_expect_success TTY 'colors are suppressed by color.pager' '
 
 test_expect_success 'color when writing to a file intended for a pager' '
        rm -f colorful.log &&
-       test_config color.ui auto ||
-       cleanup_fail &&
-
+       test_config color.ui auto &&
        (
                TERM=vt100 &&
                GIT_PAGER_IN_USE=true &&
@@ -242,9 +215,7 @@ test_default_pager() {
        $test_expectation SIMPLEPAGER,TTY "$cmd - default pager is used by default" "
                sane_unset PAGER GIT_PAGER &&
                test_unconfig core.pager &&
-               rm -f default_pager_used ||
-               cleanup_fail &&
-
+               rm -f default_pager_used &&
                cat >\$less <<-\EOF &&
                #!/bin/sh
                wc >default_pager_used
@@ -265,9 +236,7 @@ test_PAGER_overrides() {
        $test_expectation TTY "$cmd - PAGER overrides default pager" "
                sane_unset GIT_PAGER &&
                test_unconfig core.pager &&
-               rm -f PAGER_used ||
-               cleanup_fail &&
-
+               rm -f PAGER_used &&
                PAGER='wc >PAGER_used' &&
                export PAGER &&
                $full_command &&
@@ -292,9 +261,7 @@ test_core_pager() {
 
        $test_expectation TTY "$cmd - repository-local core.pager setting $used_if_wanted" "
                sane_unset GIT_PAGER &&
-               rm -f core.pager_used ||
-               cleanup_fail &&
-
+               rm -f core.pager_used &&
                PAGER=wc &&
                export PAGER &&
                test_config core.pager 'wc >core.pager_used' &&
@@ -321,9 +288,7 @@ test_pager_subdir_helper() {
        $test_expectation TTY "$cmd - core.pager $used_if_wanted from subdirectory" "
                sane_unset GIT_PAGER &&
                rm -f core.pager_used &&
-               rm -fr sub ||
-               cleanup_fail &&
-
+               rm -fr sub &&
                PAGER=wc &&
                stampname=\$(pwd)/core.pager_used &&
                export PAGER stampname &&
@@ -341,9 +306,7 @@ test_GIT_PAGER_overrides() {
        parse_args "$@"
 
        $test_expectation TTY "$cmd - GIT_PAGER overrides core.pager" "
-               rm -f GIT_PAGER_used ||
-               cleanup_fail &&
-
+               rm -f GIT_PAGER_used &&
                test_config core.pager wc &&
                GIT_PAGER='wc >GIT_PAGER_used' &&
                export GIT_PAGER &&
@@ -356,9 +319,7 @@ test_doesnt_paginate() {
        parse_args "$@"
 
        $test_expectation TTY "no pager for '$cmd'" "
-               rm -f GIT_PAGER_used ||
-               cleanup_fail &&
-
+               rm -f GIT_PAGER_used &&
                GIT_PAGER='wc >GIT_PAGER_used' &&
                export GIT_PAGER &&
                $full_command &&
index 81263b78516cbe2949ad7e426a5e44af188cccdd..7ba5b16f99443c0dc5aaff8fbb4ce4ad8874a27c 100755 (executable)
@@ -523,6 +523,20 @@ test_expect_success 'grep -W' '
        test_cmp expected actual
 '
 
+cat >expected <<EOF
+hello.c=       printf("Hello world.\n");
+hello.c:       return 0;
+hello.c-       /* char ?? */
+EOF
+
+test_expect_success 'grep -W with userdiff' '
+       test_when_finished "rm -f .gitattributes" &&
+       git config diff.custom.xfuncname "(printf.*|})$" &&
+       echo "hello.c diff=custom" >.gitattributes &&
+       git grep -W return >actual &&
+       test_cmp expected actual
+'
+
 test_expect_success 'grep from a subdirectory to search wider area (1)' '
        mkdir -p s &&
        (
index 0e932dd9758f71cbc95c6ab20f7c11e9056d7826..a65dfc7ea93b3ec95e6ab7cd5b758029fe599d22 100644 (file)
@@ -192,6 +192,7 @@ then
 fi
 
 exec 5>&1
+exec 6<&0
 if test "$verbose" = "t"
 then
        exec 4>&2 3>&1
@@ -475,7 +476,7 @@ test_debug () {
 test_eval_ () {
        # This is a separate function because some tests use
        # "return" to end a test_expect_success block early.
-       eval >&3 2>&4 "$*"
+       eval </dev/null >&3 2>&4 "$*"
 }
 
 test_run_ () {
index ee01eb957e97594ce24a61d4cac15a3a4e5a114d..10172aee18292b50aa24b3a8694b5383c1cfd98e 100755 (executable)
@@ -69,6 +69,10 @@ sub copy_stdio {
 }
 my $master_out = new IO::Pty;
 my $master_err = new IO::Pty;
+$master_out->set_raw();
+$master_err->set_raw();
+$master_out->slave->set_raw();
+$master_err->slave->set_raw();
 my $pid = start_child(\@ARGV, $master_out->slave, $master_err->slave);
 close $master_out->slave;
 close $master_err->slave;
index ab8c951c6eb39f54a9885dd15c173f974d7357d5..294d7ee2737099c94a7d768d47c6a316a6860cd7 100644 (file)
@@ -31,7 +31,7 @@ static void strtonode(struct int_node *item, const char *s)
 int main(int argc, char *argv[])
 {
        struct strbuf sb = STRBUF_INIT;
-       struct trp_root root = { ~0 };
+       struct trp_root root = { ~0U };
        uint32_t item;
 
        if (argc != 1)
index 63f38e3940516d9fd39371b4072ee296100307a7..a99b7c9c457c4ac3b76dc6859507711f847e5f62 100644 (file)
@@ -215,7 +215,7 @@ static struct ref *get_refs_via_rsync(struct transport *transport, int for_push)
        rsync.argv = args;
        rsync.stdout_to_stderr = 1;
        args[0] = "rsync";
-       args[1] = (transport->verbose > 0) ? "-rv" : "-r";
+       args[1] = (transport->verbose > 1) ? "-rv" : "-r";
        args[2] = buf.buf;
        args[3] = temp_dir.buf;
        args[4] = NULL;
@@ -268,7 +268,7 @@ static int fetch_objs_via_rsync(struct transport *transport,
        rsync.argv = args;
        rsync.stdout_to_stderr = 1;
        args[0] = "rsync";
-       args[1] = (transport->verbose > 0) ? "-rv" : "-r";
+       args[1] = (transport->verbose > 1) ? "-rv" : "-r";
        args[2] = "--ignore-existing";
        args[3] = "--exclude";
        args[4] = "info";
@@ -351,7 +351,7 @@ static int rsync_transport_push(struct transport *transport,
        args[i++] = "-a";
        if (flags & TRANSPORT_PUSH_DRY_RUN)
                args[i++] = "--dry-run";
-       if (transport->verbose > 0)
+       if (transport->verbose > 1)
                args[i++] = "-v";
        args[i++] = "--ignore-existing";
        args[i++] = "--exclude";
@@ -527,7 +527,7 @@ static int fetch_refs_via_pack(struct transport *transport,
        args.lock_pack = 1;
        args.use_thin_pack = data->options.thin;
        args.include_tag = data->options.followtags;
-       args.verbose = (transport->verbose > 0);
+       args.verbose = (transport->verbose > 1);
        args.quiet = (transport->verbose < 0);
        args.no_progress = !transport->progress;
        args.depth = data->options.depth;
@@ -980,7 +980,7 @@ int transport_set_option(struct transport *transport,
 void transport_set_verbosity(struct transport *transport, int verbosity,
        int force_progress)
 {
-       if (verbosity >= 2)
+       if (verbosity >= 1)
                transport->verbose = verbosity <= 3 ? verbosity : 3;
        if (verbosity < 0)
                transport->verbose = -1;
index 7a51d091b5a6babed91f60b9ff7079308afa4e6f..28ad6db9ffa854c3ef9185ba85108e95edc44d51 100644 (file)
@@ -209,6 +209,7 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co
        diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
        diff_opts.single_follow = opt->pathspec.raw[0];
        diff_opts.break_opt = opt->break_opt;
+       diff_opts.rename_score = opt->rename_score;
        paths[0] = NULL;
        diff_tree_setup_paths(paths, &diff_opts);
        if (diff_setup_done(&diff_opts) < 0)
index a21d89de97404479ecf2ca46824f61acb7af56e6..c3f198d29a4b90ee5959be750de0b764b5ea59e6 100644 (file)
@@ -109,7 +109,7 @@ static struct repo_dirent *repo_read_dirent(uint32_t revision,
 static void repo_write_dirent(const uint32_t *path, uint32_t mode,
                              uint32_t content_offset, uint32_t del)
 {
-       uint32_t name, revision, dir_o = ~0, parent_dir_o = ~0;
+       uint32_t name, revision, dir_o = ~0U, parent_dir_o = ~0U;
        struct repo_dir *dir;
        struct repo_dirent *key;
        struct repo_dirent *dent = NULL;
index 8af8d54d6ef41a2e84e500bd0d1a5523e59f8a32..1b63b19a383c570f69b9456c66170e592c49d9ba 100644 (file)
@@ -8,7 +8,7 @@
 #include "obj_pool.h"
 #include "string_pool.h"
 
-static struct trp_root tree = { ~0 };
+static struct trp_root tree = { ~0U };
 
 struct node {
        uint32_t offset;
@@ -78,7 +78,7 @@ void pool_print_seq(uint32_t len, uint32_t *seq, char delim, FILE *stream)
 uint32_t pool_tok_seq(uint32_t sz, uint32_t *seq, const char *delim, char *str)
 {
        char *context = NULL;
-       uint32_t token = ~0;
+       uint32_t token = ~0U;
        uint32_t length;
 
        if (sz == 0)