Merge branch 'nd/fsck-progress'
authorJunio C Hamano <gitster@pobox.com>
Mon, 5 Dec 2011 23:11:07 +0000 (15:11 -0800)
committerJunio C Hamano <gitster@pobox.com>
Mon, 5 Dec 2011 23:11:07 +0000 (15:11 -0800)
* nd/fsck-progress:
fsck: print progress
fsck: avoid reading every object twice
verify_packfile(): check as many object as possible in a pack
fsck: return error code when verify_pack() goes wrong

62 files changed:
Documentation/Makefile
Documentation/RelNotes/1.7.7.3.txt [new file with mode: 0644]
Documentation/RelNotes/1.7.7.4.txt [new file with mode: 0644]
Documentation/RelNotes/1.7.8.txt
Documentation/diff-options.txt
Documentation/git-cherry-pick.txt
Documentation/git-difftool.txt
Documentation/git-reset.txt
Documentation/git-revert.txt
Documentation/git.txt
Documentation/install-doc-quick.sh
Documentation/merge-options.txt
Documentation/sequencer.txt
GIT-VERSION-GEN
INSTALL
Makefile
branch.c
builtin/archive.c
builtin/blame.c
builtin/branch.c
builtin/commit.c
builtin/grep.c
builtin/merge.c
builtin/mktree.c
builtin/name-rev.c
builtin/pack-objects.c
builtin/remote.c
builtin/revert.c
builtin/stripspace.c
builtin/upload-archive.c
compat/mingw.h
config.c
contrib/completion/git-completion.bash
contrib/fast-import/git-p4
contrib/fast-import/git-p4.txt
convert.c
dir.c
git-compat-util.h
http.c
http.h
list-objects.c
mailmap.c
notes-merge.c
perl/.gitignore
refs.c
sequencer.h
sha1_file.c
t/t3507-cherry-pick-conflict.sh
t/t3510-cherry-pick-sequence.sh
t/t5000-tar-tree.sh
t/t5501-fetch-push-alternates.sh
t/t5700-clone-reference.sh
t/t6030-bisect-porcelain.sh
t/t7106-reset-sequence.sh
t/t7508-status.sh
t/t9802-git-p4-filetype.sh
t/t9805-skip-submit-edit.sh [new file with mode: 0755]
tree-diff.c
tree-walk.c
tree-walk.h
tree.c
unpack-trees.c
index 551325604e84713c87e2e95105861626e09fbef5..304b31edee2e5c4e998c48cc571c66e8264cc581 100644 (file)
@@ -46,8 +46,8 @@ MANPAGE_XSL = manpage-normal.xsl
 XMLTO_EXTRA =
 INSTALL?=install
 RM ?= rm -f
-DOC_REF = origin/man
-HTML_REF = origin/html
+MAN_REPO = ../../git-manpages
+HTML_REPO = ../../git-htmldocs
 
 infodir?=$(prefix)/share/info
 MAKEINFO=makeinfo
