Merge branch 'ph/parseopt'
authorShawn O. Pearce <spearce@spearce.org>
Thu, 9 Oct 2008 17:19:08 +0000 (10:19 -0700)
committerShawn O. Pearce <spearce@spearce.org>
Thu, 9 Oct 2008 17:19:08 +0000 (10:19 -0700)
* ph/parseopt:
parse-opt: migrate builtin-merge-file.
parse-opt: migrate git-merge-base.
parse-opt: migrate fmt-merge-msg.

35 files changed:
Documentation/RelNotes-1.6.0.3.txt
Documentation/git-grep.txt
Documentation/git-prune.txt
Documentation/git-push.txt
Documentation/githooks.txt
Makefile
builtin-apply.c
builtin-blame.c
builtin-checkout.c
builtin-grep.c
builtin-init-db.c
builtin-merge.c
builtin-pack-objects.c
builtin-prune.c
builtin-push.c
builtin-reset.c
builtin-rm.c
builtin-unpack-objects.c
contrib/completion/git-completion.bash
diff.c
git-rebase--interactive.sh
git-rebase.sh
git-stash.sh
grep.c
grep.h
index-pack.c
merge-tree.c
remote.c
setup.c
sha1_file.c
t/t0001-init.sh
t/t3409-rebase-hook.sh [new file with mode: 0755]
t/t3600-rm.sh
t/t4012-diff-binary.sh
transport.c
index 46e13a450afae63226a89543369fc6396436a042..6cf8ae4ea1423d3dce3522890a666a424d163fb7 100644 (file)
@@ -13,33 +13,83 @@ Fixes since v1.6.0.2
 * Continuing "git rebase -i" was also very confused when the user left
   some staged changes in the index after "edit".
 
+* "git rebase -i" now honors the pre-rebase hook, just like the
+  other rebase implementations "git rebase" and "git rebase -m".
+
 * Behaviour of "git diff --quiet" was inconsistent with "diff --exit-code"
   with the output redirected to /dev/null.
 
+* "git diff --no-index" on binary files no longer outputs a bogus
+  "diff --git" header line.
+
+* Hunk headers in "git diff" default to using extended regular
+  expressions, fixing some of the internal patterns on non-GNU
+  platforms.
+
+* New config "diff.*.xfuncname" exposes extended regular expressions
+  for user specified hunk header patterns.
+
 * "git stash apply sash@{1}" was fixed to error out.  Prior versions
   would have applied stash@{0} incorrectly.
 
+* "git stash apply" now offers a better suggestion on how to continue
+  if the working tree is currently dirty.
+
 * "git for-each-ref --format=%(subject)" fixed for commits with no
   no newline in the message body.
 
 * "git remote" fixed to protect printf from user input.
 
+* "git remote show -v" now displays all URLs of a remote.
+
 * "git checkout -q" once again suppresses the locally modified file list.
 
+* "git clone -q", "git fetch -q" asks remote side to not send
+  progress messages, actually making their output quiet.
+
 * Cross-directory renames are no longer used when creating packs.  This
   allows more graceful behavior on filesystems like sshfs.
 
 * Stale temporary files under $GIT_DIR/objects/pack are now cleaned up
   automatically by "git prune".
 
+* "git merge" once again removes directories after the last file has
+  been removed from it during the merge.
+
+* "git blame -C -C" no longer segfaults while trying to pass blame if
+   it encounters a submodule reference.
+
+* "git svn" fixed to display an error message when 'set-tree' failed,
+   instead of a Perl compile error.
+
+* "git submodule" fixed to handle checking out a different commit
+  than HEAD after initializing the submodule.
+
+* The "git commit" error message when there are still unmerged
+  files present was clarified to match "git write-tree".
+
+* Some segfaults due to uncaught NULL pointers were fixed in multiple
+  tools such as apply, reset, update-index.
+
+* Solaris builds now default to OLD_ICONV=1 to avoid compile warnings.
+
 * "Git.pm" tests relied on unnecessarily more recent version of Perl.
 
 * "gitweb" triggered undef warning on commits without log messages.
 
+* "gitweb" triggered undef warnings on missing trees.
+
+* "gitweb" now removes PATH_INFO from its URLs so users don't have
+  to manually set the URL in the gitweb configuration.
+
+* Bash completion removed support for legacy "git-fetch", "git-push"
+  and "git-pull" as these are no longer installed.  Dashless form
+  ("git fetch") is still however supported.
+
 Many other documentation updates.
 
 --
 exec >/var/tmp/1
-O=v1.6.0.2-41-g7fe4a72
+O=v1.6.0.2-76-gd70b4a8
 echo O=$(git describe maint)
 git shortlog --no-merges $O..maint
index fa4d133c1bccc088d3c8da65bce4e15cafd394aa..553da6cbb1777a94cb3d6b48dc77c445e18ca2b0 100644 (file)
@@ -15,6 +15,7 @@ SYNOPSIS
           [-E | --extended-regexp] [-G | --basic-regexp]
           [-F | --fixed-strings] [-n]
           [-l | --files-with-matches] [-L | --files-without-match]
+          [-z | --null]
           [-c | --count] [--all-match]
           [-A <post-context>] [-B <pre-context>] [-C <context>]
           [-f <file>] [-e] <pattern>
@@ -94,6 +95,11 @@ OPTIONS
        For better compatibility with 'git-diff', --name-only is a
        synonym for --files-with-matches.
 
+-z::
+--null::
+       Output \0 instead of the character that normally follows a
+       file name.
+
 -c::
 --count::
        Instead of showing every matched line, show the number of
index 54f1dab38de9e01d8452753ac6028875b91d5f6b..da6055d4b8cf78aff16fa553e684b0b3ed57138e 100644 (file)
@@ -8,7 +8,7 @@ git-prune - Prune all unreachable objects from the object database
 
 SYNOPSIS
 --------
-'git-prune' [-n] [--expire <expire>] [--] [<head>...]
+'git-prune' [-n] [-v] [--expire <expire>] [--] [<head>...]
 
 DESCRIPTION
 -----------
@@ -34,6 +34,9 @@ OPTIONS
        Do not remove anything; just report what it would
        remove.
 
+-v::
+       Report all removed objects.
+
 \--::
        Do not interpret any more arguments as options.
 
index 45c96435fa66ab4b1b57b6a860a2fc264321cfe4..6150b1b959e17655a2875d39ec3b70449684a0eb 100644 (file)
@@ -9,8 +9,8 @@ git-push - Update remote refs along with associated objects
 SYNOPSIS
 --------
 [verse]
-'git push' [--all] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>]
-          [--repo=all] [-f | --force] [-v | --verbose]
+'git push' [--all | --mirror] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>]
+          [--repo=<repository>] [-f | --force] [-v | --verbose]
           [<repository> <refspec>...]
 
 DESCRIPTION
@@ -101,9 +101,23 @@ nor in any Push line of the corresponding remotes file---see below).
        This flag disables the check.  This can cause the
        remote repository to lose commits; use it with care.
 
---repo=<repo>::
-       When no repository is specified the command defaults to
-       "origin"; this overrides it.
+--repo=<repository>::
+       This option is only relevant if no <repository> argument is
+       passed in the invocation. In this case, 'git-push' derives the
+       remote name from the current branch: If it tracks a remote
+       branch, then that remote repository is pushed to. Otherwise,
+       the name "origin" is used. For this latter case, this option
+       can be used to override the name "origin". In other words,
+       the difference between these two commands
++
+--------------------------
+git push public         #1
+git push --repo=public  #2
+--------------------------
++
+is that #1 always pushes to "public" whereas #2 pushes to "public"
+only if the current branch does not track a remote branch. This is
+useful if you write an alias or script around 'git-push'.
 
 --thin::
 --no-thin::
index 7fefdb1f453720381b4038f773d8686dd41d7b0c..5faaaa5fedcd0d61234d3927a89d77144f2a15ad 100644 (file)
@@ -130,6 +130,13 @@ parameter, and is invoked after a commit is made.
 This hook is meant primarily for notification, and cannot affect
 the outcome of 'git-commit'.
 
+pre-rebase
+----------
+
+This hook is called by 'git-rebase' and can be used to prevent a branch
+from getting rebased.
+
+
 post-checkout
 -----------
 
index 15ca6599a7b665d5d4888c00b0fecd7bbde28879..dd31e339fb8d28baaaba78ea09518de0171d35a5 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -650,7 +650,6 @@ ifeq ($(uname_S),SunOS)
        NO_MKDTEMP = YesPlease
        OLD_ICONV = UnfortunatelyYes
        ifeq ($(uname_R),5.8)
-               NEEDS_LIBICONV = YesPlease
                NO_UNSETENV = YesPlease
                NO_SETENV = YesPlease
                NO_C99_FORMAT = YesPlease
index e2c611bf964d8cd589171f74e5ccce5aeb392643..bf806105062caa47ca168720e0e987ac8957c8af 100644 (file)
@@ -1697,7 +1697,7 @@ static int match_fragment(struct image *img,
                fixlen = ws_fix_copy(buf, orig, oldlen, ws_rule, NULL);
 
                /* Try fixing the line in the target */
-               if (sizeof(tgtfixbuf) < tgtlen)
+               if (sizeof(tgtfixbuf) > tgtlen)
                        tgtfix = tgtfixbuf;
                else
                        tgtfix = xmalloc(tgtlen);
@@ -2586,6 +2586,8 @@ static void build_fake_ancestor(struct patch *list, const char *filename)
                        sha1_ptr = sha1;
 
                ce = make_cache_entry(patch->old_mode, sha1_ptr, name, 0, 0);
+               if (!ce)
+                       die("make_cache_entry failed for path '%s'", name);
                if (add_index_entry(&result, ce, ADD_CACHE_OK_TO_ADD))
                        die ("Could not add %s to temporary index", name);
        }
index 6b7b9f4466989ca02d3a5e53caac9ff5c7e8a922..df537593d052f0b4d705eb1d0d19ed296f76a39d 100644 (file)
@@ -1132,6 +1132,8 @@ static int find_copy_in_parent(struct scoreboard *sb,
 
                        if (!DIFF_FILE_VALID(p->one))
                                continue; /* does not exist in parent */
+                       if (S_ISGITLINK(p->one->mode))
+                               continue; /* ignore git links */
                        if (porigin && !strcmp(p->one->path, porigin->path))
                                /* find_move already dealt with this path */
                                continue;
index b572b3bf69c791912717eae313942316cd77ac37..3762f71aaeae623b37d38c5c03b7a0d10973efc4 100644 (file)
@@ -206,6 +206,8 @@ static int checkout_merged(int pos, struct checkout *state)
        ce = make_cache_entry(create_ce_mode(active_cache[pos+1]->ce_mode),
                              sha1,
                              path, 2, 0);
+       if (!ce)
+               die("make_cache_entry failed for path '%s'", path);
        status = checkout_entry(ce, state, NULL);
        return status;
 }