@@ -327,12 +327,23 @@ $(patsubst %.txt,%.html,$(wildcard howto/*.txt)): %.html : %.txt
 install-webdoc : html
        '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(WEBDOC_DEST)
 
+# You must have a clone of git-htmldocs and git-manpages repositories
+# next to the git repository itself for the following to work.
+
 quick-install: quick-install-man
 
-quick-install-man:
-       '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(DOC_REF) $(DESTDIR)$(mandir)
+require-manrepo::
+       @if test ! -d $(MAN_REPO); \
+       then echo "git-manpages repository must exist at $(MAN_REPO)"; exit 1; fi
+
+quick-install-man: require-manrepo
+       '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(MAN_REPO) $(DESTDIR)$(mandir)
+
+require-htmlrepo::
+       @if test ! -d $(HTML_REPO); \
+       then echo "git-htmldocs repository must exist at $(HTML_REPO)"; exit 1; fi
 
-quick-install-html:
-       '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(HTML_REF) $(DESTDIR)$(htmldir)
+quick-install-html: require-htmlrepo
+       '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(HTML_REPO) $(DESTDIR)$(htmldir)
 
 .PHONY: FORCE
diff --git a/Documentation/RelNotes/1.7.7.3.txt b/Documentation/RelNotes/1.7.7.3.txt
new file mode 100644 (file)
index 0000000..09301f0
--- /dev/null
@@ -0,0 +1,19 @@
+Git v1.7.7.3 Release Notes
+==========================
+
+Fixes since v1.7.7.2
+--------------------
+
+ * Adjust the "quick-install-doc" procedures as preformatted
+   html/manpage are no longer in the source repository.
+
+ * The logic to optimize the locality of the data in a pack introduced in
+   1.7.7 was grossly inefficient.
+
+ * The logic to filter out forked projects in the project list in
+   "gitweb" was broken for some time.
+
+ * "git branch -m/-M" advertised to update RENAME_REF ref in the
+   commit log message that introduced the feature but not anywhere in
+   the documentation, and never did update such a ref anyway. This
+   undocumented misfeature that did not exist has been excised.
diff --git a/Documentation/RelNotes/1.7.7.4.txt b/Documentation/RelNotes/1.7.7.4.txt
new file mode 100644 (file)
index 0000000..e523448
--- /dev/null
@@ -0,0 +1,14 @@
+Git v1.7.7.4 Release Notes
+==========================
+
+Fixes since v1.7.7.3
+--------------------
+
+ * A few header dependencies were missing from the Makefile.
+
+ * Some newer parts of the code used C99 __VA_ARGS__ while we still
+   try to cater to older compilers.
+
+ * "git name-rev --all" tried to name all _objects_, naturally failing to
+   describe many blobs and trees, instead of showing only commits as
+   advertised in its documentation.
index f53845f693b33124bbb8f10b5569822caf8256bf..b4d90bba0f6c761e61321bb9df8b7a8b3f725272 100644 (file)
@@ -1,5 +1,5 @@
-Git v1.7.8 Release Notes (draft)
-================================
+Git v1.7.8 Release Notes
+========================
 
 Updates since v1.7.7
 --------------------
@@ -29,7 +29,7 @@ Updates since v1.7.7
    files from the index, not from the working tree.
 
  * Variants of "git cherry-pick" and "git revert" that take multiple
-   commits learned to "--continue".
+   commits learned to "--continue" and "--abort".
 
  * "git daemon" gives more human readble error messages to clients
    using ERR packets when appropriate.
@@ -113,9 +113,6 @@ Updates since v1.7.7
    between commits in the superproject that has and does not have the
    submodule in the tree without re-cloning.
 
- * "git upload-archive" (hence "git archive --remote") can be built
-   and used on mingw port of Git.
-
  * "gitweb" leaked unescaped control characters from syntax hiliter
    outputs.
 
@@ -139,11 +136,9 @@ included in this release.
    credentials.
    (merge deba493 jk/http-auth later to maint).
 
- * "git branch -m/-M" advertised to update RENAME_REF ref in the
-   commit log message that introduced the feature but not anywhere in
-   the documentation, and never did update such a ref anyway. This
-   undocumented misfeature that did not exist has been excised.
-   (merge b0eab01 jc/maint-remove-renamed-ref later to maint).
+ * "git blame" was aborted if started from an uncommitted content and
+   the path had the textconv filter in effect.
+   (merge 8518088 ss/blame-textconv-fake-working-tree later to maint).
 
  * Adding many refs to the local repository in one go (e.g. "git fetch"
    that fetches many tags) and looking up a ref by name in a repository
@@ -160,18 +155,7 @@ included in this release.
    hooks for attempted removal of non-existing refs.
    (merge 160b81ed ph/push-to-delete-nothing later to maint).
 
- * The logic to filter out forked projects in the project list in
-   "gitweb" was broken for some time.
-   (merge 53c632f jm/maint-gitweb-filter-forks-fix later to maint).
-
- * The logic to optimize the locality of the data in a pack introduced in
-   1.7.7 was grossly inefficient.
-   (merge 38d4deb dm/pack-objects-update later to maint).
-
----
-exec >/var/tmp/1
-O=v1.7.8-rc0-32-g8e3565f
-echo O=$(git describe --always master)
-git log --first-parent --oneline --reverse ^$O master
-echo
-git shortlog --no-merges ^$O master
+ * Help text for "git remote set-url" and "git remote set-branches"
+   were misspelled.
+   (merge c49904e fc/remote-seturl-usage-fix later to maint).
+   (merge 656cdf0 jc/remote-setbranches-usage-fix later to maint).
index 08b581f040859d39aeaad8294bc7a3e7760ab0b9..9f7cba2be6a97cb85072d22b3317d37d1afe80bf 100644 (file)
@@ -413,6 +413,7 @@ endif::git-format-patch[]
        Show whole surrounding functions of changes.
 
 ifndef::git-format-patch[]
+ifndef::git-log[]
 --exit-code::
        Make the program exit with codes similar to diff(1).
        That is, it exits with 1 if there were differences and
@@ -420,6 +421,7 @@ ifndef::git-format-patch[]
 
 --quiet::
        Disable all output of the program. Implies `--exit-code`.
+endif::git-log[]
 endif::git-format-patch[]
 
 --ext-diff::
index 2660a842fc2ac76660963bc65c95ca47cb0e97cb..fed5097e00b4a031c2992ac3d421f6df975e6152 100644 (file)
@@ -9,8 +9,9 @@ SYNOPSIS
 --------
 [verse]
 'git cherry-pick' [--edit] [-n] [-m parent-number] [-s] [-x] [--ff] <commit>...
-'git cherry-pick' --reset
 'git cherry-pick' --continue
+'git cherry-pick' --quit
+'git cherry-pick' --abort
 
 DESCRIPTION
 -----------
index a03515f1eccddded2efbd46ca522f3bac8896d90..19d473c070c4f82dc4b7f04f784bcae835dca6a2 100644 (file)
@@ -31,7 +31,7 @@ OPTIONS
 -t <tool>::
 --tool=<tool>::
        Use the diff tool specified by <tool>.
-       Valid merge tools are:
+       Valid diff tools are:
        araxis, bc3, diffuse, emerge, ecmerge, gvimdiff, kdiff3,
        kompare, meld, opendiff, p4merge, tkdiff, vimdiff and xxdiff.
 +
index b2832fc7eb809af9865d83cdb20829354165f62e..b674866e6d166ccce096b58f7cecdbdb183c0194 100644 (file)
@@ -9,8 +9,8 @@ SYNOPSIS
 --------
 [verse]
 'git reset' [-q] [<commit>] [--] <paths>...
-'git reset' [--patch|-p] [<commit>] [--] [<paths>...]
-'git reset' [--soft | --mixed | --hard | --merge | --keep] [-q] [<commit>]
+'git reset' (--patch | -p) [<commit>] [--] [<paths>...]
+'git reset' (--soft | --mixed | --hard | --merge | --keep) [-q] [<commit>]
 
 DESCRIPTION
 -----------
@@ -34,7 +34,7 @@ Alternatively, using linkgit:git-checkout[1] and specifying a commit, you
 can copy the contents of a path out of a commit to the index and to the
 working tree in one go.
 
-'git reset' --patch|-p [<commit>] [--] [<paths>...]::
+'git reset' (--patch | -p) [<commit>] [--] [<paths>...]::
        Interactively select hunks in the difference between the index
        and <commit> (defaults to HEAD).  The chosen hunks are applied
        in reverse to the index.
@@ -43,7 +43,7 @@ This means that `git reset -p` is the opposite of `git add -p`, i.e.
 you can use it to selectively reset hunks. See the ``Interactive Mode''
 section of linkgit:git-add[1] to learn how to operate the `\--patch` mode.
 
-'git reset' [--<mode>] [<commit>]::
+'git reset' --<mode> [<commit>]::
        This form resets the current branch head to <commit> and
        possibly updates the index (resetting it to the tree of <commit>) and
        the working tree depending on <mode>, which
index f3519413e7e8704deee0197df6876eaed97e28b0..b699a3458eff439b05049dab94610a57ac62fc0a 100644 (file)
@@ -9,8 +9,9 @@ SYNOPSIS
 --------
 [verse]
 'git revert' [--edit | --no-edit] [-n] [-m parent-number] [-s] <commit>...
-'git revert' --reset
 'git revert' --continue
+'git revert' --quit
+'git revert' --abort
 
 DESCRIPTION
 -----------
index 5e80cfd71a5529225b607bd3f1732d19f05d0c1d..e869032fc0703aed18d3cb1417eda4341c29e093 100644 (file)
@@ -44,6 +44,11 @@ unreleased) version of git, that is available from 'master'
 branch of the `git.git` repository.
 Documentation for older releases are available here:
 
+* link:v1.7.8/git.html[documentation for release 1.7.8]
+
+* release notes for
+  link:RelNotes/1.7.8.txt[1.7.8].
+
 * link:v1.7.7.1/git.html[documentation for release 1.7.7.1]
 
 * release notes for
index 35f440876ed182de319b6d3f0b8296b1a1ede29d..327f69bcf5a20c7cf33a712b08bed9d4ccfe9d2e 100755 (executable)
@@ -1,31 +1,39 @@
 #!/bin/sh
-# This requires a branch named in $head
-# (usually 'man' or 'html', provided by the git.git repository)
-set -e
-head="$1"
-mandir="$2"
-SUBDIRECTORY_OK=t
-USAGE='<refname> <target directory>'
-. "$(git --exec-path)"/git-sh-setup
-cd_to_toplevel
+# This requires git-manpages and/or git-htmldocs repositories
 
-test -z "$mandir" && usage
-if ! git rev-parse --verify "$head^0" >/dev/null; then
-       echo >&2 "head: $head does not exist in the current repository"
-       usage
+repository=${1?repository}
+destdir=${2?destination}
+
+head=master GIT_DIR=
+for d in "$repository/.git" "$repository"
+do
+       if GIT_DIR="$d" git rev-parse refs/heads/master >/dev/null 2>&1
+       then
+               GIT_DIR="$d"
+               export GIT_DIR
+               break
+       fi
+done
+
+if test -z "$GIT_DIR"
+then
+       echo >&2 "Neither $repository nor $repository/.git is a repository"
+       exit 1
 fi
 
-GIT_INDEX_FILE=`pwd`/.quick-doc.index
-export GIT_INDEX_FILE
+GIT_WORK_TREE=$(pwd)
+GIT_INDEX_FILE=$(pwd)/.quick-doc.$$
+export GIT_INDEX_FILE GIT_WORK_TREE
 rm -f "$GIT_INDEX_FILE"
 trap 'rm -f "$GIT_INDEX_FILE"' 0
 
 git read-tree $head
-git checkout-index -a -f --prefix="$mandir"/
+git checkout-index -a -f --prefix="$destdir"/
 
-if test -n "$GZ"; then
+if test -n "$GZ"
+then
        git ls-tree -r --name-only $head |
-       xargs printf "$mandir/%s\n" |
+       xargs printf "$destdir/%s\n" |
        xargs gzip -f
 fi
 rm -f "$GIT_INDEX_FILE"
index 6bd0b041c3c1c0af5d03fce43d8016706e9256b1..1a5c12e3171ab82f489bcd53657c8a89741a3dab 100644 (file)
@@ -9,7 +9,6 @@ inspect and further tweak the merge result before committing.
 
 --edit::
 -e::
-+
        Invoke editor before committing successful merge to further
        edit the default merge message.
 
index 3e6df338bed519eb74cf233f40589ddbfb0da57b..5747f442f25e6271c7464db78496b85ee058d05f 100644 (file)
@@ -1,9 +1,12 @@
---reset::
-       Forget about the current operation in progress.  Can be used
-       to clear the sequencer state after a failed cherry-pick or
-       revert.
-
 --continue::
        Continue the operation in progress using the information in
        '.git/sequencer'.  Can be used to continue after resolving
        conflicts in a failed cherry-pick or revert.
+
+--quit::
+       Forget about the current operation in progress.  Can be used
+       to clear the sequencer state after a failed cherry-pick or
+       revert.
+
+--abort::
+       Cancel the operation and return to the pre-sequence state.
index 56dc9d66838c3767852da420b1eeaf6ee4ceb1c4..a04c8f32b767d757066526fc4f4685df812f3825 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v1.7.8-rc0
+DEF_VER=v1.7.8
 
 LF='
 '
diff --git a/INSTALL b/INSTALL
index bbb9d4dc9ab37a242d8accb86fa8a0d35d677ab8..bf0d97ef769adda0066578c7823a124385785e94 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -139,34 +139,11 @@ Issues of note:
    uses some compatibility wrappers to work on AsciiDoc 8. If you have
    AsciiDoc 7, try "make ASCIIDOC7=YesPlease".
 
-   Alternatively, pre-formatted documentation is available in
-   "html" and "man" branches of the git repository itself.  For
-   example, you could:
-
-       $ mkdir manual && cd manual
-       $ git init
-       $ git fetch-pack git://git.kernel.org/pub/scm/git/git.git man html |
-         while read a b
-         do
-           echo $a >.git/$b
-         done
-       $ cp .git/refs/heads/man .git/refs/heads/master
-       $ git checkout
-
-   to checkout the pre-built man pages.  Also in this repository:
-
-       $ git checkout html
-
-   would instead give you a copy of what you see at:
-
-       http://www.kernel.org/pub/software/scm/git/docs/
-
    There are also "make quick-install-doc", "make quick-install-man"
    and "make quick-install-html" which install preformatted man pages
-   and html documentation.
-   This does not require asciidoc/xmlto, but it only works from within
-   a cloned checkout of git.git with these two extra branches, and will
-   not work for the maintainer for obvious chicken-and-egg reasons.
+   and html documentation. To use these build targets, you need to
+   clone two separate git-htmldocs and git-manpages repositories next
+   to the clone of git itself.
 
    It has been reported that docbook-xsl version 1.72 and 1.73 are
    buggy; 1.72 misformats manual pages for callouts, and 1.73 needs
index ee34eab8c527da360a24c153a297d7a2f62d2a55..b1c80a678b5fdb80ec71f0a1ad567a384feba4e8 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -250,6 +250,12 @@ all::
 #   DEFAULT_EDITOR='$GIT_FALLBACK_EDITOR',
 #   DEFAULT_EDITOR='"C:\Program Files\Vim\gvim.exe" --nofork'
 #
+# Define COMPUTE_HEADER_DEPENDENCIES to "yes" if you want dependencies on
+# header files to be automatically computed, to avoid rebuilding objects when
+# an unrelated header file changes.  Define it to "no" to use the hard-coded
+# dependency rules.  The default is "auto", which means to use computed header
+# dependencies if your compiler is detected to support it.
+#
 # Define CHECK_HEADER_DEPENDENCIES to check for problems in the hard-coded
 # dependency rules.
 #
@@ -518,6 +524,7 @@ LIB_H += compat/win32/syslog.h
 LIB_H += compat/win32/poll.h
 LIB_H += compat/win32/dirent.h
 LIB_H += connected.h
+LIB_H += convert.h
 LIB_H += csum-file.h
 LIB_H += decorate.h
 LIB_H += delta.h
@@ -1245,21 +1252,32 @@ endif
 endif
 
 ifdef CHECK_HEADER_DEPENDENCIES
-COMPUTE_HEADER_DEPENDENCIES =
+COMPUTE_HEADER_DEPENDENCIES = no
 USE_COMPUTED_HEADER_DEPENDENCIES =
-else
+endif
+
 ifndef COMPUTE_HEADER_DEPENDENCIES
+COMPUTE_HEADER_DEPENDENCIES = auto
+endif
+
+ifeq ($(COMPUTE_HEADER_DEPENDENCIES),auto)
 dep_check = $(shell $(CC) $(ALL_CFLAGS) \
        -c -MF /dev/null -MMD -MP -x c /dev/null -o /dev/null 2>&1; \
        echo $$?)
 ifeq ($(dep_check),0)
-COMPUTE_HEADER_DEPENDENCIES=YesPlease
-endif
+override COMPUTE_HEADER_DEPENDENCIES = yes
+else
+override COMPUTE_HEADER_DEPENDENCIES = no
 endif
 endif
 
-ifdef COMPUTE_HEADER_DEPENDENCIES
+ifeq ($(COMPUTE_HEADER_DEPENDENCIES),yes)
 USE_COMPUTED_HEADER_DEPENDENCIES = YesPlease
+else
+ifneq ($(COMPUTE_HEADER_DEPENDENCIES),no)
+$(error please set COMPUTE_HEADER_DEPENDENCIES to yes, no, or auto \
+(not "$(COMPUTE_HEADER_DEPENDENCIES)"))
+endif
 endif
 
 ifdef SANE_TOOL_PATH
@@ -1906,7 +1924,7 @@ OBJECTS := $(GIT_OBJS) $(XDIFF_OBJS) $(VCSSVN_OBJS)
 dep_files := $(foreach f,$(OBJECTS),$(dir $f).depend/$(notdir $f).d)
 dep_dirs := $(addsuffix .depend,$(sort $(dir $(OBJECTS))))
 
-ifdef COMPUTE_HEADER_DEPENDENCIES
+ifeq ($(COMPUTE_HEADER_DEPENDENCIES),yes)
 $(dep_dirs):
        @mkdir -p $@
 
@@ -1919,7 +1937,7 @@ Please unset CHECK_HEADER_DEPENDENCIES and try again)
 endif
 endif
 
-ifndef COMPUTE_HEADER_DEPENDENCIES
+ifneq ($(COMPUTE_HEADER_DEPENDENCIES),yes)
 ifndef CHECK_HEADER_DEPENDENCIES
 dep_dirs =
 missing_dep_dirs =
@@ -2009,13 +2027,13 @@ builtin/branch.o builtin/checkout.o builtin/clone.o builtin/reset.o branch.o tra
 builtin/bundle.o bundle.o transport.o: bundle.h
 builtin/bisect--helper.o builtin/rev-list.o bisect.o: bisect.h
 builtin/clone.o builtin/fetch-pack.o transport.o: fetch-pack.h
-builtin/grep.o builtin/pack-objects.o transport-helper.o: thread-utils.h
+builtin/grep.o builtin/pack-objects.o transport-helper.o thread-utils.o: thread-utils.h
 builtin/send-pack.o transport.o: send-pack.h
 builtin/log.o builtin/shortlog.o: shortlog.h
 builtin/prune.o builtin/reflog.o reachable.o: reachable.h
 builtin/commit.o builtin/revert.o wt-status.o: wt-status.h
 builtin/tar-tree.o archive-tar.o: tar.h
-connect.o transport.o http-backend.o: url.h
+connect.o transport.o url.o http-backend.o: url.h
 http-fetch.o http-walker.o remote-curl.o transport.o walker.o: walker.h
 http.o http-walker.o http-push.o http-fetch.o remote-curl.o: http.h url.h
 
index d8098762f62a9dfb991f64702d34047182cfa951..025a97be0281b9fd3ccff2b36c03495b005ac4fe 100644 (file)
--- a/branch.c
+++ b/branch.c
@@ -241,6 +241,7 @@ void create_branch(const char *head,
 void remove_branch_state(void)
 {
        unlink(git_path("CHERRY_PICK_HEAD"));
+       unlink(git_path("REVERT_HEAD"));
        unlink(git_path("MERGE_HEAD"));
        unlink(git_path("MERGE_RR"));
        unlink(git_path("MERGE_MSG"));
index e405566c5eabe03160e77dec4e7843f35f4e78fb..931956def986bbdf5b77e163f1b18c961e7be09c 100644 (file)
@@ -87,7 +87,6 @@ int cmd_archive(int argc, const char **argv, const char *prefix)
        const char *exec = "git-upload-archive";
        const char *output = NULL;
        const char *remote = NULL;
-       int is_remote = 0;
        struct option local_opts[] = {
                OPT_STRING('o', "output", &output, "file",
                        "write the archive to this file"),
@@ -95,9 +94,6 @@ int cmd_archive(int argc, const char **argv, const char *prefix)
                        "retrieve the archive from remote repository <repo>"),
                OPT_STRING(0, "exec", &exec, "cmd",
                        "path to the remote git-upload-archive command"),
-               { OPTION_BOOLEAN, 0, "remote-request", &is_remote, NULL,
-                       "indicate we are serving a remote request",
-                       PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
                OPT_END()
        };
 
@@ -112,5 +108,5 @@ int cmd_archive(int argc, const char **argv, const char *prefix)
 
        setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
 
-       return write_archive(argc, argv, prefix, 1, output, is_remote);
+       return write_archive(argc, argv, prefix, 1, output, 0);
 }
index 86c0537cbb50c0e5d6169d6d316ac37b5cc5b856..80febbe420db1c75bbcf7eda6a733e7e66549790 100644 (file)
@@ -2096,6 +2096,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
        if (!contents_from || strcmp("-", contents_from)) {
                struct stat st;
                const char *read_from;
+               char *buf_ptr;
                unsigned long buf_len;
 
                if (contents_from) {
@@ -2113,10 +2114,8 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
                switch (st.st_mode & S_IFMT) {
                case S_IFREG:
                        if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) &&
-                           textconv_object(read_from, mode, null_sha1, &buf.buf, &buf_len)) {
-                               buf.alloc = buf_len;
-                               buf.len = buf_len;
-                       }
+                           textconv_object(read_from, mode, null_sha1, &buf_ptr, &buf_len))
+                               strbuf_attach(&buf, buf_ptr, buf_len, buf_len + 1);
                        else if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size)
                                die_errno("cannot open or read '%s'", read_from);
                        break;
index 51ca6a02d7433f1394de10a7f6ef1aa565ac03e2..55cad766c7e3d284b1361b1beca8c5d51de96083 100644 (file)
@@ -705,7 +705,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
        argc = parse_options(argc, argv, prefix, options, builtin_branch_usage,
                             0);
 
-       if (!delete && !rename && !force_create && argc == 0)
+       if (!delete && !rename && argc == 0)
                list = 1;
 
        if (!!delete + !!rename + !!force_create + !!list > 1)
@@ -726,7 +726,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                        rename_branch(argv[0], argv[1], rename > 1);
                else
                        usage_with_options(builtin_branch_usage, options);
-       } else if (argc <= 2) {
+       } else if (argc > 0 && argc <= 2) {
                if (kinds != REF_LOCAL_BRANCH)
                        die(_("-a and -r options to 'git branch' do not make sense with a branch name"));
                create_branch(head, argv[0], (argc == 2) ? argv[1] : head,
index c46f2d18e10bcb3b1b458d4ae94d2d3522305632..8f2bebecf313a0e4b742f9327ec178c7e3547dd2 100644 (file)
@@ -1514,6 +1514,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
        }
 
        unlink(git_path("CHERRY_PICK_HEAD"));
+       unlink(git_path("REVERT_HEAD"));
        unlink(git_path("MERGE_HEAD"));
        unlink(git_path("MERGE_MSG"));
        unlink(git_path("MERGE_MODE"));
index 3d7329d78c6e3ec31ed8ce03b8928c9ed24afb9e..988ea1d3324d6e32fcfd3b97da0fad5ae41b592c 100644 (file)
@@ -557,18 +557,19 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int
 static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
                     struct tree_desc *tree, struct strbuf *base, int tn_len)
 {
-       int hit = 0, match = 0;
+       int hit = 0;
+       enum interesting match = entry_not_interesting;
        struct name_entry entry;
        int old_baselen = base->len;
 
        while (tree_entry(tree, &entry)) {
-               int te_len = tree_entry_len(entry.path, entry.sha1);
+               int te_len = tree_entry_len(&entry);
 
-               if (match != 2) {
+               if (match != all_entries_interesting) {
                        match = tree_entry_interesting(&entry, base, tn_len, pathspec);
-                       if (match < 0)
+                       if (match == all_entries_not_interesting)
                                break;
-                       if (match == 0)
+                       if (match == entry_not_interesting)
                                continue;
                }
 
index dffd5ec1245865259fd4e72cc304286a1a5b4633..2870a6af6fbc868455f2961483cfbfdb065a1a14 100644 (file)
@@ -316,13 +316,15 @@ static void squash_message(struct commit *commit)
        struct rev_info rev;
        struct strbuf out = STRBUF_INIT;
        struct commit_list *j;
+       const char *filename;
        int fd;
        struct pretty_print_context ctx = {0};
 
        printf(_("Squash commit -- not updating HEAD\n"));
-       fd = open(git_path("SQUASH_MSG"), O_WRONLY | O_CREAT, 0666);
+       filename = git_path("SQUASH_MSG");
+       fd = open(filename, O_WRONLY | O_CREAT, 0666);
        if (fd < 0)
-               die_errno(_("Could not write to '%s'"), git_path("SQUASH_MSG"));
+               die_errno(_("Could not write to '%s'"), filename);
 
        init_revisions(&rev, NULL);
        rev.ignore_merges = 1;
@@ -492,14 +494,16 @@ static void merge_name(const char *remote, struct strbuf *msg)
 
        if (!strcmp(remote, "FETCH_HEAD") &&
                        !access(git_path("FETCH_HEAD"), R_OK)) {
+               const char *filename;
                FILE *fp;
                struct strbuf line = STRBUF_INIT;
                char *ptr;
 
-               fp = fopen(git_path("FETCH_HEAD"), "r");
+               filename = git_path("FETCH_HEAD");
+               fp = fopen(filename, "r");
                if (!fp)
                        die_errno(_("could not open '%s' for reading"),
-                                 git_path("FETCH_HEAD"));
+                                 filename);
                strbuf_getline(&line, fp, '\n');
                fclose(fp);
                ptr = strstr(line.buf, "\tnot-for-merge\t");
@@ -847,20 +851,22 @@ static void add_strategies(const char *string, unsigned attr)
 
 static void write_merge_msg(struct strbuf *msg)
 {
-       int fd = open(git_path("MERGE_MSG"), O_WRONLY | O_CREAT, 0666);
+       const char *filename = git_path("MERGE_MSG");
+       int fd = open(filename, O_WRONLY | O_CREAT, 0666);
        if (fd < 0)
                die_errno(_("Could not open '%s' for writing"),
-                         git_path("MERGE_MSG"));
+                         filename);
        if (write_in_full(fd, msg->buf, msg->len) != msg->len)
-               die_errno(_("Could not write to '%s'"), git_path("MERGE_MSG"));
+               die_errno(_("Could not write to '%s'"), filename);
        close(fd);
 }
 
 static void read_merge_msg(struct strbuf *msg)
 {
+       const char *filename = git_path("MERGE_MSG");
        strbuf_reset(msg);
-       if (strbuf_read_file(msg, git_path("MERGE_MSG"), 0) < 0)
-               die_errno(_("Could not read from '%s'"), git_path("MERGE_MSG"));
+       if (strbuf_read_file(msg, filename, 0) < 0)
+               die_errno(_("Could not read from '%s'"), filename);
 }
 
 static void write_merge_state(void);
@@ -948,13 +954,14 @@ static int finish_automerge(struct commit *head,
 
 static int suggest_conflicts(int renormalizing)
 {
+       const char *filename;
        FILE *fp;
        int pos;
 
-       fp = fopen(git_path("MERGE_MSG"), "a");
+       filename = git_path("MERGE_MSG");
+       fp = fopen(filename, "a");
        if (!fp)
-               die_errno(_("Could not open '%s' for writing"),
-                         git_path("MERGE_MSG"));
+               die_errno(_("Could not open '%s' for writing"), filename);
        fprintf(fp, "\nConflicts:\n");
        for (pos = 0; pos < active_nr; pos++) {
                struct cache_entry *ce = active_cache[pos];
@@ -1046,6 +1053,7 @@ static int setup_with_upstream(const char ***argv)
 
 static void write_merge_state(void)
 {
+       const char *filename;
        int fd;
        struct commit_list *j;
        struct strbuf buf = STRBUF_INIT;
@@ -1053,24 +1061,25 @@ static void write_merge_state(void)
        for (j = remoteheads; j; j = j->next)
                strbuf_addf(&buf, "%s\n",
                        sha1_to_hex(j->item->object.sha1));
-       fd = open(git_path("MERGE_HEAD"), O_WRONLY | O_CREAT, 0666);
+       filename = git_path("MERGE_HEAD");
+       fd = open(filename, O_WRONLY | O_CREAT, 0666);
        if (fd < 0)
-               die_errno(_("Could not open '%s' for writing"),
-                         git_path("MERGE_HEAD"));
+               die_errno(_("Could not open '%s' for writing"), filename);
        if (write_in_full(fd, buf.buf, buf.len) != buf.len)
-               die_errno(_("Could not write to '%s'"), git_path("MERGE_HEAD"));
+               die_errno(_("Could not write to '%s'"), filename);
        close(fd);
        strbuf_addch(&merge_msg, '\n');
        write_merge_msg(&merge_msg);
-       fd = open(git_path("MERGE_MODE"), O_WRONLY | O_CREAT | O_TRUNC, 0666);
+
+       filename = git_path("MERGE_MODE");
+       fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
        if (fd < 0)
-               die_errno(_("Could not open '%s' for writing"),
-                         git_path("MERGE_MODE"));
+               die_errno(_("Could not open '%s' for writing"), filename);
        strbuf_reset(&buf);
        if (!allow_fast_forward)
                strbuf_addf(&buf, "no-ff");
        if (write_in_full(fd, buf.buf, buf.len) != buf.len)
-               die_errno(_("Could not write to '%s'"), git_path("MERGE_MODE"));
+               die_errno(_("Could not write to '%s'"), filename);
        close(fd);
 }
 
index 098395fda1932674e29f8d2cb332c722a6cb275f..4ae1c412d47bd581f22ec8b821a1111224dddd28 100644 (file)
@@ -60,6 +60,7 @@ static void write_tree(unsigned char *sha1)
        }
 
        write_sha1_file(buf.buf, buf.len, tree_type, sha1);
+       strbuf_release(&buf);
 }
 
 static const char *mktree_usage[] = {
index 7864056f1ee64b896a7378cc76555e2cf7c3fd89..1b374583c2751801dfae1d0d1861d28f81c7ad7b 100644 (file)
@@ -291,7 +291,7 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
                max = get_max_object_index();
                for (i = 0; i < max; i++) {
                        struct object *obj = get_indexed_object(i);
-                       if (!obj)
+                       if (!obj || obj->type != OBJ_COMMIT)
                                continue;
                        show_name(obj, NULL,
                                  always, allow_undefined, data.name_only);
index 824ecee20b94c471083ad8c7f697b39fbb7cb2b8..558cd34bccf66b1ef4cf9d66bfefe43fae76ceb3 100644 (file)
@@ -1015,7 +1015,7 @@ static void add_pbase_object(struct tree_desc *tree,
        while (tree_entry(tree,&entry)) {
                if (S_ISGITLINK(entry.mode))
                        continue;
-               cmp = tree_entry_len(entry.path, entry.sha1) != cmplen ? 1 :
+               cmp = tree_entry_len(&entry) != cmplen ? 1 :
                      memcmp(name, entry.path, cmplen);
                if (cmp > 0)
                        continue;
index 733514979969f69ad45448a67d981b621bbee146..c810643815e38f4ada805e2af49973e4e0051801 100644 (file)
@@ -1399,7 +1399,7 @@ static int set_branches(int argc, const char **argv)
                             builtin_remote_setbranches_usage, 0);
        if (argc == 0) {
                error("no remote specified");
-               usage_with_options(builtin_remote_seturl_usage, options);
+               usage_with_options(builtin_remote_setbranches_usage, options);
        }
        argv[argc] = NULL;
 
@@ -1427,7 +1427,7 @@ static int set_url(int argc, const char **argv)
                            "delete URLs"),
                OPT_END()
        };
-       argc = parse_options(argc, argv, NULL, options, builtin_remote_update_usage,
+       argc = parse_options(argc, argv, NULL, options, builtin_remote_seturl_usage,
                             PARSE_OPT_KEEP_ARGV0);
 
        if (add_mode && delete_mode)
index 87df70edc33fcc71177b863e6ced870330e505d0..1ea525c10e4c00b66006bf46465ebd490823f25f 100644 (file)
@@ -40,7 +40,12 @@ static const char * const cherry_pick_usage[] = {
 };
 
 enum replay_action { REVERT, CHERRY_PICK };
-enum replay_subcommand { REPLAY_NONE, REPLAY_RESET, REPLAY_CONTINUE };
+enum replay_subcommand {
+       REPLAY_NONE,
+       REPLAY_REMOVE_STATE,
+       REPLAY_CONTINUE,
+       REPLAY_ROLLBACK
+};
 
 struct replay_opts {
        enum replay_action action;
@@ -133,11 +138,13 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
 {
        const char * const * usage_str = revert_or_cherry_pick_usage(opts);
        const char *me = action_name(opts);
-       int reset = 0;
+       int remove_state = 0;
        int contin = 0;
+       int rollback = 0;
        struct option options[] = {
-               OPT_BOOLEAN(0, "reset", &reset, "forget the current operation"),
-               OPT_BOOLEAN(0, "continue", &contin, "continue the current operation"),
+               OPT_BOOLEAN(0, "quit", &remove_state, "end revert or cherry-pick sequence"),
+               OPT_BOOLEAN(0, "continue", &contin, "resume revert or cherry-pick sequence"),
+               OPT_BOOLEAN(0, "abort", &rollback, "cancel revert or cherry-pick sequence"),
                OPT_BOOLEAN('n', "no-commit", &opts->no_commit, "don't automatically commit"),
                OPT_BOOLEAN('e', "edit", &opts->edit, "edit the commit message"),
                OPT_NOOP_NOARG('r', NULL),
@@ -168,25 +175,32 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
 
        /* Check for incompatible subcommands */
        verify_opt_mutually_compatible(me,
-                               "--reset", reset,
+                               "--quit", remove_state,
                                "--continue", contin,
+                               "--abort", rollback,
                                NULL);
 
        /* Set the subcommand */
-       if (reset)
-               opts->subcommand = REPLAY_RESET;
+       if (remove_state)
+               opts->subcommand = REPLAY_REMOVE_STATE;
        else if (contin)
                opts->subcommand = REPLAY_CONTINUE;
+       else if (rollback)
+               opts->subcommand = REPLAY_ROLLBACK;
        else
                opts->subcommand = REPLAY_NONE;
 
        /* Check for incompatible command line arguments */
        if (opts->subcommand != REPLAY_NONE) {
                char *this_operation;
-               if (opts->subcommand == REPLAY_RESET)
-                       this_operation = "--reset";
-               else
+               if (opts->subcommand == REPLAY_REMOVE_STATE)
+                       this_operation = "--quit";
+               else if (opts->subcommand == REPLAY_CONTINUE)
                        this_operation = "--continue";
+               else {
+                       assert(opts->subcommand == REPLAY_ROLLBACK);
+                       this_operation = "--abort";
+               }
 
                verify_opt_compatible(me, this_operation,
                                "--no-commit", opts->no_commit,
@@ -286,19 +300,20 @@ static char *get_encoding(const char *message)
        return NULL;
 }
 
-static void write_cherry_pick_head(struct commit *commit)
+static void write_cherry_pick_head(struct commit *commit, const char *pseudoref)
 {
+       const char *filename;
        int fd;
        struct strbuf buf = STRBUF_INIT;
 
        strbuf_addf(&buf, "%s\n", sha1_to_hex(commit->object.sha1));
 
-       fd = open(git_path("CHERRY_PICK_HEAD"), O_WRONLY | O_CREAT, 0666);
+       filename = git_path("%s", pseudoref);
+       fd = open(filename, O_WRONLY | O_CREAT, 0666);
        if (fd < 0)
-               die_errno(_("Could not open '%s' for writing"),
-                         git_path("CHERRY_PICK_HEAD"));
+               die_errno(_("Could not open '%s' for writing"), filename);
        if (write_in_full(fd, buf.buf, buf.len) != buf.len || close(fd))
-               die_errno(_("Could not write to '%s'"), git_path("CHERRY_PICK_HEAD"));
+               die_errno(_("Could not write to '%s'"), filename);
        strbuf_release(&buf);
 }
 
@@ -331,7 +346,7 @@ static void write_message(struct strbuf *msgbuf, const char *filename)
        int msg_fd = hold_lock_file_for_update(&msg_file, filename,
                                               LOCK_DIE_ON_ERROR);
        if (write_in_full(msg_fd, msgbuf->buf, msgbuf->len) < 0)
-               die_errno(_("Could not write to %s."), filename);
+               die_errno(_("Could not write to %s"), filename);
        strbuf_release(msgbuf);
        if (commit_lock_file(&msg_file) < 0)
                die(_("Error wrapping up %s"), filename);
@@ -593,7 +608,9 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
         * write it at all.
         */
        if (opts->action == CHERRY_PICK && !opts->no_commit && (res == 0 || res == 1))
-               write_cherry_pick_head(commit);
+               write_cherry_pick_head(commit, "CHERRY_PICK_HEAD");
+       if (opts->action == REVERT && ((opts->no_commit && res == 0) || res == 1))
+               write_cherry_pick_head(commit, "REVERT_HEAD");
 
        if (res) {
                error(opts->action == REVERT
@@ -767,7 +784,7 @@ static void read_populate_todo(struct commit_list **todo_list,
 
        fd = open(todo_file, O_RDONLY);
        if (fd < 0)
-               die_errno(_("Could not open %s."), todo_file);
+               die_errno(_("Could not open %s"), todo_file);
        if (strbuf_read(&buf, fd, 0) < 0) {
                close(fd);
                strbuf_release(&buf);
@@ -842,10 +859,13 @@ static int create_seq_dir(void)
 {
        const char *seq_dir = git_path(SEQ_DIR);
 
-       if (file_exists(seq_dir))
-               return error(_("%s already exists."), seq_dir);
+       if (file_exists(seq_dir)) {
+               error(_("a cherry-pick or revert is already in progress"));
+               advise(_("try \"git cherry-pick (--continue | --quit | --abort)\""));
+               return -1;
+       }
        else if (mkdir(seq_dir, 0777) < 0)
-               die_errno(_("Could not create sequencer directory '%s'."), seq_dir);
+               die_errno(_("Could not create sequencer directory %s"), seq_dir);
        return 0;
 }
 
@@ -859,11 +879,77 @@ static void save_head(const char *head)
        fd = hold_lock_file_for_update(&head_lock, head_file, LOCK_DIE_ON_ERROR);
        strbuf_addf(&buf, "%s\n", head);
        if (write_in_full(fd, buf.buf, buf.len) < 0)
-               die_errno(_("Could not write to %s."), head_file);
+               die_errno(_("Could not write to %s"), head_file);
        if (commit_lock_file(&head_lock) < 0)
                die(_("Error wrapping up %s."), head_file);
 }
 
+static int reset_for_rollback(const unsigned char *sha1)
+{
+       const char *argv[4];    /* reset --merge <arg> + NULL */
+       argv[0] = "reset";
+       argv[1] = "--merge";
+       argv[2] = sha1_to_hex(sha1);
+       argv[3] = NULL;
+       return run_command_v_opt(argv, RUN_GIT_CMD);
+}
+
+static int rollback_single_pick(void)
+{
+       unsigned char head_sha1[20];
+
+       if (!file_exists(git_path("CHERRY_PICK_HEAD")) &&
+           !file_exists(git_path("REVERT_HEAD")))
+               return error(_("no cherry-pick or revert in progress"));
+       if (!resolve_ref("HEAD", head_sha1, 0, NULL))
+               return error(_("cannot resolve HEAD"));
+       if (is_null_sha1(head_sha1))
+               return error(_("cannot abort from a branch yet to be born"));
+       return reset_for_rollback(head_sha1);
+}
+
+static int sequencer_rollback(struct replay_opts *opts)
+{
+       const char *filename;
+       FILE *f;
+       unsigned char sha1[20];
+       struct strbuf buf = STRBUF_INIT;
+
+       filename = git_path(SEQ_HEAD_FILE);
+       f = fopen(filename, "r");
+       if (!f && errno == ENOENT) {
+               /*
+                * There is no multiple-cherry-pick in progress.
+                * If CHERRY_PICK_HEAD or REVERT_HEAD indicates
+                * a single-cherry-pick in progress, abort that.
+                */
+               return rollback_single_pick();
+       }
+       if (!f)
+               return error(_("cannot open %s: %s"), filename,
+                                               strerror(errno));
+       if (strbuf_getline(&buf, f, '\n')) {
+               error(_("cannot read %s: %s"), filename, ferror(f) ?
+                       strerror(errno) : _("unexpected end of file"));
+               fclose(f);
+               goto fail;
+       }
+       fclose(f);
+       if (get_sha1_hex(buf.buf, sha1) || buf.buf[40] != '\0') {
+               error(_("stored pre-cherry-pick HEAD file '%s' is corrupt"),
+                       filename);
+               goto fail;
+       }
+       if (reset_for_rollback(sha1))
+               goto fail;
+       remove_sequencer_state(1);
+       strbuf_release(&buf);
+       return 0;
+fail:
+       strbuf_release(&buf);
+       return -1;
+}
+
 static void save_todo(struct commit_list *todo_list, struct replay_opts *opts)
 {
        const char *todo_file = git_path(SEQ_TODO_FILE);
@@ -876,7 +962,7 @@ static void save_todo(struct commit_list *todo_list, struct replay_opts *opts)
                die(_("Could not format %s."), todo_file);
        if (write_in_full(fd, buf.buf, buf.len) < 0) {
                strbuf_release(&buf);
-               die_errno(_("Could not write to %s."), todo_file);
+               die_errno(_("Could not write to %s"), todo_file);
        }
        if (commit_lock_file(&todo_lock) < 0) {
                strbuf_release(&buf);
@@ -964,43 +1050,41 @@ static int pick_revisions(struct replay_opts *opts)
         * cherry-pick should be handled differently from an existing
         * one that is being continued
         */
-       if (opts->subcommand == REPLAY_RESET) {
+       if (opts->subcommand == REPLAY_REMOVE_STATE) {
                remove_sequencer_state(1);
                return 0;
-       } else if (opts->subcommand == REPLAY_CONTINUE) {
+       }
+       if (opts->subcommand == REPLAY_ROLLBACK)
+               return sequencer_rollback(opts);
+       if (opts->subcommand == REPLAY_CONTINUE) {
                if (!file_exists(git_path(SEQ_TODO_FILE)))
-                       goto error;
+                       return error(_("No %s in progress"), action_name(opts));
                read_populate_opts(&opts);
                read_populate_todo(&todo_list, opts);
 
                /* Verify that the conflict has been resolved */
                if (!index_differs_from("HEAD", 0))
                        todo_list = todo_list->next;
-       } else {
-               /*
-                * Start a new cherry-pick/ revert sequence; but
-                * first, make sure that an existing one isn't in
-                * progress
-                */
+               return pick_commits(todo_list, opts);
+       }
 
-               walk_revs_populate_todo(&todo_list, opts);
-               if (create_seq_dir() < 0) {
-                       error(_("A cherry-pick or revert is in progress."));
-                       advise(_("Use --continue to continue the operation"));
-                       advise(_("or --reset to forget about it"));
-                       return -1;
-               }
-               if (get_sha1("HEAD", sha1)) {
-                       if (opts->action == REVERT)
-                               return error(_("Can't revert as initial commit"));
-                       return error(_("Can't cherry-pick into empty head"));
-               }
-               save_head(sha1_to_hex(sha1));
-               save_opts(opts);
+       /*
+        * Start a new cherry-pick/ revert sequence; but
+        * first, make sure that an existing one isn't in
+        * progress
+        */
+
+       walk_revs_populate_todo(&todo_list, opts);
+       if (create_seq_dir() < 0)
+               return -1;
+       if (get_sha1("HEAD", sha1)) {
+               if (opts->action == REVERT)
+                       return error(_("Can't revert as initial commit"));
+               return error(_("Can't cherry-pick into empty head"));
        }
+       save_head(sha1_to_hex(sha1));
+       save_opts(opts);
        return pick_commits(todo_list, opts);
-error:
-       return error(_("No %s in progress"), action_name(opts));
 }
 
 int cmd_revert(int argc, const char **argv, const char *prefix)
index 4d3b93fedb5f2eca68edca15ca1e10cb60176d36..1288ffcc52530f8ef9561acd2eb2ec5322c9e230 100644 (file)
@@ -22,8 +22,6 @@ static size_t cleanup(char *line, size_t len)
  * Remove empty lines from the beginning and end
  * and also trailing spaces from every line.
  *
- * Note that the buffer will not be NUL-terminated.
- *
  * Turn multiple consecutive empty lines between paragraphs
  * into just one empty line.
  *
index c57e8bd8c870175a1fce6cc75ceeb677a6895b46..2d0b38333eadef0a5c6501e5a3046ebc2afa048e 100644 (file)
@@ -6,7 +6,6 @@
 #include "archive.h"
 #include "pkt-line.h"
 #include "sideband.h"
-#include "run-command.h"
 
 static const char upload_archive_usage[] =
        "git upload-archive <repo>";
@@ -19,17 +18,28 @@ static const char lostchild[] =
 
 #define MAX_ARGS (64)
 
-static void prepare_argv(const char **sent_argv, const char **argv)
+static int run_upload_archive(int argc, const char **argv, const char *prefix)
 {
+       const char *sent_argv[MAX_ARGS];
        const char *arg_cmd = "argument ";
        char *p, buf[4096];
        int sent_argc;
        int len;
 
+       if (argc != 2)
+               usage(upload_archive_usage);
+
+       if (strlen(argv[1]) + 1 > sizeof(buf))
+               die("insanely long repository name");
+
+       strcpy(buf, argv[1]); /* enter-repo smudges its argument */
+
+       if (!enter_repo(buf, 0))
+               die("'%s' does not appear to be a git repository", buf);
+
        /* put received options in sent_argv[] */
-       sent_argc = 2;
-       sent_argv[0] = "archive";
-       sent_argv[1] = "--remote-request";
+       sent_argc = 1;
+       sent_argv[0] = "git-upload-archive";
        for (p = buf;;) {
                /* This will die if not enough free space in buf */
                len = packet_read_line(0, p, (buf + sizeof buf) - p);
@@ -52,6 +62,9 @@ static void prepare_argv(const char **sent_argv, const char **argv)
                *p++ = 0;
        }
        sent_argv[sent_argc] = NULL;
+
+       /* parse all options sent by the client */
+       return write_archive(sent_argc, sent_argv, prefix, 0, NULL, 1);
 }
 
 __attribute__((format (printf, 1, 2)))
@@ -83,25 +96,38 @@ static ssize_t process_input(int child_fd, int band)
 
 int cmd_upload_archive(int argc, const char **argv, const char *prefix)
 {
-       const char *sent_argv[MAX_ARGS];
-       struct child_process cld = { sent_argv };
-       cld.out = cld.err = -1;
-       cld.git_cmd = 1;
-
-       if (argc != 2)
-               usage(upload_archive_usage);
-
-       if (!enter_repo(argv[1], 0))
-               die("'%s' does not appear to be a git repository", argv[1]);
-
-       prepare_argv(sent_argv, argv);
-       if (start_command(&cld)) {
+       pid_t writer;
+       int fd1[2], fd2[2];
+       /*
+        * Set up sideband subprocess.
+        *
+        * We (parent) monitor and read from child, sending its fd#1 and fd#2
+        * multiplexed out to our fd#1.  If the child dies, we tell the other
+        * end over channel #3.
+        */
+       if (pipe(fd1) < 0 || pipe(fd2) < 0) {
+               int err = errno;
+               packet_write(1, "NACK pipe failed on the remote side\n");
+               die("upload-archive: %s", strerror(err));
+       }
+       writer = fork();
+       if (writer < 0) {
                int err = errno;
                packet_write(1, "NACK fork failed on the remote side\n");
                die("upload-archive: %s", strerror(err));
        }
+       if (!writer) {
+               /* child - connect fd#1 and fd#2 to the pipe */
+               dup2(fd1[1], 1);
+               dup2(fd2[1], 2);
+               close(fd1[1]); close(fd2[1]);
+               close(fd1[0]); close(fd2[0]); /* we do not read from pipe */
+
+               exit(run_upload_archive(argc, argv, prefix));
+       }
 
        /* parent - read from child, multiplex and send out to fd#1 */
+       close(fd1[1]); close(fd2[1]); /* we do not write to pipe */
        packet_write(1, "ACK\n");
        packet_flush(1);
 
@@ -109,9 +135,9 @@ int cmd_upload_archive(int argc, const char **argv, const char *prefix)
                struct pollfd pfd[2];
                int status;
 
-               pfd[0].fd = cld.out;
+               pfd[0].fd = fd1[0];
                pfd[0].events = POLLIN;
-               pfd[1].fd = cld.err;
+               pfd[1].fd = fd2[0];
                pfd[1].events = POLLIN;
                if (poll(pfd, 2, -1) < 0) {
                        if (errno != EINTR) {
@@ -130,7 +156,7 @@ int cmd_upload_archive(int argc, const char **argv, const char *prefix)
                        if (process_input(pfd[0].fd, 1))
                                continue;
 
-               if (waitpid(cld.pid, &status, 0) < 0)
+               if (waitpid(writer, &status, 0) < 0)
                        error_clnt("%s", lostchild);
                else if (!WIFEXITED(status) || WEXITSTATUS(status) > 0)
                        error_clnt("%s", deadchild);
index dfb0e87263a37bdee347c0a762aeea42fc57cee9..fecf0d07760d2211fac6db2e19ecbedaac81c57e 100644 (file)
@@ -85,6 +85,8 @@ static inline int symlink(const char *oldpath, const char *newpath)
 { errno = ENOSYS; return -1; }
 static inline int fchmod(int fildes, mode_t mode)
 { errno = ENOSYS; return -1; }
+static inline pid_t fork(void)
+{ errno = ENOSYS; return -1; }
 static inline unsigned int alarm(unsigned int seconds)
 { return 0; }
 static inline int fsync(int fd)
index edf9914df6a1a789780c98d53b7b779908bb9141..b6d789a189713a0259e3f8eb0e29ef657cde66c7 100644 (file)
--- a/config.c
+++ b/config.c
@@ -865,12 +865,12 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
 
        home = getenv("HOME");
        if (home) {
-               char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
+               char buf[PATH_MAX];
+               char *user_config = mksnpath(buf, sizeof(buf), "%s/.gitconfig", home);
                if (!access(user_config, R_OK)) {
                        ret += git_config_from_file(fn, user_config, data);
                        found += 1;
                }
-               free(user_config);
        }
 
        if (repo_config && !access(repo_config, R_OK)) {
index 98af8f5c7ee68876e94194524cc0cda9d3f25345..b7c1edf1cc763199d41a490b212a3b65ea581a86 100755 (executable)
@@ -110,7 +110,7 @@ __git_ps1_show_upstream ()
        local upstream=git legacy="" verbose=""
 
        # get some config options from git-config
-       output="$(git config -z --get-regexp '^(svn-remote\..*\.url|bash\.showupstream)$' 2>/dev/null | tr '\0\n' '\n ')"
+       local output="$(git config -z --get-regexp '^(svn-remote\..*\.url|bash\.showupstream)$' 2>/dev/null | tr '\0\n' '\n ')"
        while read key value; do
                case "$key" in
                bash.showupstream)
index f885d707c4a9d80928cecb3d4867deb268929670..7fd8bf031e1eb10f6dda2342f32c86454ef7efb3 100755 (executable)
@@ -847,6 +847,38 @@ class P4Submit(Command, P4UserMap):
 
         return template
 
+    def edit_template(self, template_file):
+        """Invoke the editor to let the user change the submission
+           message.  Return true if okay to continue with the submit."""
+
+        # if configured to skip the editing part, just submit
+        if gitConfig("git-p4.skipSubmitEdit") == "true":
+            return True
+
+        # look at the modification time, to check later if the user saved
+        # the file
+        mtime = os.stat(template_file).st_mtime
+
+        # invoke the editor
+        if os.environ.has_key("P4EDITOR"):
+            editor = os.environ.get("P4EDITOR")
+        else:
+            editor = read_pipe("git var GIT_EDITOR").strip()
+        system(editor + " " + template_file)
+
+        # If the file was not saved, prompt to see if this patch should
+        # be skipped.  But skip this verification step if configured so.
+        if gitConfig("git-p4.skipSubmitEditCheck") == "true":
+            return True
+
+        if os.stat(template_file).st_mtime <= mtime:
+            while True:
+                response = raw_input("Submit template unchanged. Submit anyway? [y]es, [n]o (skip this patch) ")
+                if response == 'y':
+                    return True
+                if response == 'n':
+                    return False
+
     def applyCommit(self, id):
         print "Applying %s" % (read_pipe("git log --max-count=1 --pretty=oneline %s" % id))
 
@@ -1001,7 +1033,7 @@ class P4Submit(Command, P4UserMap):
 
             separatorLine = "######## everything below this line is just the diff #######\n"
 
-            [handle, fileName] = tempfile.mkstemp()
+            (handle, fileName) = tempfile.mkstemp()
             tmpFile = os.fdopen(handle, "w+")
             if self.isWindows:
                 submitTemplate = submitTemplate.replace("\n", "\r\n")
@@ -1009,25 +1041,9 @@ class P4Submit(Command, P4UserMap):
                 newdiff = newdiff.replace("\n", "\r\n")
             tmpFile.write(submitTemplate + separatorLine + diff + newdiff)
             tmpFile.close()
-            mtime = os.stat(fileName).st_mtime
-            if os.environ.has_key("P4EDITOR"):
-                editor = os.environ.get("P4EDITOR")
-            else:
-                editor = read_pipe("git var GIT_EDITOR").strip()
-            system(editor + " " + fileName)
-
-            if gitConfig("git-p4.skipSubmitEditCheck") == "true":
-                checkModTime = False
-            else:
-                checkModTime = True
 
-            response = "y"
-            if checkModTime and (os.stat(fileName).st_mtime <= mtime):
-                response = "x"
-                while response != "y" and response != "n":
-                    response = raw_input("Submit template unchanged. Submit anyway? [y]es, [n]o (skip this patch) ")
-
-            if response == "y":
+            if self.edit_template(fileName):
+                # read the edited message and submit
                 tmpFile = open(fileName, "rb")
                 message = tmpFile.read()
                 tmpFile.close()
@@ -1039,11 +1055,12 @@ class P4Submit(Command, P4UserMap):
                 if self.preserveUser:
                     if p4User:
                         # Get last changelist number. Cannot easily get it from
-                        # the submit command output as the output is unmarshalled.
+                        # the submit command output as the output is
+                        # unmarshalled.
                         changelist = self.lastP4Changelist()
                         self.modifyChangelistUser(changelist, p4User)
-
             else:
+                # skip this patch
                 for f in editedFiles:
                     p4_revert(f)
                 for f in filesToAdd:
@@ -1318,6 +1335,19 @@ class P4Sync(Command, P4UserMap):
             text = p4_read_pipe(['print', '-q', '-o', '-', file['depotFile']])
             contents = [ text ]
 
+        if type_base == "apple":
+            # Apple filetype files will be streamed as a concatenation of
+            # its appledouble header and the contents.  This is useless
+            # on both macs and non-macs.  If using "print -q -o xx", it
+            # will create "xx" with the data, and "%xx" with the header.
+            # This is also not very useful.
+            #
+            # Ideally, someday, this script can learn how to generate
+            # appledouble files directly and import those to git, but
+            # non-mac machines can never find a use for apple filetype.
+            print "\nIgnoring apple filetype file %s" % file['depotFile']
+            return
+
         # Perhaps windows wants unicode, utf16 newlines translated too;
         # but this is not doing it.
         if self.isWindows and type_base == "text":
index 52003ae9045626077009811cd8e10c1135d69cd0..5044a121e01668d941fdc09124b9db354213c460 100644 (file)
@@ -202,11 +202,24 @@ able to find the relevant client.  This client spec will be used to
 both filter the files cloned by git and set the directory layout as
 specified in the client (this implies --keep-path style semantics).
 
-git-p4.skipSubmitModTimeCheck
+git-p4.skipSubmitEdit
 
-  git config [--global] git-p4.skipSubmitModTimeCheck false
+  git config [--global] git-p4.skipSubmitEdit false
 
-If true, submit will not check if the p4 change template has been modified.
+Normally, git-p4 invokes an editor after each commit is applied so
+that you can make changes to the submit message.  Setting this
+variable to true will skip the editing step, submitting the change as is.
+
+git-p4.skipSubmitEditCheck
+
+  git config [--global] git-p4.skipSubmitEditCheck false
+
+After the editor is invoked, git-p4 normally makes sure you saved the
+change description, as an indication that you did indeed read it over
+and edit it.  You can quit without saving to abort the submit (or skip
+this change and continue).  Setting this variable to true will cause
+git-p4 not to check if you saved the change description.  This variable
+only matters if git-p4.skipSubmitEdit has not been set to true.
 
 git-p4.preserveUser
 
index 3bb5a4dd57c669bc59be0e2317ef33b64b024992..86e9c29ec05139844ff46868e2b52dfbc274cc39 100644 (file)
--- a/convert.c
+++ b/convert.c
@@ -641,7 +641,7 @@ static int ident_to_worktree(const char *path, const char *src, size_t len,
        return 1;
 }
 
-static int git_path_check_crlf(const char *path, struct git_attr_check *check)
+static enum crlf_action git_path_check_crlf(const char *path, struct git_attr_check *check)
 {
        const char *value = check->value;
 
@@ -658,7 +658,7 @@ static int git_path_check_crlf(const char *path, struct git_attr_check *check)
        return CRLF_GUESS;
 }
 
-static int git_path_check_eol(const char *path, struct git_attr_check *check)
+static enum eol git_path_check_eol(const char *path, struct git_attr_check *check)
 {
        const char *value = check->value;
 
@@ -811,7 +811,7 @@ int renormalize_buffer(const char *path, const char *src, size_t len, struct str
                src = dst->buf;
                len = dst->len;
        }
-       return ret | convert_to_git(path, src, len, dst, 0);
+       return ret | convert_to_git(path, src, len, dst, SAFE_CRLF_FALSE);
 }
 
 /*****************************************************************
diff --git a/dir.c b/dir.c
index 6c0d7825799f6c35a2c1f1830767ab6203e2da92..0a78d00b545ac4f302ea89b6393773669907599e 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -968,34 +968,34 @@ static int read_directory_recursive(struct dir_struct *dir,
 {
        DIR *fdir = opendir(*base ? base : ".");
        int contents = 0;
+       struct dirent *de;
+       char path[PATH_MAX + 1];
 
-       if (fdir) {
-               struct dirent *de;
-               char path[PATH_MAX + 1];
-               memcpy(path, base, baselen);
-
-               while ((de = readdir(fdir)) != NULL) {
-                       int len;
-                       switch (treat_path(dir, de, path, sizeof(path),
-                                          baselen, simplify, &len)) {
-                       case path_recurse:
-                               contents += read_directory_recursive
-                                       (dir, path, len, 0, simplify);
-                               continue;
-                       case path_ignored:
-                               continue;
-                       case path_handled:
-                               break;
-                       }
-                       contents++;
-                       if (check_only)
-                               goto exit_early;
-                       else
-                               dir_add_name(dir, path, len);
+       if (!fdir)
+               return 0;
+
+       memcpy(path, base, baselen);
+
+       while ((de = readdir(fdir)) != NULL) {
+               int len;
+               switch (treat_path(dir, de, path, sizeof(path),
+                                  baselen, simplify, &len)) {
+               case path_recurse:
+                       contents += read_directory_recursive(dir, path, len, 0, simplify);
+                       continue;
+               case path_ignored:
+                       continue;
+               case path_handled:
+                       break;
                }
-exit_early:
-               closedir(fdir);
+               contents++;
+               if (check_only)
+                       goto exit_early;
+               else
+                       dir_add_name(dir, path, len);
        }
+exit_early:
+       closedir(fdir);
 
        return contents;
 }
index 5ef8ff76f6fd262c3109d25d706ebd3db35c73fa..8b4dd5c022a160de5c68d83b6237799c23e6ae0a 100644 (file)
@@ -219,7 +219,7 @@ extern char *gitbasename(char *);
 #define find_last_dir_sep(path) strrchr(path, '/')
 #endif
 
-#if __HP_cc >= 61000
+#if defined(__HP_cc) && (__HP_cc >= 61000)
 #define NORETURN __attribute__((noreturn))
 #define NORETURN_PTR
 #elif defined(__GNUC__) && !defined(NO_NORETURN)
diff --git a/http.c b/http.c
index a4bc770e2d6196958ec5b795ca89be24be182a34..44fcc4d178fcedaa87f1917608dd32a65c24c98a 100644 (file)
--- a/http.c
+++ b/http.c
@@ -4,7 +4,6 @@
 #include "run-command.h"
 #include "url.h"
 
-int data_received;
 int active_requests;
 int http_is_verbose;
 size_t http_post_buffer = 16 * LARGE_PACKET_MAX;
@@ -99,13 +98,11 @@ size_t fwrite_buffer(char *ptr, size_t eltsize, size_t nmemb, void *buffer_)
        struct strbuf *buffer = buffer_;
 
        strbuf_add(buffer, ptr, size);
-       data_received++;
        return size;
 }
 
 size_t fwrite_null(char *ptr, size_t eltsize, size_t nmemb, void *strbuf)
 {
-       data_received++;
        return eltsize * nmemb;
 }
 
@@ -279,8 +276,6 @@ static CURL *get_curl_handle(void)
        curl_easy_setopt(result, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
 #endif
 
-       init_curl_http_auth(result);
-
        if (ssl_cert != NULL)
                curl_easy_setopt(result, CURLOPT_SSLCERT, ssl_cert);
        if (has_cert_password())
@@ -538,7 +533,6 @@ struct active_request_slot *get_active_slot(void)
 
        active_requests++;
        slot->in_use = 1;
-       slot->local = NULL;
        slot->results = NULL;
        slot->finished = NULL;
        slot->callback_data = NULL;
@@ -642,8 +636,6 @@ void step_active_slots(void)
 void run_active_slot(struct active_request_slot *slot)
 {
 #ifdef USE_CURL_MULTI
-       long last_pos = 0;
-       long current_pos;
        fd_set readfds;
        fd_set writefds;
        fd_set excfds;
@@ -653,25 +645,33 @@ void run_active_slot(struct active_request_slot *slot)
 
        slot->finished = &finished;
        while (!finished) {
-               data_received = 0;
                step_active_slots();
 
-               if (!data_received && slot->local != NULL) {
-                       current_pos = ftell(slot->local);
-                       if (current_pos > last_pos)
-                               data_received++;
-                       last_pos = current_pos;
-               }
+               if (slot->in_use) {
+#if LIBCURL_VERSION_NUM >= 0x070f04
+                       long curl_timeout;
+                       curl_multi_timeout(curlm, &curl_timeout);
+                       if (curl_timeout == 0) {
+                               continue;
+                       } else if (curl_timeout == -1) {
+                               select_timeout.tv_sec  = 0;
+                               select_timeout.tv_usec = 50000;
+                       } else {
+                               select_timeout.tv_sec  =  curl_timeout / 1000;
+                               select_timeout.tv_usec = (curl_timeout % 1000) * 1000;
+                       }
+#else
+                       select_timeout.tv_sec  = 0;
+                       select_timeout.tv_usec = 50000;
+#endif
 
-               if (slot->in_use && !data_received) {
-                       max_fd = 0;
+                       max_fd = -1;
                        FD_ZERO(&readfds);
                        FD_ZERO(&writefds);
                        FD_ZERO(&excfds);
-                       select_timeout.tv_sec = 0;
-                       select_timeout.tv_usec = 50000;
-                       select(max_fd, &readfds, &writefds,
-                              &excfds, &select_timeout);
+                       curl_multi_fdset(curlm, &readfds, &writefds, &excfds, &max_fd);
+
+                       select(max_fd+1, &readfds, &writefds, &excfds, &select_timeout);
                }
        }
 #else
@@ -749,14 +749,6 @@ static inline int needs_quote(int ch)
        return 1;
 }
 
-static inline int hex(int v)
-{
-       if (v < 10)
-               return '0' + v;
-       else
-               return 'A' + v - 10;
-}
-
 static char *quote_ref_url(const char *base, const char *ref)
 {
        struct strbuf buf = STRBUF_INIT;
@@ -824,7 +816,6 @@ static int http_request(const char *url, void *result, int target, int options)
                                headers = curl_slist_append(headers, buf.buf);
                                strbuf_reset(&buf);
                        }
-                       slot->local = result;
                } else
                        curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION,
                                         fwrite_buffer);
@@ -846,7 +837,7 @@ static int http_request(const char *url, void *result, int target, int options)
                else if (missing_target(&results))
                        ret = HTTP_MISSING_TARGET;
                else if (results.http_code == 401) {
-                       if (user_name) {
+                       if (user_name && user_pass) {
                                ret = HTTP_NOAUTH;
                        } else {
                                /*
@@ -855,7 +846,8 @@ static int http_request(const char *url, void *result, int target, int options)
                                 * but that is non-portable.  Using git_getpass() can at least be stubbed
                                 * on other platforms with a different implementation if/when necessary.
                                 */
-                               user_name = xstrdup(git_getpass_with_description("Username", description));
+                               if (!user_name)
+                                       user_name = xstrdup(git_getpass_with_description("Username", description));
                                init_curl_http_auth(slot->curl);
                                ret = HTTP_REAUTH;
                        }
@@ -871,7 +863,6 @@ static int http_request(const char *url, void *result, int target, int options)
                ret = HTTP_START_FAILED;
        }
 
-       slot->local = NULL;
        curl_slist_free_all(headers);
        strbuf_release(&buf);
 
@@ -1066,7 +1057,6 @@ void release_http_pack_request(struct http_pack_request *preq)
        if (preq->packfile != NULL) {
                fclose(preq->packfile);
                preq->packfile = NULL;
-               preq->slot->local = NULL;
        }
        if (preq->range_header != NULL) {
                curl_slist_free_all(preq->range_header);
@@ -1088,7 +1078,6 @@ int finish_http_pack_request(struct http_pack_request *preq)
 
        fclose(preq->packfile);
        preq->packfile = NULL;
-       preq->slot->local = NULL;
 
        lst = preq->lst;
        while (*lst != p)
@@ -1157,7 +1146,6 @@ struct http_pack_request *new_http_pack_request(
        }
 
        preq->slot = get_active_slot();
-       preq->slot->local = preq->packfile;
        curl_easy_setopt(preq->slot->curl, CURLOPT_FILE, preq->packfile);
        curl_easy_setopt(preq->slot->curl, CURLOPT_WRITEFUNCTION, fwrite);
        curl_easy_setopt(preq->slot->curl, CURLOPT_URL, preq->url);
@@ -1214,7 +1202,6 @@ static size_t fwrite_sha1_file(char *ptr, size_t eltsize, size_t nmemb,
                git_SHA1_Update(&freq->c, expn,
                                sizeof(expn) - freq->stream.avail_out);
        } while (freq->stream.avail_in && freq->zret == Z_OK);
-       data_received++;
        return size;
 }
 
diff --git a/http.h b/http.h
index 3c332a98e9358a296b937453351018ac1042120e..ee1606942a9716b45da937873949220ab7f8092b 100644 (file)
--- a/http.h
+++ b/http.h
@@ -49,7 +49,6 @@ struct slot_results {
 
 struct active_request_slot {
        CURL *curl;
-       FILE *local;
        int in_use;
        CURLcode curl_result;
        long http_code;
@@ -89,7 +88,6 @@ extern void step_active_slots(void);
 extern void http_init(struct remote *remote, const char *url);
 extern void http_cleanup(void);
 
-extern int data_received;
 extern int active_requests;
 extern int http_is_verbose;
 extern size_t http_post_buffer;
index 39d80c01753527e45716ec762beeb891dfc7d28d..3dd4a960190a1b0016b26dec9187692111b73e3f 100644 (file)
@@ -71,7 +71,8 @@ static void process_tree(struct rev_info *revs,
        struct tree_desc desc;
        struct name_entry entry;
        struct name_path me;
-       int match = revs->diffopt.pathspec.nr == 0 ? 2 : 0;
+       enum interesting match = revs->diffopt.pathspec.nr == 0 ?
+               all_entries_interesting: entry_not_interesting;
        int baselen = base->len;
 
        if (!revs->tree_objects)
@@ -97,12 +98,12 @@ static void process_tree(struct rev_info *revs,
        init_tree_desc(&desc, tree->buffer, tree->size);
 
        while (tree_entry(&desc, &entry)) {
-               if (match != 2) {
+               if (match != all_entries_interesting) {
                        match = tree_entry_interesting(&entry, base, 0,
                                                       &revs->diffopt.pathspec);
-                       if (match < 0)
+                       if (match == all_entries_not_interesting)
                                break;
-                       if (match == 0)
+                       if (match == entry_not_interesting)
                                continue;
                }
 
index 02fcfde0b0b786af5229559586cf8ff5758429bc..8c3196c7d76ff90e90a9fb4ff569aff6a429861a 100644 (file)
--- a/mailmap.c
+++ b/mailmap.c
@@ -70,8 +70,7 @@ static void add_mapping(struct string_list *map,
        } else {
                /* create mailmap entry */
                struct string_list_item *item = string_list_insert_at_index(map, index, old_email);
-               item->util = xmalloc(sizeof(struct mailmap_entry));
-               memset(item->util, 0, sizeof(struct mailmap_entry));
+               item->util = xcalloc(1, sizeof(struct mailmap_entry));
                ((struct mailmap_entry *)item->util)->namemap.strdup_strings = 1;
        }
        me = (struct mailmap_entry *)map->items[index].util;
@@ -88,7 +87,7 @@ static void add_mapping(struct string_list *map,
                        me->email = xstrdup(new_email);
                }
        } else {
-               struct mailmap_info *mi = xmalloc(sizeof(struct mailmap_info));
+               struct mailmap_info *mi = xcalloc(1, sizeof(struct mailmap_info));
                debug_mm("mailmap: adding (complex) entry for %s at index %d\n", old_email, index);
                if (new_name)
                        mi->name = xstrdup(new_name);
index e9e41993117ae03ed7c9d1f28081a42b2eee97ca..ce10aacf2978024eda0234482964577e9235f2d2 100644 (file)
@@ -21,14 +21,6 @@ void init_notes_merge_options(struct notes_merge_options *o)
        o->verbosity = NOTES_MERGE_VERBOSITY_DEFAULT;
 }
 
-#define OUTPUT(o, v, ...) \
-       do { \
-               if ((o)->verbosity >= (v)) { \
-                       printf(__VA_ARGS__); \
-                       puts(""); \
-               } \
-       } while (0)
-
 static int path_to_sha1(const char *path, unsigned char *sha1)
 {
        char hex_sha1[40];
@@ -392,21 +384,26 @@ static int merge_one_change_manual(struct notes_merge_options *o,
 
        strbuf_addf(&(o->commit_msg), "\t%s\n", sha1_to_hex(p->obj));
 
-       OUTPUT(o, 2, "Auto-merging notes for %s", sha1_to_hex(p->obj));
+       if (o->verbosity >= 2)
+               printf("Auto-merging notes for %s\n", sha1_to_hex(p->obj));
        check_notes_merge_worktree(o);
        if (is_null_sha1(p->local)) {
                /* D/F conflict, checkout p->remote */
                assert(!is_null_sha1(p->remote));
-               OUTPUT(o, 1, "CONFLICT (delete/modify): Notes for object %s "
-                      "deleted in %s and modified in %s. Version from %s "
-                      "left in tree.", sha1_to_hex(p->obj), lref, rref, rref);
+               if (o->verbosity >= 1)
+                       printf("CONFLICT (delete/modify): Notes for object %s "
+                               "deleted in %s and modified in %s. Version from %s "
+                               "left in tree.\n",
+                               sha1_to_hex(p->obj), lref, rref, rref);
                write_note_to_worktree(p->obj, p->remote);
        } else if (is_null_sha1(p->remote)) {
                /* D/F conflict, checkout p->local */
                assert(!is_null_sha1(p->local));
-               OUTPUT(o, 1, "CONFLICT (delete/modify): Notes for object %s "
-                      "deleted in %s and modified in %s. Version from %s "
-                      "left in tree.", sha1_to_hex(p->obj), rref, lref, lref);
+               if (o->verbosity >= 1)
+                       printf("CONFLICT (delete/modify): Notes for object %s "
+                               "deleted in %s and modified in %s. Version from %s "
+                               "left in tree.\n",
+                               sha1_to_hex(p->obj), rref, lref, lref);
                write_note_to_worktree(p->obj, p->local);
        } else {
                /* "regular" conflict, checkout result of ll_merge() */
@@ -415,8 +412,9 @@ static int merge_one_change_manual(struct notes_merge_options *o,
                        reason = "add/add";
                assert(!is_null_sha1(p->local));
                assert(!is_null_sha1(p->remote));
-               OUTPUT(o, 1, "CONFLICT (%s): Merge conflict in notes for "
-                      "object %s", reason, sha1_to_hex(p->obj));
+               if (o->verbosity >= 1)
+                       printf("CONFLICT (%s): Merge conflict in notes for "
+                               "object %s\n", reason, sha1_to_hex(p->obj));
                ll_merge_in_worktree(o, p);
        }
 
@@ -438,24 +436,30 @@ static int merge_one_change(struct notes_merge_options *o,
        case NOTES_MERGE_RESOLVE_MANUAL:
                return merge_one_change_manual(o, p, t);
        case NOTES_MERGE_RESOLVE_OURS:
-               OUTPUT(o, 2, "Using local notes for %s", sha1_to_hex(p->obj));
+               if (o->verbosity >= 2)
+                       printf("Using local notes for %s\n",
+                                               sha1_to_hex(p->obj));
                /* nothing to do */
                return 0;
        case NOTES_MERGE_RESOLVE_THEIRS:
-               OUTPUT(o, 2, "Using remote notes for %s", sha1_to_hex(p->obj));
+               if (o->verbosity >= 2)
+                       printf("Using remote notes for %s\n",
+                                               sha1_to_hex(p->obj));
                if (add_note(t, p->obj, p->remote, combine_notes_overwrite))
                        die("BUG: combine_notes_overwrite failed");
                return 0;
        case NOTES_MERGE_RESOLVE_UNION:
-               OUTPUT(o, 2, "Concatenating local and remote notes for %s",
-                      sha1_to_hex(p->obj));
+               if (o->verbosity >= 2)
+                       printf("Concatenating local and remote notes for %s\n",
+                                                       sha1_to_hex(p->obj));
                if (add_note(t, p->obj, p->remote, combine_notes_concatenate))
                        die("failed to concatenate notes "
                            "(combine_notes_concatenate)");
                return 0;
        case NOTES_MERGE_RESOLVE_CAT_SORT_UNIQ:
-               OUTPUT(o, 2, "Concatenating unique lines in local and remote "
-                      "notes for %s", sha1_to_hex(p->obj));
+               if (o->verbosity >= 2)
+                       printf("Concatenating unique lines in local and remote "
+                               "notes for %s\n", sha1_to_hex(p->obj));
                if (add_note(t, p->obj, p->remote, combine_notes_cat_sort_uniq))
                        die("failed to concatenate notes "
                            "(combine_notes_cat_sort_uniq)");
@@ -518,8 +522,9 @@ static int merge_from_diffs(struct notes_merge_options *o,
        conflicts = merge_changes(o, changes, &num_changes, t);
        free(changes);
 
-       OUTPUT(o, 4, "Merge result: %i unmerged notes and a %s notes tree",
-              conflicts, t->dirty ? "dirty" : "clean");
+       if (o->verbosity >= 4)
+               printf("Merge result: %i unmerged notes and a %s notes tree\n",
+                       conflicts, t->dirty ? "dirty" : "clean");
 
        return conflicts ? -1 : 1;
 }
@@ -617,33 +622,40 @@ int notes_merge(struct notes_merge_options *o,
        if (!bases) {
                base_sha1 = null_sha1;
                base_tree_sha1 = EMPTY_TREE_SHA1_BIN;
-               OUTPUT(o, 4, "No merge base found; doing history-less merge");
+               if (o->verbosity >= 4)
+                       printf("No merge base found; doing history-less merge\n");
        } else if (!bases->next) {
                base_sha1 = bases->item->object.sha1;
                base_tree_sha1 = bases->item->tree->object.sha1;
-               OUTPUT(o, 4, "One merge base found (%.7s)",
-                      sha1_to_hex(base_sha1));
+               if (o->verbosity >= 4)
+                       printf("One merge base found (%.7s)\n",
+                               sha1_to_hex(base_sha1));
        } else {
                /* TODO: How to handle multiple merge-bases? */
                base_sha1 = bases->item->object.sha1;
                base_tree_sha1 = bases->item->tree->object.sha1;
-               OUTPUT(o, 3, "Multiple merge bases found. Using the first "
-                      "(%.7s)", sha1_to_hex(base_sha1));
+               if (o->verbosity >= 3)
+                       printf("Multiple merge bases found. Using the first "
+                               "(%.7s)\n", sha1_to_hex(base_sha1));
        }
 
-       OUTPUT(o, 4, "Merging remote commit %.7s into local commit %.7s with "
-              "merge-base %.7s", sha1_to_hex(remote->object.sha1),
-              sha1_to_hex(local->object.sha1), sha1_to_hex(base_sha1));
+       if (o->verbosity >= 4)
+               printf("Merging remote commit %.7s into local commit %.7s with "
+                       "merge-base %.7s\n", sha1_to_hex(remote->object.sha1),
+                       sha1_to_hex(local->object.sha1),
+                       sha1_to_hex(base_sha1));
 
        if (!hashcmp(remote->object.sha1, base_sha1)) {
                /* Already merged; result == local commit */
-               OUTPUT(o, 2, "Already up-to-date!");
+               if (o->verbosity >= 2)
+                       printf("Already up-to-date!\n");
                hashcpy(result_sha1, local->object.sha1);
                goto found_result;
        }
        if (!hashcmp(local->object.sha1, base_sha1)) {
                /* Fast-forward; result == remote commit */
-               OUTPUT(o, 2, "Fast-forward");
+               if (o->verbosity >= 2)
+                       printf("Fast-forward\n");
                hashcpy(result_sha1, remote->object.sha1);
                goto found_result;
        }
@@ -685,8 +697,9 @@ int notes_merge_commit(struct notes_merge_options *o,
        int path_len = strlen(path), i;
        const char *msg = strstr(partial_commit->buffer, "\n\n");
 
-       OUTPUT(o, 3, "Committing notes in notes merge worktree at %.*s",
-              path_len - 1, path);
+       if (o->verbosity >= 3)
+               printf("Committing notes in notes merge worktree at %.*s\n",
+                       path_len - 1, path);
 
        if (!msg || msg[2] == '\0')
                die("partial notes commit has empty message");
@@ -701,7 +714,9 @@ int notes_merge_commit(struct notes_merge_options *o,
                unsigned char obj_sha1[20], blob_sha1[20];
 
                if (ent->len - path_len != 40 || get_sha1_hex(relpath, obj_sha1)) {
-                       OUTPUT(o, 3, "Skipping non-SHA1 entry '%s'", ent->name);
+                       if (o->verbosity >= 3)
+                               printf("Skipping non-SHA1 entry '%s'\n",
+                                                               ent->name);
                        continue;
                }
 
@@ -713,14 +728,16 @@ int notes_merge_commit(struct notes_merge_options *o,
                if (add_note(partial_tree, obj_sha1, blob_sha1, NULL))
                        die("Failed to add resolved note '%s' to notes tree",
                            ent->name);
-               OUTPUT(o, 4, "Added resolved note for object %s: %s",
-                      sha1_to_hex(obj_sha1), sha1_to_hex(blob_sha1));
+               if (o->verbosity >= 4)
+                       printf("Added resolved note for object %s: %s\n",
+                               sha1_to_hex(obj_sha1), sha1_to_hex(blob_sha1));
        }
 
        create_notes_commit(partial_tree, partial_commit->parents, msg,
                            result_sha1);
-       OUTPUT(o, 4, "Finalized notes merge commit: %s",
-              sha1_to_hex(result_sha1));
+       if (o->verbosity >= 4)
+               printf("Finalized notes merge commit: %s\n",
+                       sha1_to_hex(result_sha1));
        free(path);
        return 0;
 }
@@ -732,7 +749,8 @@ int notes_merge_abort(struct notes_merge_options *o)
        int ret;
 
        strbuf_addstr(&buf, git_path(NOTES_MERGE_WORKTREE));
-       OUTPUT(o, 3, "Removing notes merge worktree at %s", buf.buf);
+       if (o->verbosity >= 3)
+               printf("Removing notes merge worktree at %s\n", buf.buf);
        ret = remove_dir_recursively(&buf, 0);
        strbuf_release(&buf);
        return ret;
index 98b24772c7ebe838d513d8e24f3c8acff7839cb9..9235e73163204593379cdf6367133b5b503423c2 100644 (file)
@@ -1,5 +1,6 @@
 perl.mak
 perl.mak.old
+MYMETA.yml
 blib
 blibdirs
 pm_to_blib
diff --git a/refs.c b/refs.c
index e69ba26b74e430388c63af21473438468678bb4b..e7843eb6b70b7de6c1ed1992db7adee1d99b27bc 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -48,7 +48,7 @@ static const char *parse_ref_line(char *line, unsigned char *sha1)
 }
 
 static void add_ref(const char *name, const unsigned char *sha1,
-                   int flag, struct ref_array *refs,
+                   int flag, int check_name, struct ref_array *refs,
                    struct ref_entry **new_entry)
 {
        int len;
@@ -59,7 +59,8 @@ static void add_ref(const char *name, const unsigned char *sha1,
        entry = xmalloc(sizeof(struct ref_entry) + len);
        hashcpy(entry->sha1, sha1);
        hashclr(entry->peeled);
-       if (check_refname_format(name, REFNAME_ALLOW_ONELEVEL|REFNAME_DOT_COMPONENT))
+       if (check_name &&
+           check_refname_format(name, REFNAME_ALLOW_ONELEVEL|REFNAME_DOT_COMPONENT))
                die("Reference has invalid format: '%s'", name);
        memcpy(entry->name, name, len);
        entry->flag = flag;
@@ -234,7 +235,7 @@ static void read_packed_refs(FILE *f, struct ref_array *array)
 
                name = parse_ref_line(refline, sha1);
                if (name) {
-                       add_ref(name, sha1, flag, array, &last);
+                       add_ref(name, sha1, flag, 1, array, &last);
                        continue;
                }
                if (last &&
@@ -249,7 +250,7 @@ static void read_packed_refs(FILE *f, struct ref_array *array)
 
 void add_extra_ref(const char *name, const unsigned char *sha1, int flag)
 {
-       add_ref(name, sha1, flag, &extra_refs, NULL);
+       add_ref(name, sha1, flag, 0, &extra_refs, NULL);
 }
 
 void clear_extra_refs(void)
@@ -333,12 +334,11 @@ static void get_ref_dir(const char *submodule, const char *base,
                                        hashclr(sha1);
                                        flag |= REF_ISBROKEN;
                                }
-                       } else
-                               if (!resolve_ref(ref, sha1, 1, &flag)) {
-                                       hashclr(sha1);
-                                       flag |= REF_ISBROKEN;
-                               }
-                       add_ref(ref, sha1, flag, array, NULL);
+                       } else if (!resolve_ref(ref, sha1, 1, &flag)) {
+                               hashclr(sha1);
+                               flag |= REF_ISBROKEN;
+                       }
+                       add_ref(ref, sha1, flag, 1, array, NULL);
                }
                free(ref);
                closedir(dir);
index 905d29501213f058f0d8cc88e7ba57527d506483..f435fdb4b147d2e2ce5480ddb4832228af1cb73b 100644 (file)
@@ -13,7 +13,7 @@
  *
  * With the aggressive flag, it additionally removes SEQ_OLD_DIR,
  * ignoring any errors.  Inteded to be used by the sequencer's
- * '--reset' subcommand.
+ * '--quit' subcommand.
  */
 void remove_sequencer_state(int aggressive);
 
index 27f3b9b278a97f66f92ca61a2bc39e30f0a70317..956422ba4a5df5f46caaf85f10e4c85321439272 100644 (file)
@@ -1267,7 +1267,8 @@ unsigned long unpack_object_header_buffer(const unsigned char *buf,
        while (c & 0x80) {
                if (len <= used || bitsizeof(long) <= shift) {
                        error("bad object header");
-                       return 0;
+                       size = used = 0;
+                       break;
                }
                c = buf[used++];
                size += (c & 0x7f) << shift;
@@ -2616,7 +2617,7 @@ static int index_mem(unsigned char *sha1, void *buf, size_t size,
        if ((type == OBJ_BLOB) && path) {
                struct strbuf nbuf = STRBUF_INIT;
                if (convert_to_git(path, buf, size, &nbuf,
-                                  write_object ? safe_crlf : 0)) {
+                                  write_object ? safe_crlf : SAFE_CRLF_FALSE)) {
                        buf = strbuf_detach(&nbuf, &size);
                        re_allocated = 1;
                }
index cb45574a7b5cbdf6da58f609befc4a0bb396db2f..ee1659c17810d2c9ce7836582a80fd3d0d89ca24 100755 (executable)
@@ -253,6 +253,60 @@ test_expect_success 'revert also handles conflicts sanely' '
        test_cmp expected actual
 '
 
+test_expect_success 'failed revert sets REVERT_HEAD' '
+       pristine_detach initial &&
+       test_must_fail git revert picked &&
+       test_cmp_rev picked REVERT_HEAD
+'
+
+test_expect_success 'successful revert does not set REVERT_HEAD' '
+       pristine_detach base &&
+       git revert base &&
+       test_must_fail git rev-parse --verify CHERRY_PICK_HEAD &&
+       test_must_fail git rev-parse --verify REVERT_HEAD
+'
+
+test_expect_success 'revert --no-commit sets REVERT_HEAD' '
+       pristine_detach base &&
+       git revert --no-commit base &&
+       test_must_fail git rev-parse --verify CHERRY_PICK_HEAD &&
+       test_cmp_rev base REVERT_HEAD
+'
+
+test_expect_success 'revert w/dirty tree does not set REVERT_HEAD' '
+       pristine_detach base &&
+       echo foo > foo &&
+       test_must_fail git revert base &&
+       test_must_fail git rev-parse --verify CHERRY_PICK_HEAD &&
+       test_must_fail git rev-parse --verify REVERT_HEAD
+'
+
+test_expect_success 'GIT_CHERRY_PICK_HELP does not suppress REVERT_HEAD' '
+       pristine_detach initial &&
+       (
+               GIT_CHERRY_PICK_HELP="and then do something else" &&
+               GIT_REVERT_HELP="and then do something else, again" &&
+               export GIT_CHERRY_PICK_HELP GIT_REVERT_HELP &&
+               test_must_fail git revert picked
+       ) &&
+       test_must_fail git rev-parse --verify CHERRY_PICK_HEAD &&
+       test_cmp_rev picked REVERT_HEAD
+'
+
+test_expect_success 'git reset clears REVERT_HEAD' '
+       pristine_detach initial &&
+       test_must_fail git revert picked &&
+       git reset &&
+       test_must_fail git rev-parse --verify REVERT_HEAD
+'
+
+test_expect_success 'failed commit does not clear REVERT_HEAD' '
+       pristine_detach initial &&
+       test_must_fail git revert picked &&
+       test_must_fail git commit &&
+       test_cmp_rev picked REVERT_HEAD
+'
+
 test_expect_success 'revert conflict, diff3 -m style' '
        pristine_detach initial &&
        git config merge.conflictstyle diff3 &&
index 3bca2b3dd5cc252cad615b83f84891f6dc2bacfe..2c4c1c851dcbb1cd38edc2a2620e2b04e36f7192 100755 (executable)
@@ -2,6 +2,7 @@
 
 test_description='Test cherry-pick continuation features
 
+  + yetanotherpick: rewrites foo to e
   + anotherpick: rewrites foo to d
   + picked: rewrites foo to c
   + unrelatedpick: rewrites unrelated to reallyunrelated
@@ -13,12 +14,18 @@ test_description='Test cherry-pick continuation features
 . ./test-lib.sh
 
 pristine_detach () {
-       git cherry-pick --reset &&
+       git cherry-pick --quit &&
        git checkout -f "$1^0" &&
        git read-tree -u --reset HEAD &&
        git clean -d -f -f -q -x
 }
 
+test_cmp_rev () {
+       git rev-parse --verify "$1" >expect.rev &&
+       git rev-parse --verify "$2" >actual.rev &&
+       test_cmp expect.rev actual.rev
+}
+
 test_expect_success setup '
        echo unrelated >unrelated &&
        git add unrelated &&
@@ -27,6 +34,7 @@ test_expect_success setup '
        test_commit unrelatedpick unrelated reallyunrelated &&
        test_commit picked foo c &&
        test_commit anotherpick foo d &&
+       test_commit yetanotherpick foo e &&
        git config advice.detachedhead false
 
 '
@@ -70,18 +78,117 @@ test_expect_success 'cherry-pick cleans up sequencer state upon success' '
        test_path_is_missing .git/sequencer
 '
 
-test_expect_success '--reset does not complain when no cherry-pick is in progress' '
+test_expect_success '--quit does not complain when no cherry-pick is in progress' '
        pristine_detach initial &&
-       git cherry-pick --reset
+       git cherry-pick --quit
 '
 
-test_expect_success '--reset cleans up sequencer state' '
+test_expect_success '--abort requires cherry-pick in progress' '
+       pristine_detach initial &&
+       test_must_fail git cherry-pick --abort
+'
+
+test_expect_success '--quit cleans up sequencer state' '
        pristine_detach initial &&
        test_must_fail git cherry-pick base..picked &&
-       git cherry-pick --reset &&
+       git cherry-pick --quit &&
        test_path_is_missing .git/sequencer
 '
 
+test_expect_success '--quit keeps HEAD and conflicted index intact' '
+       pristine_detach initial &&
+       cat >expect <<-\EOF &&
+       OBJID
+       :100644 100644 OBJID OBJID M    unrelated
+       OBJID
+       :000000 100644 OBJID OBJID A    foo
+       :000000 100644 OBJID OBJID A    unrelated
+       EOF
+       test_must_fail git cherry-pick base..picked &&
+       git cherry-pick --quit &&
+       test_path_is_missing .git/sequencer &&
+       test_must_fail git update-index --refresh &&
+       {
+               git rev-list HEAD |
+               git diff-tree --root --stdin |
+               sed "s/$_x40/OBJID/g"
+       } >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success '--abort to cancel multiple cherry-pick' '
+       pristine_detach initial &&
+       test_must_fail git cherry-pick base..anotherpick &&
+       git cherry-pick --abort &&
+       test_path_is_missing .git/sequencer &&
+       test_cmp_rev initial HEAD &&
+       git update-index --refresh &&
+       git diff-index --exit-code HEAD
+'
+
+test_expect_success '--abort to cancel single cherry-pick' '
+       pristine_detach initial &&
+       test_must_fail git cherry-pick picked &&
+       git cherry-pick --abort &&
+       test_path_is_missing .git/sequencer &&
+       test_cmp_rev initial HEAD &&
+       git update-index --refresh &&
+       git diff-index --exit-code HEAD
+'
+
+test_expect_success 'cherry-pick --abort to cancel multiple revert' '
+       pristine_detach anotherpick &&
+       test_must_fail git revert base..picked &&
+       git cherry-pick --abort &&
+       test_path_is_missing .git/sequencer &&
+       test_cmp_rev anotherpick HEAD &&
+       git update-index --refresh &&
+       git diff-index --exit-code HEAD
+'
+
+test_expect_success 'revert --abort works, too' '
+       pristine_detach anotherpick &&
+       test_must_fail git revert base..picked &&
+       git revert --abort &&
+       test_path_is_missing .git/sequencer &&
+       test_cmp_rev anotherpick HEAD
+'
+
+test_expect_success '--abort to cancel single revert' '
+       pristine_detach anotherpick &&
+       test_must_fail git revert picked &&
+       git revert --abort &&
+       test_path_is_missing .git/sequencer &&
+       test_cmp_rev anotherpick HEAD &&
+       git update-index --refresh &&
+       git diff-index --exit-code HEAD
+'
+
+test_expect_success '--abort keeps unrelated change, easy case' '
+       pristine_detach unrelatedpick &&
+       echo changed >expect &&
+       test_must_fail git cherry-pick picked..yetanotherpick &&
+       echo changed >unrelated &&
+       git cherry-pick --abort &&
+       test_cmp expect unrelated
+'
+
+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 &&
+       echo changed >unrelated &&
+       test_must_fail git cherry-pick --abort &&
+       test_cmp expect unrelated &&
+       git rev-list HEAD >log &&
+       test_line_count = 2 log &&
+       test_must_fail git update-index --refresh &&
+
+       git checkout unrelated &&
+       git cherry-pick --abort &&
+       test_cmp_rev initial HEAD
+'
+
 test_expect_success 'cherry-pick cleans up sequencer state when one commit is left' '
        pristine_detach initial &&
        test_must_fail git cherry-pick base..picked &&
@@ -106,6 +213,16 @@ test_expect_success 'cherry-pick cleans up sequencer state when one commit is le
        test_cmp expect actual
 '
 
+test_expect_failure '--abort after last commit in sequence' '
+       pristine_detach initial &&
+       test_must_fail git cherry-pick base..picked &&
+       git cherry-pick --abort &&
+       test_path_is_missing .git/sequencer &&
+       test_cmp_rev initial HEAD &&
+       git update-index --refresh &&
+       git diff-index --exit-code HEAD
+'
+
 test_expect_success 'cherry-pick does not implicitly stomp an existing operation' '
        pristine_detach initial &&
        test_must_fail git cherry-pick base..anotherpick &&
index 889842e7fc0cf80f7e8b6016a508bffdb0399d32..d9068981f8475c37d30e584bc6b795075a2f3063 100755 (executable)
@@ -96,7 +96,7 @@ test_expect_success 'git archive with --output' \
     'git archive --output=b4.tar HEAD &&
     test_cmp b.tar b4.tar'
 
-test_expect_success 'git archive --remote' \
+test_expect_success NOT_MINGW 'git archive --remote' \
     'git archive --remote=. HEAD >b5.tar &&
     test_cmp b.tar b5.tar'
 
@@ -266,7 +266,7 @@ test_expect_success 'archive --list mentions user filter' '
        grep "^bar\$" output
 '
 
-test_expect_success 'archive --list shows only enabled remote filters' '
+test_expect_success NOT_MINGW 'archive --list shows only enabled remote filters' '
        git archive --list --remote=. >output &&
        ! grep "^tar\.foo\$" output &&
        grep "^bar\$" output
@@ -298,7 +298,7 @@ test_expect_success 'extension matching requires dot' '
        test_cmp b.tar config-implicittar.foo
 '
 
-test_expect_success 'only enabled filters are available remotely' '
+test_expect_success NOT_MINGW 'only enabled filters are available remotely' '
        test_must_fail git archive --remote=. --format=tar.foo HEAD \
                >remote.tar.foo &&
        git archive --remote=. --format=bar >remote.bar HEAD &&
@@ -341,12 +341,12 @@ test_expect_success GZIP,GUNZIP 'extract tgz file' '
        test_cmp b.tar j.tar
 '
 
-test_expect_success GZIP 'remote tar.gz is allowed by default' '
+test_expect_success GZIP,NOT_MINGW 'remote tar.gz is allowed by default' '
        git archive --remote=. --format=tar.gz HEAD >remote.tar.gz &&
        test_cmp j.tgz remote.tar.gz
 '
 
-test_expect_success GZIP 'remote tar.gz can be disabled' '
+test_expect_success GZIP,NOT_MINGW 'remote tar.gz can be disabled' '
        git config tar.tar.gz.remote false &&
        test_must_fail git archive --remote=. --format=tar.gz HEAD \
                >remote.tar.gz
index b5ced8483a8fc663eb53b514bbb56df92f217deb..1bc57ac03f9df7e82fab5478b7234ab1435c60e3 100755 (executable)
@@ -28,7 +28,7 @@ test_expect_success setup '
                done
        ) &&
        (
-               git clone --reference=original "file:///$(pwd)/original" one &&
+               git clone --reference=original "file://$(pwd)/original" one &&
                cd one &&
                echo Z >count &&
                git add count &&
index 895f5595aee9341276e79497b9c4a8736c78e5e7..c4c375ac042bbb7f58998c87d8c9277d2f5004a6 100755 (executable)
@@ -146,4 +146,11 @@ test_expect_success 'cloning with reference being subset of source (-l -s)' \
 
 cd "$base_dir"
 
+test_expect_success 'clone with reference from a tagged repository' '
+       (
+               cd A && git tag -a -m 'tagged' HEAD
+       ) &&
+       git clone --reference=A A I
+'
+
 test_done
index c6f1f9f8ab2353ec81401828f8500cb7c1a869fb..691e4a4481eba2994ec40e498d4cd25fcff67f26 100755 (executable)
@@ -164,7 +164,7 @@ test_expect_success 'bisect start: existing ".git/BISECT_START" not modified if
        cp .git/BISECT_START saved &&
        test_must_fail git bisect start $HASH4 foo -- &&
        git branch > branch.output &&
-       grep "* (no branch)" branch.output > /dev/null &&
+       test_i18ngrep "* (no branch)" branch.output > /dev/null &&
        test_cmp saved .git/BISECT_START
 '
 test_expect_success 'bisect start: no ".git/BISECT_START" if mistaken rev' '
index 4956caaf82be8c42ef01a9adae55387e87adaa04..83f7ea59c9b4e05aa200bc4ebd77f0c16bd8ef33 100755 (executable)
@@ -12,7 +12,7 @@ test_description='Test interaction of reset --hard with sequencer
 . ./test-lib.sh
 
 pristine_detach () {
-       git cherry-pick --reset &&
+       git cherry-pick --quit &&
        git checkout -f "$1^0" &&
        git read-tree -u --reset HEAD &&
        git clean -d -f -f -q -x
@@ -41,4 +41,12 @@ test_expect_success 'reset --hard cleans up sequencer state, providing one-level
        test_path_is_missing .git/sequencer-old
 '
 
+test_expect_success 'cherry-pick --abort does not leave sequencer-old dir' '
+       pristine_detach initial &&
+       test_must_fail git cherry-pick base..anotherpick &&
+       git cherry-pick --abort &&
+       test_path_is_missing .git/sequencer &&
+       test_path_is_missing .git/sequencer-old
+'
+
 test_done
index 905255adf0ca5b15d9befa772cda4a650bd15f34..fc57b135c50e34ab86c04d0a0ec81052ce40f8ff 100755 (executable)
@@ -189,7 +189,7 @@ test_expect_success 'status with gitignore' '
        #       untracked
        EOF
        git status --ignored >output &&
-       test_cmp expect output
+       test_i18ncmp expect output
 '
 
 test_expect_success 'status with gitignore (nothing untracked)' '
@@ -247,7 +247,7 @@ test_expect_success 'status with gitignore (nothing untracked)' '
        #       untracked
        EOF
        git status --ignored >output &&
-       test_cmp expect output
+       test_i18ncmp expect output
 '
 
 rm -f .gitignore
index 3b358ef8d8fa485d9d43fe680b13f3961c5c79f8..992bb8cf0ba40104e4c6c43babcd2edbb4ac90f1 100755 (executable)
@@ -101,6 +101,37 @@ test_expect_success 'keyword file test' '
        )
 '
 
+build_gendouble() {
+       cat >gendouble.py <<-\EOF
+       import sys
+       import struct
+       import array
+
+       s = array.array("c", '\0' * 26)
+       struct.pack_into(">L", s,  0, 0x00051607)  # AppleDouble
+       struct.pack_into(">L", s,  4, 0x00020000)  # version 2
+       s.tofile(sys.stdout)
+       EOF
+}
+
+test_expect_success 'ignore apple' '
+       test_when_finished rm -f gendouble.py &&
+       build_gendouble &&
+       (
+               cd "$cli" &&
+               test-genrandom apple 1024 >double.png &&
+               "$PYTHON_PATH" "$TRASH_DIRECTORY/gendouble.py" >%double.png &&
+               p4 add -t apple double.png &&
+               p4 submit -d appledouble
+       ) &&
+       test_when_finished cleanup_git &&
+       "$GITP4" clone --dest="$git" //depot@all &&
+       (
+               cd "$git" &&
+               test ! -f double.png
+       )
+'
+
 test_expect_success 'kill p4d' '
        kill_p4d
 '
diff --git a/t/t9805-skip-submit-edit.sh b/t/t9805-skip-submit-edit.sh
new file mode 100755 (executable)
index 0000000..734ccf2
--- /dev/null
@@ -0,0 +1,82 @@
+#!/bin/sh
+
+test_description='git-p4 skipSubmitEdit config variables'
+
+. ./lib-git-p4.sh
+
+test_expect_success 'start p4d' '
+       start_p4d
+'
+
+test_expect_success 'init depot' '
+       (
+               cd "$cli" &&
+               echo file1 >file1 &&
+               p4 add file1 &&
+               p4 submit -d "change 1"
+       )
+'
+
+# this works because EDITOR is set to :
+test_expect_success 'no config, unedited, say yes' '
+       "$GITP4" clone --dest="$git" //depot &&
+       test_when_finished cleanup_git &&
+       (
+               cd "$git" &&
+               echo line >>file1 &&
+               git commit -a -m "change 2" &&
+               echo y | "$GITP4" submit &&
+               p4 changes //depot/... >wc &&
+               test_line_count = 2 wc
+       )
+'
+
+test_expect_success 'no config, unedited, say no' '
+       "$GITP4" clone --dest="$git" //depot &&
+       test_when_finished cleanup_git &&
+       (
+               cd "$git" &&
+               echo line >>file1 &&
+               git commit -a -m "change 3 (not really)" &&
+               printf "bad response\nn\n" | "$GITP4" submit
+               p4 changes //depot/... >wc &&
+               test_line_count = 2 wc
+       )
+'
+
+test_expect_success 'skipSubmitEdit' '
+       "$GITP4" clone --dest="$git" //depot &&
+       test_when_finished cleanup_git &&
+       (
+               cd "$git" &&
+               git config git-p4.skipSubmitEdit true &&
+               # will fail if editor is even invoked
+               git config core.editor /bin/false &&
+               echo line >>file1 &&
+               git commit -a -m "change 3" &&
+               "$GITP4" submit &&
+               p4 changes //depot/... >wc &&
+               test_line_count = 3 wc
+       )
+'
+
+test_expect_success 'skipSubmitEditCheck' '
+       "$GITP4" clone --dest="$git" //depot &&
+       test_when_finished cleanup_git &&
+       (
+               cd "$git" &&
+               git config git-p4.skipSubmitEditCheck true &&
+               echo line >>file1 &&
+               git commit -a -m "change 4" &&
+               "$GITP4" submit &&
+               p4 changes //depot/... >wc &&
+               test_line_count = 4 wc
+       )
+'
+
+
+test_expect_success 'kill p4d' '
+       kill_p4d
+'
+
+test_done
index b3cc2e4753447d4734ed08a70e3396771257dced..7a51d091b5a6babed91f60b9ff7079308afa4e6f 100644 (file)
@@ -21,8 +21,8 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2,
        sha1 = tree_entry_extract(t1, &path1, &mode1);
        sha2 = tree_entry_extract(t2, &path2, &mode2);
 
-       pathlen1 = tree_entry_len(path1, sha1);
-       pathlen2 = tree_entry_len(path2, sha2);
+       pathlen1 = tree_entry_len(&t1->entry);
+       pathlen2 = tree_entry_len(&t2->entry);
        cmp = base_name_compare(path1, pathlen1, mode1, path2, pathlen2, mode2);
        if (cmp < 0) {
                show_entry(opt, "-", t1, base);
@@ -64,14 +64,14 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2,
 static void show_tree(struct diff_options *opt, const char *prefix,
                      struct tree_desc *desc, struct strbuf *base)
 {
-       int match = 0;
+       enum interesting match = entry_not_interesting;
        for (; desc->size; update_tree_entry(desc)) {
-               if (match != 2) {
+               if (match != all_entries_interesting) {
                        match = tree_entry_interesting(&desc->entry, base, 0,
                                                       &opt->pathspec);
-                       if (match < 0)
+                       if (match == all_entries_not_interesting)
                                break;
-                       if (match == 0)
+                       if (match == entry_not_interesting)
                                continue;
                }
                show_entry(opt, prefix, desc, base);
@@ -85,7 +85,7 @@ static void show_entry(struct diff_options *opt, const char *prefix,
        unsigned mode;
        const char *path;
        const unsigned char *sha1 = tree_entry_extract(desc, &path, &mode);
-       int pathlen = tree_entry_len(path, sha1);
+       int pathlen = tree_entry_len(&desc->entry);
        int old_baselen = base->len;
 
        strbuf_add(base, path, pathlen);
@@ -114,12 +114,13 @@ static void show_entry(struct diff_options *opt, const char *prefix,
 }
 
 static void skip_uninteresting(struct tree_desc *t, struct strbuf *base,
-                              struct diff_options *opt, int *match)
+                              struct diff_options *opt,
+                              enum interesting *match)
 {
        while (t->size) {
                *match = tree_entry_interesting(&t->entry, base, 0, &opt->pathspec);
                if (*match) {
-                       if (*match < 0)
+                       if (*match == all_entries_not_interesting)
                                t->size = 0;
                        break;
                }
@@ -132,7 +133,8 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2,
 {
        struct strbuf base;
        int baselen = strlen(base_str);
-       int t1_match = 0, t2_match = 0;
+       enum interesting t1_match = entry_not_interesting;
+       enum interesting t2_match = entry_not_interesting;
 
        /* Enable recursion indefinitely */
        opt->pathspec.recursive = DIFF_OPT_TST(opt, RECURSIVE);
index 418107ec83728473093b43dfe74ab709f312e8a8..f82dba6a1f43bf2a259952a4fd6db94d6335deb7 100644 (file)
@@ -116,7 +116,7 @@ void setup_traverse_info(struct traverse_info *info, const char *base)
 
 char *make_traverse_path(char *path, const struct traverse_info *info, const struct name_entry *n)
 {
-       int len = tree_entry_len(n->path, n->sha1);
+       int len = tree_entry_len(n);
        int pathlen = info->pathlen;
 
        path[pathlen + len] = 0;
@@ -126,7 +126,7 @@ char *make_traverse_path(char *path, const struct traverse_info *info, const str
                        break;
                path[--pathlen] = '/';
                n = &info->name;
-               len = tree_entry_len(n->path, n->sha1);
+               len = tree_entry_len(n);
                info = info->prev;
                pathlen -= len;
        }
@@ -253,7 +253,7 @@ static void extended_entry_extract(struct tree_desc_x *t,
         * The caller wants "first" from this tree, or nothing.
         */
        path = a->path;
-       len = tree_entry_len(a->path, a->sha1);
+       len = tree_entry_len(a);
        switch (check_entry_match(first, first_len, path, len)) {
        case -1:
                entry_clear(a);
@@ -271,7 +271,7 @@ static void extended_entry_extract(struct tree_desc_x *t,
        while (probe.size) {
                entry_extract(&probe, a);
                path = a->path;
-               len = tree_entry_len(a->path, a->sha1);
+               len = tree_entry_len(a);
                switch (check_entry_match(first, first_len, path, len)) {
                case -1:
                        entry_clear(a);
@@ -362,7 +362,7 @@ int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info)
                        e = entry + i;
                        if (!e->path)
                                continue;
-                       len = tree_entry_len(e->path, e->sha1);
+                       len = tree_entry_len(e);
                        if (!first) {
                                first = e->path;
                                first_len = len;
@@ -381,7 +381,7 @@ int traverse_trees(int n, struct tree_desc *t, struct traverse_info *info)
                                /* Cull the ones that are not the earliest */
                                if (!e->path)
                                        continue;
-                               len = tree_entry_len(e->path, e->sha1);
+                               len = tree_entry_len(e);
                                if (name_compare(e->path, len, first, first_len))
                                        entry_clear(e);
                        }
@@ -434,8 +434,8 @@ static int find_tree_entry(struct tree_desc *t, const char *name, unsigned char
                int entrylen, cmp;
 
                sha1 = tree_entry_extract(t, &entry, mode);
+               entrylen = tree_entry_len(&t->entry);
                update_tree_entry(t);
-               entrylen = tree_entry_len(entry, sha1);
                if (entrylen > namelen)
                        continue;
                cmp = memcmp(name, entry, entrylen);
@@ -465,7 +465,6 @@ int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned ch
        int retval;
        void *tree;
        unsigned long size;
-       struct tree_desc t;
        unsigned char root[20];
 
        tree = read_object_with_reference(tree_sha1, tree_type, &size, root);
@@ -478,8 +477,13 @@ int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned ch
                return 0;
        }
 
-       init_tree_desc(&t, tree, size);
-       retval = find_tree_entry(&t, name, sha1, mode);
+       if (!size) {
+               retval = -1;
+       } else {
+               struct tree_desc t;
+               init_tree_desc(&t, tree, size);
+               retval = find_tree_entry(&t, name, sha1, mode);
+       }
        free(tree);
        return retval;
 }
@@ -573,30 +577,26 @@ static int match_dir_prefix(const char *base,
  *
  * Pre-condition: either baselen == base_offset (i.e. empty path)
  * or base[baselen-1] == '/' (i.e. with trailing slash).
- *
- * Return:
- *  - 2 for "yes, and all subsequent entries will be"
- *  - 1 for yes
- *  - zero for no
- *  - negative for "no, and no subsequent entries will be either"
  */
-int tree_entry_interesting(const struct name_entry *entry,
-                          struct strbuf *base, int base_offset,
-                          const struct pathspec *ps)
+enum interesting tree_entry_interesting(const struct name_entry *entry,
+                                       struct strbuf *base, int base_offset,
+                                       const struct pathspec *ps)
 {
        int i;
        int pathlen, baselen = base->len - base_offset;
-       int never_interesting = ps->has_wildcard ? 0 : -1;
+       int never_interesting = ps->has_wildcard ?
+               entry_not_interesting : all_entries_not_interesting;
 
        if (!ps->nr) {
                if (!ps->recursive || ps->max_depth == -1)
-                       return 2;
-               return !!within_depth(base->buf + base_offset, baselen,
-                                     !!S_ISDIR(entry->mode),
-                                     ps->max_depth);
+                       return all_entries_interesting;
+               return within_depth(base->buf + base_offset, baselen,
+                                   !!S_ISDIR(entry->mode),
+                                   ps->max_depth) ?
+                       entry_interesting : entry_not_interesting;
        }
 
-       pathlen = tree_entry_len(entry->path, entry->sha1);
+       pathlen = tree_entry_len(entry);
 
        for (i = ps->nr - 1; i >= 0; i--) {
                const struct pathspec_item *item = ps->items+i;
@@ -610,12 +610,13 @@ int tree_entry_interesting(const struct name_entry *entry,
                                goto match_wildcards;
 
                        if (!ps->recursive || ps->max_depth == -1)
-                               return 2;
+                               return all_entries_interesting;
 
-                       return !!within_depth(base_str + matchlen + 1,
-                                             baselen - matchlen - 1,
-                                             !!S_ISDIR(entry->mode),
-                                             ps->max_depth);
+                       return within_depth(base_str + matchlen + 1,
+                                           baselen - matchlen - 1,
+                                           !!S_ISDIR(entry->mode),
+                                           ps->max_depth) ?
+                               entry_interesting : entry_not_interesting;
                }
 
                /* Either there must be no base, or the base must match. */
@@ -623,25 +624,25 @@ int tree_entry_interesting(const struct name_entry *entry,
                        if (match_entry(entry, pathlen,
                                        match + baselen, matchlen - baselen,
                                        &never_interesting))
-                               return 1;
+                               return entry_interesting;
 
-                       if (ps->items[i].use_wildcard) {
+                       if (item->use_wildcard) {
                                if (!fnmatch(match + baselen, entry->path, 0))
-                                       return 1;
+                                       return entry_interesting;
 
                                /*
                                 * Match all directories. We'll try to
                                 * match files later on.
                                 */
                                if (ps->recursive && S_ISDIR(entry->mode))
-                                       return 1;
+                                       return entry_interesting;
                        }
 
                        continue;
                }
 
 match_wildcards:
-               if (!ps->items[i].use_wildcard)
+               if (!item->use_wildcard)
                        continue;
 
                /*
@@ -653,7 +654,7 @@ int tree_entry_interesting(const struct name_entry *entry,
 
                if (!fnmatch(match, base->buf + base_offset, 0)) {
                        strbuf_setlen(base, base_offset + baselen);
-                       return 1;
+                       return entry_interesting;
                }
                strbuf_setlen(base, base_offset + baselen);
 
@@ -662,7 +663,7 @@ int tree_entry_interesting(const struct name_entry *entry,
                 * later on.
                 */
                if (ps->recursive && S_ISDIR(entry->mode))
-                       return 1;
+                       return entry_interesting;
        }
        return never_interesting; /* No matches */
 }
index 0089581e1dd55800302799a7381d4a7ad01bd79d..2bf0db9814a5c9f77fe00c97fa4f723986a7aac1 100644 (file)
@@ -20,9 +20,9 @@ static inline const unsigned char *tree_entry_extract(struct tree_desc *desc, co
        return desc->entry.sha1;
 }
 
-static inline int tree_entry_len(const char *name, const unsigned char *sha1)
+static inline int tree_entry_len(const struct name_entry *ne)
 {
-       return (const char *)sha1 - name - 1;
+       return (const char *)ne->sha1 - ne->path - 1;
 }
 
 void update_tree_entry(struct tree_desc *);
@@ -58,9 +58,19 @@ extern void setup_traverse_info(struct traverse_info *info, const char *base);
 
 static inline int traverse_path_len(const struct traverse_info *info, const struct name_entry *n)
 {
-       return info->pathlen + tree_entry_len(n->path, n->sha1);
+       return info->pathlen + tree_entry_len(n);
 }
 
-extern int tree_entry_interesting(const struct name_entry *, struct strbuf *, int, const struct pathspec *ps);
+/* in general, positive means "kind of interesting" */
+enum interesting {
+       all_entries_not_interesting = -1, /* no, and no subsequent entries will be either */
+       entry_not_interesting = 0,
+       entry_interesting = 1,
+       all_entries_interesting = 2 /* yes, and all subsequent entries will be */
+};
+
+extern enum interesting tree_entry_interesting(const struct name_entry *,
+                                              struct strbuf *, int,
+                                              const struct pathspec *ps);
 
 #endif
diff --git a/tree.c b/tree.c
index 698ecf7af13871cf9639e969f368ba5d7b2e940a..676e9f710ca8d5a568e0c6ea2fa88132da81b48c 100644 (file)
--- a/tree.c
+++ b/tree.c
@@ -52,7 +52,8 @@ static int read_tree_1(struct tree *tree, struct strbuf *base,
        struct tree_desc desc;
        struct name_entry entry;
        unsigned char sha1[20];
-       int len, retval = 0, oldlen = base->len;
+       int len, oldlen = base->len;
+       enum interesting retval = entry_not_interesting;
 
        if (parse_tree(tree))
                return -1;
@@ -60,11 +61,11 @@ static int read_tree_1(struct tree *tree, struct strbuf *base,
        init_tree_desc(&desc, tree->buffer, tree->size);
 
        while (tree_entry(&desc, &entry)) {
-               if (retval != 2) {
+               if (retval != all_entries_interesting) {
                        retval = tree_entry_interesting(&entry, base, 0, pathspec);
-                       if (retval < 0)
+                       if (retval == all_entries_not_interesting)
                                break;
-                       if (retval == 0)
+                       if (retval == entry_not_interesting)
                                continue;
                }
 
@@ -99,7 +100,7 @@ static int read_tree_1(struct tree *tree, struct strbuf *base,
                else
                        continue;
 
-               len = tree_entry_len(entry.path, entry.sha1);
+               len = tree_entry_len(&entry);
                strbuf_add(base, entry.path, len);
                strbuf_addch(base, '/');
                retval = read_tree_1(lookup_tree(sha1),
index 8282f5e5f6c615460e1c340d66e395c2d57aef73..7c9ecf665d062d79e9208875d9bf2577e98f4fb2 100644 (file)
@@ -446,7 +446,7 @@ static int traverse_trees_recursive(int n, unsigned long dirmask,
        newinfo.prev = info;
        newinfo.pathspec = info->pathspec;
        newinfo.name = *p;
-       newinfo.pathlen += tree_entry_len(p->path, p->sha1) + 1;
+       newinfo.pathlen += tree_entry_len(p) + 1;
        newinfo.conflicts |= df_conflicts;
 
        for (i = 0; i < n; i++, dirmask >>= 1) {
@@ -495,7 +495,7 @@ static int do_compare_entry(const struct cache_entry *ce, const struct traverse_
        ce_len -= pathlen;
        ce_name = ce->name + pathlen;
 
-       len = tree_entry_len(n->path, n->sha1);
+       len = tree_entry_len(n);
        return df_name_compare(ce_name, ce_len, S_IFREG, n->path, len, n->mode);
 }
 
@@ -626,7 +626,7 @@ static int find_cache_pos(struct traverse_info *info,
        struct unpack_trees_options *o = info->data;
        struct index_state *index = o->src_index;
        int pfxlen = info->pathlen;
-       int p_len = tree_entry_len(p->path, p->sha1);
+       int p_len = tree_entry_len(p);
 
        for (pos = o->cache_bottom; pos < index->cache_nr; pos++) {
                struct cache_entry *ce = index->cache[pos];