index 3a51662a35878ae6b5965c90abb747b5b27c5493..624f86e287cf6304d122850f8258444c5f916702 100644 (file)
@@ -295,6 +295,9 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)
                push_arg("-l");
        if (opt->unmatch_name_only)
                push_arg("-L");
+       if (opt->null_following_name)
+               /* in GNU grep git's "-z" translates to "-Z" */
+               push_arg("-Z");
        if (opt->count)
                push_arg("-c");
        if (opt->post_context || opt->pre_context) {
@@ -599,6 +602,11 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                        opt.unmatch_name_only = 1;
                        continue;
                }
+               if (!strcmp("-z", arg) ||
+                   !strcmp("--null", arg)) {
+                       opt.null_following_name = 1;
+                       continue;
+               }
                if (!strcmp("-c", arg) ||
                    !strcmp("--count", arg)) {
                        opt.count = 1;
index 8140c1299afe368266de1153f3bb891f000fe5f5..d30c3fe2ca542b061ab8b7a7696cdd5416e17147 100644 (file)
@@ -17,6 +17,9 @@
 #define TEST_FILEMODE 1
 #endif
 
+static int init_is_bare_repository = 0;
+static int init_shared_repository = -1;
+
 static void safe_create_dir(const char *dir, int share)
 {
        if (mkdir(dir, 0777) < 0) {
@@ -191,6 +194,9 @@ static int create_default_files(const char *template_path)
        copy_templates(template_path);
 
        git_config(git_default_config, NULL);
+       is_bare_repository_cfg = init_is_bare_repository;
+       if (init_shared_repository != -1)
+               shared_repository = init_shared_repository;
 
        /*
         * We would have created the above under user's umask -- under
@@ -277,6 +283,8 @@ int init_db(const char *template_dir, unsigned int flags)
 
        safe_create_dir(get_git_dir(), 0);
 
+       init_is_bare_repository = is_bare_repository();
+
        /* Check to see if the repository version is right.
         * Note that a newly created repository does not have
         * config file, so this will not fail.  What we are catching
@@ -381,9 +389,9 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
                        setenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir,
                                                sizeof(git_dir)), 0);
                } else if (!strcmp(arg, "--shared"))
-                       shared_repository = PERM_GROUP;
+                       init_shared_repository = PERM_GROUP;
                else if (!prefixcmp(arg, "--shared="))
-                       shared_repository = git_config_perm("arg", arg+9);
+                       init_shared_repository = git_config_perm("arg", arg+9);
                else if (!strcmp(arg, "-q") || !strcmp(arg, "--quiet"))
                        flags |= INIT_DB_QUIET;
                else
index 5c65a5869900ad1a1014fb3aad88c874a5410bf7..fa7c95472c984b0a8325aa61a75137c0a8c1e36e 100644 (file)
@@ -123,8 +123,7 @@ static struct strategy *get_strategy(const char *name)
                exit(1);
        }
 
-       ret = xmalloc(sizeof(struct strategy));
-       memset(ret, 0, sizeof(struct strategy));
+       ret = xcalloc(1, sizeof(struct strategy));
        ret->name = xstrdup(name);
        return ret;
 }
@@ -723,12 +722,12 @@ static void add_strategies(const char *string, unsigned attr)
 static int merge_trivial(void)
 {
        unsigned char result_tree[20], result_commit[20];
-       struct commit_list *parent = xmalloc(sizeof(struct commit_list *));
+       struct commit_list *parent = xmalloc(sizeof(*parent));
 
        write_tree_trivial(result_tree);
        printf("Wonderful.\n");
        parent->item = lookup_commit(head);
-       parent->next = xmalloc(sizeof(struct commit_list *));
+       parent->next = xmalloc(sizeof(*parent->next));
        parent->next->item = remoteheads->item;
        parent->next->next = NULL;
        commit_tree(merge_msg.buf, result_tree, parent, result_commit, NULL);
index 1158e42cba81e2bdb8640cd6c5a3835453d17e7f..59c30d1caa37416041177ff4aaf01b67f4e8add4 100644 (file)
@@ -1369,12 +1369,10 @@ static void find_deltas(struct object_entry **list, unsigned *list_size,
                        int window, int depth, unsigned *processed)
 {
        uint32_t i, idx = 0, count = 0;
-       unsigned int array_size = window * sizeof(struct unpacked);
        struct unpacked *array;
        unsigned long mem_usage = 0;
 
-       array = xmalloc(array_size);
-       memset(array, 0, array_size);
+       array = xcalloc(window, sizeof(struct unpacked));
 
        for (;;) {
                struct object_entry *entry = *list++;
index 1663f8bdb1e27713bab6cf7a16ca15cfcfc1abef..7b4ec80e62997fe70f53c92380cd4d66e80d62a0 100644 (file)
@@ -7,10 +7,11 @@
 #include "parse-options.h"
 
 static const char * const prune_usage[] = {
-       "git prune [-n] [--expire <time>] [--] [<head>...]",
+       "git prune [-n] [-v] [--expire <time>] [--] [<head>...]",
        NULL
 };
 static int show_only;
+static int verbose;
 static unsigned long expire;
 
 static int prune_tmp_object(const char *path, const char *filename)
@@ -39,11 +40,12 @@ static int prune_object(char *path, const char *filename, const unsigned char *s
                if (st.st_mtime > expire)
                        return 0;
        }
-       if (show_only) {
+       if (show_only || verbose) {
                enum object_type type = sha1_object_info(sha1, NULL);
                printf("%s %s\n", sha1_to_hex(sha1),
                       (type > 0) ? typename(type) : "unknown");
-       } else
+       }
+       if (!show_only)
                unlink(fullpath);
        return 0;
 }
@@ -135,6 +137,8 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
        const struct option options[] = {
                OPT_BOOLEAN('n', NULL, &show_only,
                            "do not remove, show only"),
+               OPT_BOOLEAN('v', NULL, &verbose,
+                       "report pruned objects"),
                OPT_DATE(0, "expire", &expire,
                         "expire objects older than <time>"),
                OPT_END()
index cc6666f75e7db8a546d4a1589335589190e414fe..122fdcfbdc13a11388a091e5ec33d077648fab0a 100644 (file)
@@ -10,7 +10,7 @@
 #include "parse-options.h"
 
 static const char * const push_usage[] = {
-       "git push [--all | --mirror] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]",
+       "git push [--all | --mirror] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=<repository>] [-f | --force] [-v] [<repository> <refspec>...]",
        NULL,
 };
 
index c24c21909194014b467c86fd3598796e7db576b3..16e6bb20f1af6a7a684a747b3c0cc26ceabe8ce7 100644 (file)
@@ -121,6 +121,9 @@ static void update_index_from_diff(struct diff_queue_struct *q,
                        struct cache_entry *ce;
                        ce = make_cache_entry(one->mode, one->sha1, one->path,
                                0, 0);
+                       if (!ce)
+                               die("make_cache_entry failed for path '%s'",
+                                   one->path);
                        add_cache_entry(ce, ADD_CACHE_OK_TO_ADD |
                                ADD_CACHE_OK_TO_REPLACE);
                } else
index 50ae6d54011fad89387f0d56ce7a4591d07874f3..e06640cf8d3418cbbe177b8fdcdccd19e0f3379f 100644 (file)
@@ -137,6 +137,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
 
        if (read_cache() < 0)
                die("index file corrupt");
+       refresh_cache(REFRESH_QUIET);
 
        pathspec = get_pathspec(prefix, argv);
        seen = NULL;
index d2796b6309d3b13a6c401b502aafd53d684328d8..9f4bdd3296d19b75211ca0f2434d227eafac44b6 100644 (file)
@@ -477,8 +477,7 @@ static void unpack_all(void)
 
        if (!quiet)
                progress = start_progress("Unpacking objects", nr_objects);
-       obj_list = xmalloc(nr_objects * sizeof(*obj_list));
-       memset(obj_list, 0, nr_objects * sizeof(*obj_list));
+       obj_list = xcalloc(nr_objects, sizeof(*obj_list));
        for (i = 0; i < nr_objects; i++) {
                unpack_one(i);
                display_progress(progress, i + 1);
index 93f088189e6b65e03eddea9013273f0559837d26..15073d4c9fbccb06e9b17dff4a8d134e805aed6d 100755 (executable)
@@ -785,14 +785,9 @@ _git_fetch ()
 {
        local cur="${COMP_WORDS[COMP_CWORD]}"
 
-       case "${COMP_WORDS[0]},$COMP_CWORD" in
-       git-fetch*,1)
+       if [ "$COMP_CWORD" = 2 ]; then
                __gitcomp "$(__git_remotes)"
-               ;;
-       git,2)
-               __gitcomp "$(__git_remotes)"
-               ;;
-       *)
+       else
                case "$cur" in
                *:*)
                        local pfx=""
@@ -811,8 +806,7 @@ _git_fetch ()
                        __gitcomp "$(__git_refs2 "$remote")"
                        ;;
                esac
-               ;;
-       esac
+       fi
 }
 
 _git_format_patch ()
@@ -1049,36 +1043,25 @@ _git_pull ()
 {
        local cur="${COMP_WORDS[COMP_CWORD]}"
 
-       case "${COMP_WORDS[0]},$COMP_CWORD" in
-       git-pull*,1)
-               __gitcomp "$(__git_remotes)"
-               ;;
-       git,2)
+       if [ "$COMP_CWORD" = 2 ]; then
                __gitcomp "$(__git_remotes)"
-               ;;
-       *)
+       else
                local remote
                case "${COMP_WORDS[0]}" in
                git-pull)  remote="${COMP_WORDS[1]}" ;;
                git)       remote="${COMP_WORDS[2]}" ;;
                esac
                __gitcomp "$(__git_refs "$remote")"
-               ;;
-       esac
+       fi
 }
 
 _git_push ()
 {
        local cur="${COMP_WORDS[COMP_CWORD]}"
 
-       case "${COMP_WORDS[0]},$COMP_CWORD" in
-       git-push*,1)
-               __gitcomp "$(__git_remotes)"
-               ;;
-       git,2)
+       if [ "$COMP_CWORD" = 2 ]; then
                __gitcomp "$(__git_remotes)"
-               ;;
-       *)
+       else
                case "$cur" in
                *:*)
                        local remote
@@ -1102,8 +1085,7 @@ _git_push ()
                        __gitcomp "$(__git_refs)"
                        ;;
                esac
-               ;;
-       esac
+       fi
 }
 
 _git_rebase ()
diff --git a/diff.c b/diff.c
index 4e4e439e03f13a2bd9aaf63179ce50e4b72ed48e..02e948c9dd6244a0003c2c6bc81f55e46cf0ad2b 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -1509,6 +1509,10 @@ static void builtin_diff(const char *name_a,
                b_prefix = o->b_prefix;
        }
 
+       /* Never use a non-valid filename anywhere if at all possible */
+       name_a = DIFF_FILE_VALID(one) ? name_a : name_b;
+       name_b = DIFF_FILE_VALID(two) ? name_b : name_a;
+
        a_one = quote_two(a_prefix, name_a + (*name_a == '/'));
        b_two = quote_two(b_prefix, name_b + (*name_b == '/'));
        lbl[0] = DIFF_FILE_VALID(one) ? a_one : "/dev/null";
index edb6ec6ed00b74764764802d0ebae56d223a2ac6..bdec43c3f604b22d29b52bd6a026785a6ac0f21b 100755 (executable)
@@ -65,6 +65,16 @@ output () {
        esac
 }
 
+run_pre_rebase_hook () {
+       if test -x "$GIT_DIR/hooks/pre-rebase"
+       then
+               "$GIT_DIR/hooks/pre-rebase" ${1+"$@"} || {
+                       echo >&2 "The pre-rebase hook refused to rebase."
+                       exit 1
+               }
+       fi
+}
+
 require_clean_work_tree () {
        # test if working tree is dirty
        git rev-parse --verify HEAD > /dev/null &&
@@ -304,23 +314,28 @@ do_next () {
 
                mark_action_done
                make_squash_message $sha1 > "$MSG"
+               failed=f
+               author_script=$(get_author_ident_from_commit HEAD)
+               output git reset --soft HEAD^
+               pick_one -n $sha1 || failed=t
                case "$(peek_next_command)" in
                squash|s)
                        EDIT_COMMIT=
                        USE_OUTPUT=output
+                       MSG_OPT=-F
+                       MSG_FILE="$MSG"
                        cp "$MSG" "$SQUASH_MSG"
                        ;;
                *)
                        EDIT_COMMIT=-e
                        USE_OUTPUT=
+                       MSG_OPT=
+                       MSG_FILE=
                        rm -f "$SQUASH_MSG" || exit
+                       cp "$MSG" "$GIT_DIR"/SQUASH_MSG
+                       rm -f "$GIT_DIR"/MERGE_MSG || exit
                        ;;
                esac
-
-               failed=f
-               author_script=$(get_author_ident_from_commit HEAD)
-               output git reset --soft HEAD^
-               pick_one -n $sha1 || failed=t
                echo "$author_script" > "$DOTEST"/author-script
                if test $failed = f
                then
@@ -329,7 +344,7 @@ do_next () {
                        GIT_AUTHOR_NAME="$GIT_AUTHOR_NAME" \
                        GIT_AUTHOR_EMAIL="$GIT_AUTHOR_EMAIL" \
                        GIT_AUTHOR_DATE="$GIT_AUTHOR_DATE" \
-                       $USE_OUTPUT git commit --no-verify -F "$MSG" $EDIT_COMMIT || failed=t
+                       $USE_OUTPUT git commit --no-verify $MSG_OPT "$MSG_FILE" $EDIT_COMMIT || failed=t
                fi
                if test $failed = t
                then
@@ -507,6 +522,7 @@ first and then run 'git rebase --continue' again."
                ;;
        --)
                shift
+               run_pre_rebase_hook ${1+"$@"}
                test $# -eq 1 -o $# -eq 2 || usage
                test -d "$DOTEST" &&
                        die "Interactive rebase already started"
index 528b604cd57a774030c5f5830d3d78b5a04454cf..a30d40c0056dc32aa6123adc9856e649c469fcd0 100755 (executable)
@@ -144,6 +144,16 @@ is_interactive () {
        done && test -n "$1"
 }
 
+run_pre_rebase_hook () {
+       if test -x "$GIT_DIR/hooks/pre-rebase"
+       then
+               "$GIT_DIR/hooks/pre-rebase" ${1+"$@"} || {
+                       echo >&2 "The pre-rebase hook refused to rebase."
+                       exit 1
+               }
+       fi
+}
+
 test -f "$GIT_DIR"/rebase-apply/applying &&
        die 'It looks like git-am is in progress. Cannot rebase.'
 
@@ -320,13 +330,7 @@ onto_name=${newbase-"$upstream_name"}
 onto=$(git rev-parse --verify "${onto_name}^0") || exit
 
 # If a hook exists, give it a chance to interrupt
-if test -x "$GIT_DIR/hooks/pre-rebase"
-then
-       "$GIT_DIR/hooks/pre-rebase" ${1+"$@"} || {
-               echo >&2 "The pre-rebase hook refused to rebase."
-               exit 1
-       }
-fi
+run_pre_rebase_hook ${1+"$@"}
 
 # If the branch to rebase is given, that is the branch we will rebase
 # $branch_name -- branch being rebased, or HEAD (already detached)
index 42f626f9d555f26f3e50441c0ab27de5cac19bf4..b9ace9970492aaf48472904d978d809d90ca33db 100755 (executable)
@@ -145,16 +145,8 @@ show_stash () {
                flags=--stat
        fi
 
-       if test $# = 0
-       then
-               set x "$ref_stash@{0}"
-               shift
-       fi
-
-       s=$(git rev-parse --revs-only --no-flags "$@")
-
-       w_commit=$(git rev-parse --verify "$s") &&
-       b_commit=$(git rev-parse --verify "$s^") &&
+       w_commit=$(git rev-parse --verify --default $ref_stash "$@") &&
+       b_commit=$(git rev-parse --verify "$w_commit^") &&
        git diff $flags $b_commit $w_commit
 }
 
@@ -170,19 +162,13 @@ apply_stash () {
                shift
        esac
 
-       if test $# = 0
-       then
-               set x "$ref_stash@{0}"
-               shift
-       fi
-
        # current index state
        c_tree=$(git write-tree) ||
                die 'Cannot apply a stash in the middle of a merge'
 
        # stash records the work tree, and is a merge between the
        # base commit (first parent) and the index tree (second parent).
-       s=$(git rev-parse --revs-only --no-flags "$@") &&
+       s=$(git rev-parse --verify --default $ref_stash "$@") &&
        w_tree=$(git rev-parse --verify "$s:") &&
        b_tree=$(git rev-parse --verify "$s^1:") &&
        i_tree=$(git rev-parse --verify "$s^2:") ||
@@ -242,7 +228,7 @@ drop_stash () {
                shift
        fi
        # Verify supplied argument looks like a stash entry
-       s=$(git rev-parse --revs-only --no-flags "$@") &&
+       s=$(git rev-parse --verify "$@") &&
        git rev-parse --verify "$s:"   > /dev/null 2>&1 &&
        git rev-parse --verify "$s^1:" > /dev/null 2>&1 &&
        git rev-parse --verify "$s^2:" > /dev/null 2>&1 ||
diff --git a/grep.c b/grep.c
index 706351197fc26efa10c4666d38433f8fbdf1d6b5..e2c190a7f66f9e9311f91d9a41b7dc3f295f00fb 100644 (file)
--- a/grep.c
+++ b/grep.c
@@ -239,6 +239,8 @@ static int word_char(char ch)
 static void show_line(struct grep_opt *opt, const char *bol, const char *eol,
                      const char *name, unsigned lno, char sign)
 {
+       if (opt->null_following_name)
+               sign = '\0';
        if (opt->pathname)
                printf("%s%c", name, sign);
        if (opt->linenum)
@@ -246,6 +248,11 @@ static void show_line(struct grep_opt *opt, const char *bol, const char *eol,
        printf("%.*s\n", (int)(eol-bol), bol);
 }
 
+static void show_name(struct grep_opt *opt, const char *name)
+{
+       printf("%s%c", name, opt->null_following_name ? '\0' : '\n');
+}
+
 static int fixmatch(const char *pattern, char *line, regmatch_t *match)
 {
        char *hit = strstr(line, pattern);
@@ -489,7 +496,7 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
                                return 1;
                        }
                        if (opt->name_only) {
-                               printf("%s\n", name);
+                               show_name(opt, name);
                                return 1;
                        }
                        /* Hit at this line.  If we haven't shown the
@@ -555,7 +562,7 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
                return 0;
        if (opt->unmatch_name_only) {
                /* We did not see any hit, so we want to show this */
-               printf("%s\n", name);
+               show_name(opt, name);
                return 1;
        }
 
@@ -565,7 +572,8 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
         * make it another option?  For now suppress them.
         */
        if (opt->count && count)
-               printf("%s:%u\n", name, count);
+               printf("%s%c%u\n", name,
+                      opt->null_following_name ? '\0' : ':', count);
        return !!last_hit;
 }
 
diff --git a/grep.h b/grep.h
index 59b3f871ea63619f8d3caae74c41b4da1e9a2b9f..45a222d904b5898758c3c84f6ef1e0119c81f6b2 100644 (file)
--- a/grep.h
+++ b/grep.h
@@ -74,6 +74,7 @@ struct grep_opt {
        unsigned extended:1;
        unsigned relative:1;
        unsigned pathname:1;
+       unsigned null_following_name:1;
        int regflags;
        unsigned pre_context;
        unsigned post_context;
index 2e4c0885f2c6f6907481dfefe7e0761c3957d8a6..73860bf3da062d283c266f6b83fdf3f613af26e7 100644 (file)
@@ -365,8 +365,11 @@ static void *get_data_from_pack(struct object_entry *obj)
        data = src;
        do {
                ssize_t n = pread(pack_fd, data + rdy, len - rdy, from + rdy);
-               if (n <= 0)
+               if (n < 0)
                        die("cannot pread pack file: %s", strerror(errno));
+               if (!n)
+                       die("premature end of pack file, %lu bytes missing",
+                           len - rdy);
                rdy += n;
        } while (rdy < len);
        data = xmalloc(obj->size);
index 02fc10f7e622ba1c53065e7cf4563ff10af0c41f..2d1413efbbc33c51fd4820933dcb54164e12d706 100644 (file)
@@ -158,9 +158,8 @@ static int same_entry(struct name_entry *a, struct name_entry *b)
 
 static struct merge_list *create_entry(unsigned stage, unsigned mode, const unsigned char *sha1, const char *path)
 {
-       struct merge_list *res = xmalloc(sizeof(*res));
+       struct merge_list *res = xcalloc(1, sizeof(*res));
 
-       memset(res, 0, sizeof(*res));
        res->stage = stage;
        res->path = path;
        res->mode = mode;
index c45d96e98fffe3411284144b6d836cf499d42ba4..a2d7ab146ed6627cae5c845ef4801963635bf395 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -751,8 +751,7 @@ int remote_find_tracking(struct remote *remote, struct refspec *refspec)
 
 struct ref *alloc_ref(unsigned namelen)
 {
-       struct ref *ret = xmalloc(sizeof(struct ref) + namelen);
-       memset(ret, 0, sizeof(struct ref) + namelen);
+       struct ref *ret = xcalloc(1, sizeof(struct ref) + namelen);
        return ret;
 }
 
diff --git a/setup.c b/setup.c
index 2e3248a0c4958f31001213470a88d1154b5947fc..78a8041ff0d17a5220133549880ccbc507b1890d 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -110,9 +110,7 @@ const char *prefix_path(const char *prefix, int len, const char *path)
                if (strncmp(sanitized, work_tree, len) ||
                    (sanitized[len] != '\0' && sanitized[len] != '/')) {
                error_out:
-                       error("'%s' is outside repository", orig);
-                       free(sanitized);
-                       return NULL;
+                       die("'%s' is outside repository", orig);
                }
                if (sanitized[len] == '/')
                        len++;
@@ -216,10 +214,7 @@ const char **get_pathspec(const char *prefix, const char **pathspec)
        prefixlen = prefix ? strlen(prefix) : 0;
        while (*src) {
                const char *p = prefix_path(prefix, prefixlen, *src);
-               if (p)
-                       *(dst++) = p;
-               else
-                       exit(128); /* error message already given */
+               *(dst++) = p;
                src++;
        }
        *dst = NULL;
index 751598786822950766668b4d1c97198b183586f7..ea6bd996b2953e876a02fcf972229c97cb7d590a 100644 (file)
@@ -1571,11 +1571,9 @@ static void *cache_or_unpack_entry(struct packed_git *p, off_t base_offset,
        struct delta_base_cache_entry *ent = delta_base_cache + hash;
 
        ret = ent->data;
-       if (ret && ent->p == p && ent->base_offset == base_offset)
-               goto found_cache_entry;
-       return unpack_entry(p, base_offset, type, base_size);
+       if (!ret || ent->p != p || ent->base_offset != base_offset)
+               return unpack_entry(p, base_offset, type, base_size);
 
-found_cache_entry:
        if (!keep_cache) {
                ent->data = NULL;
                ent->lru.next->prev = ent->lru.prev;
index 620da5b32041b1ad69bfdcb6d139f2705386a5ff..5ac0a273a94c033fbb7c48cb9a22e44c389e0f7d 100755 (executable)
@@ -167,4 +167,36 @@ test_expect_success 'init with --template (blank)' '
        ! test -f template-blank/.git/info/exclude
 '
 
+test_expect_success 'init --bare/--shared overrides system/global config' '
+       (
+               HOME="`pwd`" &&
+               export HOME &&
+               test_config="$HOME"/.gitconfig &&
+               unset GIT_CONFIG_NOGLOBAL &&
+               git config -f "$test_config" core.bare false &&
+               git config -f "$test_config" core.sharedRepository 0640 &&
+               mkdir init-bare-shared-override &&
+               cd init-bare-shared-override &&
+               git init --bare --shared=0666
+       ) &&
+       check_config init-bare-shared-override true unset &&
+       test x0666 = \
+       x`git config -f init-bare-shared-override/config core.sharedRepository`
+'
+
+test_expect_success 'init honors global core.sharedRepository' '
+       (
+               HOME="`pwd`" &&
+               export HOME &&
+               test_config="$HOME"/.gitconfig &&
+               unset GIT_CONFIG_NOGLOBAL &&
+               git config -f "$test_config" core.sharedRepository 0666 &&
+               mkdir shared-honor-global &&
+               cd shared-honor-global &&
+               git init
+       ) &&
+       test x0666 = \
+       x`git config -f shared-honor-global/.git/config core.sharedRepository`
+'
+
 test_done
diff --git a/t/t3409-rebase-hook.sh b/t/t3409-rebase-hook.sh
new file mode 100755 (executable)
index 0000000..bc93dda
--- /dev/null
@@ -0,0 +1,126 @@
+#!/bin/sh
+
+test_description='git rebase with its hook(s)'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+       echo hello >file &&
+       git add file &&
+       test_tick &&
+       git commit -m initial &&
+       echo goodbye >file &&
+       git add file &&
+       test_tick &&
+       git commit -m second &&
+       git checkout -b side HEAD^ &&
+       echo world >git &&
+       git add git &&
+       test_tick &&
+       git commit -m side &&
+       git checkout master &&
+       git log --pretty=oneline --abbrev-commit --graph --all &&
+       git branch test side
+'
+
+test_expect_success 'rebase' '
+       git checkout test &&
+       git reset --hard side &&
+       git rebase master &&
+       test "z$(cat git)" = zworld
+'
+
+test_expect_success 'rebase -i' '
+       git checkout test &&
+       git reset --hard side &&
+       EDITOR=true git rebase -i master &&
+       test "z$(cat git)" = zworld
+'
+
+test_expect_success 'setup pre-rebase hook' '
+       mkdir -p .git/hooks &&
+       cat >.git/hooks/pre-rebase <<EOF &&
+#!$SHELL_PATH
+echo "\$1,\$2" >.git/PRE-REBASE-INPUT
+EOF
+       chmod +x .git/hooks/pre-rebase
+'
+
+test_expect_success 'pre-rebase hook gets correct input (1)' '
+       git checkout test &&
+       git reset --hard side &&
+       git rebase master &&
+       test "z$(cat git)" = zworld &&
+       test "z$(cat .git/PRE-REBASE-INPUT)" = zmaster,
+
+'
+
+test_expect_success 'pre-rebase hook gets correct input (2)' '
+       git checkout test &&
+       git reset --hard side &&
+       git rebase master test &&
+       test "z$(cat git)" = zworld &&
+       test "z$(cat .git/PRE-REBASE-INPUT)" = zmaster,test
+'
+
+test_expect_success 'pre-rebase hook gets correct input (3)' '
+       git checkout test &&
+       git reset --hard side &&
+       git checkout master &&
+       git rebase master test &&
+       test "z$(cat git)" = zworld &&
+       test "z$(cat .git/PRE-REBASE-INPUT)" = zmaster,test
+'
+
+test_expect_success 'pre-rebase hook gets correct input (4)' '
+       git checkout test &&
+       git reset --hard side &&
+       EDITOR=true git rebase -i master &&
+       test "z$(cat git)" = zworld &&
+       test "z$(cat .git/PRE-REBASE-INPUT)" = zmaster,
+
+'
+
+test_expect_success 'pre-rebase hook gets correct input (5)' '
+       git checkout test &&
+       git reset --hard side &&
+       EDITOR=true git rebase -i master test &&
+       test "z$(cat git)" = zworld &&
+       test "z$(cat .git/PRE-REBASE-INPUT)" = zmaster,test
+'
+
+test_expect_success 'pre-rebase hook gets correct input (6)' '
+       git checkout test &&
+       git reset --hard side &&
+       git checkout master &&
+       EDITOR=true git rebase -i master test &&
+       test "z$(cat git)" = zworld &&
+       test "z$(cat .git/PRE-REBASE-INPUT)" = zmaster,test
+'
+
+test_expect_success 'setup pre-rebase hook that fails' '
+       mkdir -p .git/hooks &&
+       cat >.git/hooks/pre-rebase <<EOF &&
+#!$SHELL_PATH
+false
+EOF
+       chmod +x .git/hooks/pre-rebase
+'
+
+test_expect_success 'pre-rebase hook stops rebase (1)' '
+       git checkout test &&
+       git reset --hard side &&
+       test_must_fail git rebase master &&
+       test "z$(git symbolic-ref HEAD)" = zrefs/heads/test &&
+       test 0 = $(git rev-list HEAD...side | wc -l)
+'
+
+test_expect_success 'pre-rebase hook stops rebase (2)' '
+       git checkout test &&
+       git reset --hard side &&
+       EDITOR=true test_must_fail git rebase -i master &&
+       test "z$(git symbolic-ref HEAD)" = zrefs/heads/test &&
+       test 0 = $(git rev-list HEAD...side | wc -l)
+'
+
+test_done
index 558c80edbfa5c0c90566a0be94723e2783d6df9b..66aca99fd32c6b98f5e6e34a3cf7b096b3e236cf 100755 (executable)
@@ -219,14 +219,23 @@ test_expect_success 'Remove nonexistent file returns nonzero exit status' '
 
 test_expect_success 'Call "rm" from outside the work tree' '
        mkdir repo &&
-       cd repo &&
-       git init &&
-       echo something > somefile &&
-       git add somefile &&
-       git commit -m "add a file" &&
-       (cd .. &&
-        git --git-dir=repo/.git --work-tree=repo rm somefile) &&
-       test_must_fail git ls-files --error-unmatch somefile
+       (cd repo &&
+        git init &&
+        echo something > somefile &&
+        git add somefile &&
+        git commit -m "add a file" &&
+        (cd .. &&
+         git --git-dir=repo/.git --work-tree=repo rm somefile) &&
+       test_must_fail git ls-files --error-unmatch somefile)
+'
+
+test_expect_success 'refresh index before checking if it is up-to-date' '
+
+       git reset --hard &&
+       test-chmtime -86400 frotz/nitfol &&
+       git rm frotz/nitfol &&
+       test ! -f frotz/nitfol
+
 '
 
 test_done
index b8ec6e90afb970b1b2540e30901b2f058522544e..421f4bba3fbc666cf2ab7ec4289f10d29d61eebb 100755 (executable)
@@ -77,4 +77,25 @@ test_expect_success 'apply binary patch' \
         tree1=`git write-tree` &&
         test "$tree1" = "$tree0"'
 
+q_to_nul() {
+       perl -pe 'y/Q/\000/'
+}
+
+nul_to_q() {
+       perl -pe 'y/\000/Q/'
+}
+
+test_expect_success 'diff --no-index with binary creation' '
+       echo Q | q_to_nul >binary &&
+       (:# hide error code from diff, which just indicates differences
+        git diff --binary --no-index /dev/null binary >current ||
+        true
+       ) &&
+       rm binary &&
+       git apply --binary <current &&
+       echo Q >expected &&
+       nul_to_q <binary >actual &&
+       test_cmp expected actual
+'
+
 test_done
index f7db5d91103c09a8cdc9bdbd27de4b0d4a15ea73..5110c56c4e80dc224ff3308e643fad6d5ed77ffb 100644 (file)
@@ -643,8 +643,8 @@ static int fetch_refs_via_pack(struct transport *transport,
        args.use_thin_pack = data->thin;
        args.include_tag = data->followtags;
        args.verbose = (transport->verbose > 0);
-       args.quiet = args.no_progress = (transport->verbose < 0);
-       args.no_progress = !isatty(1);
+       args.quiet = (transport->verbose < 0);
+       args.no_progress = args.quiet || !isatty(1);
        args.depth = data->depth;
 
        for (i = 0; i < nr_heads; i++)