Merge branch 'jk/rev-list-empty-input'
authorJunio C Hamano <gitster@pobox.com>
Fri, 11 Aug 2017 20:27:07 +0000 (13:27 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 11 Aug 2017 20:27:07 +0000 (13:27 -0700)
"git log --tag=no-such-tag" showed log starting from HEAD, which
has been fixed---it now shows nothing.

* jk/rev-list-empty-input:
revision: do not fallback to default when rev_input_given is set
rev-list: don't show usage when we see empty ref patterns
revision: add rev_input_given flag
t6018: flesh out empty input/output rev-list tests

139 files changed:
Documentation/RelNotes/2.10.4.txt [new file with mode: 0644]
Documentation/RelNotes/2.11.3.txt [new file with mode: 0644]
Documentation/RelNotes/2.12.4.txt [new file with mode: 0644]
Documentation/RelNotes/2.13.5.txt [new file with mode: 0644]
Documentation/RelNotes/2.14.0.txt
Documentation/RelNotes/2.14.1.txt [new file with mode: 0644]
Documentation/RelNotes/2.7.6.txt [new file with mode: 0644]
Documentation/RelNotes/2.8.6.txt [new file with mode: 0644]
Documentation/RelNotes/2.9.5.txt [new file with mode: 0644]
Documentation/diff-config.txt
Documentation/diff-options.txt
Documentation/git-for-each-ref.txt
Documentation/git-patch-id.txt
Documentation/gitattributes.txt
Documentation/githooks.txt
Documentation/pretty-formats.txt
Documentation/technical/api-sub-process.txt [deleted file]
GIT-VERSION-GEN
RelNotes
apply.c
archive.c
attr.c
bisect.c
builtin/am.c
builtin/branch.c
builtin/cat-file.c
builtin/checkout.c
builtin/clean.c
builtin/commit-tree.c
builtin/commit.c
builtin/describe.c
builtin/difftool.c
builtin/fmt-merge-msg.c
builtin/for-each-ref.c
builtin/fsck.c
builtin/grep.c
builtin/log.c
builtin/ls-files.c
builtin/merge-tree.c
builtin/merge.c
builtin/notes.c
builtin/pack-objects.c
builtin/receive-pack.c
builtin/replace.c
builtin/reset.c
builtin/rev-list.c
builtin/rev-parse.c
builtin/show-branch.c
builtin/submodule--helper.c
builtin/tag.c
builtin/unpack-file.c
builtin/update-ref.c
builtin/verify-tag.c
cache-tree.c
cache.h
color.c
commit.c
commit.h
compat/bswap.h
config.c
config.h
connect.c
contrib/coccinelle/array.cocci
contrib/contacts/git-contacts
contrib/rerere-train.sh
convert.c
convert.h
credential-cache.c
diff.c
dir.c
entry.c
fsck.c
git-compat-util.h
git-gui/Makefile
git-gui/lib/choose_repository.tcl
git-rebase.sh
gitweb/gitweb.perl
http.c
mailmap.c
name-hash.c
notes-merge.c
notes.c
object.c
object.h
patch-ids.c
path.c
pkt-line.c
pkt-line.h
pretty.c
read-cache.c
ref-filter.c
ref-filter.h
reflog-walk.c
reflog-walk.h
refs.c
remote.c
remote.h
repository.c
revision.c
run-command.c
sequencer.c
sha1_name.c
shallow.c
strbuf.h
string-list.c
sub-process.c
sub-process.h
submodule-config.c
submodule-config.h
submodule.c
submodule.h
t/helper/test-hashmap.c
t/helper/test-submodule-config.c
t/lib-gpg.sh
t/lib-proto-disable.sh
t/t0021-conversion.sh
t/t0021/rot13-filter.pl
t/t1411-reflog-show.sh
t/t1414-reflog-walk.sh [new file with mode: 0755]
t/t1450-fsck.sh
t/t3200-branch.sh
t/t3203-branch-output.sh
t/t4207-log-decoration-colors.sh
t/t5520-pull.sh
t/t5532-fetch-proxy.sh
t/t5810-proto-disable-local.sh
t/t5813-proto-disable-ssh.sh
t/t6006-rev-list-format.sh
t/t6300-for-each-ref.sh
t/t7004-tag.sh
t/t7301-clean-interactive.sh
t/t8008-blame-formats.sh
t/test-lib-functions.sh
tag.c
tag.h
templates/hooks--prepare-commit-msg.sample
transport-helper.c
tree-diff.c
unpack-trees.c
diff --git a/Documentation/RelNotes/2.10.4.txt b/Documentation/RelNotes/2.10.4.txt
new file mode 100644 (file)
index 0000000..ee8142a
--- /dev/null
@@ -0,0 +1,4 @@
+Git v2.10.4 Release Notes
+=========================
+
+This release forward-ports the fix for "ssh://..." URL from Git v2.7.6
diff --git a/Documentation/RelNotes/2.11.3.txt b/Documentation/RelNotes/2.11.3.txt
new file mode 100644 (file)
index 0000000..4e3b78d
--- /dev/null
@@ -0,0 +1,4 @@
+Git v2.11.3 Release Notes
+=========================
+
+This release forward-ports the fix for "ssh://..." URL from Git v2.7.6
diff --git a/Documentation/RelNotes/2.12.4.txt b/Documentation/RelNotes/2.12.4.txt
new file mode 100644 (file)
index 0000000..3f56938
--- /dev/null
@@ -0,0 +1,4 @@
+Git v2.12.4 Release Notes
+=========================
+
+This release forward-ports the fix for "ssh://..." URL from Git v2.7.6
diff --git a/Documentation/RelNotes/2.13.5.txt b/Documentation/RelNotes/2.13.5.txt
new file mode 100644 (file)
index 0000000..6949fcd
--- /dev/null
@@ -0,0 +1,4 @@
+Git v2.13.5 Release Notes
+=========================
+
+This release forward-ports the fix for "ssh://..." URL from Git v2.7.6
index 6544e7f82ab13b47dbf62f1d75cba5f6d3440652..4246c68ff51eda9b4c32b5976816820999017c02 100644 (file)
@@ -469,14 +469,12 @@ notes for details).
    set does.
 
  * Code clean-up to fix possible buffer over-reading.
-   (merge 2d105451c0 rs/apply-avoid-over-reading later to maint).
 
  * A few tests that tried to verify the contents of push certificates
    did not use 'git rev-parse' to formulate the line to look for in
    the certificate correctly.
 
  * Update the character width tables.
-   (merge 7560aacd7c bb/unicode-10.0 later to maint).
 
  * After "git branch --move" of the currently checked out branch, the
    code to walk the reflog of HEAD via "log -g" and friends
@@ -495,33 +493,25 @@ notes for details).
    ought to mean a repository on a network share that can be accessed
    locally, but this did not work correctly due to stripping the double
    slashes at the beginning.
-   (merge 496f256989 tb/push-to-cygwin-unc-path later to maint).
 
  * The progress meter did not give a useful output when we haven't had
    0.5 seconds to measure the throughput during the interval.  Instead
    show the overall throughput rate at the end, which is a much more
    useful number.
-   (merge 0fae1e072a rs/progress-overall-throughput-at-the-end later to maint).
 
  * Code clean-up, that makes us in sync with Debian by one patch.
-   (merge 8db1ae5740 jn/hooks-pre-rebase-sample-fix later to maint).
 
  * We run an early part of "git gc" that deals with refs before
    daemonising (and not under lock) even when running a background
    auto-gc, which caused multiple gc processes attempting to run the
    early part at the same time.  This is now prevented by running the
    early part also under the GC lock.
-   (merge c45af94dbc jk/gc-pre-detach-under-hook later to maint).
 
  * A recent update broke an alias that contained an uppercase letter.
-   (merge 643df7e234 js/alias-case-sensitivity later to maint).
 
  * Other minor doc, test and build updates and code cleanups.
-   (merge 3f9c637ec7 pw/unquote-path-in-git-pm later to maint).
    (merge 5053313562 rs/urlmatch-cleanup later to maint).
    (merge 42c78a216e rs/use-div-round-up later to maint).
    (merge 5e8d2729ae rs/wt-status-cleanup later to maint).
-   (merge 01826066b0 ks/fix-rebase-doc-picture later to maint).
-   (merge f7f6dc340e jk/test-copy-bytes-fix later to maint).
-   (merge 9fb9495dae ew/fd-cloexec-fix later to maint).
-   (merge 3a33fe5c97 ks/doc-fixes later to maint).
+   (merge bc9b7e207f as/diff-options-grammofix later to maint).
+   (merge ac05222b31 ah/patch-id-doc later to maint).
diff --git a/Documentation/RelNotes/2.14.1.txt b/Documentation/RelNotes/2.14.1.txt
new file mode 100644 (file)
index 0000000..9403340
--- /dev/null
@@ -0,0 +1,4 @@
+Git v2.14.1 Release Notes
+=========================
+
+This release forward-ports the fix for "ssh://..." URL from Git v2.7.6
diff --git a/Documentation/RelNotes/2.7.6.txt b/Documentation/RelNotes/2.7.6.txt
new file mode 100644 (file)
index 0000000..4c6d1dc
--- /dev/null
@@ -0,0 +1,25 @@
+Git v2.7.6 Release Notes
+========================
+
+Fixes since v2.7.5
+------------------
+
+ * A "ssh://..." URL can result in a "ssh" command line with a
+   hostname that begins with a dash "-", which would cause the "ssh"
+   command to instead (mis)treat it as an option.  This is now
+   prevented by forbidding such a hostname (which will not be
+   necessary in the real world).
+
+ * Similarly, when GIT_PROXY_COMMAND is configured, the command is
+   run with host and port that are parsed out from "ssh://..." URL;
+   a poorly written GIT_PROXY_COMMAND could be tricked into treating
+   a string that begins with a dash "-".  This is now prevented by
+   forbidding such a hostname and port number (again, which will not
+   be necessary in the real world).
+
+ * In the same spirit, a repository name that begins with a dash "-"
+   is also forbidden now.
+
+Credits go to Brian Neel at GitLab, Joern Schneeweisz of Recurity
+Labs and Jeff King at GitHub.
+
diff --git a/Documentation/RelNotes/2.8.6.txt b/Documentation/RelNotes/2.8.6.txt
new file mode 100644 (file)
index 0000000..d8db55d
--- /dev/null
@@ -0,0 +1,4 @@
+Git v2.8.6 Release Notes
+========================
+
+This release forward-ports the fix for "ssh://..." URL from Git v2.7.6
diff --git a/Documentation/RelNotes/2.9.5.txt b/Documentation/RelNotes/2.9.5.txt
new file mode 100644 (file)
index 0000000..668313a
--- /dev/null
@@ -0,0 +1,4 @@
+Git v2.9.5 Release Notes
+========================
+
+This release forward-ports the fix for "ssh://..." URL from Git v2.7.6
index cbce8ec63841e8631f7122dae6e084b15e16832d..5ca942ab5e2d5dfd67ceb06c5991f446b207de90 100644 (file)
@@ -200,7 +200,10 @@ diff.algorithm::
 +
 
 diff.wsErrorHighlight::
-       A comma separated list of `old`, `new`, `context`, that
-       specifies how whitespace errors on lines are highlighted
-       with `color.diff.whitespace`.  Can be overridden by the
-       command line option `--ws-error-highlight=<kind>`
+       Highlight whitespace errors in the `context`, `old` or `new`
+       lines of the diff.  Multiple values are separated by comma,
+       `none` resets previous values, `default` reset the list to
+       `new` and `all` is a shorthand for `old,new,context`.  The
+       whitespace errors are colored with `color.diff.whitespace`.
+       The command line option `--ws-error-highlight=<kind>`
+       overrides this setting.
index 89cc0f48deef7152d59f4d4665ff3179ed8e4315..56dedafcd4bd68c4192fbe22469428ed274a46a0 100644 (file)
@@ -300,15 +300,14 @@ ifndef::git-format-patch[]
        with --exit-code.
 
 --ws-error-highlight=<kind>::
-       Highlight whitespace errors on lines specified by <kind>
-       in the color specified by `color.diff.whitespace`.  <kind>
-       is a comma separated list of `old`, `new`, `context`.  When
-       this option is not given, only whitespace errors in `new`
-       lines are highlighted.  E.g. `--ws-error-highlight=new,old`
-       highlights whitespace errors on both deleted and added lines.
-       `all` can be used as a short-hand for `old,new,context`.
-       The `diff.wsErrorHighlight` configuration variable can be
-       used to specify the default behaviour.
+       Highlight whitespace errors in the `context`, `old` or `new`
+       lines of the diff.  Multiple values are separated by comma,
+       `none` resets previous values, `default` reset the list to
+       `new` and `all` is a shorthand for `old,new,context`.  When
+       this option is not given, and the configuration variable
+       `diff.wsErrorHighlight` is not set, only whitespace errors in
+       `new` lines are highlighted. The whitespace errors are colored
+       whith `color.diff.whitespace`.
 
 endif::git-format-patch[]
 
@@ -392,7 +391,7 @@ endif::git-log[]
        the diff between the preimage and `/dev/null`. The resulting patch
        is not meant to be applied with `patch` or `git apply`; this is
        solely for people who want to just concentrate on reviewing the
-       text after the change. In addition, the output obviously lack
+       text after the change. In addition, the output obviously lacks
        enough information to apply such a patch in reverse, even manually,
        hence the name of the option.
 +
index 03e187a105b1bd5ffa6e615c2dc9199f0b803e44..cc42c128323d32bd1a9bf47688722321857a5d65 100644 (file)
@@ -156,8 +156,10 @@ HEAD::
        otherwise.
 
 color::
-       Change output color.  Followed by `:<colorname>`, where names
-       are described in `color.branch.*`.
+       Change output color. Followed by `:<colorname>`, where color
+       names are described under Values in the "CONFIGURATION FILE"
+       section of linkgit:git-config[1].  For example,
+       `%(color:bold red)`.
 
 align::
        Left-, middle-, or right-align the content between
index cf71fba1c0a9c18ea6428ab49820cb9e707608c6..442caff8a9c394168839e63f4612c9083386175a 100644 (file)
@@ -56,9 +56,6 @@ OPTIONS
 
        This is the default.
 
-<patch>::
-       The diff to create the ID of.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 2a2d7e2a4d2a9cab2af8bd881dd880ca2a52235a..c4f2be2542d1fcd417c69596dafdf89bc3a93f00 100644 (file)
@@ -425,8 +425,8 @@ packet:          git< capability=clean
 packet:          git< capability=smudge
 packet:          git< 0000
 ------------------------
-Supported filter capabilities in version 2 are "clean" and
-"smudge".
+Supported filter capabilities in version 2 are "clean", "smudge",
+and "delay".
 
 Afterwards Git sends a list of "key=value" pairs terminated with
 a flush packet. The list will contain at least the filter command
@@ -512,12 +512,73 @@ the protocol then Git will stop the filter process and restart it
 with the next file that needs to be processed. Depending on the
 `filter.<driver>.required` flag Git will interpret that as error.
 
-After the filter has processed a blob it is expected to wait for
-the next "key=value" list containing a command. Git will close
+After the filter has processed a command it is expected to wait for
+a "key=value" list containing the next command. Git will close
 the command pipe on exit. The filter is expected to detect EOF
 and exit gracefully on its own. Git will wait until the filter
 process has stopped.
 
+Delay
+^^^^^
+
+If the filter supports the "delay" capability, then Git can send the
+flag "can-delay" after the filter command and pathname. This flag
+denotes that the filter can delay filtering the current blob (e.g. to
+compensate network latencies) by responding with no content but with
+the status "delayed" and a flush packet.
+------------------------
+packet:          git> command=smudge
+packet:          git> pathname=path/testfile.dat
+packet:          git> can-delay=1
+packet:          git> 0000
+packet:          git> CONTENT
+packet:          git> 0000
+packet:          git< status=delayed
+packet:          git< 0000
+------------------------
+
+If the filter supports the "delay" capability then it must support the
+"list_available_blobs" command. If Git sends this command, then the
+filter is expected to return a list of pathnames representing blobs
+that have been delayed earlier and are now available.
+The list must be terminated with a flush packet followed
+by a "success" status that is also terminated with a flush packet. If
+no blobs for the delayed paths are available, yet, then the filter is
+expected to block the response until at least one blob becomes
+available. The filter can tell Git that it has no more delayed blobs
+by sending an empty list. As soon as the filter responds with an empty
+list, Git stops asking. All blobs that Git has not received at this
+point are considered missing and will result in an error.
+
+------------------------
+packet:          git> command=list_available_blobs
+packet:          git> 0000
+packet:          git< pathname=path/testfile.dat
+packet:          git< pathname=path/otherfile.dat
+packet:          git< 0000
+packet:          git< status=success
+packet:          git< 0000
+------------------------
+
+After Git received the pathnames, it will request the corresponding
+blobs again. These requests contain a pathname and an empty content
+section. The filter is expected to respond with the smudged content
+in the usual way as explained above.
+------------------------
+packet:          git> command=smudge
+packet:          git> pathname=path/testfile.dat
+packet:          git> 0000
+packet:          git> 0000  # empty content!
+packet:          git< status=success
+packet:          git< 0000
+packet:          git< SMUDGED_CONTENT
+packet:          git< 0000
+packet:          git< 0000  # empty list, keep "status=success" unchanged!
+------------------------
+
+Example
+^^^^^^^
+
 A long running filter demo implementation can be found in
 `contrib/long-running-filter/example.pl` located in the Git
 core repository. If you develop your own long running filter
index b2514f4d4426a730e65bcae264a6364eb50bcd60..623ed1a13829188971531aa62c6e109e9d29ec44 100644 (file)
@@ -121,8 +121,8 @@ it is not suppressed by the `--no-verify` option.  A non-zero exit
 means a failure of the hook and aborts the commit.  It should not
 be used as replacement for pre-commit hook.
 
-The sample `prepare-commit-msg` hook that comes with Git comments
-out the `Conflicts:` part of a merge's commit message.
+The sample `prepare-commit-msg` hook that comes with Git removes the
+help message found in the commented portion of the commit template.
 
 commit-msg
 ~~~~~~~~~~
index 4d6dac5770bed76cada2f53334e239c70d15a073..973d19606b63c314786de4965160b2c285987947 100644 (file)
@@ -173,13 +173,17 @@ endif::git-rev-list[]
 - '%Cblue': switch color to blue
 - '%Creset': reset color
 - '%C(...)': color specification, as described under Values in the
-  "CONFIGURATION FILE" section of linkgit:git-config[1];
-  adding `auto,` at the beginning (e.g. `%C(auto,red)`) will emit
-  color only when colors are enabled for log output (by `color.diff`,
-  `color.ui`, or `--color`, and respecting the `auto` settings of the
-  former if we are going to a terminal). `auto` alone (i.e.
-  `%C(auto)`) will turn on auto coloring on the next placeholders
-  until the color is switched again.
+  "CONFIGURATION FILE" section of linkgit:git-config[1].
+  By default, colors are shown only when enabled for log output (by
+  `color.diff`, `color.ui`, or `--color`, and respecting the `auto`
+  settings of the former if we are going to a terminal). `%C(auto,...)`
+  is accepted as a historical synonym for the default (e.g.,
+  `%C(auto,red)`). Specifying `%C(always,...) will show the colors
+  even when color is not otherwise enabled (though consider
+  just using `--color=always` to enable color for the whole output,
+  including this format and anything else git might color).  `auto`
+  alone (i.e. `%C(auto)`) will turn on auto coloring on the next
+  placeholders until the color is switched again.
 - '%m': left (`<`), right (`>`) or boundary (`-`) mark
 - '%n': newline
 - '%%': a raw '%'
diff --git a/Documentation/technical/api-sub-process.txt b/Documentation/technical/api-sub-process.txt
deleted file mode 100644 (file)
index 793508c..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-sub-process API
-===============
-
-The sub-process API makes it possible to run background sub-processes
-for the entire lifetime of a Git invocation. If Git needs to communicate
-with an external process multiple times, then this can reduces the process
-invocation overhead. Git and the sub-process communicate through stdin and
-stdout.
-
-The sub-processes are kept in a hashmap by command name and looked up
-via the subprocess_find_entry function.  If an existing instance can not
-be found then a new process should be created and started.  When the
-parent git command terminates, all sub-processes are also terminated.
-
-This API is based on the run-command API.
-
-Data structures
----------------
-
-* `struct subprocess_entry`
-
-The sub-process structure.  Members should not be accessed directly.
-
-Types
------
-
-'int(*subprocess_start_fn)(struct subprocess_entry *entry)'::
-
-       User-supplied function to initialize the sub-process.  This is
-       typically used to negotiate the interface version and capabilities.
-
-
-Functions
----------
-
-`cmd2process_cmp`::
-
-       Function to test two subprocess hashmap entries for equality.
-
-`subprocess_start`::
-
-       Start a subprocess and add it to the subprocess hashmap.
-
-`subprocess_stop`::
-
-       Kill a subprocess and remove it from the subprocess hashmap.
-
-`subprocess_find_entry`::
-
-       Find a subprocess in the subprocess hashmap.
-
-`subprocess_get_child_process`::
-
-       Get the underlying `struct child_process` from a subprocess.
-
-`subprocess_read_status`::
-
-       Helper function to read packets looking for the last "status=<foo>"
-       key/value pair.
index 96c688bd21c5cfae1b5e6e83e8c931a5b75889f2..75beb2e7750f82db233c8365f0ba2223ca4e2486 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v2.14.0-rc1
+DEF_VER=v2.14.GIT
 
 LF='
 '
index 983f6689bd29f83fa3514e74362858daaf879cce..86e33ed6820a9d3391011bde90852e9a593358db 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.14.0.txt
\ No newline at end of file
+Documentation/RelNotes/2.14.1.txt
\ No newline at end of file
diff --git a/apply.c b/apply.c
index f2d599141d00c64d8c50b3f5519412ada94bcd6f..41ee63e1db5f702509e51b2e6dd37b8617a40559 100644 (file)
--- a/apply.c
+++ b/apply.c
@@ -2809,13 +2809,10 @@ static void update_image(struct apply_state *state,
                img->line_allocated = img->line;
        }
        if (preimage_limit != postimage->nr)
-               memmove(img->line + applied_pos + postimage->nr,
-                       img->line + applied_pos + preimage_limit,
-                       (img->nr - (applied_pos + preimage_limit)) *
-                       sizeof(*img->line));
-       memcpy(img->line + applied_pos,
-              postimage->line,
-              postimage->nr * sizeof(*img->line));
+               MOVE_ARRAY(img->line + applied_pos + postimage->nr,
+                          img->line + applied_pos + preimage_limit,
+                          img->nr - (applied_pos + preimage_limit));
+       COPY_ARRAY(img->line + applied_pos, postimage->line, postimage->nr);
        if (!state->allow_overlap)
                for (i = 0; i < postimage->nr; i++)
                        img->line[applied_pos + i].flag |= LINE_PATCHED;
@@ -3551,7 +3548,7 @@ static int try_threeway(struct apply_state *state,
        /* Preimage the patch was prepared for */
        if (patch->is_new)
                write_sha1_file("", 0, blob_type, pre_oid.hash);
-       else if (get_sha1(patch->old_sha1_prefix, pre_oid.hash) ||
+       else if (get_oid(patch->old_sha1_prefix, &pre_oid) ||
                 read_blob_object(&buf, &pre_oid, patch->old_mode))
                return error(_("repository lacks the necessary blob to fall back on 3-way merge."));
 
@@ -4075,7 +4072,7 @@ static int build_fake_ancestor(struct apply_state *state, struct patch *list)
                        else
                                return error(_("sha1 information is lacking or "
                                               "useless for submodule %s"), name);
-               } else if (!get_sha1_blob(patch->old_sha1_prefix, oid.hash)) {
+               } else if (!get_oid_blob(patch->old_sha1_prefix, &oid)) {
                        ; /* ok */
                } else if (!patch->lines_added && !patch->lines_deleted) {
                        /* mode-only change: update the current */
index 60b3035a7a6a9e7c2e69b4ba7de00ebdf8bfdbb8..557dd2db85ff261ee00ec50ea0bfe286bff7bda3 100644 (file)
--- a/archive.c
+++ b/archive.c
@@ -358,7 +358,7 @@ static void parse_treeish_arg(const char **argv,
                free(ref);
        }
 
-       if (get_sha1(name, oid.hash))
+       if (get_oid(name, &oid))
                die("Not a valid object name");
 
        commit = lookup_commit_reference_gently(&oid, 1);
diff --git a/attr.c b/attr.c
index 56961f02361129b5cb49e6ffb7ab185655f09c41..2f49151736095cf2e2a76ea91d72743df3778a5d 100644 (file)
--- a/attr.c
+++ b/attr.c
@@ -76,18 +76,20 @@ struct attr_hash_entry {
 };
 
 /* attr_hashmap comparison function */
-static int attr_hash_entry_cmp(void *unused_cmp_data,
-                              const struct attr_hash_entry *a,
-                              const struct attr_hash_entry *b,
-                              void *unused_keydata)
+static int attr_hash_entry_cmp(const void *unused_cmp_data,
+                              const void *entry,
+                              const void *entry_or_key,
+                              const void *unused_keydata)
 {
+       const struct attr_hash_entry *a = entry;
+       const struct attr_hash_entry *b = entry_or_key;
        return (a->keylen != b->keylen) || strncmp(a->key, b->key, a->keylen);
 }
 
 /* Initialize an 'attr_hashmap' object */
 static void attr_hashmap_init(struct attr_hashmap *map)
 {
-       hashmap_init(&map->map, (hashmap_cmp_fn) attr_hash_entry_cmp, NULL, 0);
+       hashmap_init(&map->map, attr_hash_entry_cmp, NULL, 0);
 }
 
 /*
index a9fd9fbc61a661ab19e18713b115f868daab2f98..2549eaf7b15152a9c130e63e44c8d8f4fc865233 100644 (file)
--- a/bisect.c
+++ b/bisect.c
@@ -680,16 +680,16 @@ static int is_expected_rev(const struct object_id *oid)
        return res;
 }
 
-static int bisect_checkout(const unsigned char *bisect_rev, int no_checkout)
+static int bisect_checkout(const struct object_id *bisect_rev, int no_checkout)
 {
        char bisect_rev_hex[GIT_MAX_HEXSZ + 1];
 
-       memcpy(bisect_rev_hex, sha1_to_hex(bisect_rev), GIT_SHA1_HEXSZ + 1);
-       update_ref(NULL, "BISECT_EXPECTED_REV", bisect_rev, NULL, 0, UPDATE_REFS_DIE_ON_ERR);
+       memcpy(bisect_rev_hex, oid_to_hex(bisect_rev), GIT_SHA1_HEXSZ + 1);
+       update_ref(NULL, "BISECT_EXPECTED_REV", bisect_rev->hash, NULL, 0, UPDATE_REFS_DIE_ON_ERR);
 
        argv_checkout[2] = bisect_rev_hex;
        if (no_checkout) {
-               update_ref(NULL, "BISECT_HEAD", bisect_rev, NULL, 0, UPDATE_REFS_DIE_ON_ERR);
+               update_ref(NULL, "BISECT_HEAD", bisect_rev->hash, NULL, 0, UPDATE_REFS_DIE_ON_ERR);
        } else {
                int res;
                res = run_command_v_opt(argv_checkout, RUN_GIT_CMD);
@@ -796,7 +796,7 @@ static void check_merge_bases(int no_checkout)
                        handle_skipped_merge_base(mb);
                } else {
                        printf(_("Bisecting: a merge base must be tested\n"));
-                       exit(bisect_checkout(mb->hash, no_checkout));
+                       exit(bisect_checkout(mb, no_checkout));
                }
        }
 
@@ -939,7 +939,7 @@ int bisect_next_all(const char *prefix, int no_checkout)
        struct rev_info revs;
        struct commit_list *tried;
        int reaches = 0, all = 0, nr, steps;
-       const unsigned char *bisect_rev;
+       struct object_id *bisect_rev;
        char *steps_msg;
 
        read_bisect_terms(&term_bad, &term_good);
@@ -977,11 +977,11 @@ int bisect_next_all(const char *prefix, int no_checkout)
                exit(4);
        }
 
-       bisect_rev = revs.commits->item->object.oid.hash;
+       bisect_rev = &revs.commits->item->object.oid;
 
-       if (!hashcmp(bisect_rev, current_bad_oid->hash)) {
+       if (!oidcmp(bisect_rev, current_bad_oid)) {
                exit_if_skipped_commits(tried, current_bad_oid);
-               printf("%s is the first %s commit\n", sha1_to_hex(bisect_rev),
+               printf("%s is the first %s commit\n", oid_to_hex(bisect_rev),
                        term_bad);
                show_diff_tree(prefix, revs.commits->item);
                /* This means the bisection process succeeded. */
index c973bd96dcb5d630d56e935733bfa4530ccd2872..40cc6d6fe8e7d440d544e88cba03be15e675c93f 100644 (file)
@@ -1131,7 +1131,7 @@ static int index_has_changes(struct strbuf *sb)
        struct object_id head;
        int i;
 
-       if (!get_sha1_tree("HEAD", head.hash)) {
+       if (!get_oid_tree("HEAD", &head)) {
                struct diff_options opt;
 
                diff_setup(&opt);
@@ -1432,7 +1432,7 @@ static void write_index_patch(const struct am_state *state)
        struct rev_info rev_info;
        FILE *fp;
 
-       if (!get_sha1_tree("HEAD", head.hash))
+       if (!get_oid_tree("HEAD", &head))
                tree = lookup_tree(&head);
        else
                tree = lookup_tree(&empty_tree_oid);
@@ -1661,7 +1661,7 @@ static void do_commit(const struct am_state *state)
        if (write_cache_as_tree(tree.hash, 0, NULL))
                die(_("git write-tree failed to write a tree"));
 
-       if (!get_sha1_commit("HEAD", parent.hash)) {
+       if (!get_oid_commit("HEAD", &parent)) {
                old_oid = &parent;
                commit_list_insert(lookup_commit(&parent), &parents);
        } else {
index 8a0595e11587aeac0f784400c43609404da3e045..16d391b407c9fa688b48a3e28f77800dcc1e2e0c 100644 (file)
@@ -92,7 +92,7 @@ static int git_branch_config(const char *var, const char *value, void *cb)
                        return config_error_nonbool(var);
                return color_parse(value, branch_colors[slot]);
        }
-       return git_color_default_config(var, value, cb);
+       return git_default_config(var, value, cb);
 }
 
 static const char *branch_get_color(enum color_branch ix)
@@ -383,7 +383,7 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r
        return strbuf_detach(&fmt, NULL);
 }
 
-static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sorting, const char *format)
+static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sorting, struct ref_format *format)
 {
        int i;
        struct ref_array array;
@@ -407,14 +407,17 @@ static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sortin
        if (filter->verbose)
                maxwidth = calc_maxwidth(&array, strlen(remote_prefix));
 
-       if (!format)
-               format = to_free = build_format(filter, maxwidth, remote_prefix);
-       verify_ref_format(format);
+       if (!format->format)
+               format->format = to_free = build_format(filter, maxwidth, remote_prefix);
+       format->use_color = branch_use_color;
+
+       if (verify_ref_format(format))
+               die(_("unable to parse format string"));
 
        ref_array_sort(sorting, &array);
 
        for (i = 0; i < array.nr; i++) {
-               format_ref_array_item(array.items[i], format, 0, &out);
+               format_ref_array_item(array.items[i], format, &out);
                if (column_active(colopts)) {
                        assert(!filter->verbose && "--column and --verbose are incompatible");
                         /* format to a string_list to let print_columns() do its job */
@@ -549,7 +552,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
        struct ref_filter filter;
        int icase = 0;
        static struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;
-       const char *format = NULL;
+       struct ref_format format = REF_FORMAT_INIT;
 
        struct option options[] = {
                OPT_GROUP(N_("Generic options")),
@@ -593,7 +596,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                        N_("print only branches of the object"), 0, parse_opt_object_name
                },
                OPT_BOOL('i', "ignore-case", &icase, N_("sorting and filtering are case insensitive")),
-               OPT_STRING(  0 , "format", &format, N_("format"), N_("format to use for the output")),
+               OPT_STRING(  0 , "format", &format.format, N_("format"), N_("format to use for the output")),
                OPT_END(),
        };
 
@@ -667,7 +670,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                if (!sorting)
                        sorting = ref_default_sorting();
                sorting->ignore_case = icase;
-               print_ref_list(&filter, sorting, format);
+               print_ref_list(&filter, sorting, &format);
                print_columns(&output, colopts, NULL);
                string_list_clear(&output, 0);
                return 0;
index 96b786e4892aec0ed7e5d07ac8d3261c7b765f33..62c8cf0ebf3f2ba063945fc44714a9da29b599ef 100644 (file)
@@ -63,8 +63,8 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
        if (unknown_type)
                flags |= OBJECT_INFO_ALLOW_UNKNOWN_TYPE;
 
-       if (get_sha1_with_context(obj_name, GET_SHA1_RECORD_PATH,
-                                 oid.hash, &obj_context))
+       if (get_oid_with_context(obj_name, GET_OID_RECORD_PATH,
+                                &oid, &obj_context))
                die("Not a valid object name %s", obj_name);
 
        if (!path)
@@ -361,10 +361,10 @@ static void batch_one_object(const char *obj_name, struct batch_options *opt,
                             struct expand_data *data)
 {
        struct object_context ctx;
-       int flags = opt->follow_symlinks ? GET_SHA1_FOLLOW_SYMLINKS : 0;
+       int flags = opt->follow_symlinks ? GET_OID_FOLLOW_SYMLINKS : 0;
        enum follow_symlinks_result result;
 
-       result = get_sha1_with_context(obj_name, flags, data->oid.hash, &ctx);
+       result = get_oid_with_context(obj_name, flags, &data->oid, &ctx);
        if (result != FOUND) {
                switch (result) {
                case MISSING_OBJECT:
index 9661e1bcba31ffa4f7b8a2fb1a9d2060cb8efda7..2d75ac66c7f8447e846e0bc38072b76bddc3672b 100644 (file)
@@ -358,6 +358,8 @@ static int checkout_paths(const struct checkout_opts *opts,
        state.force = 1;
        state.refresh_cache = 1;
        state.istate = &the_index;
+
+       enable_delayed_checkout(&state);
        for (pos = 0; pos < active_nr; pos++) {
                struct cache_entry *ce = active_cache[pos];
                if (ce->ce_flags & CE_MATCHED) {
@@ -372,6 +374,7 @@ static int checkout_paths(const struct checkout_opts *opts,
                        pos = skip_same_name(ce, pos) - 1;
                }
        }
+       errs |= finish_delayed_checkout(&state);
 
        if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
                die(_("unable to write new index file"));
index 057fc97fe4494338e6a85ac9f695563f1fcb9596..21a7a3299408ac507917ac13f9342e3148ac53ec 100644 (file)
@@ -33,15 +33,6 @@ static const char *msg_skip_git_dir = N_("Skipping repository %s\n");
 static const char *msg_would_skip_git_dir = N_("Would skip repository %s\n");
 static const char *msg_warn_remove_failed = N_("failed to remove %s");
 
-static int clean_use_color = -1;
-static char clean_colors[][COLOR_MAXLEN] = {
-       GIT_COLOR_RESET,
-       GIT_COLOR_NORMAL,       /* PLAIN */
-       GIT_COLOR_BOLD_BLUE,    /* PROMPT */
-       GIT_COLOR_BOLD,         /* HEADER */
-       GIT_COLOR_BOLD_RED,     /* HELP */
-       GIT_COLOR_BOLD_RED,     /* ERROR */
-};
 enum color_clean {
        CLEAN_COLOR_RESET = 0,
        CLEAN_COLOR_PLAIN = 1,
@@ -51,6 +42,16 @@ enum color_clean {
        CLEAN_COLOR_ERROR = 5
 };
 
+static int clean_use_color = -1;
+static char clean_colors[][COLOR_MAXLEN] = {
+       [CLEAN_COLOR_ERROR] = GIT_COLOR_BOLD_RED,
+       [CLEAN_COLOR_HEADER] = GIT_COLOR_BOLD,
+       [CLEAN_COLOR_HELP] = GIT_COLOR_BOLD_RED,
+       [CLEAN_COLOR_PLAIN] = GIT_COLOR_NORMAL,
+       [CLEAN_COLOR_PROMPT] = GIT_COLOR_BOLD_BLUE,
+       [CLEAN_COLOR_RESET] = GIT_COLOR_RESET,
+};
+
 #define MENU_OPTS_SINGLETON            01
 #define MENU_OPTS_IMMEDIATE            02
 #define MENU_OPTS_LIST_ONLY            04
@@ -125,8 +126,7 @@ static int git_clean_config(const char *var, const char *value, void *cb)
                return 0;
        }
 
-       /* inspect the color.ui config variable and others */
-       return git_color_default_config(var, value, cb);
+       return git_default_config(var, value, cb);
 }
 
 static const char *clean_get_color(enum color_clean ix)
index a4a923d7c0b688e162c8e4d0411ff9b72748fb5c..19e898fa4e46da9271de950ad9add75af2051ed6 100644 (file)
@@ -56,7 +56,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
                        struct object_id oid;
                        if (argc <= ++i)
                                usage(commit_tree_usage);
-                       if (get_sha1_commit(argv[i], oid.hash))
+                       if (get_oid_commit(argv[i], &oid))
                                die("Not a valid object name %s", argv[i]);
                        assert_sha1_type(oid.hash, OBJ_COMMIT);
                        new_parent(lookup_commit(&oid), &parents);
@@ -106,7 +106,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
                        continue;
                }
 
-               if (get_sha1_tree(arg, tree_oid.hash))
+               if (get_oid_tree(arg, &tree_oid))
                        die("Not a valid object name %s", arg);
                if (got_tree)
                        die("Cannot give more than one trees");
index 8e93802511e2a798e43d30da9218a56f97404dc7..e7a2cb628554c7db3370521521291a28b060f574 100644 (file)
@@ -510,7 +510,7 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int
        s->index_file = index_file;
        s->fp = fp;
        s->nowarn = nowarn;
-       s->is_initial = get_sha1(s->reference, oid.hash) ? 1 : 0;
+       s->is_initial = get_oid(s->reference, &oid) ? 1 : 0;
        if (!s->is_initial)
                hashcpy(s->sha1_commit, oid.hash);
        s->status_format = status_format;
@@ -891,7 +891,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
                if (amend)
                        parent = "HEAD^1";
 
-               if (get_sha1(parent, oid.hash)) {
+               if (get_oid(parent, &oid)) {
                        int i, ita_nr = 0;
 
                        for (i = 0; i < active_nr; i++)
@@ -1387,7 +1387,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
 
        fd = hold_locked_index(&index_lock, 0);
 
-       s.is_initial = get_sha1(s.reference, oid.hash) ? 1 : 0;
+       s.is_initial = get_oid(s.reference, &oid) ? 1 : 0;
        if (!s.is_initial)
                hashcpy(s.sha1_commit, oid.hash);
 
@@ -1657,7 +1657,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
        status_format = STATUS_FORMAT_NONE; /* Ignore status.short */
        s.colopts = 0;
 
-       if (get_sha1("HEAD", oid.hash))
+       if (get_oid("HEAD", &oid))
                current_head = NULL;
        else {
                current_head = lookup_commit_or_die(&oid, "HEAD");
@@ -1739,17 +1739,17 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
        if (verbose || /* Truncate the message just before the diff, if any. */
            cleanup_mode == CLEANUP_SCISSORS)
                strbuf_setlen(&sb, wt_status_locate_end(sb.buf, sb.len));
-
        if (cleanup_mode != CLEANUP_NONE)
                strbuf_stripspace(&sb, cleanup_mode == CLEANUP_ALL);
-       if (template_untouched(&sb) && !allow_empty_message) {
+
+       if (message_is_empty(&sb) && !allow_empty_message) {
                rollback_index_files();
-               fprintf(stderr, _("Aborting commit; you did not edit the message.\n"));
+               fprintf(stderr, _("Aborting commit due to empty commit message.\n"));
                exit(1);
        }
-       if (message_is_empty(&sb) && !allow_empty_message) {
+       if (template_untouched(&sb) && !allow_empty_message) {
                rollback_index_files();
-               fprintf(stderr, _("Aborting commit due to empty commit message.\n"));
+               fprintf(stderr, _("Aborting commit; you did not edit the message.\n"));
                exit(1);
        }
 
index 89ea1cdd60a215473ecb52ff2a4ce51932e1cf6d..9c13c6817bd784fb9c0e3eff781911577ef7ef8c 100644 (file)
@@ -55,10 +55,13 @@ static const char *prio_names[] = {
 };
 
 static int commit_name_cmp(const void *unused_cmp_data,
-                          const struct commit_name *cn1,
-                          const struct commit_name *cn2,
+                          const void *entry,
+                          const void *entry_or_key,
                           const void *peeled)
 {
+       const struct commit_name *cn1 = entry;
+       const struct commit_name *cn2 = entry_or_key;
+
        return oidcmp(&cn1->peeled, peeled ? peeled : &cn2->peeled);
 }
 
@@ -503,7 +506,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
                return cmd_name_rev(args.argc, args.argv, prefix);
        }
 
-       hashmap_init(&names, (hashmap_cmp_fn) commit_name_cmp, NULL, 0);
+       hashmap_init(&names, commit_name_cmp, NULL, 0);
        for_each_rawref(get_name, NULL);
        if (!names.size && !always)
                die(_("No names found, cannot describe anything."));
index a1a26ba8912f4ee49527b287657826440fd92e9e..8864d846f89846669a5403d3a9436aa784d47be2 100644 (file)
@@ -131,10 +131,12 @@ struct working_tree_entry {
 };
 
 static int working_tree_entry_cmp(const void *unused_cmp_data,
-                                 struct working_tree_entry *a,
-                                 struct working_tree_entry *b,
-                                 void *unused_keydata)
+                                 const void *entry,
+                                 const void *entry_or_key,
+                                 const void *unused_keydata)
 {
+       const struct working_tree_entry *a = entry;
+       const struct working_tree_entry *b = entry_or_key;
        return strcmp(a->path, b->path);
 }
 
@@ -149,9 +151,13 @@ struct pair_entry {
 };
 
 static int pair_cmp(const void *unused_cmp_data,
-                   struct pair_entry *a, struct pair_entry *b,
-                   void *unused_keydata)
+                   const void *entry,
+                   const void *entry_or_key,
+                   const void *unused_keydata)
 {
+       const struct pair_entry *a = entry;
+       const struct pair_entry *b = entry_or_key;
+
        return strcmp(a->path, b->path);
 }
 
@@ -179,9 +185,13 @@ struct path_entry {
 };
 
 static int path_entry_cmp(const void *unused_cmp_data,
-                         struct path_entry *a, struct path_entry *b,
-                         void *key)
+                         const void *entry,
+                         const void *entry_or_key,
+                         const void *key)
 {
+       const struct path_entry *a = entry;
+       const struct path_entry *b = entry_or_key;
+
        return strcmp(a->path, key ? key : b->path);
 }
 
@@ -372,10 +382,9 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
        rdir_len = rdir.len;
        wtdir_len = wtdir.len;
 
-       hashmap_init(&working_tree_dups,
-                    (hashmap_cmp_fn)working_tree_entry_cmp, NULL, 0);
-       hashmap_init(&submodules, (hashmap_cmp_fn)pair_cmp, NULL, 0);
-       hashmap_init(&symlinks2, (hashmap_cmp_fn)pair_cmp, NULL, 0);
+       hashmap_init(&working_tree_dups, working_tree_entry_cmp, NULL, 0);
+       hashmap_init(&submodules, pair_cmp, NULL, 0);
+       hashmap_init(&symlinks2, pair_cmp, NULL, 0);
 
        child.no_stdin = 1;
        child.git_cmd = 1;
@@ -585,10 +594,8 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
         * in the common case of --symlinks and the difftool updating
         * files through the symlink.
         */
-       hashmap_init(&wt_modified, (hashmap_cmp_fn)path_entry_cmp,
-                    NULL, wtindex.cache_nr);
-       hashmap_init(&tmp_modified, (hashmap_cmp_fn)path_entry_cmp,
-                    NULL, wtindex.cache_nr);
+       hashmap_init(&wt_modified, path_entry_cmp, NULL, wtindex.cache_nr);
+       hashmap_init(&tmp_modified, path_entry_cmp, NULL, wtindex.cache_nr);
 
        for (i = 0; i < wtindex.cache_nr; i++) {
                struct hashmap_entry dummy;
index 10cbb434163f2f6e60e0cc9cb55bab220004a549..e99b5ddbf9a51be17bc0d976c942c29afe6563cd 100644 (file)
@@ -408,7 +408,8 @@ static void shortlog(const char *name,
 }
 
 static void fmt_merge_msg_title(struct strbuf *out,
-       const char *current_branch) {
+                               const char *current_branch)
+{
        int i = 0;
        char *sep = "";
 
index 52be99cbacdd84f60e5b9f2efd1f1d50f602cdb8..5d7c921a773718d6bee7f85b8d868fc22602377d 100644 (file)
@@ -17,25 +17,25 @@ static char const * const for_each_ref_usage[] = {
 int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
 {
        int i;
-       const char *format = "%(objectname) %(objecttype)\t%(refname)";
        struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;
-       int maxcount = 0, quote_style = 0, icase = 0;
+       int maxcount = 0, icase = 0;
        struct ref_array array;
        struct ref_filter filter;
+       struct ref_format format = REF_FORMAT_INIT;
 
        struct option opts[] = {
-               OPT_BIT('s', "shell", &quote_style,
+               OPT_BIT('s', "shell", &format.quote_style,
                        N_("quote placeholders suitably for shells"), QUOTE_SHELL),
-               OPT_BIT('p', "perl",  &quote_style,
+               OPT_BIT('p', "perl",  &format.quote_style,
                        N_("quote placeholders suitably for perl"), QUOTE_PERL),
-               OPT_BIT(0 , "python", &quote_style,
+               OPT_BIT(0 , "python", &format.quote_style,
                        N_("quote placeholders suitably for python"), QUOTE_PYTHON),
-               OPT_BIT(0 , "tcl",  &quote_style,
+               OPT_BIT(0 , "tcl",  &format.quote_style,
                        N_("quote placeholders suitably for Tcl"), QUOTE_TCL),
 
                OPT_GROUP(""),
                OPT_INTEGER( 0 , "count", &maxcount, N_("show only <n> matched refs")),
-               OPT_STRING(  0 , "format", &format, N_("format"), N_("format to use for the output")),
+               OPT_STRING(  0 , "format", &format.format, N_("format"), N_("format to use for the output")),
                OPT_CALLBACK(0 , "sort", sorting_tail, N_("key"),
                            N_("field name to sort on"), &parse_opt_ref_sorting),
                OPT_CALLBACK(0, "points-at", &filter.points_at,
@@ -52,16 +52,20 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
        memset(&array, 0, sizeof(array));
        memset(&filter, 0, sizeof(filter));
 
+       format.format = "%(objectname) %(objecttype)\t%(refname)";
+
+       git_config(git_default_config, NULL);
+
        parse_options(argc, argv, prefix, opts, for_each_ref_usage, 0);
        if (maxcount < 0) {
                error("invalid --count argument: `%d'", maxcount);
                usage_with_options(for_each_ref_usage, opts);
        }
-       if (HAS_MULTI_BITS(quote_style)) {
+       if (HAS_MULTI_BITS(format.quote_style)) {
                error("more than one quoting style?");
                usage_with_options(for_each_ref_usage, opts);
        }
-       if (verify_ref_format(format))
+       if (verify_ref_format(&format))
                usage_with_options(for_each_ref_usage, opts);
 
        if (!sorting)
@@ -69,9 +73,6 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
        sorting->ignore_case = icase;
        filter.ignore_case = icase;
 
-       /* for warn_ambiguous_refs */
-       git_config(git_default_config, NULL);
-
        filter.name_patterns = argv;
        filter.match_as_path = 1;
        filter_refs(&array, &filter, FILTER_REFS_ALL | FILTER_REFS_INCLUDE_BROKEN);
@@ -80,7 +81,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
        if (!maxcount || array.nr < maxcount)
                maxcount = array.nr;
        for (i = 0; i < maxcount; i++)
-               show_ref_array_item(array.items[i], format, quote_style);
+               show_ref_array_item(array.items[i], &format);
        ref_array_clear(&array);
        return 0;
 }
index 99dea7adf60a61906500b4aebc6cb7d566339b38..a92f44818610784091f8aac5ea14612be59cd184 100644 (file)
@@ -19,6 +19,8 @@
 #define REACHABLE 0x0001
 #define SEEN      0x0002
 #define HAS_OBJ   0x0004
+/* This flag is set if something points to this object. */
+#define USED      0x0008
 
 static int show_root;
 static int show_tags;
@@ -168,18 +170,7 @@ static void mark_object_reachable(struct object *obj)
 
 static int traverse_one_object(struct object *obj)
 {
-       int result;
-       struct tree *tree = NULL;
-
-       if (obj->type == OBJ_TREE) {
-               tree = (struct tree *)obj;
-               if (parse_tree(tree) < 0)
-                       return 1; /* error already displayed */
-       }
-       result = fsck_walk(obj, obj, &fsck_walk_options);
-       if (tree)
-               free_tree_buffer(tree);
-       return result;
+       return fsck_walk(obj, obj, &fsck_walk_options);
 }
 
 static int traverse_reachable(void)
@@ -206,7 +197,7 @@ static int mark_used(struct object *obj, int type, void *data, struct fsck_optio
 {
        if (!obj)
                return 1;
-       obj->used = 1;
+       obj->flags |= USED;
        return 0;
 }
 
@@ -255,7 +246,7 @@ static void check_unreachable_object(struct object *obj)
        }
 
        /*
-        * "!used" means that nothing at all points to it, including
+        * "!USED" means that nothing at all points to it, including
         * other unreachable objects. In other words, it's the "tip"
         * of some set of unreachable objects, usually a commit that
         * got dropped.
@@ -266,7 +257,7 @@ static void check_unreachable_object(struct object *obj)
         * deleted a branch by mistake, this is a prime candidate to
         * start looking at, for example.
         */
-       if (!obj->used) {
+       if (!(obj->flags & USED)) {
                if (show_dangling)
                        printf("dangling %s %s\n", printable_type(obj),
                               describe_object(obj));
@@ -390,7 +381,8 @@ static int fsck_obj_buffer(const struct object_id *oid, enum object_type type,
                errors_found |= ERROR_OBJECT;
                return error("%s: object corrupt or missing", oid_to_hex(oid));
        }
-       obj->flags = HAS_OBJ;
+       obj->flags &= ~(REACHABLE | SEEN);
+       obj->flags |= HAS_OBJ;
        return fsck_obj(obj);
 }
 
@@ -408,7 +400,7 @@ static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,
                                add_decoration(fsck_walk_options.object_names,
                                        obj,
                                        xstrfmt("%s@{%"PRItime"}", refname, timestamp));
-                       obj->used = 1;
+                       obj->flags |= USED;
                        mark_object_reachable(obj);
                } else {
                        error("%s: invalid reflog entry %s", refname, oid_to_hex(oid));
@@ -456,7 +448,7 @@ static int fsck_handle_ref(const char *refname, const struct object_id *oid,
                errors_found |= ERROR_REFS;
        }
        default_refs++;
-       obj->used = 1;
+       obj->flags |= USED;
        if (name_objects)
                add_decoration(fsck_walk_options.object_names,
                        obj, xstrdup(refname));
@@ -524,7 +516,8 @@ static int fsck_loose(const struct object_id *oid, const char *path, void *data)
                return 0; /* keep checking other objects */
        }
 
-       obj->flags = HAS_OBJ;
+       obj->flags &= ~(REACHABLE | SEEN);
+       obj->flags |= HAS_OBJ;
        if (fsck_obj(obj))
                errors_found |= ERROR_OBJECT;
        return 0;
@@ -606,7 +599,7 @@ static int fsck_cache_tree(struct cache_tree *it)
                        errors_found |= ERROR_REFS;
                        return 1;
                }
-               obj->used = 1;
+               obj->flags |= USED;
                if (name_objects)
                        add_decoration(fsck_walk_options.object_names,
                                obj, xstrdup(":"));
@@ -667,7 +660,7 @@ static struct option fsck_opts[] = {
 
 int cmd_fsck(int argc, const char **argv, const char *prefix)
 {
-       int i, heads;
+       int i;
        struct alternate_object_database *alt;
 
        errors_found = 0;
@@ -735,25 +728,23 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
                }
        }
 
-       heads = 0;
        for (i = 0; i < argc; i++) {
                const char *arg = argv[i];
-               unsigned char sha1[20];
-               if (!get_sha1(arg, sha1)) {
-                       struct object *obj = lookup_object(sha1);
+               struct object_id oid;
+               if (!get_oid(arg, &oid)) {
+                       struct object *obj = lookup_object(oid.hash);
 
                        if (!obj || !(obj->flags & HAS_OBJ)) {
-                               error("%s: object missing", sha1_to_hex(sha1));
+                               error("%s: object missing", oid_to_hex(&oid));
                                errors_found |= ERROR_OBJECT;
                                continue;
                        }
 
-                       obj->used = 1;
+                       obj->flags |= USED;
                        if (name_objects)
                                add_decoration(fsck_walk_options.object_names,
                                        obj, xstrdup(arg));
                        mark_object_reachable(obj);
-                       heads++;
                        continue;
                }
                error("invalid parameter: expected sha1, got '%s'", arg);
@@ -785,7 +776,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
                        if (!blob)
                                continue;
                        obj = &blob->object;
-                       obj->used = 1;
+                       obj->flags |= USED;
                        if (name_objects)
                                add_decoration(fsck_walk_options.object_names,
                                        obj,
index 7e79eb1a754a5f604829e3e9e6d98d83712be9b6..3cbee04dc4164255148b7f4b0c6f8f6dcd86a8fe 100644 (file)
@@ -284,7 +284,7 @@ static int wait_all(void)
 static int grep_cmd_config(const char *var, const char *value, void *cb)
 {
        int st = grep_config(var, value, cb);
-       if (git_color_default_config(var, value, cb) < 0)
+       if (git_default_config(var, value, cb) < 0)
                st = -1;
 
        if (!strcmp(var, "grep.threads")) {
@@ -653,7 +653,7 @@ static int grep_submodule(struct grep_opt *opt, const struct object_id *oid,
                 */
                if (oid) {
                        const struct submodule *sub =
-                                       submodule_from_path(null_sha1, path);
+                                       submodule_from_path(&null_oid, path);
                        if (sub)
                                path = git_path("modules/%s", sub->name);
 
@@ -862,7 +862,7 @@ static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec,
                /* load the gitmodules file for this rev */
                if (recurse_submodules) {
                        submodule_free();
-                       gitmodules_config_sha1(real_obj->oid.hash);
+                       gitmodules_config_oid(&real_obj->oid);
                }
                if (grep_object(opt, pathspec, real_obj, list->objects[i].name, list->objects[i].path)) {
                        hit = 1;
@@ -1205,8 +1205,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                        break;
                }
 
-               if (get_sha1_with_context(arg, GET_SHA1_RECORD_PATH,
-                                         oid.hash, &oc)) {
+               if (get_oid_with_context(arg, GET_OID_RECORD_PATH,
+                                        &oid, &oc)) {
                        if (seen_dashdash)
                                die(_("unable to resolve revision: %s"), arg);
                        break;
index c6362cf92ed799696128a5da6c802813db62fbcf..725c7b8a1a40f3dd943e4f42c801121d9c8ea78f 100644 (file)
@@ -372,11 +372,14 @@ static int cmd_log_walk(struct rev_info *rev)
                         */
                        rev->max_count++;
                if (!rev->reflog_info) {
-                       /* we allow cycles in reflog ancestry */
+                       /*
+                        * We may show a given commit multiple times when
+                        * walking the reflogs.
+                        */
                        free_commit_buffer(commit);
+                       free_commit_list(commit->parents);
+                       commit->parents = NULL;
                }
-               free_commit_list(commit->parents);
-               commit->parents = NULL;
                if (saved_nrl < rev->diffopt.needed_rename_limit)
                        saved_nrl = rev->diffopt.needed_rename_limit;
                if (rev->diffopt.degraded_cc_to_c)
@@ -484,8 +487,8 @@ static int show_blob_object(const struct object_id *oid, struct rev_info *rev, c
            !DIFF_OPT_TST(&rev->diffopt, ALLOW_TEXTCONV))
                return stream_blob_to_fd(1, oid, NULL, 0);
 
-       if (get_sha1_with_context(obj_name, GET_SHA1_RECORD_PATH,
-                                 oidc.hash, &obj_context))
+       if (get_oid_with_context(obj_name, GET_OID_RECORD_PATH,
+                                &oidc, &obj_context))
                die(_("Not a valid object name %s"), obj_name);
        if (!obj_context.path ||
            !textconv_object(obj_context.path, obj_context.mode, &oidc, 1, &buf, &size)) {
index b8514a0029a1437687a5cf6b6f8bad9792340bc3..c6126eae550beb75e7c90094be337efbb48cd3bc 100644 (file)
@@ -362,7 +362,7 @@ static void prune_index(struct index_state *istate,
        int pos;
        unsigned int first, last;
 
-       if (!prefix)
+       if (!prefix || !istate->cache_nr)
                return;
        pos = index_name_pos(istate, prefix, prefixlen);
        if (pos < 0)
@@ -378,8 +378,7 @@ static void prune_index(struct index_state *istate,
                }
                last = next;
        }
-       memmove(istate->cache, istate->cache + pos,
-               (last - pos) * sizeof(struct cache_entry *));
+       MOVE_ARRAY(istate->cache, istate->cache + pos, last - pos);
        istate->cache_nr = last - pos;
 }
 
index bad6735c76fd0647547edfd1201d91c3c86dfc8f..f12da292cf91b1ecb9fc785fd50bd1ef83b361e9 100644 (file)
@@ -347,12 +347,12 @@ static void merge_trees(struct tree_desc t[3], const char *base)
 
 static void *get_tree_descriptor(struct tree_desc *desc, const char *rev)
 {
-       unsigned char sha1[20];
+       struct object_id oid;
        void *buf;
 
-       if (get_sha1(rev, sha1))
+       if (get_oid(rev, &oid))
                die("unknown rev %s", rev);
-       buf = fill_tree_descriptor(desc, sha1);
+       buf = fill_tree_descriptor(desc, oid.hash);
        if (!buf)
                die("%s is not a tree", rev);
        return buf;
index 900bafdb45d0b28ab5497cfd251535266fc92be5..d5797b8fe77c99c89323348f3a0bd1d68ae9b453 100644 (file)
@@ -537,7 +537,7 @@ static void parse_branch_merge_options(char *bmo)
                die(_("Bad branch.%s.mergeoptions string: %s"), branch,
                    split_cmdline_strerror(argc));
        REALLOC_ARRAY(argv, argc + 2);
-       memmove(argv + 1, argv, sizeof(*argv) * (argc + 1));
+       MOVE_ARRAY(argv + 1, argv, argc + 1);
        argc++;
        argv[0] = "branch.*.mergeoptions";
        parse_options(argc, argv, NULL, builtin_merge_options,
index 77573cf1ea8cb4d998597e265263487e22fde592..4303848e044c9f9c6a12236d887a521316b4fc05 100644 (file)
@@ -456,7 +456,7 @@ static int add(int argc, const char **argv, const char *prefix)
                        oid_to_hex(&object));
        }
 
-       prepare_note_data(&object, &d, note->hash);
+       prepare_note_data(&object, &d, note ? note->hash : NULL);
        if (d.buf.len || allow_empty) {
                write_note_data(&d, new_note.hash);
                if (add_note(t, &object, &new_note, combine_notes_overwrite))
index f4a8441fe913850e7a1cadf3376837237519e761..c753e9237a8d5981a17e872db33d5326bd8d7eab 100644 (file)
@@ -1289,7 +1289,7 @@ static int done_pbase_path_pos(unsigned hash)
 
 static int check_pbase_path(unsigned hash)
 {
-       int pos = (!done_pbase_paths) ? -1 : done_pbase_path_pos(hash);
+       int pos = done_pbase_path_pos(hash);
        if (0 <= pos)
                return 1;
        pos = -pos - 1;
@@ -1298,9 +1298,8 @@ static int check_pbase_path(unsigned hash)
                   done_pbase_paths_alloc);
        done_pbase_paths_num++;
        if (pos < done_pbase_paths_num)
-               memmove(done_pbase_paths + pos + 1,
-                       done_pbase_paths + pos,
-                       (done_pbase_paths_num - pos - 1) * sizeof(unsigned));
+               MOVE_ARRAY(done_pbase_paths + pos + 1, done_pbase_paths + pos,
+                          done_pbase_paths_num - pos - 1);
        done_pbase_paths[pos] = hash;
        return 0;
 }
index cabdc55e0933adb09d459a5a0747c718fd2c7d1e..14b6e09b42f1d423307c98275f5b203078b82445 100644 (file)
@@ -919,9 +919,9 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
  */
 static int head_has_history(void)
 {
-       unsigned char sha1[20];
+       struct object_id oid;
 
-       return !get_sha1("HEAD", sha1);
+       return !get_oid("HEAD", &oid);
 }
 
 static const char *push_to_deploy(unsigned char *sha1,
@@ -1138,7 +1138,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
                }
                if (ref_transaction_delete(transaction,
                                           namespaced_name,
-                                          old_oid->hash,
+                                          old_oid ? old_oid->hash : NULL,
                                           0, "push", &err)) {
                        rp_error("%s", err.buf);
                        strbuf_release(&err);
index fba336a68a375e20e9b40d332eb58a3f302249fa..f4a85a165bbff187f331a0a4675066fc5f7b4316 100644 (file)
@@ -50,7 +50,7 @@ static int show_reference(const char *refname, const struct object_id *oid,
                        struct object_id object;
                        enum object_type obj_type, repl_type;
 
-                       if (get_sha1(refname, object.hash))
+                       if (get_oid(refname, &object))
                                return error("Failed to resolve '%s' as a valid ref.", refname);
 
                        obj_type = sha1_object_info(object.hash, NULL);
@@ -365,7 +365,7 @@ static void check_one_mergetag(struct commit *commit,
        /* iterate over new parents */
        for (i = 1; i < mergetag_data->argc; i++) {
                struct object_id oid;
-               if (get_sha1(mergetag_data->argv[i], oid.hash) < 0)
+               if (get_oid(mergetag_data->argv[i], &oid) < 0)
                        die(_("Not a valid object name: '%s'"), mergetag_data->argv[i]);
                if (!oidcmp(&tag->tagged->oid, &oid))
                        return; /* found */
index 7aeaea2737991f021eb788708c1710305abb4b08..046403ed6881f452271c636e935ad3ab05da0b78 100644 (file)
@@ -219,8 +219,8 @@ static void parse_args(struct pathspec *pathspec,
                 * has to be unambiguous. If there is a single argument, it
                 * can not be a tree
                 */
-               else if ((!argv[1] && !get_sha1_committish(argv[0], unused.hash)) ||
-                        (argv[1] && !get_sha1_treeish(argv[0], unused.hash))) {
+               else if ((!argv[1] && !get_oid_committish(argv[0], &unused)) ||
+                        (argv[1] && !get_oid_treeish(argv[0], &unused))) {
                        /*
                         * Ok, argv[0] looks like a commit/tree; it should not
                         * be a filename.
@@ -310,13 +310,13 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
 
        load_submodule_cache();
 
-       unborn = !strcmp(rev, "HEAD") && get_sha1("HEAD", oid.hash);
+       unborn = !strcmp(rev, "HEAD") && get_oid("HEAD", &oid);
        if (unborn) {
                /* reset on unborn branch: treat as reset to empty tree */
                hashcpy(oid.hash, EMPTY_TREE_SHA1_BIN);
        } else if (!pathspec.nr) {
                struct commit *commit;
-               if (get_sha1_committish(rev, oid.hash))
+               if (get_oid_committish(rev, &oid))
                        die(_("Failed to resolve '%s' as a valid revision."), rev);
                commit = lookup_commit_reference(&oid);
                if (!commit)
@@ -324,7 +324,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
                oidcpy(&oid, &commit->object.oid);
        } else {
                struct tree *tree;
-               if (get_sha1_treeish(rev, oid.hash))
+               if (get_oid_treeish(rev, &oid))
                        die(_("Failed to resolve '%s' as a valid tree."), rev);
                tree = parse_tree_indirect(&oid);
                if (!tree)
index 1e9cc594881f8f08fb12c284271b00bcaae18ddc..95b4128250c850eb130fbdfea2407bad819a85b8 100644 (file)
@@ -11,6 +11,7 @@
 #include "graph.h"
 #include "bisect.h"
 #include "progress.h"
+#include "reflog-walk.h"
 
 static const char rev_list_usage[] =
 "git rev-list [OPTION] <commit-id>... [ -- paths... ]\n"
@@ -122,6 +123,7 @@ static void show_commit(struct commit *commit, void *data)
                ctx.date_mode_explicit = revs->date_mode_explicit;
                ctx.fmt = revs->commit_format;
                ctx.output_encoding = get_log_output_encoding();
+               ctx.color = revs->diffopt.use_color;
                pretty_print_commit(&ctx, commit, &buf);
                if (buf.len) {
                        if (revs->commit_format != CMIT_FMT_ONELINE)
@@ -348,7 +350,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
                /* Only --header was specified */
                revs.commit_format = CMIT_FMT_RAW;
 
-       if ((!revs.commits &&
+       if ((!revs.commits && reflog_walk_empty(revs.reflog_info) &&
             (!(revs.tag_objects || revs.tree_objects || revs.blob_objects) &&
              !revs.pending.nr) &&
             !revs.rev_input_given) ||
index c78b7b33d6604bb38a16e30d64cfabee0fd67f40..2bd28d3c085c9f7f86072bb7e1aae443aee745e6 100644 (file)
@@ -274,7 +274,7 @@ static int try_difference(const char *arg)
                return 0;
        }
 
-       if (!get_sha1_committish(this, oid.hash) && !get_sha1_committish(next, end.hash)) {
+       if (!get_oid_committish(this, &oid) && !get_oid_committish(next, &end)) {
                show_rev(NORMAL, &end, next);
                show_rev(symmetric ? NORMAL : REVERSED, &oid, this);
                if (symmetric) {
@@ -328,7 +328,7 @@ static int try_parent_shorthands(const char *arg)
                return 0;
 
        *dotdot = 0;
-       if (get_sha1_committish(arg, oid.hash)) {
+       if (get_oid_committish(arg, &oid)) {
                *dotdot = '^';
                return 0;
        }
@@ -702,7 +702,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
                        }
                        if (!strcmp(arg, "--quiet") || !strcmp(arg, "-q")) {
                                quiet = 1;
-                               flags |= GET_SHA1_QUIETLY;
+                               flags |= GET_OID_QUIETLY;
                                continue;
                        }
                        if (opt_with_value(arg, "--short", &arg)) {
@@ -911,7 +911,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
                        name++;
                        type = REVERSED;
                }
-               if (!get_sha1_with_context(name, flags, oid.hash, &unused)) {
+               if (!get_oid_with_context(name, flags, &oid, &unused)) {
                        if (verify)
                                revs_count++;
                        else
index 7073a3eb9769cae1f00e714a93528b33ca651d9c..84547d6fba07cb7770d94e80cda170c391d04a21 100644 (file)
@@ -393,7 +393,7 @@ static int append_head_ref(const char *refname, const struct object_id *oid,
        /* If both heads/foo and tags/foo exists, get_sha1 would
         * get confused.
         */
-       if (get_sha1(refname + ofs, tmp.hash) || oidcmp(&tmp, oid))
+       if (get_oid(refname + ofs, &tmp) || oidcmp(&tmp, oid))
                ofs = 5;
        return append_ref(refname + ofs, oid, 0);
 }
@@ -408,7 +408,7 @@ static int append_remote_ref(const char *refname, const struct object_id *oid,
        /* If both heads/foo and tags/foo exists, get_sha1 would
         * get confused.
         */
-       if (get_sha1(refname + ofs, tmp.hash) || oidcmp(&tmp, oid))
+       if (get_oid(refname + ofs, &tmp) || oidcmp(&tmp, oid))
                ofs = 5;
        return append_ref(refname + ofs, oid, 0);
 }
@@ -514,7 +514,7 @@ static int show_independent(struct commit **rev,
 static void append_one_rev(const char *av)
 {
        struct object_id revkey;
-       if (!get_sha1(av, revkey.hash)) {
+       if (!get_oid(av, &revkey)) {
                append_ref(av, &revkey, 0);
                return;
        }
@@ -554,7 +554,7 @@ static int git_show_branch_config(const char *var, const char *value, void *cb)
                return 0;
        }
 
-       return git_color_default_config(var, value, cb);
+       return git_default_config(var, value, cb);
 }
 
 static int omit_in_dense(struct commit *commit, struct commit **rev, int n)
@@ -808,7 +808,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
                        die(Q_("cannot handle more than %d rev.",
                               "cannot handle more than %d revs.",
                               MAX_REVS), MAX_REVS);
-               if (get_sha1(ref_name[num_rev], revkey.hash))
+               if (get_oid(ref_name[num_rev], &revkey))
                        die(_("'%s' is not a valid ref."), ref_name[num_rev]);
                commit = lookup_commit_reference(&revkey);
                if (!commit)
index 6abdad3294ce84652a55522aff55f6e7673d192f..84562ec8337a49c823da6c641d73cd363a972f27 100644 (file)
@@ -350,7 +350,7 @@ static void init_submodule(const char *path, const char *prefix, int quiet)
        } else
                displaypath = xstrdup(path);
 
-       sub = submodule_from_path(null_sha1, path);
+       sub = submodule_from_path(&null_oid, path);
 
        if (!sub)
                die(_("No url found for submodule path '%s' in .gitmodules"),
@@ -476,7 +476,7 @@ static int module_name(int argc, const char **argv, const char *prefix)
                usage(_("git submodule--helper name <path>"));
 
        gitmodules_config();
-       sub = submodule_from_path(null_sha1, argv[1]);
+       sub = submodule_from_path(&null_oid, argv[1]);
 
        if (!sub)
                die(_("no submodule mapping found in .gitmodules for path '%s'"),
@@ -795,7 +795,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
                goto cleanup;
        }
 
-       sub = submodule_from_path(null_sha1, ce->name);
+       sub = submodule_from_path(&null_oid, ce->name);
 
        if (suc->recursive_prefix)
                displaypath = relative_path(suc->recursive_prefix,
@@ -930,7 +930,7 @@ static int update_clone_task_finished(int result,
        const struct cache_entry *ce;
        struct submodule_update_clone *suc = suc_cb;
 
-       int *idxP = *(int**)idx_task_cb;
+       int *idxP = idx_task_cb;
        int idx = *idxP;
        free(idxP);
 
@@ -1060,7 +1060,7 @@ static const char *remote_submodule_branch(const char *path)
        gitmodules_config();
        git_config(submodule_config, NULL);
 
-       sub = submodule_from_path(null_sha1, path);
+       sub = submodule_from_path(&null_oid, path);
        if (!sub)
                return NULL;
 
index 01154ea8dcca869ed635eb433d5afe879b8e883c..e8a30e6110f9782d72a4fd2592bd82af9842ef19 100644 (file)
@@ -32,7 +32,8 @@ static const char * const git_tag_usage[] = {
 static unsigned int colopts;
 static int force_sign_annotate;
 
-static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting, const char *format)
+static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting,
+                    struct ref_format *format)
 {
        struct ref_array array;
        char *to_free = NULL;
@@ -43,23 +44,24 @@ static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting, con
        if (filter->lines == -1)
                filter->lines = 0;
 
-       if (!format) {
+       if (!format->format) {
                if (filter->lines) {
                        to_free = xstrfmt("%s %%(contents:lines=%d)",
                                          "%(align:15)%(refname:lstrip=2)%(end)",
                                          filter->lines);
-                       format = to_free;
+                       format->format = to_free;
                } else
-                       format = "%(refname:lstrip=2)";
+                       format->format = "%(refname:lstrip=2)";
        }
 
-       verify_ref_format(format);
+       if (verify_ref_format(format))
+               die(_("unable to parse format string"));
        filter->with_commit_tag_algo = 1;
        filter_refs(&array, filter, FILTER_REFS_TAGS);
        ref_array_sort(sorting, &array);
 
        for (i = 0; i < array.nr; i++)
-               show_ref_array_item(array.items[i], format, 0);
+               show_ref_array_item(array.items[i], format);
        ref_array_clear(&array);
        free(to_free);
 
@@ -105,17 +107,17 @@ static int verify_tag(const char *name, const char *ref,
                      const struct object_id *oid, const void *cb_data)
 {
        int flags;
-       const char *fmt_pretty = cb_data;
+       const struct ref_format *format = cb_data;
        flags = GPG_VERIFY_VERBOSE;
 
-       if (fmt_pretty)
+       if (format->format)
                flags = GPG_VERIFY_OMIT_STATUS;
 
-       if (gpg_verify_tag(oid->hash, name, flags))
+       if (gpg_verify_tag(oid, name, flags))
                return -1;
 
-       if (fmt_pretty)
-               pretty_print_ref(name, oid->hash, fmt_pretty);
+       if (format->format)
+               pretty_print_ref(name, oid->hash, format);
 
        return 0;
 }
@@ -134,30 +136,6 @@ static const char tag_template_nocleanup[] =
        "Lines starting with '%c' will be kept; you may remove them"
        " yourself if you want to.\n");
 
-/* Parse arg given and add it the ref_sorting array */
-static int parse_sorting_string(const char *arg, struct ref_sorting **sorting_tail)
-{
-       struct ref_sorting *s;
-       int len;
-
-       s = xcalloc(1, sizeof(*s));
-       s->next = *sorting_tail;
-       *sorting_tail = s;
-
-       if (*arg == '-') {
-               s->reverse = 1;
-               arg++;
-       }
-       if (skip_prefix(arg, "version:", &arg) ||
-           skip_prefix(arg, "v:", &arg))
-               s->version = 1;
-
-       len = strlen(arg);
-       s->atom = parse_ref_filter_atom(arg, arg+len);
-
-       return 0;
-}
-
 static int git_tag_config(const char *var, const char *value, void *cb)
 {
        int status;
@@ -166,7 +144,7 @@ static int git_tag_config(const char *var, const char *value, void *cb)
        if (!strcmp(var, "tag.sort")) {
                if (!value)
                        return config_error_nonbool(var);
-               parse_sorting_string(value, sorting_tail);
+               parse_ref_sorting(sorting_tail, value);
                return 0;
        }
 
@@ -392,7 +370,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
        struct strbuf err = STRBUF_INIT;
        struct ref_filter filter;
        static struct ref_sorting *sorting = NULL, **sorting_tail = &sorting;
-       const char *format = NULL;
+       struct ref_format format = REF_FORMAT_INIT;
        int icase = 0;
        struct option options[] = {
                OPT_CMDMODE('l', "list", &cmdmode, N_("list tag names"), 'l'),
@@ -431,7 +409,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
                        N_("print only tags of the object"), PARSE_OPT_LASTARG_DEFAULT,
                        parse_opt_object_name, (intptr_t) "HEAD"
                },
-               OPT_STRING(  0 , "format", &format, N_("format"), N_("format to use for the output")),
+               OPT_STRING(  0 , "format", &format.format, N_("format"),
+                          N_("format to use for the output")),
                OPT_BOOL('i', "ignore-case", &icase, N_("sorting and filtering are case insensitive")),
                OPT_END()
        };
@@ -483,7 +462,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
                        run_column_filter(colopts, &copts);
                }
                filter.name_patterns = argv;
-               ret = list_tags(&filter, sorting, format);
+               ret = list_tags(&filter, sorting, &format);
                if (column_active(colopts))
                        stop_column_filter();
                return ret;
@@ -501,9 +480,9 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
        if (cmdmode == 'd')
                return for_each_tag_name(argv, delete_tag, NULL);
        if (cmdmode == 'v') {
-               if (format)
-                       verify_ref_format(format);
-               return for_each_tag_name(argv, verify_tag, format);
+               if (format.format && verify_ref_format(&format))
+                       usage_with_options(git_tag_usage, options);
+               return for_each_tag_name(argv, verify_tag, &format);
        }
 
        if (msg.given || msgfile) {
index 73f133419167840d150300faa696bc32027cd02f..281ca1db6ce13ddb4cc227ebb7ea454176e8e9e1 100644 (file)
@@ -1,7 +1,7 @@
 #include "builtin.h"
 #include "config.h"
 
-static char *create_temp_file(unsigned char *sha1)
+static char *create_temp_file(struct object_id *oid)
 {
        static char path[50];
        void *buf;
@@ -9,9 +9,9 @@ static char *create_temp_file(unsigned char *sha1)
        unsigned long size;
        int fd;
 
-       buf = read_sha1_file(sha1, &type, &size);
+       buf = read_sha1_file(oid->hash, &type, &size);
        if (!buf || type != OBJ_BLOB)
-               die("unable to read blob object %s", sha1_to_hex(sha1));
+               die("unable to read blob object %s", oid_to_hex(oid));
 
        xsnprintf(path, sizeof(path), ".merge_file_XXXXXX");
        fd = xmkstemp(path);
@@ -23,15 +23,15 @@ static char *create_temp_file(unsigned char *sha1)
 
 int cmd_unpack_file(int argc, const char **argv, const char *prefix)
 {
-       unsigned char sha1[20];
+       struct object_id oid;
 
        if (argc != 2 || !strcmp(argv[1], "-h"))
                usage("git unpack-file <sha1>");
-       if (get_sha1(argv[1], sha1))
+       if (get_oid(argv[1], &oid))
                die("Not a valid object name %s", argv[1]);
 
        git_config(git_default_config, NULL);
 
-       puts(create_temp_file(sha1));
+       puts(create_temp_file(&oid));
        return 0;
 }
index 40ccfc193bf785cfae0f83526c561eedf0d310bc..6b90c5deadb62600aa08166f500bde24cb800fbf 100644 (file)
@@ -94,10 +94,10 @@ static char *parse_refname(struct strbuf *input, const char **next)
  * provided but cannot be converted to a SHA-1, die.  flags can
  * include PARSE_SHA1_OLD and/or PARSE_SHA1_ALLOW_EMPTY.
  */
-static int parse_next_sha1(struct strbuf *input, const char **next,
-                          unsigned char *sha1,
-                          const char *command, const char *refname,
-                          int flags)
+static int parse_next_oid(struct strbuf *input, const char **next,
+                         struct object_id *oid,
+                         const char *command, const char *refname,
+                         int flags)
 {
        struct strbuf arg = STRBUF_INIT;
        int ret = 0;
@@ -115,11 +115,11 @@ static int parse_next_sha1(struct strbuf *input, const char **next,
                (*next)++;
                *next = parse_arg(*next, &arg);
                if (arg.len) {
-                       if (get_sha1(arg.buf, sha1))
+                       if (get_oid(arg.buf, oid))
                                goto invalid;
                } else {
                        /* Without -z, an empty value means all zeros: */
-                       hashclr(sha1);
+                       oidclr(oid);
                }
        } else {
                /* With -z, read the next NUL-terminated line */
@@ -133,13 +133,13 @@ static int parse_next_sha1(struct strbuf *input, const char **next,
                *next += arg.len;
 
                if (arg.len) {
-                       if (get_sha1(arg.buf, sha1))
+                       if (get_oid(arg.buf, oid))
                                goto invalid;
                } else if (flags & PARSE_SHA1_ALLOW_EMPTY) {
                        /* With -z, treat an empty value as all zeros: */
                        warning("%s %s: missing <newvalue>, treating as zero",
                                command, refname);
-                       hashclr(sha1);
+                       oidclr(oid);
                } else {
                        /*
                         * With -z, an empty non-required value means
@@ -182,26 +182,25 @@ static const char *parse_cmd_update(struct ref_transaction *transaction,
 {
        struct strbuf err = STRBUF_INIT;
        char *refname;
-       unsigned char new_sha1[20];
-       unsigned char old_sha1[20];
+       struct object_id new_oid, old_oid;
        int have_old;
 
        refname = parse_refname(input, &next);
        if (!refname)
                die("update: missing <ref>");
 
-       if (parse_next_sha1(input, &next, new_sha1, "update", refname,
-                           PARSE_SHA1_ALLOW_EMPTY))
+       if (parse_next_oid(input, &next, &new_oid, "update", refname,
+                          PARSE_SHA1_ALLOW_EMPTY))
                die("update %s: missing <newvalue>", refname);
 
-       have_old = !parse_next_sha1(input, &next, old_sha1, "update", refname,
-                                   PARSE_SHA1_OLD);
+       have_old = !parse_next_oid(input, &next, &old_oid, "update", refname,
+                                  PARSE_SHA1_OLD);
 
        if (*next != line_termination)
                die("update %s: extra input: %s", refname, next);
 
        if (ref_transaction_update(transaction, refname,
-                                  new_sha1, have_old ? old_sha1 : NULL,
+                                  new_oid.hash, have_old ? old_oid.hash : NULL,
                                   update_flags | create_reflog_flag,
                                   msg, &err))
                die("%s", err.buf);
@@ -218,22 +217,22 @@ static const char *parse_cmd_create(struct ref_transaction *transaction,
 {
        struct strbuf err = STRBUF_INIT;
        char *refname;
-       unsigned char new_sha1[20];
+       struct object_id new_oid;
 
        refname = parse_refname(input, &next);
        if (!refname)
                die("create: missing <ref>");
 
-       if (parse_next_sha1(input, &next, new_sha1, "create", refname, 0))
+       if (parse_next_oid(input, &next, &new_oid, "create", refname, 0))
                die("create %s: missing <newvalue>", refname);
 
-       if (is_null_sha1(new_sha1))
+       if (is_null_oid(&new_oid))
                die("create %s: zero <newvalue>", refname);
 
        if (*next != line_termination)
                die("create %s: extra input: %s", refname, next);
 
-       if (ref_transaction_create(transaction, refname, new_sha1,
+       if (ref_transaction_create(transaction, refname, new_oid.hash,
                                   update_flags | create_reflog_flag,
                                   msg, &err))
                die("%s", err.buf);
@@ -250,18 +249,18 @@ static const char *parse_cmd_delete(struct ref_transaction *transaction,
 {
        struct strbuf err = STRBUF_INIT;
        char *refname;
-       unsigned char old_sha1[20];
+       struct object_id old_oid;
        int have_old;
 
        refname = parse_refname(input, &next);
        if (!refname)
                die("delete: missing <ref>");
 
-       if (parse_next_sha1(input, &next, old_sha1, "delete", refname,
-                           PARSE_SHA1_OLD)) {
+       if (parse_next_oid(input, &next, &old_oid, "delete", refname,
+                          PARSE_SHA1_OLD)) {
                have_old = 0;
        } else {
-               if (is_null_sha1(old_sha1))
+               if (is_null_oid(&old_oid))
                        die("delete %s: zero <oldvalue>", refname);
                have_old = 1;
        }
@@ -270,7 +269,7 @@ static const char *parse_cmd_delete(struct ref_transaction *transaction,
                die("delete %s: extra input: %s", refname, next);
 
        if (ref_transaction_delete(transaction, refname,
-                                  have_old ? old_sha1 : NULL,
+                                  have_old ? old_oid.hash : NULL,
                                   update_flags, msg, &err))
                die("%s", err.buf);
 
@@ -286,20 +285,20 @@ static const char *parse_cmd_verify(struct ref_transaction *transaction,
 {
        struct strbuf err = STRBUF_INIT;
        char *refname;
-       unsigned char old_sha1[20];
+       struct object_id old_oid;
 
        refname = parse_refname(input, &next);
        if (!refname)
                die("verify: missing <ref>");
 
-       if (parse_next_sha1(input, &next, old_sha1, "verify", refname,
-                           PARSE_SHA1_OLD))
-               hashclr(old_sha1);
+       if (parse_next_oid(input, &next, &old_oid, "verify", refname,
+                          PARSE_SHA1_OLD))
+               oidclr(&old_oid);
 
        if (*next != line_termination)
                die("verify %s: extra input: %s", refname, next);
 
-       if (ref_transaction_verify(transaction, refname, old_sha1,
+       if (ref_transaction_verify(transaction, refname, old_oid.hash,
                                   update_flags, &err))
                die("%s", err.buf);
 
@@ -355,7 +354,7 @@ static void update_refs_stdin(struct ref_transaction *transaction)
 int cmd_update_ref(int argc, const char **argv, const char *prefix)
 {
        const char *refname, *oldval;
-       unsigned char sha1[20], oldsha1[20];
+       struct object_id oid, oldoid;
        int delete = 0, no_deref = 0, read_stdin = 0, end_null = 0;
        unsigned int flags = 0;
        int create_reflog = 0;
@@ -412,7 +411,7 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
                refname = argv[0];
                value = argv[1];
                oldval = argv[2];
-               if (get_sha1(value, sha1))
+               if (get_oid(value, &oid))
                        die("%s: not a valid SHA1", value);
        }
 
@@ -422,8 +421,8 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
                         * The empty string implies that the reference
                         * must not already exist:
                         */
-                       hashclr(oldsha1);
-               else if (get_sha1(oldval, oldsha1))
+                       oidclr(&oldoid);
+               else if (get_oid(oldval, &oldoid))
                        die("%s: not a valid old SHA1", oldval);
        }
 
@@ -435,10 +434,10 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
                 * NULL_SHA1 as "don't care" here:
                 */
                return delete_ref(msg, refname,
-                                 (oldval && !is_null_sha1(oldsha1)) ? oldsha1 : NULL,
+                                 (oldval && !is_null_oid(&oldoid)) ? oldoid.hash : NULL,
                                  flags);
        else
-               return update_ref(msg, refname, sha1, oldval ? oldsha1 : NULL,
+               return update_ref(msg, refname, oid.hash, oldval ? oldoid.hash : NULL,
                                  flags | create_reflog_flag,
                                  UPDATE_REFS_DIE_ON_ERR);
 }
index f9a5f7535aad9c24041e0677dfa4ed4af87cabf0..ad7b79fa5cd718daf3be5f1a46a1fbb2bed41ad5 100644 (file)
@@ -32,11 +32,11 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix)
 {
        int i = 1, verbose = 0, had_error = 0;
        unsigned flags = 0;
-       char *fmt_pretty = NULL;
+       struct ref_format format = REF_FORMAT_INIT;
        const struct option verify_tag_options[] = {
                OPT__VERBOSE(&verbose, N_("print tag contents")),
                OPT_BIT(0, "raw", &flags, N_("print raw gpg status output"), GPG_VERIFY_RAW),
-               OPT_STRING(  0 , "format", &fmt_pretty, N_("format"), N_("format to use for the output")),
+               OPT_STRING(0, "format", &format.format, N_("format"), N_("format to use for the output")),
                OPT_END()
        };
 
@@ -50,26 +50,29 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix)
        if (verbose)
                flags |= GPG_VERIFY_VERBOSE;
 
-       if (fmt_pretty) {
-               verify_ref_format(fmt_pretty);
+       if (format.format) {
+               if (verify_ref_format(&format))
+                       usage_with_options(verify_tag_usage,
+                                          verify_tag_options);
                flags |= GPG_VERIFY_OMIT_STATUS;
        }
 
        while (i < argc) {
-               unsigned char sha1[20];
+               struct object_id oid;
                const char *name = argv[i++];
-               if (get_sha1(name, sha1)) {
+
+               if (get_oid(name, &oid)) {
                        had_error = !!error("tag '%s' not found.", name);
                        continue;
                }
 
-               if (gpg_verify_tag(sha1, name, flags)) {
+               if (gpg_verify_tag(&oid, name, flags)) {
                        had_error = 1;
                        continue;
                }
 
-               if (fmt_pretty)
-                       pretty_print_ref(name, sha1, fmt_pretty);
+               if (format.format)
+                       pretty_print_ref(name, oid.hash, &format);
        }
        return had_error;
 }
index ec23d8c03d10bd3815f59c2d70ae5eb45170aaad..2440d1dc89175efaf74286da4b2c8f97fc52fbd9 100644 (file)
@@ -131,9 +131,8 @@ static int do_invalidate_path(struct cache_tree *it, const char *path)
                         * move 4 and 5 up one place (2 entries)
                         * 2 = 6 - 3 - 1 = subtree_nr - pos - 1
                         */
-                       memmove(it->down+pos, it->down+pos+1,
-                               sizeof(struct cache_tree_sub *) *
-                               (it->subtree_nr - pos - 1));
+                       MOVE_ARRAY(it->down + pos, it->down + pos + 1,
+                                  it->subtree_nr - pos - 1);
                        it->subtree_nr--;
                }
                return 1;
diff --git a/cache.h b/cache.h
index 71fe092644c2c4032ed29c2801fefdf976736db0..1c69d2a05aaf1f5e737bd5229cfaf0fedbe6ca92 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -1146,6 +1146,14 @@ char *strip_path_suffix(const char *path, const char *suffix);
 int daemon_avoid_alias(const char *path);
 extern int is_ntfs_dotgit(const char *name);
 
+/*
+ * Returns true iff "str" could be confused as a command-line option when
+ * passed to a sub-program like "ssh". Note that this has nothing to do with
+ * shell-quoting, which should be handled separately; we're assuming here that
+ * the string makes it verbatim to the sub-program.
+ */
+int looks_like_command_line_option(const char *str);
+
 /**
  * Return a newly allocated string with the evaluation of
  * "$XDG_CONFIG_HOME/git/$filename" if $XDG_CONFIG_HOME is non-empty, otherwise
@@ -1283,38 +1291,37 @@ struct object_context {
         */
        struct strbuf symlink_path;
        /*
-        * If GET_SHA1_RECORD_PATH is set, this will record path (if any)
+        * If GET_OID_RECORD_PATH is set, this will record path (if any)
         * found when resolving the name. The caller is responsible for
         * releasing the memory.
         */
        char *path;
 };
 
-#define GET_SHA1_QUIETLY           01
-#define GET_SHA1_COMMIT            02
-#define GET_SHA1_COMMITTISH        04
-#define GET_SHA1_TREE             010
-#define GET_SHA1_TREEISH          020
-#define GET_SHA1_BLOB             040
-#define GET_SHA1_FOLLOW_SYMLINKS 0100
-#define GET_SHA1_RECORD_PATH     0200
-#define GET_SHA1_ONLY_TO_DIE    04000
-
-#define GET_SHA1_DISAMBIGUATORS \
-       (GET_SHA1_COMMIT | GET_SHA1_COMMITTISH | \
-       GET_SHA1_TREE | GET_SHA1_TREEISH | \
-       GET_SHA1_BLOB)
-
-extern int get_sha1(const char *str, unsigned char *sha1);
-extern int get_sha1_commit(const char *str, unsigned char *sha1);
-extern int get_sha1_committish(const char *str, unsigned char *sha1);
-extern int get_sha1_tree(const char *str, unsigned char *sha1);
-extern int get_sha1_treeish(const char *str, unsigned char *sha1);
-extern int get_sha1_blob(const char *str, unsigned char *sha1);
-extern void maybe_die_on_misspelt_object_name(const char *name, const char *prefix);
-extern int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *oc);
+#define GET_OID_QUIETLY           01
+#define GET_OID_COMMIT            02
+#define GET_OID_COMMITTISH        04
+#define GET_OID_TREE             010
+#define GET_OID_TREEISH          020
+#define GET_OID_BLOB             040
+#define GET_OID_FOLLOW_SYMLINKS 0100
+#define GET_OID_RECORD_PATH     0200
+#define GET_OID_ONLY_TO_DIE    04000
+
+#define GET_OID_DISAMBIGUATORS \
+       (GET_OID_COMMIT | GET_OID_COMMITTISH | \
+       GET_OID_TREE | GET_OID_TREEISH | \
+       GET_OID_BLOB)
 
 extern int get_oid(const char *str, struct object_id *oid);
+extern int get_oid_commit(const char *str, struct object_id *oid);
+extern int get_oid_committish(const char *str, struct object_id *oid);
+extern int get_oid_tree(const char *str, struct object_id *oid);
+extern int get_oid_treeish(const char *str, struct object_id *oid);
+extern int get_oid_blob(const char *str, struct object_id *oid);
+extern void maybe_die_on_misspelt_object_name(const char *name, const char *prefix);
+extern int get_oid_with_context(const char *str, unsigned flags, struct object_id *oid, struct object_context *oc);
+
 
 typedef int each_abbrev_fn(const struct object_id *oid, void *);
 extern int for_each_abbrev(const char *prefix, each_abbrev_fn, void *);
@@ -1492,6 +1499,7 @@ struct checkout {
        struct index_state *istate;
        const char *base_dir;
        int base_dir_len;
+       struct delayed_checkout *delayed_checkout;
        unsigned force:1,
                 quiet:1,
                 not_new:1,
@@ -1501,6 +1509,8 @@ struct checkout {
 
 #define TEMPORARY_FILENAME_LENGTH 25
 extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath);
+extern void enable_delayed_checkout(struct checkout *state);
+extern int finish_delayed_checkout(struct checkout *state);
 
 struct cache_def {
        struct strbuf path;
diff --git a/color.c b/color.c
index 31b6207a00de42a386e98c5656209ea7a010abe4..7aa8b076f045e5c0b74826153030e2923c0fc56e 100644 (file)
--- a/color.c
+++ b/color.c
@@ -361,14 +361,6 @@ int git_color_config(const char *var, const char *value, void *cb)
        return 0;
 }
 
-int git_color_default_config(const char *var, const char *value, void *cb)
-{
-       if (git_color_config(var, value, cb) < 0)
-               return -1;
-
-       return git_default_config(var, value, cb);
-}
-
 void color_print_strbuf(FILE *fp, const char *color, const struct strbuf *sb)
 {
        if (*color)
index cbfd6899392e8715b206c96b3b58cbdaf29c77cd..8b28415939035e2b40153013e6f8805422094d84 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -59,7 +59,7 @@ struct commit *lookup_commit_reference_by_name(const char *name)
        struct object_id oid;
        struct commit *commit;
 
-       if (get_sha1_committish(name, oid.hash))
+       if (get_oid_committish(name, &oid))
                return NULL;
        commit = lookup_commit_reference(&oid);
        if (parse_commit(commit))
@@ -199,11 +199,11 @@ static void prepare_commit_graft(void)
        commit_graft_prepared = 1;
 }
 
-struct commit_graft *lookup_commit_graft(const unsigned char *sha1)
+struct commit_graft *lookup_commit_graft(const struct object_id *oid)
 {
        int pos;
        prepare_commit_graft();
-       pos = commit_graft_pos(sha1);
+       pos = commit_graft_pos(oid->hash);
        if (pos < 0)
                return NULL;
        return commit_graft[pos];
@@ -223,9 +223,8 @@ int unregister_shallow(const struct object_id *oid)
        if (pos < 0)
                return -1;
        if (pos + 1 < commit_graft_nr)
-               memmove(commit_graft + pos, commit_graft + pos + 1,
-                               sizeof(struct commit_graft *)
-                               * (commit_graft_nr - pos - 1));
+               MOVE_ARRAY(commit_graft + pos, commit_graft + pos + 1,
+                          commit_graft_nr - pos - 1);
        commit_graft_nr--;
        return 0;
 }
@@ -335,7 +334,7 @@ int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long s
        bufptr += tree_entry_len + 1; /* "tree " + "hex sha1" + "\n" */
        pptr = &item->parents;
 
-       graft = lookup_commit_graft(item->object.oid.hash);
+       graft = lookup_commit_graft(&item->object.oid);
        while (bufptr + parent_entry_len < tail && !memcmp(bufptr, "parent ", 7)) {
                struct commit *new_parent;
 
@@ -1587,7 +1586,7 @@ struct commit *get_merge_parent(const char *name)
        struct object *obj;
        struct commit *commit;
        struct object_id oid;
-       if (get_sha1(name, oid.hash))
+       if (get_oid(name, &oid))
                return NULL;
        obj = parse_object(&oid);
        commit = (struct commit *)peel_to_type(name, 0, obj, OBJ_COMMIT);
index 4127c298cb1370a9ab56ca9d003e853b3e26b67e..6d857f06c16c0dfc3a447355d9a185b416e4e664 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -249,7 +249,7 @@ typedef int (*each_commit_graft_fn)(const struct commit_graft *, void *);
 
 struct commit_graft *read_graft_line(char *buf, int len);
 int register_commit_graft(struct commit_graft *, int);
-struct commit_graft *lookup_commit_graft(const unsigned char *sha1);
+struct commit_graft *lookup_commit_graft(const struct object_id *oid);
 
 extern struct commit_list *get_merge_bases(struct commit *rev1, struct commit *rev2);
 extern struct commit_list *get_merge_bases_many(struct commit *one, int n, struct commit **twos);
index d47c0035449b412ee074c9a94c0f5281211f5f7e..7d063e9e40a213ce378d90377a9ac2b1f04ddbe3 100644 (file)
@@ -162,19 +162,29 @@ static inline uint64_t git_bswap64(uint64_t x)
 
 #else
 
-#define get_be16(p)    ( \
-       (*((unsigned char *)(p) + 0) << 8) | \
-       (*((unsigned char *)(p) + 1) << 0) )
-#define get_be32(p)    ( \
-       (*((unsigned char *)(p) + 0) << 24) | \
-       (*((unsigned char *)(p) + 1) << 16) | \
-       (*((unsigned char *)(p) + 2) <<  8) | \
-       (*((unsigned char *)(p) + 3) <<  0) )
-#define put_be32(p, v) do { \
-       unsigned int __v = (v); \
-       *((unsigned char *)(p) + 0) = __v >> 24; \
-       *((unsigned char *)(p) + 1) = __v >> 16; \
-       *((unsigned char *)(p) + 2) = __v >>  8; \
-       *((unsigned char *)(p) + 3) = __v >>  0; } while (0)
+static inline uint16_t get_be16(const void *ptr)
+{
+       const unsigned char *p = ptr;
+       return  (uint16_t)p[0] << 8 |
+               (uint16_t)p[1] << 0;
+}
+
+static inline uint32_t get_be32(const void *ptr)
+{
+       const unsigned char *p = ptr;
+       return  (uint32_t)p[0] << 24 |
+               (uint32_t)p[1] << 16 |
+               (uint32_t)p[2] <<  8 |
+               (uint32_t)p[3] <<  0;
+}
+
+static inline void put_be32(void *ptr, uint32_t value)
+{
+       unsigned char *p = ptr;
+       p[0] = value >> 24;
+       p[1] = value >> 16;
+       p[2] = value >>  8;
+       p[3] = value >>  0;
+}
 
 #endif
index 231f9a750b96deda8d62f5a5debb384f40481566..9ec8c4488229a4f6a15550fd80496ef1b5bb85fe 100644 (file)
--- a/config.c
+++ b/config.c
@@ -16,6 +16,7 @@
 #include "string-list.h"
 #include "utf8.h"
 #include "dir.h"
+#include "color.h"
 
 struct config_source {
        struct config_source *prev;
@@ -1350,6 +1351,9 @@ int git_default_config(const char *var, const char *value, void *dummy)
        if (starts_with(var, "advice."))
                return git_default_advice_config(var, value);
 
+       if (git_color_config(var, value, dummy) < 0)
+               return -1;
+
        if (!strcmp(var, "pager.color") || !strcmp(var, "color.pager")) {
                pager_use_color = git_config_bool(var,value);
                return 0;
@@ -1460,9 +1464,9 @@ int git_config_from_mem(config_fn_t fn, const enum config_origin_type origin_typ
        return do_config_from(&top, fn, data);
 }
 
-int git_config_from_blob_sha1(config_fn_t fn,
+int git_config_from_blob_oid(config_fn_t fn,
                              const char *name,
-                             const unsigned char *sha1,
+                             const struct object_id *oid,
                              void *data)
 {
        enum object_type type;
@@ -1470,7 +1474,7 @@ int git_config_from_blob_sha1(config_fn_t fn,
        unsigned long size;
        int ret;
 
-       buf = read_sha1_file(sha1, &type, &size);
+       buf = read_sha1_file(oid->hash, &type, &size);
        if (!buf)
                return error("unable to load config blob object '%s'", name);
        if (type != OBJ_BLOB) {
@@ -1488,11 +1492,11 @@ static int git_config_from_blob_ref(config_fn_t fn,
                                    const char *name,
                                    void *data)
 {
-       unsigned char sha1[20];
+       struct object_id oid;
 
-       if (get_sha1(name, sha1) < 0)
+       if (get_oid(name, &oid) < 0)
                return error("unable to resolve config blob '%s'", name);
-       return git_config_from_blob_sha1(fn, name, sha1, data);
+       return git_config_from_blob_oid(fn, name, &oid, data);
 }
 
 const char *git_etc_gitconfig(void)
@@ -1715,17 +1719,19 @@ static int configset_add_value(struct config_set *cs, const char *key, const cha
 }
 
 static int config_set_element_cmp(const void *unused_cmp_data,
-                                 const struct config_set_element *e1,
-                                 const struct config_set_element *e2,
+                                 const void *entry,
+                                 const void *entry_or_key,
                                  const void *unused_keydata)
 {
+       const struct config_set_element *e1 = entry;
+       const struct config_set_element *e2 = entry_or_key;
+
        return strcmp(e1->key, e2->key);
 }
 
 void git_configset_init(struct config_set *cs)
 {
-       hashmap_init(&cs->config_hash, (hashmap_cmp_fn)config_set_element_cmp,
-                    NULL, 0);
+       hashmap_init(&cs->config_hash, config_set_element_cmp, NULL, 0);
        cs->hash_initialized = 1;
        cs->list.nr = 0;
        cs->list.alloc = 0;
index 0352da117b9a61498311da5a5b5fdf5e14af8b58..827f2b0e4a652b008fd9e3f36cee4ae656836f4e 100644 (file)
--- a/config.h
+++ b/config.h
@@ -39,8 +39,8 @@ extern int git_default_config(const char *, const char *, void *);
 extern int git_config_from_file(config_fn_t fn, const char *, void *);
 extern int git_config_from_mem(config_fn_t fn, const enum config_origin_type,
                                        const char *name, const char *buf, size_t len, void *data);
-extern int git_config_from_blob_sha1(config_fn_t fn, const char *name,
-                                    const unsigned char *sha1, void *data);
+extern int git_config_from_blob_oid(config_fn_t fn, const char *name,
+                                   const struct object_id *oid, void *data);
 extern void git_config_push_parameter(const char *text);
 extern int git_config_from_parameters(config_fn_t fn, void *data);
 extern void read_early_config(config_fn_t cb, void *data);
index e78d3f43d84b7f90f4395cb289c9cf0cb34e8297..49b28b83be2717027ac33570b1041604db5a062d 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -578,6 +578,11 @@ static struct child_process *git_proxy_connect(int fd[2], char *host)
 
        get_host_and_port(&host, &port);
 
+       if (looks_like_command_line_option(host))
+               die("strange hostname '%s' blocked", host);
+       if (looks_like_command_line_option(port))
+               die("strange port '%s' blocked", port);
+
        proxy = xmalloc(sizeof(*proxy));
        child_process_init(proxy);
        argv_array_push(&proxy->args, git_proxy_command);
@@ -824,6 +829,9 @@ struct child_process *git_connect(int fd[2], const char *url,
                conn = xmalloc(sizeof(*conn));
                child_process_init(conn);
 
+               if (looks_like_command_line_option(path))
+                       die("strange pathname '%s' blocked", path);
+
                strbuf_addstr(&cmd, prog);
                strbuf_addch(&cmd, ' ');
                sq_quote_buf(&cmd, path);
@@ -857,6 +865,9 @@ struct child_process *git_connect(int fd[2], const char *url,
                                return NULL;
                        }
 
+                       if (looks_like_command_line_option(ssh_host))
+                               die("strange hostname '%s' blocked", ssh_host);
+
                        ssh = get_ssh_command();
                        if (ssh)
                                handle_ssh_variant(ssh, 1, &port_option,
index 4ba98b7eaff268c6fc9f2f984449fd4d9e1bfd4b..c61d1ca8dc49f1da8dd70cf0c00ce97b1f18fcd2 100644 (file)
@@ -25,6 +25,23 @@ expression n;
 - memcpy(dst, src, n * sizeof(T));
 + COPY_ARRAY(dst, src, n);
 
+@@
+type T;
+T *dst;
+T *src;
+expression n;
+@@
+(
+- memmove(dst, src, (n) * sizeof(*dst));
++ MOVE_ARRAY(dst, src, n);
+|
+- memmove(dst, src, (n) * sizeof(*src));
++ MOVE_ARRAY(dst, src, n);
+|
+- memmove(dst, src, (n) * sizeof(T));
++ MOVE_ARRAY(dst, src, n);
+)
+
 @@
 type T;
 T *ptr;
index dbe2abf27730e20fcbd692012e9dd07a2e70404f..85ad732fc0636062634453a58be69454dd745b80 100755 (executable)
@@ -11,7 +11,7 @@ use IPC::Open2;
 
 my $since = '5-years-ago';
 my $min_percent = 10;
-my $labels_rx = qr/Signed-off-by|Reviewed-by|Acked-by|Cc/i;
+my $labels_rx = qr/Signed-off-by|Reviewed-by|Acked-by|Cc|Reported-by/i;
 my %seen;
 
 sub format_contact {
index 52ad9e41fb7aba37abf71dad2bf5a0015b01dca7..eeee45dd341b25d51b7497c4def555c4133c4267 100755 (executable)
@@ -3,10 +3,56 @@
 # Prime rerere database from existing merge commits
 
 me=rerere-train
-USAGE="$me rev-list-args"
+USAGE=$(cat <<-EOF
+usage: $me [--overwrite] <rev-list-args>
+
+    -h, --help            show the help
+    -o, --overwrite       overwrite any existing rerere cache
+EOF
+)
 
 SUBDIRECTORY_OK=Yes
-OPTIONS_SPEC=
+
+overwrite=0
+
+while test $# -gt 0
+do
+       opt="$1"
+       case "$opt" in
+       -h|--help)
+               echo "$USAGE"
+               exit 0
+               ;;
+       -o|--overwrite)
+               overwrite=1
+               shift
+               break
+               ;;
+       --)
+               shift
+               break
+               ;;
+       *)
+               break
+               ;;
+       esac
+done
+
+# Overwrite or help options are not valid except as first arg
+for opt in "$@"
+do
+       case "$opt" in
+       -h|--help)
+               echo "$USAGE"
+               exit 0
+               ;;
+       -o|--overwrite)
+               echo "$USAGE"
+               exit 0
+               ;;
+       esac
+done
+
 . "$(git --exec-path)/git-sh-setup"
 require_work_tree
 cd_to_toplevel
@@ -34,6 +80,10 @@ do
                # Cleanly merges
                continue
        fi
+       if test $overwrite = 1
+       then
+               git rerere forget .
+       fi
        if test -s "$GIT_DIR/MERGE_RR"
        then
                git show -s --pretty=format:"Learning from %h %s" "$commit"
index deaf0ba7b30ffa4e0003649985ef1594ee2ac049..1012462e3c9c114ad1b2374a2ae27568ace57bac 100644 (file)
--- a/convert.c
+++ b/convert.c
@@ -501,6 +501,7 @@ static int apply_single_file_filter(const char *path, const char *src, size_t le
 
 #define CAP_CLEAN    (1u<<0)
 #define CAP_SMUDGE   (1u<<1)
+#define CAP_DELAY    (1u<<2)
 
 struct cmd2process {
        struct subprocess_entry subprocess; /* must be the first member! */
@@ -512,69 +513,49 @@ static struct hashmap subprocess_map;
 
 static int start_multi_file_filter_fn(struct subprocess_entry *subprocess)
 {
-       int err;
+       static int versions[] = {2, 0};
+       static struct subprocess_capability capabilities[] = {
+               { "clean",  CAP_CLEAN  },
+               { "smudge", CAP_SMUDGE },
+               { "delay",  CAP_DELAY  },
+               { NULL, 0 }
+       };
        struct cmd2process *entry = (struct cmd2process *)subprocess;
-       struct string_list cap_list = STRING_LIST_INIT_NODUP;
-       char *cap_buf;
-       const char *cap_name;
-       struct child_process *process = &subprocess->process;
-       const char *cmd = subprocess->cmd;
-
-       sigchain_push(SIGPIPE, SIG_IGN);
-
-       err = packet_writel(process->in, "git-filter-client", "version=2", NULL);
-       if (err)
-               goto done;
-
-       err = strcmp(packet_read_line(process->out, NULL), "git-filter-server");
-       if (err) {
-               error("external filter '%s' does not support filter protocol version 2", cmd);
-               goto done;
-       }
-       err = strcmp(packet_read_line(process->out, NULL), "version=2");
-       if (err)
-               goto done;
-       err = packet_read_line(process->out, NULL) != NULL;
-       if (err)
-               goto done;
-
-       err = packet_writel(process->in, "capability=clean", "capability=smudge", NULL);
-
-       for (;;) {
-               cap_buf = packet_read_line(process->out, NULL);
-               if (!cap_buf)
-                       break;
-               string_list_split_in_place(&cap_list, cap_buf, '=', 1);
-
-               if (cap_list.nr != 2 || strcmp(cap_list.items[0].string, "capability"))
-                       continue;
-
-               cap_name = cap_list.items[1].string;
-               if (!strcmp(cap_name, "clean")) {
-                       entry->supported_capabilities |= CAP_CLEAN;
-               } else if (!strcmp(cap_name, "smudge")) {
-                       entry->supported_capabilities |= CAP_SMUDGE;
-               } else {
-                       warning(
-                               "external filter '%s' requested unsupported filter capability '%s'",
-                               cmd, cap_name
-                       );
-               }
+       return subprocess_handshake(subprocess, "git-filter", versions, NULL,
+                                   capabilities,
+                                   &entry->supported_capabilities);
+}
 
-               string_list_clear(&cap_list, 0);
+static void handle_filter_error(const struct strbuf *filter_status,
+                               struct cmd2process *entry,
+                               const unsigned int wanted_capability) {
+       if (!strcmp(filter_status->buf, "error"))
+               ; /* The filter signaled a problem with the file. */
+       else if (!strcmp(filter_status->buf, "abort") && wanted_capability) {
+               /*
+                * The filter signaled a permanent problem. Don't try to filter
+                * files with the same command for the lifetime of the current
+                * Git process.
+                */
+                entry->supported_capabilities &= ~wanted_capability;
+       } else {
+               /*
+                * Something went wrong with the protocol filter.
+                * Force shutdown and restart if another blob requires filtering.
+                */
+               error("external filter '%s' failed", entry->subprocess.cmd);
+               subprocess_stop(&subprocess_map, &entry->subprocess);
+               free(entry);
        }
-
-done:
-       sigchain_pop(SIGPIPE);
-
-       return err;
 }
 
 static int apply_multi_file_filter(const char *path, const char *src, size_t len,
                                   int fd, struct strbuf *dst, const char *cmd,
-                                  const unsigned int wanted_capability)
+                                  const unsigned int wanted_capability,
+                                  struct delayed_checkout *dco)
 {
        int err;
+       int can_delay = 0;
        struct cmd2process *entry;
        struct child_process *process;
        struct strbuf nbuf = STRBUF_INIT;
@@ -583,8 +564,7 @@ static int apply_multi_file_filter(const char *path, const char *src, size_t len
 
        if (!subprocess_map_initialized) {
                subprocess_map_initialized = 1;
-               hashmap_init(&subprocess_map, (hashmap_cmp_fn) cmd2process_cmp,
-                            NULL, 0);
+               hashmap_init(&subprocess_map, cmd2process_cmp, NULL, 0);
                entry = NULL;
        } else {
                entry = (struct cmd2process *)subprocess_find_entry(&subprocess_map, cmd);
@@ -603,12 +583,12 @@ static int apply_multi_file_filter(const char *path, const char *src, size_t len
        }
        process = &entry->subprocess.process;
 
-       if (!(wanted_capability & entry->supported_capabilities))
+       if (!(entry->supported_capabilities & wanted_capability))
                return 0;
 
-       if (CAP_CLEAN & wanted_capability)
+       if (wanted_capability & CAP_CLEAN)
                filter_type = "clean";
-       else if (CAP_SMUDGE & wanted_capability)
+       else if (wanted_capability & CAP_SMUDGE)
                filter_type = "smudge";
        else
                die("unexpected filter type");
@@ -630,6 +610,14 @@ static int apply_multi_file_filter(const char *path, const char *src, size_t len
        if (err)
                goto done;
 
+       if ((entry->supported_capabilities & CAP_DELAY) &&
+           dco && dco->state == CE_CAN_DELAY) {
+               can_delay = 1;
+               err = packet_write_fmt_gently(process->in, "can-delay=1\n");
+               if (err)
+                       goto done;
+       }
+
        err = packet_flush_gently(process->in);
        if (err)
                goto done;
@@ -645,14 +633,73 @@ static int apply_multi_file_filter(const char *path, const char *src, size_t len
        if (err)
                goto done;
 
-       err = strcmp(filter_status.buf, "success");
+       if (can_delay && !strcmp(filter_status.buf, "delayed")) {
+               string_list_insert(&dco->filters, cmd);
+               string_list_insert(&dco->paths, path);
+       } else {
+               /* The filter got the blob and wants to send us a response. */
+               err = strcmp(filter_status.buf, "success");
+               if (err)
+                       goto done;
+
+               err = read_packetized_to_strbuf(process->out, &nbuf) < 0;
+               if (err)
+                       goto done;
+
+               err = subprocess_read_status(process->out, &filter_status);
+               if (err)
+                       goto done;
+
+               err = strcmp(filter_status.buf, "success");
+       }
+
+done:
+       sigchain_pop(SIGPIPE);
+
+       if (err)
+               handle_filter_error(&filter_status, entry, wanted_capability);
+       else
+               strbuf_swap(dst, &nbuf);
+       strbuf_release(&nbuf);
+       return !err;
+}
+
+
+int async_query_available_blobs(const char *cmd, struct string_list *available_paths)
+{
+       int err;
+       char *line;
+       struct cmd2process *entry;
+       struct child_process *process;
+       struct strbuf filter_status = STRBUF_INIT;
+
+       assert(subprocess_map_initialized);
+       entry = (struct cmd2process *)subprocess_find_entry(&subprocess_map, cmd);
+       if (!entry) {
+               error("external filter '%s' is not available anymore although "
+                     "not all paths have been filtered", cmd);
+               return 0;
+       }
+       process = &entry->subprocess.process;
+       sigchain_push(SIGPIPE, SIG_IGN);
+
+       err = packet_write_fmt_gently(
+               process->in, "command=list_available_blobs\n");
        if (err)
                goto done;
 
-       err = read_packetized_to_strbuf(process->out, &nbuf) < 0;
+       err = packet_flush_gently(process->in);
        if (err)
                goto done;
 
+       while ((line = packet_read_line(process->out, NULL))) {
+               const char *path;
+               if (skip_prefix(line, "pathname=", &path))
+                       string_list_insert(available_paths, xstrdup(path));
+               else
+                       ; /* ignore unknown keys */
+       }
+
        err = subprocess_read_status(process->out, &filter_status);
        if (err)
                goto done;
@@ -662,29 +709,8 @@ static int apply_multi_file_filter(const char *path, const char *src, size_t len
 done:
        sigchain_pop(SIGPIPE);
 
-       if (err) {
-               if (!strcmp(filter_status.buf, "error")) {
-                       /* The filter signaled a problem with the file. */
-               } else if (!strcmp(filter_status.buf, "abort")) {
-                       /*
-                        * The filter signaled a permanent problem. Don't try to filter
-                        * files with the same command for the lifetime of the current
-                        * Git process.
-                        */
-                        entry->supported_capabilities &= ~wanted_capability;
-               } else {
-                       /*
-                        * Something went wrong with the protocol filter.
-                        * Force shutdown and restart if another blob requires filtering.
-                        */
-                       error("external filter '%s' failed", cmd);
-                       subprocess_stop(&subprocess_map, &entry->subprocess);
-                       free(entry);
-               }
-       } else {
-               strbuf_swap(dst, &nbuf);
-       }
-       strbuf_release(&nbuf);
+       if (err)
+               handle_filter_error(&filter_status, entry, 0);
        return !err;
 }
 
@@ -699,7 +725,8 @@ static struct convert_driver {
 
 static int apply_filter(const char *path, const char *src, size_t len,
                        int fd, struct strbuf *dst, struct convert_driver *drv,
-                       const unsigned int wanted_capability)
+                       const unsigned int wanted_capability,
+                       struct delayed_checkout *dco)
 {
        const char *cmd = NULL;
 
@@ -709,15 +736,16 @@ static int apply_filter(const char *path, const char *src, size_t len,
        if (!dst)
                return 1;
 
-       if ((CAP_CLEAN & wanted_capability) && !drv->process && drv->clean)
+       if ((wanted_capability & CAP_CLEAN) && !drv->process && drv->clean)
                cmd = drv->clean;
-       else if ((CAP_SMUDGE & wanted_capability) && !drv->process && drv->smudge)
+       else if ((wanted_capability & CAP_SMUDGE) && !drv->process && drv->smudge)
                cmd = drv->smudge;
 
        if (cmd && *cmd)
                return apply_single_file_filter(path, src, len, fd, dst, cmd);
        else if (drv->process && *drv->process)
-               return apply_multi_file_filter(path, src, len, fd, dst, drv->process, wanted_capability);
+               return apply_multi_file_filter(path, src, len, fd, dst,
+                       drv->process, wanted_capability, dco);
 
        return 0;
 }
@@ -1058,7 +1086,7 @@ int would_convert_to_git_filter_fd(const char *path)
        if (!ca.drv->required)
                return 0;
 
-       return apply_filter(path, NULL, 0, -1, NULL, ca.drv, CAP_CLEAN);
+       return apply_filter(path, NULL, 0, -1, NULL, ca.drv, CAP_CLEAN, NULL);
 }
 
 const char *get_convert_attr_ascii(const char *path)
@@ -1096,7 +1124,7 @@ int convert_to_git(const struct index_state *istate,
 
        convert_attrs(&ca, path);
 
-       ret |= apply_filter(path, src, len, -1, dst, ca.drv, CAP_CLEAN);
+       ret |= apply_filter(path, src, len, -1, dst, ca.drv, CAP_CLEAN, NULL);
        if (!ret && ca.drv && ca.drv->required)
                die("%s: clean filter '%s' failed", path, ca.drv->name);
 
@@ -1122,7 +1150,7 @@ void convert_to_git_filter_fd(const struct index_state *istate,
        assert(ca.drv);
        assert(ca.drv->clean || ca.drv->process);
 
-       if (!apply_filter(path, NULL, 0, fd, dst, ca.drv, CAP_CLEAN))
+       if (!apply_filter(path, NULL, 0, fd, dst, ca.drv, CAP_CLEAN, NULL))
                die("%s: clean filter '%s' failed", path, ca.drv->name);
 
        crlf_to_git(istate, path, dst->buf, dst->len, dst, ca.crlf_action, checksafe);
@@ -1131,7 +1159,7 @@ void convert_to_git_filter_fd(const struct index_state *istate,
 
 static int convert_to_working_tree_internal(const char *path, const char *src,
                                            size_t len, struct strbuf *dst,
-                                           int normalizing)
+                                           int normalizing, struct delayed_checkout *dco)
 {
        int ret = 0, ret_filter = 0;
        struct conv_attrs ca;
@@ -1156,22 +1184,30 @@ static int convert_to_working_tree_internal(const char *path, const char *src,
                }
        }
 
-       ret_filter = apply_filter(path, src, len, -1, dst, ca.drv, CAP_SMUDGE);
+       ret_filter = apply_filter(
+               path, src, len, -1, dst, ca.drv, CAP_SMUDGE, dco);
        if (!ret_filter && ca.drv && ca.drv->required)
                die("%s: smudge filter %s failed", path, ca.drv->name);
 
        return ret | ret_filter;
 }
 
+int async_convert_to_working_tree(const char *path, const char *src,
+                                 size_t len, struct strbuf *dst,
+                                 void *dco)
+{
+       return convert_to_working_tree_internal(path, src, len, dst, 0, dco);
+}
+
 int convert_to_working_tree(const char *path, const char *src, size_t len, struct strbuf *dst)
 {
-       return convert_to_working_tree_internal(path, src, len, dst, 0);
+       return convert_to_working_tree_internal(path, src, len, dst, 0, NULL);
 }
 
 int renormalize_buffer(const struct index_state *istate, const char *path,
                       const char *src, size_t len, struct strbuf *dst)
 {
-       int ret = convert_to_working_tree_internal(path, src, len, dst, 1);
+       int ret = convert_to_working_tree_internal(path, src, len, dst, 1, NULL);
        if (ret) {
                src = dst->buf;
                len = dst->len;
index cecf59d1aa15f234473dc16520c0a6647e255280..6b06144281c797a08c10e0dc5bf72f97d260be88 100644 (file)
--- a/convert.h
+++ b/convert.h
@@ -4,6 +4,8 @@
 #ifndef CONVERT_H
 #define CONVERT_H
 
+#include "string-list.h"
+
 struct index_state;
 
 enum safe_crlf {
@@ -34,6 +36,26 @@ enum eol {
 #endif
 };
 
+enum ce_delay_state {
+       CE_NO_DELAY = 0,
+       CE_CAN_DELAY = 1,
+       CE_RETRY = 2
+};
+
+struct delayed_checkout {
+       /*
+        * State of the currently processed cache entry. If the state is
+        * CE_CAN_DELAY, then the filter can delay the current cache entry.
+        * If the state is CE_RETRY, then this signals the filter that the
+        * cache entry was requested before.
+        */
+       enum ce_delay_state state;
+       /* List of filter drivers that signaled delayed blobs. */
+       struct string_list filters;
+       /* List of delayed blobs identified by their path. */
+       struct string_list paths;
+};
+
 extern enum eol core_eol;
 extern const char *get_cached_convert_stats_ascii(const struct index_state *istate,
                                                  const char *path);
@@ -46,6 +68,10 @@ extern int convert_to_git(const struct index_state *istate,
                          struct strbuf *dst, enum safe_crlf checksafe);
 extern int convert_to_working_tree(const char *path, const char *src,
                                   size_t len, struct strbuf *dst);
+extern int async_convert_to_working_tree(const char *path, const char *src,
+                                        size_t len, struct strbuf *dst,
+                                        void *dco);
+extern int async_query_available_blobs(const char *cmd, struct string_list *available_paths);
 extern int renormalize_buffer(const struct index_state *istate,
                              const char *path, const char *src, size_t len,
                              struct strbuf *dst);
index 91550bfb0b3325ad92a3f3c65d5f779b61fa9951..1cccc3a0b9cfb2a14e9c87d5afc29234fa62adc4 100644 (file)
@@ -25,7 +25,7 @@ static int send_request(const char *socket, const struct strbuf *out)
                int r;
 
                r = read_in_full(fd, in, sizeof(in));
-               if (r == 0)
+               if (r == 0 || (r < 0 && errno == ECONNRESET))
                        break;
                if (r < 0)
                        die_errno("read error from cache daemon");
diff --git a/diff.c b/diff.c
index 85e714f6c68d24e11228b69d2511c49811c979b4..9c382580306e340ed6333f96bc4919c4c507a7b9 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -299,9 +299,6 @@ int git_diff_ui_config(const char *var, const char *value, void *cb)
                return 0;
        }
 
-       if (git_color_config(var, value, cb) < 0)
-               return -1;
-
        return git_diff_basic_config(var, value, cb);
 }
 
diff --git a/dir.c b/dir.c
index ae6f5c9636abd34d026579b7ddc8452825af9b30..1c55dc3e366f8c9e8bcbc62305d7085533059512 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -2398,7 +2398,8 @@ struct ondisk_untracked_cache {
        char exclude_per_dir[FLEX_ARRAY];
 };
 
-#define ouc_size(len) (offsetof(struct ondisk_untracked_cache, exclude_per_dir) + len + 1)
+#define ouc_offset(x) offsetof(struct ondisk_untracked_cache, x)
+#define ouc_size(len) (ouc_offset(exclude_per_dir) + len + 1)
 
 struct write_data {
        int index;         /* number of written untracked_cache_dir */
@@ -2560,17 +2561,18 @@ struct read_data {
        const unsigned char *end;
 };
 
-static void stat_data_from_disk(struct stat_data *to, const struct stat_data *from)
+static void stat_data_from_disk(struct stat_data *to, const unsigned char *data)
 {
-       to->sd_ctime.sec  = get_be32(&from->sd_ctime.sec);
-       to->sd_ctime.nsec = get_be32(&from->sd_ctime.nsec);
-       to->sd_mtime.sec  = get_be32(&from->sd_mtime.sec);
-       to->sd_mtime.nsec = get_be32(&from->sd_mtime.nsec);
-       to->sd_dev        = get_be32(&from->sd_dev);
-       to->sd_ino        = get_be32(&from->sd_ino);
-       to->sd_uid        = get_be32(&from->sd_uid);
-       to->sd_gid        = get_be32(&from->sd_gid);
-       to->sd_size       = get_be32(&from->sd_size);
+       memcpy(to, data, sizeof(*to));
+       to->sd_ctime.sec  = ntohl(to->sd_ctime.sec);
+       to->sd_ctime.nsec = ntohl(to->sd_ctime.nsec);
+       to->sd_mtime.sec  = ntohl(to->sd_mtime.sec);
+       to->sd_mtime.nsec = ntohl(to->sd_mtime.nsec);
+       to->sd_dev        = ntohl(to->sd_dev);
+       to->sd_ino        = ntohl(to->sd_ino);
+       to->sd_uid        = ntohl(to->sd_uid);
+       to->sd_gid        = ntohl(to->sd_gid);
+       to->sd_size       = ntohl(to->sd_size);
 }
 
 static int read_one_dir(struct untracked_cache_dir **untracked_,
@@ -2645,7 +2647,7 @@ static void read_stat(size_t pos, void *cb)
                rd->data = rd->end + 1;
                return;
        }
-       stat_data_from_disk(&ud->stat_data, (struct stat_data *)rd->data);
+       stat_data_from_disk(&ud->stat_data, rd->data);
        rd->data += sizeof(struct stat_data);
        ud->valid = 1;
 }
@@ -2663,22 +2665,22 @@ static void read_sha1(size_t pos, void *cb)
 }
 
 static void load_sha1_stat(struct sha1_stat *sha1_stat,
-                          const struct stat_data *stat,
+                          const unsigned char *data,
                           const unsigned char *sha1)
 {
-       stat_data_from_disk(&sha1_stat->stat, stat);
+       stat_data_from_disk(&sha1_stat->stat, data);
        hashcpy(sha1_stat->sha1, sha1);
        sha1_stat->valid = 1;
 }
 
 struct untracked_cache *read_untracked_extension(const void *data, unsigned long sz)
 {
-       const struct ondisk_untracked_cache *ouc;
        struct untracked_cache *uc;
        struct read_data rd;
        const unsigned char *next = data, *end = (const unsigned char *)data + sz;
        const char *ident;
        int ident_len, len;
+       const char *exclude_per_dir;
 
        if (sz <= 1 || end[-1] != '\0')
                return NULL;
@@ -2690,21 +2692,23 @@ struct untracked_cache *read_untracked_extension(const void *data, unsigned long
        ident = (const char *)next;
        next += ident_len;
 
-       ouc = (const struct ondisk_untracked_cache *)next;
        if (next + ouc_size(0) > end)
                return NULL;
 
        uc = xcalloc(1, sizeof(*uc));
        strbuf_init(&uc->ident, ident_len);
        strbuf_add(&uc->ident, ident, ident_len);
-       load_sha1_stat(&uc->ss_info_exclude, &ouc->info_exclude_stat,
-                      ouc->info_exclude_sha1);
-       load_sha1_stat(&uc->ss_excludes_file, &ouc->excludes_file_stat,
-                      ouc->excludes_file_sha1);
-       uc->dir_flags = get_be32(&ouc->dir_flags);
-       uc->exclude_per_dir = xstrdup(ouc->exclude_per_dir);
+       load_sha1_stat(&uc->ss_info_exclude,
+                      next + ouc_offset(info_exclude_stat),
+                      next + ouc_offset(info_exclude_sha1));
+       load_sha1_stat(&uc->ss_excludes_file,
+                      next + ouc_offset(excludes_file_stat),
+                      next + ouc_offset(excludes_file_sha1));
+       uc->dir_flags = get_be32(next + ouc_offset(dir_flags));
+       exclude_per_dir = (const char *)next + ouc_offset(exclude_per_dir);
+       uc->exclude_per_dir = xstrdup(exclude_per_dir);
        /* NUL after exclude_per_dir is covered by sizeof(*ouc) */
-       next += ouc_size(strlen(ouc->exclude_per_dir));
+       next += ouc_size(strlen(exclude_per_dir));
        if (next >= end)
                goto done2;
 
diff --git a/entry.c b/entry.c
index d6b263f78e0d2dfef997d94905412b0543a8b8c7..65458f07a4453fa29731fe2b9c20848d6b192b20 100644 (file)
--- a/entry.c
+++ b/entry.c
@@ -137,6 +137,105 @@ static int streaming_write_entry(const struct cache_entry *ce, char *path,
        return result;
 }
 
+void enable_delayed_checkout(struct checkout *state)
+{
+       if (!state->delayed_checkout) {
+               state->delayed_checkout = xmalloc(sizeof(*state->delayed_checkout));
+               state->delayed_checkout->state = CE_CAN_DELAY;
+               string_list_init(&state->delayed_checkout->filters, 0);
+               string_list_init(&state->delayed_checkout->paths, 0);
+       }
+}
+
+static int remove_available_paths(struct string_list_item *item, void *cb_data)
+{
+       struct string_list *available_paths = cb_data;
+       struct string_list_item *available;
+
+       available = string_list_lookup(available_paths, item->string);
+       if (available)
+               available->util = (void *)item->string;
+       return !available;
+}
+
+int finish_delayed_checkout(struct checkout *state)
+{
+       int errs = 0;
+       struct string_list_item *filter, *path;
+       struct delayed_checkout *dco = state->delayed_checkout;
+
+       if (!state->delayed_checkout)
+               return errs;
+
+       dco->state = CE_RETRY;
+       while (dco->filters.nr > 0) {
+               for_each_string_list_item(filter, &dco->filters) {
+                       struct string_list available_paths = STRING_LIST_INIT_NODUP;
+
+                       if (!async_query_available_blobs(filter->string, &available_paths)) {
+                               /* Filter reported an error */
+                               errs = 1;
+                               filter->string = "";
+                               continue;
+                       }
+                       if (available_paths.nr <= 0) {
+                               /*
+                                * Filter responded with no entries. That means
+                                * the filter is done and we can remove the
+                                * filter from the list (see
+                                * "string_list_remove_empty_items" call below).
+                                */
+                               filter->string = "";
+                               continue;
+                       }
+
+                       /*
+                        * In dco->paths we store a list of all delayed paths.
+                        * The filter just send us a list of available paths.
+                        * Remove them from the list.
+                        */
+                       filter_string_list(&dco->paths, 0,
+                               &remove_available_paths, &available_paths);
+
+                       for_each_string_list_item(path, &available_paths) {
+                               struct cache_entry* ce;
+
+                               if (!path->util) {
+                                       error("external filter '%s' signaled that '%s' "
+                                             "is now available although it has not been "
+                                             "delayed earlier",
+                                             filter->string, path->string);
+                                       errs |= 1;
+
+                                       /*
+                                        * Do not ask the filter for available blobs,
+                                        * again, as the filter is likely buggy.
+                                        */
+                                       filter->string = "";
+                                       continue;
+                               }
+                               ce = index_file_exists(state->istate, path->string,
+                                                      strlen(path->string), 0);
+                               errs |= (ce ? checkout_entry(ce, state, NULL) : 1);
+                       }
+               }
+               string_list_remove_empty_items(&dco->filters, 0);
+       }
+       string_list_clear(&dco->filters, 0);
+
+       /* At this point we should not have any delayed paths anymore. */
+       errs |= dco->paths.nr;
+       for_each_string_list_item(path, &dco->paths) {
+               error("'%s' was not filtered properly", path->string);
+       }
+       string_list_clear(&dco->paths, 0);
+
+       free(dco);
+       state->delayed_checkout = NULL;
+
+       return errs;
+}
+
 static int write_entry(struct cache_entry *ce,
                       char *path, const struct checkout *state, int to_tempfile)
 {
@@ -179,11 +278,34 @@ static int write_entry(struct cache_entry *ce,
                /*
                 * Convert from git internal format to working tree format
                 */
-               if (ce_mode_s_ifmt == S_IFREG &&
-                   convert_to_working_tree(ce->name, new, size, &buf)) {
-                       free(new);
-                       new = strbuf_detach(&buf, &newsize);
-                       size = newsize;
+               if (ce_mode_s_ifmt == S_IFREG) {
+                       struct delayed_checkout *dco = state->delayed_checkout;
+                       if (dco && dco->state != CE_NO_DELAY) {
+                               /* Do not send the blob in case of a retry. */
+                               if (dco->state == CE_RETRY) {
+                                       new = NULL;
+                                       size = 0;
+                               }
+                               ret = async_convert_to_working_tree(
+                                       ce->name, new, size, &buf, dco);
+                               if (ret && string_list_has_string(&dco->paths, ce->name)) {
+                                       free(new);
+                                       goto finish;
+                               }
+                       } else
+                               ret = convert_to_working_tree(
+                                       ce->name, new, size, &buf);
+
+                       if (ret) {
+                               free(new);
+                               new = strbuf_detach(&buf, &newsize);
+                               size = newsize;
+                       }
+                       /*
+                        * No "else" here as errors from convert are OK at this
+                        * point. If the error would have been fatal (e.g.
+                        * filter is required), then we would have died already.
+                        */
                }
 
                fd = open_output_fd(path, ce, to_tempfile);
diff --git a/fsck.c b/fsck.c
index b4204d772b39335c5feb5c85a11c517bcedcd562..2d2d2e9432b96e5ff2ad893bd8661c0157d42eee 100644 (file)
--- a/fsck.c
+++ b/fsck.c
@@ -736,7 +736,7 @@ static int fsck_commit_buffer(struct commit *commit, const char *buffer,
                buffer += 41;
                parent_line_count++;
        }
-       graft = lookup_commit_graft(commit->object.oid.hash);
+       graft = lookup_commit_graft(&commit->object.oid);
        parent_count = commit_list_count(commit->parents);
        if (graft) {
                if (graft->nr_parent == -1 && !parent_count)
index db9c22de7693af4e905fdeb0a1766ba4469eda94..7d2c0ca75922ea1ca8c67ec798ff8ce1249c925f 100644 (file)
@@ -828,6 +828,14 @@ static inline void copy_array(void *dst, const void *src, size_t n, size_t size)
                memcpy(dst, src, st_mult(size, n));
 }
 
+#define MOVE_ARRAY(dst, src, n) move_array((dst), (src), (n), sizeof(*(dst)) + \
+       BUILD_ASSERT_OR_ZERO(sizeof(*(dst)) == sizeof(*(src))))
+static inline void move_array(void *dst, const void *src, size_t n, size_t size)
+{
+       if (n)
+               memmove(dst, src, st_mult(size, n));
+}
+
 /*
  * These functions help you allocate structs with flex arrays, and copy
  * the data directly into the array. For example, if you had:
index fe30be38dc8c534cabf8a0f7145c41aecd1e6989..918a8de369113bb022f5080ac9c516771f544577 100644 (file)
@@ -161,7 +161,9 @@ ifeq ($(uname_S),Darwin)
        endif
 endif
 ifneq (,$(findstring MINGW,$(uname_S)))
+ifeq ($(shell expr "$(uname_R)" : '1\.'),2)
        NO_MSGFMT=1
+endif
        GITGUI_WINDOWS_WRAPPER := YesPlease
        GITGUI_RELATIVE := 1
 endif
index 75d1da8d31c31db298aea078db863735b6d45439..80f5a59bbbfcf1623913fd1196370a4de75729d6 100644 (file)
@@ -142,6 +142,10 @@ constructor pick {} {
                                -label [mc "Recent Repositories"]
                }
 
+       if {[set lenrecent [llength $sorted_recent]] < $maxrecent} {
+               set lenrecent $maxrecent
+       }
+
                ${NS}::label $w_body.space
                ${NS}::label $w_body.recentlabel \
                        -anchor w \
@@ -153,7 +157,7 @@ constructor pick {} {
                        -background [get_bg_color $w_body.recentlabel] \
                        -wrap none \
                        -width 50 \
-                       -height $maxrecent
+                       -height $lenrecent
                $w_recentlist tag conf link \
                        -foreground blue \
                        -underline 1
@@ -235,19 +239,19 @@ method _invoke_next {} {
 
 proc _get_recentrepos {} {
        set recent [list]
-       foreach p [get_config gui.recentrepo] {
+       foreach p [lsort -unique [get_config gui.recentrepo]] {
                if {[_is_git [file join $p .git]]} {
                        lappend recent $p
                } else {
                        _unset_recentrepo $p
                }
        }
-       return [lsort $recent]
+       return $recent
 }
 
 proc _unset_recentrepo {p} {
        regsub -all -- {([()\[\]{}\.^$+*?\\])} $p {\\\1} p
-       git config --global --unset gui.recentrepo "^$p\$"
+       catch {git config --global --unset-all gui.recentrepo "^$p\$"}
        load_config 1
 }
 
@@ -262,12 +266,11 @@ proc _append_recentrepos {path} {
        set i [lsearch $recent $path]
        if {$i >= 0} {
                _unset_recentrepo $path
-               set recent [lreplace $recent $i $i]
        }
 
-       lappend recent $path
        git config --global --add gui.recentrepo $path
        load_config 1
+       set recent [get_config gui.recentrepo]
 
        if {[set maxrecent [get_config gui.maxrecentrepo]] eq {}} {
                set maxrecent 10
@@ -275,7 +278,7 @@ proc _append_recentrepos {path} {
 
        while {[llength $recent] > $maxrecent} {
                _unset_recentrepo [lindex $recent 0]
-               set recent [lrange $recent 1 end]
+               set recent [get_config gui.recentrepo]
        }
 }
 
index 2cf73b88e8e83ca34b9eb319dbc2b0a220139b0f..f8b3d1fd9752a37c5424e06ba36da4648d0aba1b 100755 (executable)
@@ -55,9 +55,10 @@ LF='
 '
 ok_to_skip_pre_rebase=
 resolvemsg="
-$(gettext 'When you have resolved this problem, run "git rebase --continue".
-If you prefer to skip this patch, run "git rebase --skip" instead.
-To check out the original branch and stop rebasing, run "git rebase --abort".')
+$(gettext 'Resolve all conflicts manually, mark them as resolved with
+"git add/rm <conflicted_files>", then run "git rebase --continue".
+You can instead skip this commit: run "git rebase --skip".
+To abort and get back to the state before "git rebase", run "git rebase --abort".')
 "
 unset onto
 unset restrict_revision
index 3d4a8ee27c96a8e1eb94f95771aeca7825f8a076..9208f42ed1753530b8ea46761f8ecc61bbe95976 100755 (executable)
@@ -3071,6 +3071,8 @@ sub git_get_projects_list {
                                return if (m!^[/.]$!);
                                # only directories can be git repositories
                                return unless (-d $_);
+                               # need search permission
+                               return unless (-x $_);
                                # don't traverse too deep (Find is super slow on os x)
                                # $project_maxdepth excludes depth of $projectroot
                                if (($File::Find::name =~ tr!/!!) - $pfxdepth > $project_maxdepth) {
diff --git a/http.c b/http.c
index c6c010f8816f4a01c4b7658a9044b179515590ea..76ff63c14d44057f78b532fb9d873c94ae56231e 100644 (file)
--- a/http.c
+++ b/http.c
@@ -272,10 +272,10 @@ static int http_options(const char *var, const char *value, void *cb)
        if (!strcmp("http.sslversion", var))
                return git_config_string(&ssl_version, var, value);
        if (!strcmp("http.sslcert", var))
-               return git_config_string(&ssl_cert, var, value);
+               return git_config_pathname(&ssl_cert, var, value);
 #if LIBCURL_VERSION_NUM >= 0x070903
        if (!strcmp("http.sslkey", var))
-               return git_config_string(&ssl_key, var, value);
+               return git_config_pathname(&ssl_key, var, value);
 #endif
 #if LIBCURL_VERSION_NUM >= 0x070908
        if (!strcmp("http.sslcapath", var))
index c1a79c100c9a71083a58401081fb2929420ce361..cb921b4db676e3db918ee16f419cd2b78e0bf57e 100644 (file)
--- a/mailmap.c
+++ b/mailmap.c
@@ -214,17 +214,17 @@ static int read_mailmap_blob(struct string_list *map,
                             const char *name,
                             char **repo_abbrev)
 {
-       unsigned char sha1[20];
+       struct object_id oid;
        char *buf;
        unsigned long size;
        enum object_type type;
 
        if (!name)
                return 0;
-       if (get_sha1(name, sha1) < 0)
+       if (get_oid(name, &oid) < 0)
                return 0;
 
-       buf = read_sha1_file(sha1, &type, &size);
+       buf = read_sha1_file(oid.hash, &type, &size);
        if (!buf)
                return error("unable to read mailmap object at %s", name);
        if (type != OBJ_BLOB)
index 0e10f3eab804cdc08d3a2f97021e8b18edcb552a..bd8dc7a6a7498d42f2576eb866e97dd55797194d 100644 (file)
@@ -17,10 +17,14 @@ struct dir_entry {
 };
 
 static int dir_entry_cmp(const void *unused_cmp_data,
-                        const struct dir_entry *e1,
-                        const struct dir_entry *e2,
-                        const char *name)
+                        const void *entry,
+                        const void *entry_or_key,
+                        const void *keydata)
 {
+       const struct dir_entry *e1 = entry;
+       const struct dir_entry *e2 = entry_or_key;
+       const char *name = keydata;
+
        return e1->namelen != e2->namelen || strncasecmp(e1->name,
                        name ? name : e2->name, e1->namelen);
 }
@@ -110,10 +114,12 @@ static void hash_index_entry(struct index_state *istate, struct cache_entry *ce)
 }
 
 static int cache_entry_cmp(const void *unused_cmp_data,
-                          const struct cache_entry *ce1,
-                          const struct cache_entry *ce2,
+                          const void *entry,
+                          const void *entry_or_key,
                           const void *remove)
 {
+       const struct cache_entry *ce1 = entry;
+       const struct cache_entry *ce2 = entry_or_key;
        /*
         * For remove_name_hash, find the exact entry (pointer equality); for
         * index_file_exists, find all entries with matching hash code and
@@ -574,10 +580,8 @@ static void lazy_init_name_hash(struct index_state *istate)
 {
        if (istate->name_hash_initialized)
                return;
-       hashmap_init(&istate->name_hash, (hashmap_cmp_fn) cache_entry_cmp,
-                       NULL, istate->cache_nr);
-       hashmap_init(&istate->dir_hash, (hashmap_cmp_fn) dir_entry_cmp,
-                       NULL, istate->cache_nr);
+       hashmap_init(&istate->name_hash, cache_entry_cmp, NULL, istate->cache_nr);
+       hashmap_init(&istate->dir_hash, dir_entry_cmp, NULL, istate->cache_nr);
 
        if (lookup_lazy_params(istate)) {
                hashmap_disallow_rehash(&istate->dir_hash, 1);
index 70e3fbeefbe24233a545e75c0322a8a310778e43..c12b354f1003a29c6faf58e7ec970e4ac761812e 100644 (file)
@@ -99,8 +99,7 @@ static struct notes_merge_pair *find_notes_merge_pair_pos(
        else {
                *occupied = 0;
                if (insert_new && i < len) {
-                       memmove(list + i + 1, list + i,
-                               (len - i) * sizeof(struct notes_merge_pair));
+                       MOVE_ARRAY(list + i + 1, list + i, len - i);
                        memset(list + i, 0, sizeof(struct notes_merge_pair));
                }
        }
diff --git a/notes.c b/notes.c
index 8f47c202c58752b6d9d56852ae9c315e2f144769..503754d79ebdca94fb102ccff7886ccef30f31e5 100644 (file)
--- a/notes.c
+++ b/notes.c
@@ -1026,7 +1026,7 @@ void init_notes(struct notes_tree *t, const char *notes_ref,
        t->dirty = 0;
 
        if (flags & NOTES_INIT_EMPTY || !notes_ref ||
-           get_sha1_treeish(notes_ref, object_oid.hash))
+           get_oid_treeish(notes_ref, &object_oid))
                return;
        if (flags & NOTES_INIT_WRITABLE && read_ref(notes_ref, object_oid.hash))
                die("Cannot use notes ref %s", notes_ref);
index f818777412187890b88a6c90507b8b41f131487c..321d7e9201b2ba6c8b39592a591786409a87edb1 100644 (file)
--- a/object.c
+++ b/object.c
@@ -141,7 +141,6 @@ void *create_object(const unsigned char *sha1, void *o)
        struct object *obj = o;
 
        obj->parsed = 0;
-       obj->used = 0;
        obj->flags = 0;
        hashcpy(obj->oid.hash, sha1);
 
index 33e5cc9943eeff8618493fbd750aecde0b836710..0a419ba8da52453ebbd202f50d5c2aa1c9aea2f0 100644 (file)
--- a/object.h
+++ b/object.h
@@ -38,6 +38,7 @@ struct object_array {
  * http-push.c:                            16-----19
  * commit.c:                               16-----19
  * sha1_name.c:                                     20
+ * builtin/fsck.c:  0--3
  */
 #define FLAG_BITS  27
 
@@ -46,7 +47,6 @@ struct object_array {
  */
 struct object {
        unsigned parsed : 1;
-       unsigned used : 1;
        unsigned type : TYPE_BITS;
        unsigned flags : FLAG_BITS;
        struct object_id oid;
index b4166b0f384691ada862ff0b1e37387b018587b1..7a583b3011390c1a3cb1c0885e420e76b7751d26 100644 (file)
@@ -35,11 +35,16 @@ int commit_patch_id(struct commit *commit, struct diff_options *options,
  * the side of safety.  The actual value being negative does not have
  * any significance; only that it is non-zero matters.
  */
-static int patch_id_cmp(struct diff_options *opt,
-                       struct patch_id *a,
-                       struct patch_id *b,
+static int patch_id_cmp(const void *cmpfn_data,
+                       const void *entry,
+                       const void *entry_or_key,
                        const void *unused_keydata)
 {
+       /* NEEDSWORK: const correctness? */
+       struct diff_options *opt = (void *)cmpfn_data;
+       struct patch_id *a = (void *)entry;
+       struct patch_id *b = (void *)entry_or_key;
+
        if (is_null_oid(&a->patch_id) &&
            commit_patch_id(a->commit, opt, &a->patch_id, 0))
                return error("Could not get patch ID for %s",
@@ -58,8 +63,7 @@ int init_patch_ids(struct patch_ids *ids)
        ids->diffopts.detect_rename = 0;
        DIFF_OPT_SET(&ids->diffopts, RECURSIVE);
        diff_setup_done(&ids->diffopts);
-       hashmap_init(&ids->patches, (hashmap_cmp_fn)patch_id_cmp,
-                    &ids->diffopts, 256);
+       hashmap_init(&ids->patches, patch_id_cmp, &ids->diffopts, 256);
        return 0;
 }
 
diff --git a/path.c b/path.c
index e485f9f93181778de3acfe3cd4b6811ec82c7940..e50d2befcf826680c70ac59295c06004dd6221cf 100644 (file)
--- a/path.c
+++ b/path.c
@@ -1321,6 +1321,11 @@ int is_ntfs_dotgit(const char *name)
                }
 }
 
+int looks_like_command_line_option(const char *str)
+{
+       return str && str[0] == '-';
+}
+
 char *xdg_config_home(const char *filename)
 {
        const char *home, *config_home;
index 9d845ecc3ccc65194852a1821432cec771ac49dc..7db9119573abe2c8308bd37c670c027c07b425c8 100644 (file)
@@ -171,25 +171,6 @@ int packet_write_fmt_gently(int fd, const char *fmt, ...)
        return status;
 }
 
-int packet_writel(int fd, const char *line, ...)
-{
-       va_list args;
-       int err;
-       va_start(args, line);
-       for (;;) {
-               if (!line)
-                       break;
-               if (strlen(line) > LARGE_PACKET_DATA_MAX)
-                       return -1;
-               err = packet_write_fmt_gently(fd, "%s\n", line);
-               if (err)
-                       return err;
-               line = va_arg(args, const char*);
-       }
-       va_end(args);
-       return packet_flush_gently(fd);
-}
-
 static int packet_write_gently(const int fd_out, const char *buf, size_t size)
 {
        static char packet_write_buffer[LARGE_PACKET_MAX];
index 450183b6496fce4ec3077322f61623152c87cf07..66ef610fc4f7de2f6b7572f1e5fb36438c5dec19 100644 (file)
@@ -25,8 +25,6 @@ void packet_buf_flush(struct strbuf *buf);
 void packet_buf_write(struct strbuf *buf, const char *fmt, ...) __attribute__((format (printf, 2, 3)));
 int packet_flush_gently(int fd);
 int packet_write_fmt_gently(int fd, const char *fmt, ...) __attribute__((format (printf, 2, 3)));
-LAST_ARG_MUST_BE_NULL
-int packet_writel(int fd, const char *line, ...);
 int write_packetized_from_fd(int fd_in, int fd_out);
 int write_packetized_from_buf(const char *src_in, size_t len, int fd_out);
 
index e4b561c5822b7b19878065c77a04ffa0c9e43d61..39cad5112b603df9c8ed927e738b2f7917da7522 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -947,6 +947,7 @@ static size_t parse_color(struct strbuf *sb, /* in UTF-8 */
                          struct format_commit_context *c)
 {
        const char *rest = placeholder;
+       const char *basic_color = NULL;
 
        if (placeholder[1] == '(') {
                const char *begin = placeholder + 2;
@@ -955,23 +956,41 @@ static size_t parse_color(struct strbuf *sb, /* in UTF-8 */
 
                if (!end)
                        return 0;
+
                if (skip_prefix(begin, "auto,", &begin)) {
                        if (!want_color(c->pretty_ctx->color))
                                return end - placeholder + 1;
+               } else if (skip_prefix(begin, "always,", &begin)) {
+                       /* nothing to do; we do not respect want_color at all */
+               } else {
+                       /* the default is the same as "auto" */
+                       if (!want_color(c->pretty_ctx->color))
+                               return end - placeholder + 1;
                }
+
                if (color_parse_mem(begin, end - begin, color) < 0)
                        die(_("unable to parse --pretty format"));
                strbuf_addstr(sb, color);
                return end - placeholder + 1;
        }
+
+       /*
+        * We handle things like "%C(red)" above; for historical reasons, there
+        * are a few colors that can be specified without parentheses (and
+        * they cannot support things like "auto" or "always" at all).
+        */
        if (skip_prefix(placeholder + 1, "red", &rest))
-               strbuf_addstr(sb, GIT_COLOR_RED);
+               basic_color = GIT_COLOR_RED;
        else if (skip_prefix(placeholder + 1, "green", &rest))
-               strbuf_addstr(sb, GIT_COLOR_GREEN);
+               basic_color = GIT_COLOR_GREEN;
        else if (skip_prefix(placeholder + 1, "blue", &rest))
-               strbuf_addstr(sb, GIT_COLOR_BLUE);
+               basic_color = GIT_COLOR_BLUE;
        else if (skip_prefix(placeholder + 1, "reset", &rest))
-               strbuf_addstr(sb, GIT_COLOR_RESET);
+               basic_color = GIT_COLOR_RESET;
+
+       if (basic_color && want_color(c->pretty_ctx->color))
+               strbuf_addstr(sb, basic_color);
+
        return rest - placeholder;
 }
 
index 2121b6e7bba5f310825e0b1f2eccd524cc8658ce..acfb028f480b5545aa82d5c0533fe8bdfc581dfd 100644 (file)
@@ -515,9 +515,8 @@ int remove_index_entry_at(struct index_state *istate, int pos)
        istate->cache_nr--;
        if (pos >= istate->cache_nr)
                return 0;
-       memmove(istate->cache + pos,
-               istate->cache + pos + 1,
-               (istate->cache_nr - pos) * sizeof(struct cache_entry *));
+       MOVE_ARRAY(istate->cache + pos, istate->cache + pos + 1,
+                  istate->cache_nr - pos);
        return 1;
 }
 
index ae6ecbd1cfe42936b22488d7761e4e487e2922ca..bc591f4f3de0c07b0cfe3813d5d9daaf1ad44b63 100644 (file)
@@ -97,14 +97,19 @@ static struct used_atom {
        } u;
 } *used_atom;
 static int used_atom_cnt, need_tagged, need_symref;
-static int need_color_reset_at_eol;
 
-static void color_atom_parser(struct used_atom *atom, const char *color_value)
+static void color_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *color_value)
 {
        if (!color_value)
                die(_("expected format: %%(color:<color>)"));
        if (color_parse(color_value, atom->u.color) < 0)
                die(_("unrecognized color: %%(color:%s)"), color_value);
+       /*
+        * We check this after we've parsed the color, which lets us complain
+        * about syntactically bogus color names even if they won't be used.
+        */
+       if (!want_color(format->use_color))
+               color_parse("", atom->u.color);
 }
 
 static void refname_atom_parser_internal(struct refname_atom *atom,
@@ -127,7 +132,7 @@ static void refname_atom_parser_internal(struct refname_atom *atom,
                die(_("unrecognized %%(%s) argument: %s"), name, arg);
 }
 
-static void remote_ref_atom_parser(struct used_atom *atom, const char *arg)
+static void remote_ref_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
 {
        struct string_list params = STRING_LIST_INIT_DUP;
        int i;
@@ -161,28 +166,28 @@ static void remote_ref_atom_parser(struct used_atom *atom, const char *arg)
        string_list_clear(&params, 0);
 }
 
-static void body_atom_parser(struct used_atom *atom, const char *arg)
+static void body_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
 {
        if (arg)
                die(_("%%(body) does not take arguments"));
        atom->u.contents.option = C_BODY_DEP;
 }
 
-static void subject_atom_parser(struct used_atom *atom, const char *arg)
+static void subject_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
 {
        if (arg)
                die(_("%%(subject) does not take arguments"));
        atom->u.contents.option = C_SUB;
 }
 
-static void trailers_atom_parser(struct used_atom *atom, const char *arg)
+static void trailers_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
 {
        if (arg)
                die(_("%%(trailers) does not take arguments"));
        atom->u.contents.option = C_TRAILERS;
 }
 
-static void contents_atom_parser(struct used_atom *atom, const char *arg)
+static void contents_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
 {
        if (!arg)
                atom->u.contents.option = C_BARE;
@@ -202,7 +207,7 @@ static void contents_atom_parser(struct used_atom *atom, const char *arg)
                die(_("unrecognized %%(contents) argument: %s"), arg);
 }
 
-static void objectname_atom_parser(struct used_atom *atom, const char *arg)
+static void objectname_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
 {
        if (!arg)
                atom->u.objectname.option = O_FULL;
@@ -219,7 +224,7 @@ static void objectname_atom_parser(struct used_atom *atom, const char *arg)
                die(_("unrecognized %%(objectname) argument: %s"), arg);
 }
 
-static void refname_atom_parser(struct used_atom *atom, const char *arg)
+static void refname_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
 {
        refname_atom_parser_internal(&atom->u.refname, arg, atom->name);
 }
@@ -235,7 +240,7 @@ static align_type parse_align_position(const char *s)
        return -1;
 }
 
-static void align_atom_parser(struct used_atom *atom, const char *arg)
+static void align_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
 {
        struct align *align = &atom->u.align;
        struct string_list params = STRING_LIST_INIT_DUP;
@@ -274,7 +279,7 @@ static void align_atom_parser(struct used_atom *atom, const char *arg)
        string_list_clear(&params, 0);
 }
 
-static void if_atom_parser(struct used_atom *atom, const char *arg)
+static void if_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
 {
        if (!arg) {
                atom->u.if_then_else.cmp_status = COMPARE_NONE;
@@ -288,7 +293,7 @@ static void if_atom_parser(struct used_atom *atom, const char *arg)
        }
 }
 
-static void head_atom_parser(struct used_atom *atom, const char *arg)
+static void head_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg)
 {
        struct object_id unused;
 
@@ -298,7 +303,7 @@ static void head_atom_parser(struct used_atom *atom, const char *arg)
 static struct {
        const char *name;
        cmp_type cmp_type;
-       void (*parser)(struct used_atom *atom, const char *arg);
+       void (*parser)(const struct ref_format *format, struct used_atom *atom, const char *arg);
 } valid_atom[] = {
        { "refname" , FIELD_STR, refname_atom_parser },
        { "objecttype" },
@@ -365,7 +370,8 @@ struct atom_value {
 /*
  * Used to parse format string and sort specifiers
  */
-int parse_ref_filter_atom(const char *atom, const char *ep)
+static int parse_ref_filter_atom(const struct ref_format *format,
+                                const char *atom, const char *ep)
 {
        const char *sp;
        const char *arg;
@@ -413,7 +419,7 @@ int parse_ref_filter_atom(const char *atom, const char *ep)
                arg = used_atom[at].name + (arg - atom) + 1;
        memset(&used_atom[at].u, 0, sizeof(used_atom[at].u));
        if (valid_atom[i].parser)
-               valid_atom[i].parser(&used_atom[at], arg);
+               valid_atom[i].parser(format, &used_atom[at], arg);
        if (*atom == '*')
                need_tagged = 1;
        if (!strcmp(valid_atom[i].name, "symref"))
@@ -657,24 +663,26 @@ static const char *find_next(const char *cp)
  * Make sure the format string is well formed, and parse out
  * the used atoms.
  */
-int verify_ref_format(const char *format)
+int verify_ref_format(struct ref_format *format)
 {
        const char *cp, *sp;
 
-       need_color_reset_at_eol = 0;
-       for (cp = format; *cp && (sp = find_next(cp)); ) {
+       format->need_color_reset_at_eol = 0;
+       for (cp = format->format; *cp && (sp = find_next(cp)); ) {
                const char *color, *ep = strchr(sp, ')');
                int at;
 
                if (!ep)
                        return error(_("malformed format string %s"), sp);
                /* sp points at "%(" and ep points at the closing ")" */
-               at = parse_ref_filter_atom(sp + 2, ep);
+               at = parse_ref_filter_atom(format, sp + 2, ep);
                cp = ep + 1;
 
                if (skip_prefix(used_atom[at].name, "color:", &color))
-                       need_color_reset_at_eol = !!strcmp(color, "reset");
+                       format->need_color_reset_at_eol = !!strcmp(color, "reset");
        }
+       if (format->need_color_reset_at_eol && !want_color(format->use_color))
+               format->need_color_reset_at_eol = 0;
        return 0;
 }
 
@@ -2060,35 +2068,34 @@ static void append_literal(const char *cp, const char *ep, struct ref_formatting
        }
 }
 
-void format_ref_array_item(struct ref_array_item *info, const char *format,
-                          int quote_style, struct strbuf *final_buf)
+void format_ref_array_item(struct ref_array_item *info,
+                          const struct ref_format *format,
+                          struct strbuf *final_buf)
 {
        const char *cp, *sp, *ep;
        struct ref_formatting_state state = REF_FORMATTING_STATE_INIT;
 
-       state.quote_style = quote_style;
+       state.quote_style = format->quote_style;
        push_stack_element(&state.stack);
 
-       for (cp = format; *cp && (sp = find_next(cp)); cp = ep + 1) {
+       for (cp = format->format; *cp && (sp = find_next(cp)); cp = ep + 1) {
                struct atom_value *atomv;
 
                ep = strchr(sp, ')');
                if (cp < sp)
                        append_literal(cp, sp, &state);
-               get_ref_atom_value(info, parse_ref_filter_atom(sp + 2, ep), &atomv);
+               get_ref_atom_value(info,
+                                  parse_ref_filter_atom(format, sp + 2, ep),
+                                  &atomv);
                atomv->handler(atomv, &state);
        }
        if (*cp) {
                sp = cp + strlen(cp);
                append_literal(cp, sp, &state);
        }
-       if (need_color_reset_at_eol) {
+       if (format->need_color_reset_at_eol) {
                struct atom_value resetv;
-               char color[COLOR_MAXLEN] = "";
-
-               if (color_parse("reset", color) < 0)
-                       die("BUG: couldn't parse 'reset' as a color");
-               resetv.s = color;
+               resetv.s = GIT_COLOR_RESET;
                append_atom(&resetv, &state);
        }
        if (state.stack->prev)
@@ -2097,26 +2104,38 @@ void format_ref_array_item(struct ref_array_item *info, const char *format,
        pop_stack_element(&state.stack);
 }
 
-void show_ref_array_item(struct ref_array_item *info, const char *format, int quote_style)
+void show_ref_array_item(struct ref_array_item *info,
+                        const struct ref_format *format)
 {
        struct strbuf final_buf = STRBUF_INIT;
 
-       format_ref_array_item(info, format, quote_style, &final_buf);
+       format_ref_array_item(info, format, &final_buf);
        fwrite(final_buf.buf, 1, final_buf.len, stdout);
        strbuf_release(&final_buf);
        putchar('\n');
 }
 
 void pretty_print_ref(const char *name, const unsigned char *sha1,
-               const char *format)
+                     const struct ref_format *format)
 {
        struct ref_array_item *ref_item;
        ref_item = new_ref_array_item(name, sha1, 0);
        ref_item->kind = ref_kind_from_refname(name);
-       show_ref_array_item(ref_item, format, 0);
+       show_ref_array_item(ref_item, format);
        free_array_item(ref_item);
 }
 
+static int parse_sorting_atom(const char *atom)
+{
+       /*
+        * This parses an atom using a dummy ref_format, since we don't
+        * actually care about the formatting details.
+        */
+       struct ref_format dummy = REF_FORMAT_INIT;
+       const char *end = atom + strlen(atom);
+       return parse_ref_filter_atom(&dummy, atom, end);
+}
+
 /*  If no sorting option is given, use refname to sort as default */
 struct ref_sorting *ref_default_sorting(void)
 {
@@ -2125,18 +2144,13 @@ struct ref_sorting *ref_default_sorting(void)
        struct ref_sorting *sorting = xcalloc(1, sizeof(*sorting));
 
        sorting->next = NULL;
-       sorting->atom = parse_ref_filter_atom(cstr_name, cstr_name + strlen(cstr_name));
+       sorting->atom = parse_sorting_atom(cstr_name);
        return sorting;
 }
 
-int parse_opt_ref_sorting(const struct option *opt, const char *arg, int unset)
+void parse_ref_sorting(struct ref_sorting **sorting_tail, const char *arg)
 {
-       struct ref_sorting **sorting_tail = opt->value;
        struct ref_sorting *s;
-       int len;
-
-       if (!arg) /* should --no-sort void the list ? */
-               return -1;
 
        s = xcalloc(1, sizeof(*s));
        s->next = *sorting_tail;
@@ -2149,8 +2163,14 @@ int parse_opt_ref_sorting(const struct option *opt, const char *arg, int unset)
        if (skip_prefix(arg, "version:", &arg) ||
            skip_prefix(arg, "v:", &arg))
                s->version = 1;
-       len = strlen(arg);
-       s->atom = parse_ref_filter_atom(arg, arg+len);
+       s->atom = parse_sorting_atom(arg);
+}
+
+int parse_opt_ref_sorting(const struct option *opt, const char *arg, int unset)
+{
+       if (!arg) /* should --no-sort void the list ? */
+               return -1;
+       parse_ref_sorting(opt->value, arg);
        return 0;
 }
 
index 6552024f09e4d4d587eaf49377e7504a79818c1d..0d98342b343196387c0f4e2dcd5978a9361d8edb 100644 (file)
@@ -72,6 +72,21 @@ struct ref_filter {
                verbose;
 };
 
+struct ref_format {
+       /*
+        * Set these to define the format; make sure you call
+        * verify_ref_format() afterwards to finalize.
+        */
+       const char *format;
+       int quote_style;
+       int use_color;
+
+       /* Internal state to ref-filter */
+       int need_color_reset_at_eol;
+};
+
+#define REF_FORMAT_INIT { NULL, 0, -1 }
+
 /*  Macros for checking --merged and --no-merged options */
 #define _OPT_MERGED_NO_MERGED(option, filter, h) \
        { OPTION_CALLBACK, 0, option, (filter), N_("commit"), (h), \
@@ -90,17 +105,18 @@ struct ref_filter {
 int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int type);
 /*  Clear all memory allocated to ref_array */
 void ref_array_clear(struct ref_array *array);
-/*  Parse format string and sort specifiers */
-int parse_ref_filter_atom(const char *atom, const char *ep);
 /*  Used to verify if the given format is correct and to parse out the used atoms */
-int verify_ref_format(const char *format);
+int verify_ref_format(struct ref_format *format);
 /*  Sort the given ref_array as per the ref_sorting provided */
 void ref_array_sort(struct ref_sorting *sort, struct ref_array *array);
 /*  Based on the given format and quote_style, fill the strbuf */
-void format_ref_array_item(struct ref_array_item *info, const char *format,
-                          int quote_style, struct strbuf *final_buf);
+void format_ref_array_item(struct ref_array_item *info,
+                          const struct ref_format *format,
+                          struct strbuf *final_buf);
 /*  Print the ref using the given format and quote_style */
-void show_ref_array_item(struct ref_array_item *info, const char *format, int quote_style);
+void show_ref_array_item(struct ref_array_item *info, const struct ref_format *format);
+/*  Parse a single sort specifier and add it to the list */
+void parse_ref_sorting(struct ref_sorting **sorting_tail, const char *atom);
 /*  Callback function for parsing the sort option */
 int parse_opt_ref_sorting(const struct option *opt, const char *arg, int unset);
 /*  Default sort option based on refname */
@@ -117,6 +133,6 @@ void setup_ref_filter_porcelain_msg(void);
  * name must be a fully qualified refname.
  */
 void pretty_print_ref(const char *name, const unsigned char *sha1,
-               const char *format);
+                     const struct ref_format *format);
 
 #endif /*  REF_FILTER_H  */
index 081f89b70d643514f148aaff9121263361fdb956..74ebe5148f6623f0bffd612262519266a8ab2cc4 100644 (file)
@@ -94,45 +94,6 @@ static int get_reflog_recno_by_time(struct complete_reflogs *array,
        return -1;
 }
 
-struct commit_info_lifo {
-       struct commit_info {
-               struct commit *commit;
-               void *util;
-       } *items;
-       int nr, alloc;
-};
-
-static struct commit_info *get_commit_info(struct commit *commit,
-               struct commit_info_lifo *lifo, int pop)
-{
-       int i;
-       for (i = 0; i < lifo->nr; i++)
-               if (lifo->items[i].commit == commit) {
-                       struct commit_info *result = &lifo->items[i];
-                       if (pop) {
-                               if (i + 1 < lifo->nr)
-                                       memmove(lifo->items + i,
-                                               lifo->items + i + 1,
-                                               (lifo->nr - i) *
-                                               sizeof(struct commit_info));
-                               lifo->nr--;
-                       }
-                       return result;
-               }
-       return NULL;
-}
-
-static void add_commit_info(struct commit *commit, void *util,
-               struct commit_info_lifo *lifo)
-{
-       struct commit_info *info;
-       ALLOC_GROW(lifo->items, lifo->nr + 1, lifo->alloc);
-       info = lifo->items + lifo->nr;
-       info->commit = commit;
-       info->util = util;
-       lifo->nr++;
-}
-
 struct commit_reflog {
        int recno;
        enum selector_type {
@@ -144,7 +105,8 @@ struct commit_reflog {
 };
 
 struct reflog_walk_info {
-       struct commit_info_lifo reflogs;
+       struct commit_reflog **logs;
+       size_t nr, alloc;
        struct string_list complete_reflogs;
        struct commit_reflog *last_commit_reflog;
 };
@@ -233,52 +195,10 @@ int add_reflog_for_walk(struct reflog_walk_info *info,
        commit_reflog->selector = selector;
        commit_reflog->reflogs = reflogs;
 
-       add_commit_info(commit, commit_reflog, &info->reflogs);
-       return 0;
-}
+       ALLOC_GROW(info->logs, info->nr + 1, info->alloc);
+       info->logs[info->nr++] = commit_reflog;
 
-void fake_reflog_parent(struct reflog_walk_info *info, struct commit *commit)
-{
-       struct commit_info *commit_info =
-               get_commit_info(commit, &info->reflogs, 0);
-       struct commit_reflog *commit_reflog;
-       struct object *logobj;
-       struct reflog_info *reflog;
-
-       info->last_commit_reflog = NULL;
-       if (!commit_info)
-               return;
-
-       commit_reflog = commit_info->util;
-       if (commit_reflog->recno < 0) {
-               commit->parents = NULL;
-               return;
-       }
-       info->last_commit_reflog = commit_reflog;
-
-       do {
-               reflog = &commit_reflog->reflogs->items[commit_reflog->recno];
-               commit_reflog->recno--;
-               logobj = parse_object(&reflog->ooid);
-       } while (commit_reflog->recno && (logobj && logobj->type != OBJ_COMMIT));
-
-       if (!logobj && commit_reflog->recno >= 0 && is_null_oid(&reflog->ooid)) {
-               /* a root commit, but there are still more entries to show */
-               reflog = &commit_reflog->reflogs->items[commit_reflog->recno];
-               logobj = parse_object(&reflog->noid);
-               if (!logobj)
-                       logobj = parse_object(&reflog->ooid);
-       }
-
-       if (!logobj || logobj->type != OBJ_COMMIT) {
-               commit_info->commit = NULL;
-               commit->parents = NULL;
-               return;
-       }
-       commit_info->commit = (struct commit *)logobj;
-
-       commit->parents = xcalloc(1, sizeof(struct commit_list));
-       commit->parents->item = commit_info->commit;
+       return 0;
 }
 
 void get_reflog_selector(struct strbuf *sb,
@@ -344,6 +264,18 @@ const char *get_reflog_ident(struct reflog_walk_info *reflog_info)
        return info->email;
 }
 
+timestamp_t get_reflog_timestamp(struct reflog_walk_info *reflog_info)
+{
+       struct commit_reflog *commit_reflog = reflog_info->last_commit_reflog;
+       struct reflog_info *info;
+
+       if (!commit_reflog)
+               return 0;
+
+       info = &commit_reflog->reflogs->items[commit_reflog->recno+1];
+       return info->timestamp;
+}
+
 void show_reflog_message(struct reflog_walk_info *reflog_info, int oneline,
                         const struct date_mode *dmode, int force_date)
 {
@@ -365,3 +297,53 @@ void show_reflog_message(struct reflog_walk_info *reflog_info, int oneline,
                strbuf_release(&selector);
        }
 }
+
+int reflog_walk_empty(struct reflog_walk_info *info)
+{
+       return !info || !info->nr;
+}
+
+static struct commit *next_reflog_commit(struct commit_reflog *log)
+{
+       for (; log->recno >= 0; log->recno--) {
+               struct reflog_info *entry = &log->reflogs->items[log->recno];
+               struct object *obj = parse_object(&entry->noid);
+
+               if (obj && obj->type == OBJ_COMMIT)
+                       return (struct commit *)obj;
+       }
+       return NULL;
+}
+
+static timestamp_t log_timestamp(struct commit_reflog *log)
+{
+       return log->reflogs->items[log->recno].timestamp;
+}
+
+struct commit *next_reflog_entry(struct reflog_walk_info *walk)
+{
+       struct commit_reflog *best = NULL;
+       struct commit *best_commit = NULL;
+       size_t i;
+
+       for (i = 0; i < walk->nr; i++) {
+               struct commit_reflog *log = walk->logs[i];
+               struct commit *commit = next_reflog_commit(log);
+
+               if (!commit)
+                       continue;
+
+               if (!best || log_timestamp(log) > log_timestamp(best)) {
+                       best = log;
+                       best_commit = commit;
+               }
+       }
+
+       if (best) {
+               best->recno--;
+               walk->last_commit_reflog = best;
+               return best_commit;
+       }
+
+       return NULL;
+}
index 27886f793e75de484b2a3c168e6024cf4139aae3..7553c448fe5bf8b432d7fdb2ef5cba967bb985cd 100644 (file)
@@ -8,16 +8,19 @@ struct reflog_walk_info;
 extern void init_reflog_walk(struct reflog_walk_info **info);
 extern int add_reflog_for_walk(struct reflog_walk_info *info,
                struct commit *commit, const char *name);
-extern void fake_reflog_parent(struct reflog_walk_info *info,
-               struct commit *commit);
 extern void show_reflog_message(struct reflog_walk_info *info, int,
                                const struct date_mode *, int force_date);
 extern void get_reflog_message(struct strbuf *sb,
                struct reflog_walk_info *reflog_info);
 extern const char *get_reflog_ident(struct reflog_walk_info *reflog_info);
+extern timestamp_t get_reflog_timestamp(struct reflog_walk_info *reflog_info);
 extern void get_reflog_selector(struct strbuf *sb,
                struct reflog_walk_info *reflog_info,
                const struct date_mode *dmode, int force_date,
                int shorten);
 
+extern int reflog_walk_empty(struct reflog_walk_info *walk);
+
+struct commit *next_reflog_entry(struct reflog_walk_info *reflog_info);
+
 #endif
diff --git a/refs.c b/refs.c
index ba22f4acefa262cc1029bcf8360edb21c0635953..fe4c59aa8b681e15abb75032d36605abce1940b4 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -818,7 +818,7 @@ int read_ref_at(const char *refname, unsigned int flags, timestamp_t at_time, in
        for_each_reflog_ent_reverse(refname, read_ref_at_ent, &cb);
 
        if (!cb.reccnt) {
-               if (flags & GET_SHA1_QUIETLY)
+               if (flags & GET_OID_QUIETLY)
                        exit(128);
                else
                        die("Log for %s is empty.", refname);
@@ -1160,7 +1160,7 @@ int ref_is_hidden(const char *refname, const char *refname_full)
                const char *match = hide_refs->items[i].string;
                const char *subject;
                int neg = 0;
-               int len;
+               const char *p;
 
                if (*match == '!') {
                        neg = 1;
@@ -1175,10 +1175,9 @@ int ref_is_hidden(const char *refname, const char *refname_full)
                }
 
                /* refname can be NULL when namespaces are used. */
-               if (!subject || !starts_with(subject, match))
-                       continue;
-               len = strlen(match);
-               if (!subject[len] || subject[len] == '/')
+               if (subject &&
+                   skip_prefix(subject, match, &p) &&
+                   (!*p || *p == '/'))
                        return !neg;
        }
        return 0;
index 60d004392109f1e39f0bf34578e195cdf3af1639..43c317e4e9f6e67aa3e1d0ae245d097bdba664db 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -134,10 +134,14 @@ struct remotes_hash_key {
 };
 
 static int remotes_hash_cmp(const void *unused_cmp_data,
-                           const struct remote *a,
-                           const struct remote *b,
-                           const struct remotes_hash_key *key)
+                           const void *entry,
+                           const void *entry_or_key,
+                           const void *keydata)
 {
+       const struct remote *a = entry;
+       const struct remote *b = entry_or_key;
+       const struct remotes_hash_key *key = keydata;
+
        if (key)
                return strncmp(a->name, key->str, key->len) || a->name[key->len];
        else
@@ -147,7 +151,7 @@ static int remotes_hash_cmp(const void *unused_cmp_data,
 static inline void init_remotes_hash(void)
 {
        if (!remotes_hash.cmpfn)
-               hashmap_init(&remotes_hash, (hashmap_cmp_fn)remotes_hash_cmp, NULL, 0);
+               hashmap_init(&remotes_hash, remotes_hash_cmp, NULL, 0);
 }
 
 static struct remote *make_remote(const char *name, int len)
@@ -1081,7 +1085,7 @@ static int try_explicit_object_name(const char *name,
                return 0;
        }
 
-       if (get_sha1(name, oid.hash))
+       if (get_oid(name, &oid))
                return -1;
 
        if (match) {
@@ -2297,8 +2301,8 @@ static int parse_push_cas_option(struct push_cas_option *cas, const char *arg, i
        if (!*colon)
                entry->use_tracking = 1;
        else if (!colon[1])
-               hashclr(entry->expect);
-       else if (get_sha1(colon + 1, entry->expect))
+               oidclr(&entry->expect);
+       else if (get_oid(colon + 1, &entry->expect))
                return error("cannot parse expected object name '%s'", colon + 1);
        return 0;
 }
@@ -2345,7 +2349,7 @@ static void apply_cas(struct push_cas_option *cas,
                        continue;
                ref->expect_old_sha1 = 1;
                if (!entry->use_tracking)
-                       hashcpy(ref->old_oid_expect.hash, cas->entry[i].expect);
+                       oidcpy(&ref->old_oid_expect, &entry->expect);
                else if (remote_tracking(remote, ref->name, &ref->old_oid_expect))
                        oidclr(&ref->old_oid_expect);
                return;
index 6c28cd3e4bfe2e8be058485d0b963b23622b999f..2ecf4c8c74ce590c9bcc917d997b3c7acf9c07c1 100644 (file)
--- a/remote.h
+++ b/remote.h
@@ -282,7 +282,7 @@ struct ref *get_stale_heads(struct refspec *refs, int ref_count, struct ref *fet
 struct push_cas_option {
        unsigned use_tracking_for_rest:1;
        struct push_cas {
-               unsigned char expect[20];
+               struct object_id expect;
                unsigned use_tracking:1;
                char *refname;
        } *entry;
index edca9074046ab1ca9826d2479bcca11018ba1873..1617467568c76e685d5f852c27ca16f26ed0494c 100644 (file)
@@ -158,7 +158,7 @@ int repo_submodule_init(struct repository *submodule,
        struct strbuf worktree = STRBUF_INIT;
        int ret = 0;
 
-       sub = submodule_from_cache(superproject, null_sha1, path);
+       sub = submodule_from_cache(superproject, &null_oid, path);
        if (!sub) {
                ret = -1;
                goto out;
index ba2b166cd67fab9f68c303f2fe300511bf416b4d..aa3b946a8d831702f503f3b91d6866d190aef885 100644 (file)
@@ -148,16 +148,14 @@ static void add_pending_object_with_path(struct rev_info *revs,
        if (revs->reflog_info && obj->type == OBJ_COMMIT) {
                struct strbuf buf = STRBUF_INIT;
                int len = interpret_branch_name(name, 0, &buf, 0);
-               int st;
 
                if (0 < len && name[len] && buf.len)
                        strbuf_addstr(&buf, name + len);
-               st = add_reflog_for_walk(revs->reflog_info,
-                                        (struct commit *)obj,
-                                        buf.buf[0] ? buf.buf: name);
+               add_reflog_for_walk(revs->reflog_info,
+                                   (struct commit *)obj,
+                                   buf.buf[0] ? buf.buf: name);
                strbuf_release(&buf);
-               if (st)
-                       return;
+               return; /* do not add the commit itself */
        }
        add_object_array_with_path(obj, name, &revs->pending, mode, path);
 }
@@ -1304,7 +1302,7 @@ static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,
                flags ^= UNINTERESTING | BOTTOM;
                arg++;
        }
-       if (get_sha1_committish(arg, oid.hash))
+       if (get_oid_committish(arg, &oid))
                return 0;
        while (1) {
                it = get_reference(revs, arg, &oid, 0);
@@ -1453,7 +1451,7 @@ static int handle_dotdot_1(const char *arg, char *dotdot,
        unsigned int a_flags, b_flags;
        int symmetric = 0;
        unsigned int flags_exclude = flags ^ (UNINTERESTING | BOTTOM);
-       unsigned int oc_flags = GET_SHA1_COMMITTISH | GET_SHA1_RECORD_PATH;
+       unsigned int oc_flags = GET_OID_COMMITTISH | GET_OID_RECORD_PATH;
 
        a_name = arg;
        if (!*a_name)
@@ -1467,8 +1465,8 @@ static int handle_dotdot_1(const char *arg, char *dotdot,
        if (!*b_name)
                b_name = "HEAD";
 
-       if (get_sha1_with_context(a_name, oc_flags, a_oid.hash, a_oc) ||
-           get_sha1_with_context(b_name, oc_flags, b_oid.hash, b_oc))
+       if (get_oid_with_context(a_name, oc_flags, &a_oid, a_oc) ||
+           get_oid_with_context(b_name, oc_flags, &b_oid, b_oc))
                return -1;
 
        if (!cant_be_filename) {
@@ -1549,7 +1547,7 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsi
        int local_flags;
        const char *arg = arg_;
        int cant_be_filename = revarg_opt & REVARG_CANNOT_BE_FILENAME;
-       unsigned get_sha1_flags = GET_SHA1_RECORD_PATH;
+       unsigned get_sha1_flags = GET_OID_RECORD_PATH;
 
        flags = flags & UNINTERESTING ? flags | BOTTOM : flags & ~BOTTOM;
 
@@ -1600,9 +1598,9 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsi
        }
 
        if (revarg_opt & REVARG_COMMITTISH)
-               get_sha1_flags |= GET_SHA1_COMMITTISH;
+               get_sha1_flags |= GET_OID_COMMITTISH;
 
-       if (get_sha1_with_context(arg, get_sha1_flags, oid.hash, &oc))
+       if (get_oid_with_context(arg, get_sha1_flags, &oid, &oc))
                return revs->ignore_missing ? 0 : -1;
        if (!cant_be_filename)
                verify_non_filename(revs->prefix, arg);
@@ -2320,7 +2318,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
                struct object_id oid;
                struct object *object;
                struct object_context oc;
-               if (get_sha1_with_context(revs->def, 0, oid.hash, &oc))
+               if (get_oid_with_context(revs->def, 0, &oid, &oc))
                        diagnose_missing_default(revs->def);
                object = get_reference(revs, revs->def, &oid, 0);
                add_pending_object_with_mode(revs, object, revs->def, oc.mode);
@@ -2365,6 +2363,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
 
        if (revs->reverse && revs->reflog_info)
                die("cannot combine --reverse with --walk-reflogs");
+       if (revs->reflog_info && revs->limited)
+               die("cannot combine --walk-reflogs with history-limiting options");
        if (revs->rewrite_parents && revs->children.name)
                die("cannot combine --parents and --children");
 
@@ -2964,6 +2964,18 @@ static inline int want_ancestry(const struct rev_info *revs)
        return (revs->rewrite_parents || revs->children.name);
 }
 
+/*
+ * Return a timestamp to be used for --since/--until comparisons for this
+ * commit, based on the revision options.
+ */
+static timestamp_t comparison_date(const struct rev_info *revs,
+                                  struct commit *commit)
+{
+       return revs->reflog_info ?
+               get_reflog_timestamp(revs->reflog_info) :
+               commit->date;
+}
+
 enum commit_action get_commit_action(struct rev_info *revs, struct commit *commit)
 {
        if (commit->object.flags & SHOWN)
@@ -2974,8 +2986,9 @@ enum commit_action get_commit_action(struct rev_info *revs, struct commit *commi
                return commit_show;
        if (commit->object.flags & UNINTERESTING)
                return commit_ignore;
-       if (revs->min_age != -1 && (commit->date > revs->min_age))
-               return commit_ignore;
+       if (revs->min_age != -1 &&
+           comparison_date(revs, commit) > revs->min_age)
+                       return commit_ignore;
        if (revs->min_parents || (revs->max_parents >= 0)) {
                int n = commit_list_count(commit->parents);
                if ((n < revs->min_parents) ||
@@ -3108,17 +3121,19 @@ static void track_linear(struct rev_info *revs, struct commit *commit)
 
 static struct commit *get_revision_1(struct rev_info *revs)
 {
-       if (!revs->commits)
-               return NULL;
+       while (1) {
+               struct commit *commit;
 
-       do {
-               struct commit *commit = pop_commit(&revs->commits);
+               if (revs->reflog_info)
+                       commit = next_reflog_entry(revs->reflog_info);
+               else
+                       commit = pop_commit(&revs->commits);
 
-               if (revs->reflog_info) {
-                       save_parents(revs, commit);
-                       fake_reflog_parent(revs->reflog_info, commit);
+               if (!commit)
+                       return NULL;
+
+               if (revs->reflog_info)
                        commit->object.flags &= ~(ADDED | SEEN | SHOWN);
-               }
 
                /*
                 * If we haven't done the list limiting, we need to look at
@@ -3127,9 +3142,12 @@ static struct commit *get_revision_1(struct rev_info *revs)
                 */
                if (!revs->limited) {
                        if (revs->max_age != -1 &&
-                           (commit->date < revs->max_age))
+                           comparison_date(revs, commit) < revs->max_age)
                                continue;
-                       if (add_parents_to_list(revs, commit, &revs->commits, NULL) < 0) {
+
+                       if (revs->reflog_info)
+                               try_to_simplify_commit(revs, commit);
+                       else if (add_parents_to_list(revs, commit, &revs->commits, NULL) < 0) {
                                if (!revs->ignore_missing_links)
                                        die("Failed to traverse parents of commit %s",
                                                oid_to_hex(&commit->object.oid));
@@ -3147,8 +3165,7 @@ static struct commit *get_revision_1(struct rev_info *revs)
                                track_linear(revs, commit);
                        return commit;
                }
-       } while (revs->commits);
-       return NULL;
+       }
 }
 
 /*
index 9e36151bf97d36945ca3464e719687718ee6d1c7..b5e6eb37c0eb3d6ed0cbd4fc35e879bf9fbd3db6 100644 (file)
@@ -1533,7 +1533,7 @@ static int pp_start_one(struct parallel_processes *pp)
        if (start_command(&pp->children[i].process)) {
                code = pp->start_failure(&pp->children[i].err,
                                         pp->data,
-                                        &pp->children[i].data);
+                                        pp->children[i].data);
                strbuf_addbuf(&pp->buffered_output, &pp->children[i].err);
                strbuf_reset(&pp->children[i].err);
                if (code)
@@ -1601,7 +1601,7 @@ static int pp_collect_finished(struct parallel_processes *pp)
 
                code = pp->task_finished(code,
                                         &pp->children[i].err, pp->data,
-                                        &pp->children[i].data);
+                                        pp->children[i].data);
 
                if (code)
                        result = code;
index 3010faf86398697469e903318a35421d911acb23..f5e85a398dd06ef466a073c463e41a0b9278360c 100644 (file)
@@ -691,7 +691,7 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,
 
 static int is_original_commit_empty(struct commit *commit)
 {
-       const unsigned char *ptree_sha1;
+       const struct object_id *ptree_oid;
 
        if (parse_commit(commit))
                return error(_("could not parse commit %s\n"),
@@ -701,12 +701,12 @@ static int is_original_commit_empty(struct commit *commit)
                if (parse_commit(parent))
                        return error(_("could not parse parent commit %s\n"),
                                oid_to_hex(&parent->object.oid));
-               ptree_sha1 = parent->tree->object.oid.hash;
+               ptree_oid = &parent->tree->object.oid;
        } else {
-               ptree_sha1 = EMPTY_TREE_SHA1_BIN; /* commit is root */
+               ptree_oid = &empty_tree_oid; /* commit is root */
        }
 
-       return !hashcmp(ptree_sha1, commit->tree->object.oid.hash);
+       return !oidcmp(ptree_oid, &commit->tree->object.oid);
 }
 
 /*
@@ -896,18 +896,18 @@ static int update_squash_messages(enum todo_command command,
 
 static void flush_rewritten_pending(void) {
        struct strbuf buf = STRBUF_INIT;
-       unsigned char newsha1[20];
+       struct object_id newoid;
        FILE *out;
 
-       if (strbuf_read_file(&buf, rebase_path_rewritten_pending(), 82) > 0 &&
-           !get_sha1("HEAD", newsha1) &&
+       if (strbuf_read_file(&buf, rebase_path_rewritten_pending(), (GIT_MAX_HEXSZ + 1) * 2) > 0 &&
+           !get_oid("HEAD", &newoid) &&
            (out = fopen_or_warn(rebase_path_rewritten_list(), "a"))) {
                char *bol = buf.buf, *eol;
 
                while (*bol) {
                        eol = strchrnul(bol, '\n');
                        fprintf(out, "%.*s %s\n", (int)(eol - bol),
-                                       bol, sha1_to_hex(newsha1));
+                                       bol, oid_to_hex(&newoid));
                        if (!*eol)
                                break;
                        bol = eol + 1;
@@ -1594,36 +1594,37 @@ static int rollback_is_safe(void)
        return !oidcmp(&actual_head, &expected_head);
 }
 
-static int reset_for_rollback(const unsigned char *sha1)
+static int reset_for_rollback(const struct object_id *oid)
 {
        const char *argv[4];    /* reset --merge <arg> + NULL */
 
        argv[0] = "reset";
        argv[1] = "--merge";
-       argv[2] = sha1_to_hex(sha1);
+       argv[2] = oid_to_hex(oid);
        argv[3] = NULL;
        return run_command_v_opt(argv, RUN_GIT_CMD);
 }
 
 static int rollback_single_pick(void)
 {
-       unsigned char head_sha1[20];
+       struct object_id head_oid;
 
        if (!file_exists(git_path_cherry_pick_head()) &&
            !file_exists(git_path_revert_head()))
                return error(_("no cherry-pick or revert in progress"));
-       if (read_ref_full("HEAD", 0, head_sha1, NULL))
+       if (read_ref_full("HEAD", 0, head_oid.hash, NULL))
                return error(_("cannot resolve HEAD"));
-       if (is_null_sha1(head_sha1))
+       if (is_null_oid(&head_oid))
                return error(_("cannot abort from a branch yet to be born"));
-       return reset_for_rollback(head_sha1);
+       return reset_for_rollback(&head_oid);
 }
 
 int sequencer_rollback(struct replay_opts *opts)
 {
        FILE *f;
-       unsigned char sha1[20];
+       struct object_id oid;
        struct strbuf buf = STRBUF_INIT;
+       const char *p;
 
        f = fopen(git_path_head_file(), "r");
        if (!f && errno == ENOENT) {
@@ -1643,12 +1644,12 @@ int sequencer_rollback(struct replay_opts *opts)
                goto fail;
        }
        fclose(f);
-       if (get_sha1_hex(buf.buf, sha1) || buf.buf[40] != '\0') {
+       if (parse_oid_hex(buf.buf, &oid, &p) || *p != '\0') {
                error(_("stored pre-cherry-pick HEAD file '%s' is corrupt"),
                        git_path_head_file());
                goto fail;
        }
-       if (is_null_sha1(sha1)) {
+       if (is_null_oid(&oid)) {
                error(_("cannot abort from a branch yet to be born"));
                goto fail;
        }
@@ -1658,7 +1659,7 @@ int sequencer_rollback(struct replay_opts *opts)
                warning(_("You seem to have moved HEAD. "
                          "Not rewinding, check your HEAD!"));
        } else
-       if (reset_for_rollback(sha1))
+       if (reset_for_rollback(&oid))
                goto fail;
        strbuf_release(&buf);
        return sequencer_remove_state(opts);
@@ -1788,13 +1789,13 @@ static int make_patch(struct commit *commit, struct replay_opts *opts)
 
 static int intend_to_amend(void)
 {
-       unsigned char head[20];
+       struct object_id head;
        char *p;
 
-       if (get_sha1("HEAD", head))
+       if (get_oid("HEAD", &head))
                return error(_("cannot read HEAD"));
 
-       p = sha1_to_hex(head);
+       p = oid_to_hex(&head);
        return write_message(p, strlen(p), rebase_path_amend(), 1);
 }
 
@@ -2079,10 +2080,10 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
                if (read_oneliner(&head_ref, rebase_path_head_name(), 0) &&
                                starts_with(head_ref.buf, "refs/")) {
                        const char *msg;
-                       unsigned char head[20], orig[20];
+                       struct object_id head, orig;
                        int res;
 
-                       if (get_sha1("HEAD", head)) {
+                       if (get_oid("HEAD", &head)) {
                                res = error(_("cannot read HEAD"));
 cleanup_head_ref:
                                strbuf_release(&head_ref);
@@ -2090,7 +2091,7 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
                                return res;
                        }
                        if (!read_oneliner(&buf, rebase_path_orig_head(), 0) ||
-                                       get_sha1_hex(buf.buf, orig)) {
+                                       get_oid_hex(buf.buf, &orig)) {
                                res = error(_("could not read orig-head"));
                                goto cleanup_head_ref;
                        }
@@ -2101,7 +2102,7 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
                        }
                        msg = reflog_message(opts, "finish", "%s onto %s",
                                head_ref.buf, buf.buf);
-                       if (update_ref(msg, head_ref.buf, head, orig,
+                       if (update_ref(msg, head_ref.buf, head.hash, orig.hash,
                                        REF_NODEREF, UPDATE_REFS_MSG_ON_ERR)) {
                                res = error(_("could not update %s"),
                                        head_ref.buf);
@@ -2129,8 +2130,8 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
                        log_tree_opt.disable_stdin = 1;
 
                        if (read_oneliner(&buf, rebase_path_orig_head(), 0) &&
-                           !get_sha1(buf.buf, orig.hash) &&
-                           !get_sha1("HEAD", head.hash)) {
+                           !get_oid(buf.buf, &orig) &&
+                           !get_oid("HEAD", &head)) {
                                diff_tree_oid(&orig, &head, "",
                                              &log_tree_opt.diffopt);
                                log_tree_diff_flush(&log_tree_opt);
@@ -2205,16 +2206,16 @@ static int commit_staged_changes(struct replay_opts *opts)
 
        if (file_exists(rebase_path_amend())) {
                struct strbuf rev = STRBUF_INIT;
-               unsigned char head[20], to_amend[20];
+               struct object_id head, to_amend;
 
-               if (get_sha1("HEAD", head))
+               if (get_oid("HEAD", &head))
                        return error(_("cannot amend non-existing commit"));
                if (!read_oneliner(&rev, rebase_path_amend(), 0))
                        return error(_("invalid file: '%s'"), rebase_path_amend());
-               if (get_sha1_hex(rev.buf, to_amend))
+               if (get_oid_hex(rev.buf, &to_amend))
                        return error(_("invalid contents: '%s'"),
                                rebase_path_amend());
-               if (hashcmp(head, to_amend))
+               if (oidcmp(&head, &to_amend))
                        return error(_("\nYou have uncommitted changes in your "
                                       "working tree. Please, commit them\n"
                                       "first and then run 'git rebase "
@@ -2266,7 +2267,7 @@ int sequencer_continue(struct replay_opts *opts)
                struct object_id oid;
 
                if (read_oneliner(&buf, rebase_path_stopped_sha(), 1) &&
-                   !get_sha1_committish(buf.buf, oid.hash))
+                   !get_oid_committish(buf.buf, &oid))
                        record_in_rewritten(&oid, peek_command(&todo_list, 0));
                strbuf_release(&buf);
        }
index 74fcb6d788f4cb591a9f7d3c6a2692f5c6d84022..862b6f1308e7031317ab6eb6d181652a6fc644ad 100644 (file)
@@ -10,7 +10,7 @@
 #include "dir.h"
 #include "sha1-array.h"
 
-static int get_sha1_oneline(const char *, unsigned char *, struct commit_list *);
+static int get_oid_oneline(const char *, struct object_id *, struct commit_list *);
 
 typedef int (*disambiguate_hint_fn)(const struct object_id *, void *);
 
@@ -200,7 +200,7 @@ static void find_short_packed_object(struct disambiguate_state *ds)
 #define SHORT_NAME_AMBIGUOUS (-2)
 
 static int finish_object_disambiguation(struct disambiguate_state *ds,
-                                       unsigned char *sha1)
+                                       struct object_id *oid)
 {
        if (ds->ambiguous)
                return SHORT_NAME_AMBIGUOUS;
@@ -229,7 +229,7 @@ static int finish_object_disambiguation(struct disambiguate_state *ds,
        if (!ds->candidate_ok)
                return SHORT_NAME_AMBIGUOUS;
 
-       hashcpy(sha1, ds->candidate.hash);
+       oidcpy(oid, &ds->candidate);
        return 0;
 }
 
@@ -385,35 +385,35 @@ static int show_ambiguous_object(const struct object_id *oid, void *data)
        return 0;
 }
 
-static int get_short_sha1(const char *name, int len, unsigned char *sha1,
+static int get_short_oid(const char *name, int len, struct object_id *oid,
                          unsigned flags)
 {
        int status;
        struct disambiguate_state ds;
-       int quietly = !!(flags & GET_SHA1_QUIETLY);
+       int quietly = !!(flags & GET_OID_QUIETLY);
 
        if (init_object_disambiguation(name, len, &ds) < 0)
                return -1;
 
-       if (HAS_MULTI_BITS(flags & GET_SHA1_DISAMBIGUATORS))
-               die("BUG: multiple get_short_sha1 disambiguator flags");
+       if (HAS_MULTI_BITS(flags & GET_OID_DISAMBIGUATORS))
+               die("BUG: multiple get_short_oid disambiguator flags");
 
-       if (flags & GET_SHA1_COMMIT)
+       if (flags & GET_OID_COMMIT)
                ds.fn = disambiguate_commit_only;
-       else if (flags & GET_SHA1_COMMITTISH)
+       else if (flags & GET_OID_COMMITTISH)
                ds.fn = disambiguate_committish_only;
-       else if (flags & GET_SHA1_TREE)
+       else if (flags & GET_OID_TREE)
                ds.fn = disambiguate_tree_only;
-       else if (flags & GET_SHA1_TREEISH)
+       else if (flags & GET_OID_TREEISH)
                ds.fn = disambiguate_treeish_only;
-       else if (flags & GET_SHA1_BLOB)
+       else if (flags & GET_OID_BLOB)
                ds.fn = disambiguate_blob_only;
        else
                ds.fn = default_disambiguate_hint;
 
        find_short_object_filename(&ds);
        find_short_packed_object(&ds);
-       status = finish_object_disambiguation(&ds, sha1);
+       status = finish_object_disambiguation(&ds, oid);
 
        if (!quietly && (status == SHORT_NAME_AMBIGUOUS)) {
                error(_("short SHA1 %s is ambiguous"), ds.hex_pfx);
@@ -500,12 +500,12 @@ int find_unique_abbrev_r(char *hex, const unsigned char *sha1, int len)
        }
 
        sha1_to_hex_r(hex, sha1);
-       if (len == 40 || !len)
-               return 40;
+       if (len == GIT_SHA1_HEXSZ || !len)
+               return GIT_SHA1_HEXSZ;
        exists = has_sha1_file(sha1);
-       while (len < 40) {
-               unsigned char sha1_ret[20];
-               status = get_short_sha1(hex, len, sha1_ret, GET_SHA1_QUIETLY);
+       while (len < GIT_SHA1_HEXSZ) {
+               struct object_id oid_ret;
+               status = get_short_oid(hex, len, &oid_ret, GET_OID_QUIETLY);
                if (exists
                    ? !status
                    : status == SHORT_NAME_NOT_FOUND) {
@@ -578,10 +578,10 @@ static inline int push_mark(const char *string, int len)
        return at_mark(string, len, suffix, ARRAY_SIZE(suffix));
 }
 
-static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned lookup_flags);
+static int get_oid_1(const char *name, int len, struct object_id *oid, unsigned lookup_flags);
 static int interpret_nth_prior_checkout(const char *name, int namelen, struct strbuf *buf);
 
-static int get_sha1_basic(const char *str, int len, unsigned char *sha1,
+static int get_oid_basic(const char *str, int len, struct object_id *oid,
                          unsigned int flags)
 {
        static const char *warn_msg = "refname '%.*s' is ambiguous.";
@@ -595,14 +595,14 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1,
        "where \"$br\" is somehow empty and a 40-hex ref is created. Please\n"
        "examine these refs and maybe delete them. Turn this message off by\n"
        "running \"git config advice.objectNameWarning false\"");
-       unsigned char tmp_sha1[20];
+       struct object_id tmp_oid;
        char *real_ref = NULL;
        int refs_found = 0;
        int at, reflog_len, nth_prior = 0;
 
-       if (len == 40 && !get_sha1_hex(str, sha1)) {
+       if (len == GIT_SHA1_HEXSZ && !get_oid_hex(str, oid)) {
                if (warn_ambiguous_refs && warn_on_object_refname_ambiguity) {
-                       refs_found = dwim_ref(str, len, tmp_sha1, &real_ref);
+                       refs_found = dwim_ref(str, len, tmp_oid.hash, &real_ref);
                        if (refs_found > 0) {
                                warning(warn_msg, len, str);
                                if (advice_object_name_warning)
@@ -644,7 +644,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1,
                int detached;
 
                if (interpret_nth_prior_checkout(str, len, &buf) > 0) {
-                       detached = (buf.len == 40 && !get_sha1_hex(buf.buf, sha1));
+                       detached = (buf.len == GIT_SHA1_HEXSZ && !get_oid_hex(buf.buf, oid));
                        strbuf_release(&buf);
                        if (detached)
                                return 0;
@@ -653,18 +653,18 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1,
 
        if (!len && reflog_len)
                /* allow "@{...}" to mean the current branch reflog */
-               refs_found = dwim_ref("HEAD", 4, sha1, &real_ref);
+               refs_found = dwim_ref("HEAD", 4, oid->hash, &real_ref);
        else if (reflog_len)
-               refs_found = dwim_log(str, len, sha1, &real_ref);
+               refs_found = dwim_log(str, len, oid->hash, &real_ref);
        else
-               refs_found = dwim_ref(str, len, sha1, &real_ref);
+               refs_found = dwim_ref(str, len, oid->hash, &real_ref);
 
        if (!refs_found)
                return -1;
 
-       if (warn_ambiguous_refs && !(flags & GET_SHA1_QUIETLY) &&
+       if (warn_ambiguous_refs && !(flags & GET_OID_QUIETLY) &&
            (refs_found > 1 ||
-            !get_short_sha1(str, len, tmp_sha1, GET_SHA1_QUIETLY)))
+            !get_short_oid(str, len, &tmp_oid, GET_OID_QUIETLY)))
                warning(warn_msg, len, str);
 
        if (reflog_len) {
@@ -696,7 +696,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1,
                                return -1;
                        }
                }
-               if (read_ref_at(real_ref, flags, at_time, nth, sha1, NULL,
+               if (read_ref_at(real_ref, flags, at_time, nth, oid->hash, NULL,
                                &co_time, &co_tz, &co_cnt)) {
                        if (!len) {
                                if (starts_with(real_ref, "refs/heads/")) {
@@ -709,13 +709,13 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1,
                                }
                        }
                        if (at_time) {
-                               if (!(flags & GET_SHA1_QUIETLY)) {
+                               if (!(flags & GET_OID_QUIETLY)) {
                                        warning("Log for '%.*s' only goes "
                                                "back to %s.", len, str,
                                                show_date(co_time, co_tz, DATE_MODE(RFC2822)));
                                }
                        } else {
-                               if (flags & GET_SHA1_QUIETLY) {
+                               if (flags & GET_OID_QUIETLY) {
                                        exit(128);
                                }
                                die("Log for '%.*s' only has %d entries.",
@@ -729,10 +729,10 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1,
 }
 
 static int get_parent(const char *name, int len,
-                     unsigned char *result, int idx)
+                     struct object_id *result, int idx)
 {
        struct object_id oid;
-       int ret = get_sha1_1(name, len, oid.hash, GET_SHA1_COMMITTISH);
+       int ret = get_oid_1(name, len, &oid, GET_OID_COMMITTISH);
        struct commit *commit;
        struct commit_list *p;
 
@@ -742,13 +742,13 @@ static int get_parent(const char *name, int len,
        if (parse_commit(commit))
                return -1;
        if (!idx) {
-               hashcpy(result, commit->object.oid.hash);
+               oidcpy(result, &commit->object.oid);
                return 0;
        }
        p = commit->parents;
        while (p) {
                if (!--idx) {
-                       hashcpy(result, p->item->object.oid.hash);
+                       oidcpy(result, &p->item->object.oid);
                        return 0;
                }
                p = p->next;
@@ -757,13 +757,13 @@ static int get_parent(const char *name, int len,
 }
 
 static int get_nth_ancestor(const char *name, int len,
-                           unsigned char *result, int generation)
+                           struct object_id *result, int generation)
 {
        struct object_id oid;
        struct commit *commit;
        int ret;
 
-       ret = get_sha1_1(name, len, oid.hash, GET_SHA1_COMMITTISH);
+       ret = get_oid_1(name, len, &oid, GET_OID_COMMITTISH);
        if (ret)
                return ret;
        commit = lookup_commit_reference(&oid);
@@ -775,7 +775,7 @@ static int get_nth_ancestor(const char *name, int len,
                        return -1;
                commit = commit->parents->item;
        }
-       hashcpy(result, commit->object.oid.hash);
+       oidcpy(result, &commit->object.oid);
        return 0;
 }
 
@@ -804,7 +804,7 @@ struct object *peel_to_type(const char *name, int namelen,
        }
 }
 
-static int peel_onion(const char *name, int len, unsigned char *sha1,
+static int peel_onion(const char *name, int len, struct object_id *oid,
                      unsigned lookup_flags)
 {
        struct object_id outer;
@@ -849,13 +849,13 @@ static int peel_onion(const char *name, int len, unsigned char *sha1,
        else
                return -1;
 
-       lookup_flags &= ~GET_SHA1_DISAMBIGUATORS;
+       lookup_flags &= ~GET_OID_DISAMBIGUATORS;
        if (expected_type == OBJ_COMMIT)
-               lookup_flags |= GET_SHA1_COMMITTISH;
+               lookup_flags |= GET_OID_COMMITTISH;
        else if (expected_type == OBJ_TREE)
-               lookup_flags |= GET_SHA1_TREEISH;
+               lookup_flags |= GET_OID_TREEISH;
 
-       if (get_sha1_1(name, sp - name - 2, outer.hash, lookup_flags))
+       if (get_oid_1(name, sp - name - 2, &outer, lookup_flags))
                return -1;
 
        o = parse_object(&outer);
@@ -865,7 +865,7 @@ static int peel_onion(const char *name, int len, unsigned char *sha1,
                o = deref_tag(o, name, sp - name - 2);
                if (!o || (!o->parsed && !parse_object(&o->oid)))
                        return -1;
-               hashcpy(sha1, o->oid.hash);
+               oidcpy(oid, &o->oid);
                return 0;
        }
 
@@ -878,7 +878,7 @@ static int peel_onion(const char *name, int len, unsigned char *sha1,
        if (!o)
                return -1;
 
-       hashcpy(sha1, o->oid.hash);
+       oidcpy(oid, &o->oid);
        if (sp[0] == '/') {
                /* "$commit^{/foo}" */
                char *prefix;
@@ -894,17 +894,17 @@ static int peel_onion(const char *name, int len, unsigned char *sha1,
 
                prefix = xstrndup(sp + 1, name + len - 1 - (sp + 1));
                commit_list_insert((struct commit *)o, &list);
-               ret = get_sha1_oneline(prefix, sha1, list);
+               ret = get_oid_oneline(prefix, oid, list);
                free(prefix);
                return ret;
        }
        return 0;
 }
 
-static int get_describe_name(const char *name, int len, unsigned char *sha1)
+static int get_describe_name(const char *name, int len, struct object_id *oid)
 {
        const char *cp;
-       unsigned flags = GET_SHA1_QUIETLY | GET_SHA1_COMMIT;
+       unsigned flags = GET_OID_QUIETLY | GET_OID_COMMIT;
 
        for (cp = name + len - 1; name + 2 <= cp; cp--) {
                char ch = *cp;
@@ -915,14 +915,14 @@ static int get_describe_name(const char *name, int len, unsigned char *sha1)
                        if (ch == 'g' && cp[-1] == '-') {
                                cp++;
                                len -= cp - name;
-                               return get_short_sha1(cp, len, sha1, flags);
+                               return get_short_oid(cp, len, oid, flags);
                        }
                }
        }
        return -1;
 }
 
-static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned lookup_flags)
+static int get_oid_1(const char *name, int len, struct object_id *oid, unsigned lookup_flags)
 {
        int ret, has_suffix;
        const char *cp;
@@ -949,25 +949,25 @@ static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned l
                if (!num && len1 == len - 1)
                        num = 1;
                if (has_suffix == '^')
-                       return get_parent(name, len1, sha1, num);
+                       return get_parent(name, len1, oid, num);
                /* else if (has_suffix == '~') -- goes without saying */
-               return get_nth_ancestor(name, len1, sha1, num);
+               return get_nth_ancestor(name, len1, oid, num);
        }
 
-       ret = peel_onion(name, len, sha1, lookup_flags);
+       ret = peel_onion(name, len, oid, lookup_flags);
        if (!ret)
                return 0;
 
-       ret = get_sha1_basic(name, len, sha1, lookup_flags);
+       ret = get_oid_basic(name, len, oid, lookup_flags);
        if (!ret)
                return 0;
 
        /* It could be describe output that is "SOMETHING-gXXXX" */
-       ret = get_describe_name(name, len, sha1);
+       ret = get_describe_name(name, len, oid);
        if (!ret)
                return 0;
 
-       return get_short_sha1(name, len, sha1, lookup_flags);
+       return get_short_oid(name, len, oid, lookup_flags);
 }
 
 /*
@@ -1004,7 +1004,7 @@ static int handle_one_ref(const char *path, const struct object_id *oid,
        return 0;
 }
 
-static int get_sha1_oneline(const char *prefix, unsigned char *sha1,
+static int get_oid_oneline(const char *prefix, struct object_id *oid,
                            struct commit_list *list)
 {
        struct commit_list *backup = NULL, *l;
@@ -1044,7 +1044,7 @@ static int get_sha1_oneline(const char *prefix, unsigned char *sha1,
                unuse_commit_buffer(commit, buf);
 
                if (matches) {
-                       hashcpy(sha1, commit->object.oid.hash);
+                       oidcpy(oid, &commit->object.oid);
                        found = 1;
                        break;
                }
@@ -1140,7 +1140,7 @@ int get_oid_mb(const char *name, struct object_id *oid)
                struct strbuf sb;
                strbuf_init(&sb, dots - name);
                strbuf_add(&sb, name, dots - name);
-               st = get_sha1_committish(sb.buf, oid_tmp.hash);
+               st = get_oid_committish(sb.buf, &oid_tmp);
                strbuf_release(&sb);
        }
        if (st)
@@ -1149,7 +1149,7 @@ int get_oid_mb(const char *name, struct object_id *oid)
        if (!one)
                return -1;
 
-       if (get_sha1_committish(dots[3] ? (dots + 3) : "HEAD", oid_tmp.hash))
+       if (get_oid_committish(dots[3] ? (dots + 3) : "HEAD", &oid_tmp))
                return -1;
        two = lookup_commit_reference_gently(&oid_tmp, 0);
        if (!two)
@@ -1338,21 +1338,13 @@ int strbuf_check_branch_ref(struct strbuf *sb, const char *name)
 }
 
 /*
- * This is like "get_sha1_basic()", except it allows "sha1 expressions",
+ * This is like "get_oid_basic()", except it allows "object ID expressions",
  * notably "xyz^" for "parent of xyz"
  */
-int get_sha1(const char *name, unsigned char *sha1)
-{
-       struct object_context unused;
-       return get_sha1_with_context(name, 0, sha1, &unused);
-}
-
-/*
- * This is like "get_sha1()", but for struct object_id.
- */
 int get_oid(const char *name, struct object_id *oid)
 {
-       return get_sha1(name, oid->hash);
+       struct object_context unused;
+       return get_oid_with_context(name, 0, oid, &unused);
 }
 
 
@@ -1366,49 +1358,49 @@ int get_oid(const char *name, struct object_id *oid)
  * commit-ish. It is merely to give a hint to the disambiguation
  * machinery.
  */
-int get_sha1_committish(const char *name, unsigned char *sha1)
+int get_oid_committish(const char *name, struct object_id *oid)
 {
        struct object_context unused;
-       return get_sha1_with_context(name, GET_SHA1_COMMITTISH,
-                                    sha1, &unused);
+       return get_oid_with_context(name, GET_OID_COMMITTISH,
+                                   oid, &unused);
 }
 
-int get_sha1_treeish(const char *name, unsigned char *sha1)
+int get_oid_treeish(const char *name, struct object_id *oid)
 {
        struct object_context unused;
-       return get_sha1_with_context(name, GET_SHA1_TREEISH,
-                                    sha1, &unused);
+       return get_oid_with_context(name, GET_OID_TREEISH,
+                                   oid, &unused);
 }
 
-int get_sha1_commit(const char *name, unsigned char *sha1)
+int get_oid_commit(const char *name, struct object_id *oid)
 {
        struct object_context unused;
-       return get_sha1_with_context(name, GET_SHA1_COMMIT,
-                                    sha1, &unused);
+       return get_oid_with_context(name, GET_OID_COMMIT,
+                                   oid, &unused);
 }
 
-int get_sha1_tree(const char *name, unsigned char *sha1)
+int get_oid_tree(const char *name, struct object_id *oid)
 {
        struct object_context unused;
-       return get_sha1_with_context(name, GET_SHA1_TREE,
-                                    sha1, &unused);
+       return get_oid_with_context(name, GET_OID_TREE,
+                                   oid, &unused);
 }
 
-int get_sha1_blob(const char *name, unsigned char *sha1)
+int get_oid_blob(const char *name, struct object_id *oid)
 {
        struct object_context unused;
-       return get_sha1_with_context(name, GET_SHA1_BLOB,
-                                    sha1, &unused);
+       return get_oid_with_context(name, GET_OID_BLOB,
+                                   oid, &unused);
 }
 
 /* Must be called only when object_name:filename doesn't exist. */
-static void diagnose_invalid_sha1_path(const char *prefix,
-                                      const char *filename,
-                                      const unsigned char *tree_sha1,
-                                      const char *object_name,
-                                      int object_name_len)
+static void diagnose_invalid_oid_path(const char *prefix,
+                                     const char *filename,
+                                     const struct object_id *tree_oid,
+                                     const char *object_name,
+                                     int object_name_len)
 {
-       unsigned char sha1[20];
+       struct object_id oid;
        unsigned mode;
 
        if (!prefix)
@@ -1420,8 +1412,8 @@ static void diagnose_invalid_sha1_path(const char *prefix,
        if (is_missing_file_error(errno)) {
                char *fullname = xstrfmt("%s%s", prefix, filename);
 
-               if (!get_tree_entry(tree_sha1, fullname,
-                                   sha1, &mode)) {
+               if (!get_tree_entry(tree_oid->hash, fullname,
+                                   oid.hash, &mode)) {
                        die("Path '%s' exists, but not '%s'.\n"
                            "Did you mean '%.*s:%s' aka '%.*s:./%s'?",
                            fullname,
@@ -1504,24 +1496,24 @@ static char *resolve_relative_path(const char *rel)
                           rel);
 }
 
-static int get_sha1_with_context_1(const char *name,
-                                  unsigned flags,
-                                  const char *prefix,
-                                  unsigned char *sha1,
-                                  struct object_context *oc)
+static int get_oid_with_context_1(const char *name,
+                                 unsigned flags,
+                                 const char *prefix,
+                                 struct object_id *oid,
+                                 struct object_context *oc)
 {
        int ret, bracket_depth;
        int namelen = strlen(name);
        const char *cp;
-       int only_to_die = flags & GET_SHA1_ONLY_TO_DIE;
+       int only_to_die = flags & GET_OID_ONLY_TO_DIE;
 
        if (only_to_die)
-               flags |= GET_SHA1_QUIETLY;
+               flags |= GET_OID_QUIETLY;
 
        memset(oc, 0, sizeof(*oc));
        oc->mode = S_IFINVALID;
        strbuf_init(&oc->symlink_path, 0);
-       ret = get_sha1_1(name, namelen, sha1, flags);
+       ret = get_oid_1(name, namelen, oid, flags);
        if (!ret)
                return ret;
        /*
@@ -1541,7 +1533,7 @@ static int get_sha1_with_context_1(const char *name,
 
                        for_each_ref(handle_one_ref, &list);
                        commit_list_sort_by_date(&list);
-                       return get_sha1_oneline(name + 2, sha1, list);
+                       return get_oid_oneline(name + 2, oid, list);
                }
                if (namelen < 3 ||
                    name[2] != ':' ||
@@ -1559,7 +1551,7 @@ static int get_sha1_with_context_1(const char *name,
                        namelen = strlen(cp);
                }
 
-               if (flags & GET_SHA1_RECORD_PATH)
+               if (flags & GET_OID_RECORD_PATH)
                        oc->path = xstrdup(cp);
 
                if (!active_cache)
@@ -1573,7 +1565,7 @@ static int get_sha1_with_context_1(const char *name,
                            memcmp(ce->name, cp, namelen))
                                break;
                        if (ce_stage(ce) == stage) {
-                               hashcpy(sha1, ce->oid.hash);
+                               oidcpy(oid, &ce->oid);
                                oc->mode = ce->ce_mode;
                                free(new_path);
                                return 0;
@@ -1594,36 +1586,36 @@ static int get_sha1_with_context_1(const char *name,
                        break;
        }
        if (*cp == ':') {
-               unsigned char tree_sha1[20];
+               struct object_id tree_oid;
                int len = cp - name;
                unsigned sub_flags = flags;
 
-               sub_flags &= ~GET_SHA1_DISAMBIGUATORS;
-               sub_flags |= GET_SHA1_TREEISH;
+               sub_flags &= ~GET_OID_DISAMBIGUATORS;
+               sub_flags |= GET_OID_TREEISH;
 
-               if (!get_sha1_1(name, len, tree_sha1, sub_flags)) {
+               if (!get_oid_1(name, len, &tree_oid, sub_flags)) {
                        const char *filename = cp+1;
                        char *new_filename = NULL;
 
                        new_filename = resolve_relative_path(filename);
                        if (new_filename)
                                filename = new_filename;
-                       if (flags & GET_SHA1_FOLLOW_SYMLINKS) {
-                               ret = get_tree_entry_follow_symlinks(tree_sha1,
-                                       filename, sha1, &oc->symlink_path,
+                       if (flags & GET_OID_FOLLOW_SYMLINKS) {
+                               ret = get_tree_entry_follow_symlinks(tree_oid.hash,
+                                       filename, oid->hash, &oc->symlink_path,
                                        &oc->mode);
                        } else {
-                               ret = get_tree_entry(tree_sha1, filename,
-                                                    sha1, &oc->mode);
+                               ret = get_tree_entry(tree_oid.hash, filename,
+                                                    oid->hash, &oc->mode);
                                if (ret && only_to_die) {
-                                       diagnose_invalid_sha1_path(prefix,
+                                       diagnose_invalid_oid_path(prefix,
                                                                   filename,
-                                                                  tree_sha1,
+                                                                  &tree_oid,
                                                                   name, len);
                                }
                        }
-                       hashcpy(oc->tree, tree_sha1);
-                       if (flags & GET_SHA1_RECORD_PATH)
+                       hashcpy(oc->tree, tree_oid.hash);
+                       if (flags & GET_OID_RECORD_PATH)
                                oc->path = xstrdup(filename);
 
                        free(new_filename);
@@ -1646,13 +1638,13 @@ static int get_sha1_with_context_1(const char *name,
 void maybe_die_on_misspelt_object_name(const char *name, const char *prefix)
 {
        struct object_context oc;
-       unsigned char sha1[20];
-       get_sha1_with_context_1(name, GET_SHA1_ONLY_TO_DIE, prefix, sha1, &oc);
+       struct object_id oid;
+       get_oid_with_context_1(name, GET_OID_ONLY_TO_DIE, prefix, &oid, &oc);
 }
 
-int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *oc)
+int get_oid_with_context(const char *str, unsigned flags, struct object_id *oid, struct object_context *oc)
 {
-       if (flags & GET_SHA1_FOLLOW_SYMLINKS && flags & GET_SHA1_ONLY_TO_DIE)
+       if (flags & GET_OID_FOLLOW_SYMLINKS && flags & GET_OID_ONLY_TO_DIE)
                die("BUG: incompatible flags for get_sha1_with_context");
-       return get_sha1_with_context_1(str, flags, NULL, sha1, oc);
+       return get_oid_with_context_1(str, flags, NULL, oid, oc);
 }
index 54359d549075b5cfe1670ca979ff3cf5eeedc9d1..f5591e56dab67d6113deb8196c4a68c8af3f2ee0 100644 (file)
--- a/shallow.c
+++ b/shallow.c
@@ -107,7 +107,7 @@ struct commit_list *get_shallow_commits(struct object_array *heads, int depth,
                cur_depth++;
                if ((depth != INFINITE_DEPTH && cur_depth >= depth) ||
                    (is_repository_shallow() && !commit->parents &&
-                    (graft = lookup_commit_graft(commit->object.oid.hash)) != NULL &&
+                    (graft = lookup_commit_graft(&commit->object.oid)) != NULL &&
                     graft->nr_parent < 0)) {
                        commit_list_insert(commit, &result);
                        commit->object.flags |= shallow_flag;
@@ -398,7 +398,7 @@ void prepare_shallow_info(struct shallow_info *info, struct oid_array *sa)
        for (i = 0; i < sa->nr; i++) {
                if (has_object_file(sa->oid + i)) {
                        struct commit_graft *graft;
-                       graft = lookup_commit_graft(sa->oid[i].hash);
+                       graft = lookup_commit_graft(&sa->oid[i]);
                        if (graft && graft->nr_parent < 0)
                                continue;
                        info->ours[info->nr_ours++] = i;
index 2075384e0b2df97a6d113acebcbcdcc853237166..e705b94db55578aabb2063f7364220978cea5a40 100644 (file)
--- a/strbuf.h
+++ b/strbuf.h
@@ -68,7 +68,7 @@ struct strbuf {
 };
 
 extern char strbuf_slopbuf[];
-#define STRBUF_INIT  { 0, 0, strbuf_slopbuf }
+#define STRBUF_INIT  { .alloc = 0, .len = 0, .buf = strbuf_slopbuf }
 
 /**
  * Life Cycle Functions
index c650500c6e51d983dc45a4be3b8dad98f1dece92..806b4c87232fb2ed307f6ce64817e14feefc216f 100644 (file)
@@ -43,9 +43,8 @@ static int add_entry(int insert_at, struct string_list *list, const char *string
 
        ALLOC_GROW(list->items, list->nr+1, list->alloc);
        if (index < list->nr)
-               memmove(list->items + index + 1, list->items + index,
-                               (list->nr - index)
-                               * sizeof(struct string_list_item));
+               MOVE_ARRAY(list->items + index + 1, list->items + index,
+                          list->nr - index);
        list->items[index].string = list->strdup_strings ?
                xstrdup(string) : (char *)string;
        list->items[index].util = NULL;
@@ -77,8 +76,7 @@ void string_list_remove(struct string_list *list, const char *string,
                        free(list->items[i].util);
 
                list->nr--;
-               memmove(list->items + i, list->items + i + 1,
-                       (list->nr - i) * sizeof(struct string_list_item));
+               MOVE_ARRAY(list->items + i, list->items + i + 1, list->nr - i);
        }
 }
 
index a3cfab1a9d1feb1fea3fbc9bb9dbe04a89b9c874..6edb97c1c68c063216bda710d5880b1d08de27da 100644 (file)
@@ -6,10 +6,13 @@
 #include "pkt-line.h"
 
 int cmd2process_cmp(const void *unused_cmp_data,
-                   const struct subprocess_entry *e1,
-                   const struct subprocess_entry *e2,
+                   const void *entry,
+                   const void *entry_or_key,
                    const void *unused_keydata)
 {
+       const struct subprocess_entry *e1 = entry;
+       const struct subprocess_entry *e2 = entry_or_key;
+
        return strcmp(e1->cmd, e2->cmd);
 }
 
@@ -105,3 +108,107 @@ int subprocess_start(struct hashmap *hashmap, struct subprocess_entry *entry, co
        hashmap_add(hashmap, entry);
        return 0;
 }
+
+static int handshake_version(struct child_process *process,
+                            const char *welcome_prefix, int *versions,
+                            int *chosen_version)
+{
+       int version_scratch;
+       int i;
+       char *line;
+       const char *p;
+
+       if (!chosen_version)
+               chosen_version = &version_scratch;
+
+       if (packet_write_fmt_gently(process->in, "%s-client\n",
+                                   welcome_prefix))
+               return error("Could not write client identification");
+       for (i = 0; versions[i]; i++) {
+               if (packet_write_fmt_gently(process->in, "version=%d\n",
+                                           versions[i]))
+                       return error("Could not write requested version");
+       }
+       if (packet_flush_gently(process->in))
+               return error("Could not write flush packet");
+
+       if (!(line = packet_read_line(process->out, NULL)) ||
+           !skip_prefix(line, welcome_prefix, &p) ||
+           strcmp(p, "-server"))
+               return error("Unexpected line '%s', expected %s-server",
+                            line ? line : "<flush packet>", welcome_prefix);
+       if (!(line = packet_read_line(process->out, NULL)) ||
+           !skip_prefix(line, "version=", &p) ||
+           strtol_i(p, 10, chosen_version))
+               return error("Unexpected line '%s', expected version",
+                            line ? line : "<flush packet>");
+       if ((line = packet_read_line(process->out, NULL)))
+               return error("Unexpected line '%s', expected flush", line);
+
+       /* Check to make sure that the version received is supported */
+       for (i = 0; versions[i]; i++) {
+               if (versions[i] == *chosen_version)
+                       break;
+       }
+       if (!versions[i])
+               return error("Version %d not supported", *chosen_version);
+
+       return 0;
+}
+
+static int handshake_capabilities(struct child_process *process,
+                                 struct subprocess_capability *capabilities,
+                                 unsigned int *supported_capabilities)
+{
+       int i;
+       char *line;
+
+       for (i = 0; capabilities[i].name; i++) {
+               if (packet_write_fmt_gently(process->in, "capability=%s\n",
+                                           capabilities[i].name))
+                       return error("Could not write requested capability");
+       }
+       if (packet_flush_gently(process->in))
+               return error("Could not write flush packet");
+
+       while ((line = packet_read_line(process->out, NULL))) {
+               const char *p;
+               if (!skip_prefix(line, "capability=", &p))
+                       continue;
+
+               for (i = 0;
+                    capabilities[i].name && strcmp(p, capabilities[i].name);
+                    i++)
+                       ;
+               if (capabilities[i].name) {
+                       if (supported_capabilities)
+                               *supported_capabilities |= capabilities[i].flag;
+               } else {
+                       warning("external filter requested unsupported filter capability '%s'",
+                               p);
+               }
+       }
+
+       return 0;
+}
+
+int subprocess_handshake(struct subprocess_entry *entry,
+                        const char *welcome_prefix,
+                        int *versions,
+                        int *chosen_version,
+                        struct subprocess_capability *capabilities,
+                        unsigned int *supported_capabilities)
+{
+       int retval;
+       struct child_process *process = &entry->process;
+
+       sigchain_push(SIGPIPE, SIG_IGN);
+
+       retval = handshake_version(process, welcome_prefix, versions,
+                                  chosen_version) ||
+                handshake_capabilities(process, capabilities,
+                                       supported_capabilities);
+
+       sigchain_pop(SIGPIPE);
+       return retval;
+}
index 96a2cca360c5660fb8e72c684dc4c25e96ba0546..49701998c9bd663073244e64c4edd7e80991a3ef 100644 (file)
@@ -6,41 +6,88 @@
 #include "run-command.h"
 
 /*
- * Generic implementation of background process infrastructure.
- * See: Documentation/technical/api-sub-process.txt
+ * The sub-process API makes it possible to run background sub-processes
+ * for the entire lifetime of a Git invocation. If Git needs to communicate
+ * with an external process multiple times, then this can reduces the process
+ * invocation overhead. Git and the sub-process communicate through stdin and
+ * stdout.
+ *
+ * The sub-processes are kept in a hashmap by command name and looked up
+ * via the subprocess_find_entry function.  If an existing instance can not
+ * be found then a new process should be created and started.  When the
+ * parent git command terminates, all sub-processes are also terminated.
+ *
+ * This API is based on the run-command API.
  */
 
  /* data structures */
 
+/* Members should not be accessed directly. */
 struct subprocess_entry {
        struct hashmap_entry ent; /* must be the first member! */
        const char *cmd;
        struct child_process process;
 };
 
+struct subprocess_capability {
+       const char *name;
+
+       /*
+        * subprocess_handshake will "|=" this value to supported_capabilities
+        * if the server reports that it supports this capability.
+        */
+       unsigned int flag;
+};
+
 /* subprocess functions */
 
+/* Function to test two subprocess hashmap entries for equality. */
 extern int cmd2process_cmp(const void *unused_cmp_data,
-                          const struct subprocess_entry *e1,
-                          const struct subprocess_entry *e2,
+                          const void *e1,
+                          const void *e2,
                           const void *unused_keydata);
 
+/*
+ * User-supplied function to initialize the sub-process.  This is
+ * typically used to negotiate the interface version and capabilities.
+ */
 typedef int(*subprocess_start_fn)(struct subprocess_entry *entry);
+
+/* Start a subprocess and add it to the subprocess hashmap. */
 int subprocess_start(struct hashmap *hashmap, struct subprocess_entry *entry, const char *cmd,
                subprocess_start_fn startfn);
 
+/* Kill a subprocess and remove it from the subprocess hashmap. */
 void subprocess_stop(struct hashmap *hashmap, struct subprocess_entry *entry);
 
+/* Find a subprocess in the subprocess hashmap. */
 struct subprocess_entry *subprocess_find_entry(struct hashmap *hashmap, const char *cmd);
 
 /* subprocess helper functions */
 
+/* Get the underlying `struct child_process` from a subprocess. */
 static inline struct child_process *subprocess_get_child_process(
                struct subprocess_entry *entry)
 {
        return &entry->process;
 }
 
+/*
+ * Perform the version and capability negotiation as described in the "Long
+ * Running Filter Process" section of the gitattributes documentation using the
+ * given requested versions and capabilities. The "versions" and "capabilities"
+ * parameters are arrays terminated by a 0 or blank struct.
+ *
+ * This function is typically called when a subprocess is started (as part of
+ * the "startfn" passed to subprocess_start).
+ */
+int subprocess_handshake(struct subprocess_entry *entry,
+                        const char *welcome_prefix,
+                        int *versions,
+                        int *chosen_version,
+                        struct subprocess_capability *capabilities,
+                        unsigned int *supported_capabilities);
+
 /*
  * Helper function that will read packets looking for "status=<foo>"
  * key/value pairs and return the value from the last "status" packet
index 5fe2d0787745de4d97218c738b808667dc8348d3..bede338c8539f18081168bacd0b562a927e9532c 100644 (file)
@@ -35,19 +35,25 @@ enum lookup_type {
 };
 
 static int config_path_cmp(const void *unused_cmp_data,
-                          const struct submodule_entry *a,
-                          const struct submodule_entry *b,
+                          const void *entry,
+                          const void *entry_or_key,
                           const void *unused_keydata)
 {
+       const struct submodule_entry *a = entry;
+       const struct submodule_entry *b = entry_or_key;
+
        return strcmp(a->config->path, b->config->path) ||
               hashcmp(a->config->gitmodules_sha1, b->config->gitmodules_sha1);
 }
 
 static int config_name_cmp(const void *unused_cmp_data,
-                          const struct submodule_entry *a,
-                          const struct submodule_entry *b,
+                          const void *entry,
+                          const void *entry_or_key,
                           const void *unused_keydata)
 {
+       const struct submodule_entry *a = entry;
+       const struct submodule_entry *b = entry_or_key;
+
        return strcmp(a->config->name, b->config->name) ||
               hashcmp(a->config->gitmodules_sha1, b->config->gitmodules_sha1);
 }
@@ -59,8 +65,8 @@ static struct submodule_cache *submodule_cache_alloc(void)
 
 static void submodule_cache_init(struct submodule_cache *cache)
 {
-       hashmap_init(&cache->for_path, (hashmap_cmp_fn) config_path_cmp, NULL, 0);
-       hashmap_init(&cache->for_name, (hashmap_cmp_fn) config_name_cmp, NULL, 0);
+       hashmap_init(&cache->for_path, config_path_cmp, NULL, 0);
+       hashmap_init(&cache->for_name, config_name_cmp, NULL, 0);
        cache->initialized = 1;
 }
 
@@ -441,19 +447,19 @@ static int parse_config(const char *var, const char *value, void *data)
        return ret;
 }
 
-int gitmodule_sha1_from_commit(const unsigned char *treeish_name,
-                                     unsigned char *gitmodules_sha1,
+int gitmodule_oid_from_commit(const struct object_id *treeish_name,
+                                     struct object_id *gitmodules_oid,
                                      struct strbuf *rev)
 {
        int ret = 0;
 
-       if (is_null_sha1(treeish_name)) {
-               hashclr(gitmodules_sha1);
+       if (is_null_oid(treeish_name)) {
+               oidclr(gitmodules_oid);
                return 1;
        }
 
-       strbuf_addf(rev, "%s:.gitmodules", sha1_to_hex(treeish_name));
-       if (get_sha1(rev->buf, gitmodules_sha1) >= 0)
+       strbuf_addf(rev, "%s:.gitmodules", oid_to_hex(treeish_name));
+       if (get_oid(rev->buf, gitmodules_oid) >= 0)
                ret = 1;
 
        return ret;
@@ -464,13 +470,13 @@ int gitmodule_sha1_from_commit(const unsigned char *treeish_name,
  * revisions.
  */
 static const struct submodule *config_from(struct submodule_cache *cache,
-               const unsigned char *treeish_name, const char *key,
+               const struct object_id *treeish_name, const char *key,
                enum lookup_type lookup_type)
 {
        struct strbuf rev = STRBUF_INIT;
        unsigned long config_size;
        char *config = NULL;
-       unsigned char sha1[20];
+       struct object_id oid;
        enum object_type type;
        const struct submodule *submodule = NULL;
        struct parse_config_parameter parameter;
@@ -490,28 +496,28 @@ static const struct submodule *config_from(struct submodule_cache *cache,
                return entry->config;
        }
 
-       if (!gitmodule_sha1_from_commit(treeish_name, sha1, &rev))
+       if (!gitmodule_oid_from_commit(treeish_name, &oid, &rev))
                goto out;
 
        switch (lookup_type) {
        case lookup_name:
-               submodule = cache_lookup_name(cache, sha1, key);
+               submodule = cache_lookup_name(cache, oid.hash, key);
                break;
        case lookup_path:
-               submodule = cache_lookup_path(cache, sha1, key);
+               submodule = cache_lookup_path(cache, oid.hash, key);
                break;
        }
        if (submodule)
                goto out;
 
-       config = read_sha1_file(sha1, &type, &config_size);
+       config = read_sha1_file(oid.hash, &type, &config_size);
        if (!config || type != OBJ_BLOB)
                goto out;
 
        /* fill the submodule config into the cache */
        parameter.cache = cache;
-       parameter.treeish_name = treeish_name;
-       parameter.gitmodules_sha1 = sha1;
+       parameter.treeish_name = treeish_name->hash;
+       parameter.gitmodules_sha1 = oid.hash;
        parameter.overwrite = 0;
        git_config_from_mem(parse_config, CONFIG_ORIGIN_SUBMODULE_BLOB, rev.buf,
                        config, config_size, &parameter);
@@ -520,9 +526,9 @@ static const struct submodule *config_from(struct submodule_cache *cache,
 
        switch (lookup_type) {
        case lookup_name:
-               return cache_lookup_name(cache, sha1, key);
+               return cache_lookup_name(cache, oid.hash, key);
        case lookup_path:
-               return cache_lookup_path(cache, sha1, key);
+               return cache_lookup_path(cache, oid.hash, key);
        default:
                return NULL;
        }
@@ -564,14 +570,14 @@ int parse_submodule_config_option(const char *var, const char *value)
        return submodule_config_option(the_repository, var, value);
 }
 
-const struct submodule *submodule_from_name(const unsigned char *treeish_name,
+const struct submodule *submodule_from_name(const struct object_id *treeish_name,
                const char *name)
 {
        submodule_cache_check_init(the_repository);
        return config_from(the_repository->submodule_cache, treeish_name, name, lookup_name);
 }
 
-const struct submodule *submodule_from_path(const unsigned char *treeish_name,
+const struct submodule *submodule_from_path(const struct object_id *treeish_name,
                const char *path)
 {
        submodule_cache_check_init(the_repository);
@@ -579,7 +585,7 @@ const struct submodule *submodule_from_path(const unsigned char *treeish_name,
 }
 
 const struct submodule *submodule_from_cache(struct repository *repo,
-                                            const unsigned char *treeish_name,
+                                            const struct object_id *treeish_name,
                                             const char *key)
 {
        submodule_cache_check_init(repo);
index 233bfcb7fff0b2dedc64fbb11d167734bf0fad7e..4ffa2fa840a5fc27ac209a2e976b118b15b124ef 100644 (file)
@@ -37,15 +37,15 @@ extern int parse_submodule_config_option(const char *var, const char *value);
 extern int submodule_config_option(struct repository *repo,
                                   const char *var, const char *value);
 extern const struct submodule *submodule_from_name(
-               const unsigned char *commit_or_tree, const char *name);
+               const struct object_id *commit_or_tree, const char *name);
 extern const struct submodule *submodule_from_path(
-               const unsigned char *commit_or_tree, const char *path);
+               const struct object_id *commit_or_tree, const char *path);
 extern const struct submodule *submodule_from_cache(struct repository *repo,
-                                                   const unsigned char *treeish_name,
+                                                   const struct object_id *treeish_name,
                                                    const char *key);
-extern int gitmodule_sha1_from_commit(const unsigned char *commit_sha1,
-                                     unsigned char *gitmodules_sha1,
-                                     struct strbuf *rev);
+extern int gitmodule_oid_from_commit(const struct object_id *commit_oid,
+                                    struct object_id *gitmodules_oid,
+                                    struct strbuf *rev);
 extern void submodule_free(void);
 
 #endif /* SUBMODULE_CONFIG_H */
index 6531c5d6094e47b251e69ce741699abfee7a64df..27de65a4a04a45c75479ae60d43dfdab0cf6d1aa 100644 (file)
@@ -69,7 +69,7 @@ int update_path_in_gitmodules(const char *oldpath, const char *newpath)
        if (gitmodules_is_unmerged)
                die(_("Cannot change unmerged .gitmodules, resolve merge conflicts first"));
 
-       submodule = submodule_from_path(null_sha1, oldpath);
+       submodule = submodule_from_path(&null_oid, oldpath);
        if (!submodule || !submodule->name) {
                warning(_("Could not find section in .gitmodules where path=%s"), oldpath);
                return -1;
@@ -103,7 +103,7 @@ int remove_path_from_gitmodules(const char *path)
        if (gitmodules_is_unmerged)
                die(_("Cannot change unmerged .gitmodules, resolve merge conflicts first"));
 
-       submodule = submodule_from_path(null_sha1, path);
+       submodule = submodule_from_path(&null_oid, path);
        if (!submodule || !submodule->name) {
                warning(_("Could not find section in .gitmodules where path=%s"), path);
                return -1;
@@ -147,7 +147,7 @@ static int add_submodule_odb(const char *path)
 void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,
                                             const char *path)
 {
-       const struct submodule *submodule = submodule_from_path(null_sha1, path);
+       const struct submodule *submodule = submodule_from_path(&null_oid, path);
        if (submodule) {
                if (submodule->ignore)
                        handle_ignore_submodules_arg(diffopt, submodule->ignore);
@@ -270,14 +270,14 @@ void repo_read_gitmodules(struct repository *repo)
        free(gitmodules_path);
 }
 
-void gitmodules_config_sha1(const unsigned char *commit_sha1)
+void gitmodules_config_oid(const struct object_id *commit_oid)
 {
        struct strbuf rev = STRBUF_INIT;
-       unsigned char sha1[20];
+       struct object_id oid;
 
-       if (gitmodule_sha1_from_commit(commit_sha1, sha1, &rev)) {
-               git_config_from_blob_sha1(git_modules_config, rev.buf,
-                                         sha1, NULL);
+       if (gitmodule_oid_from_commit(commit_oid, &oid, &rev)) {
+               git_config_from_blob_oid(submodule_config, rev.buf,
+                                        &oid, NULL);
        }
        strbuf_release(&rev);
 }
@@ -293,7 +293,7 @@ int is_submodule_active(struct repository *repo, const char *path)
        const struct string_list *sl;
        const struct submodule *module;
 
-       module = submodule_from_cache(repo, null_sha1, path);
+       module = submodule_from_cache(repo, &null_oid, path);
 
        /* early return if there isn't a path->module mapping */
        if (!module)
@@ -738,7 +738,7 @@ const struct submodule *submodule_from_ce(const struct cache_entry *ce)
        if (!should_update_submodules())
                return NULL;
 
-       return submodule_from_path(null_sha1, ce->name);
+       return submodule_from_path(&null_oid, ce->name);
 }
 
 static struct oid_array *submodule_commits(struct string_list *submodules,
@@ -1192,9 +1192,9 @@ static int get_next_submodule(struct child_process *cp,
                if (!S_ISGITLINK(ce->ce_mode))
                        continue;
 
-               submodule = submodule_from_path(null_sha1, ce->name);
+               submodule = submodule_from_path(&null_oid, ce->name);
                if (!submodule)
-                       submodule = submodule_from_name(null_sha1, ce->name);
+                       submodule = submodule_from_name(&null_oid, ce->name);
 
                default_argv = "yes";
                if (spf->command_line_option == RECURSE_SUBMODULES_DEFAULT) {
@@ -1570,7 +1570,7 @@ int submodule_move_head(const char *path,
        if (old && !is_submodule_populated_gently(path, error_code_ptr))
                return 0;
 
-       sub = submodule_from_path(null_sha1, path);
+       sub = submodule_from_path(&null_oid, path);
 
        if (!sub)
                die("BUG: could not get submodule information for '%s'", path);
@@ -1852,7 +1852,7 @@ static void relocate_single_git_dir_into_superproject(const char *prefix,
 
        real_old_git_dir = real_pathdup(old_git_dir, 1);
 
-       sub = submodule_from_path(null_sha1, path);
+       sub = submodule_from_path(&null_oid, path);
        if (!sub)
                die(_("could not lookup name for submodule '%s'"), path);
 
@@ -1908,7 +1908,7 @@ void absorb_git_dir_into_superproject(const char *prefix,
                * superproject did not rewrite the git file links yet,
                * fix it now.
                */
-               sub = submodule_from_path(null_sha1, path);
+               sub = submodule_from_path(&null_oid, path);
                if (!sub)
                        die(_("could not lookup name for submodule '%s'"), path);
                connect_work_tree_and_git_dir(path,
@@ -2051,7 +2051,7 @@ int submodule_to_gitdir(struct strbuf *buf, const char *submodule)
        }
        if (!is_git_directory(buf->buf)) {
                gitmodules_config();
-               sub = submodule_from_path(null_sha1, submodule);
+               sub = submodule_from_path(&null_oid, submodule);
                if (!sub) {
                        ret = -1;
                        goto cleanup;
index e85b1448638ac7255a48a1bc1e2d6409c3a85ba6..f1aa3ffeb19e4e477295b66f85ab4cb85d24437e 100644 (file)
@@ -48,7 +48,7 @@ int option_parse_recurse_submodules_worktree_updater(const struct option *opt,
 void load_submodule_cache(void);
 extern void gitmodules_config(void);
 extern void repo_read_gitmodules(struct repository *repo);
-extern void gitmodules_config_sha1(const unsigned char *commit_sha1);
+extern void gitmodules_config_oid(const struct object_id *commit_oid);
 extern int is_submodule_active(struct repository *repo, const char *path);
 /*
  * Determine if a submodule has been populated at a given 'path' by checking if
index 095d7395f3c25d042c60095e8c56d8a22a9a0ba6..6004c81f0bce4d701a341c963f56caca425da067 100644 (file)
@@ -13,20 +13,20 @@ static const char *get_value(const struct test_entry *e)
        return e->key + strlen(e->key) + 1;
 }
 
-static int test_entry_cmp(const void *unused_cmp_data,
-                         const struct test_entry *e1,
-                         const struct test_entry *e2,
-                         const char* key)
+static int test_entry_cmp(const void *cmp_data,
+                         const void *entry,
+                         const void *entry_or_key,
+                         const void *keydata)
 {
-       return strcmp(e1->key, key ? key : e2->key);
-}
-
-static int test_entry_cmp_icase(const void *unused_cmp_data,
-                               const struct test_entry *e1,
-                               const struct test_entry *e2,
-                               const char* key)
-{
-       return strcasecmp(e1->key, key ? key : e2->key);
+       const int ignore_case = cmp_data ? *((int *)cmp_data) : 0;
+       const struct test_entry *e1 = entry;
+       const struct test_entry *e2 = entry_or_key;
+       const char *key = keydata;
+
+       if (ignore_case)
+               return strcasecmp(e1->key, key ? key : e2->key);
+       else
+               return strcmp(e1->key, key ? key : e2->key);
 }
 
 static struct test_entry *alloc_test_entry(int hash, char *key, int klen,
@@ -96,8 +96,7 @@ static void perf_hashmap(unsigned int method, unsigned int rounds)
        if (method & TEST_ADD) {
                /* test adding to the map */
                for (j = 0; j < rounds; j++) {
-                       hashmap_init(&map, (hashmap_cmp_fn) test_entry_cmp,
-                                    NULL, 0);
+                       hashmap_init(&map, test_entry_cmp, NULL, 0);
 
                        /* add entries */
                        for (i = 0; i < TEST_SIZE; i++) {
@@ -109,7 +108,7 @@ static void perf_hashmap(unsigned int method, unsigned int rounds)
                }
        } else {
                /* test map lookups */
-               hashmap_init(&map, (hashmap_cmp_fn) test_entry_cmp, NULL, 0);
+               hashmap_init(&map, test_entry_cmp, NULL, 0);
 
                /* fill the map (sparsely if specified) */
                j = (method & TEST_SPARSE) ? TEST_SIZE / 10 : TEST_SIZE;
@@ -151,8 +150,7 @@ int cmd_main(int argc, const char **argv)
 
        /* init hash map */
        icase = argc > 1 && !strcmp("ignorecase", argv[1]);
-       hashmap_init(&map, (hashmap_cmp_fn) (icase ? test_entry_cmp_icase
-                       : test_entry_cmp), NULL, 0);
+       hashmap_init(&map, test_entry_cmp, &icase, 0);
 
        /* process commands from stdin */
        while (fgets(line, sizeof(line), stdin)) {
index c6c57bba0d397e44e8897b05d479a30b53311517..e13fbcc1b5c271c1b2a4a2b3449544e844282358 100644 (file)
@@ -41,7 +41,7 @@ int cmd_main(int argc, const char **argv)
        git_config(git_test_config, NULL);
 
        while (*arg) {
-               unsigned char commit_sha1[20];
+               struct object_id commit_oid;
                const struct submodule *submodule;
                const char *commit;
                const char *path_or_name;
@@ -50,14 +50,14 @@ int cmd_main(int argc, const char **argv)
                path_or_name = arg[1];
 
                if (commit[0] == '\0')
-                       hashclr(commit_sha1);
-               else if (get_sha1(commit, commit_sha1) < 0)
+                       oidclr(&commit_oid);
+               else if (get_oid(commit, &commit_oid) < 0)
                        die_usage(argc, argv, "Commit not found.");
 
                if (lookup_name) {
-                       submodule = submodule_from_name(commit_sha1, path_or_name);
+                       submodule = submodule_from_name(&commit_oid, path_or_name);
                } else
-                       submodule = submodule_from_path(commit_sha1, path_or_name);
+                       submodule = submodule_from_path(&commit_oid, path_or_name);
                if (!submodule)
                        die_usage(argc, argv, "Submodule not found.");
 
index ec2aa8f6879d68078caeccaff25d89178b9fb902..43679a4c640e874aed8d3a378a378b1a6080fc1c 100755 (executable)
@@ -31,6 +31,7 @@ then
                chmod 0700 ./gpghome &&
                GNUPGHOME="$(pwd)/gpghome" &&
                export GNUPGHOME &&
+               (gpgconf --kill gpg-agent 2>&1 >/dev/null || : ) &&
                gpg --homedir "${GNUPGHOME}" 2>/dev/null --import \
                        "$TEST_DIRECTORY"/lib-gpg/keyring.gpg &&
                gpg --homedir "${GNUPGHOME}" 2>/dev/null --import-ownertrust \
index 02f49cb4097153f84d5e397b1801128e229c7909..83babe57d959005315ed0780caced285b440e8bc 100644 (file)
@@ -147,29 +147,33 @@ test_config () {
        # Test clone/fetch/push with protocol.allow user defined default
        test_expect_success "clone $desc (enabled)" '
                rm -rf tmp.git &&
-               git config --global protocol.allow always &&
+               test_config_global protocol.allow always &&
                git clone --bare "$url" tmp.git
        '
 
        test_expect_success "fetch $desc (enabled)" '
+               test_config_global protocol.allow always &&
                git -C tmp.git fetch
        '
 
        test_expect_success "push $desc (enabled)" '
+               test_config_global protocol.allow always &&
                git -C tmp.git push origin HEAD:pushed
        '
 
        test_expect_success "push $desc (disabled)" '
-               git config --global protocol.allow never &&
+               test_config_global protocol.allow never &&
                test_must_fail git -C tmp.git push origin HEAD:pushed
        '
 
        test_expect_success "fetch $desc (disabled)" '
+               test_config_global protocol.allow never &&
                test_must_fail git -C tmp.git fetch
        '
 
        test_expect_success "clone $desc (disabled)" '
                rm -rf tmp.git &&
+               test_config_global protocol.allow never &&
                test_must_fail git clone --bare "$url" tmp.git
        '
 }
index 161f5604464d2f963e60af54eedea3f91be041fa..46f8e583c37da7d03d715ea5cb1a4ee5bbe0ca28 100755 (executable)
@@ -28,7 +28,7 @@ file_size () {
 }
 
 filter_git () {
-       rm -f rot13-filter.log &&
+       rm -f *.log &&
        git "$@"
 }
 
@@ -42,10 +42,10 @@ test_cmp_count () {
        for FILE in "$expect" "$actual"
        do
                sort "$FILE" | uniq -c |
-               sed -e "s/^ *[0-9][0-9]*[       ]*IN: /x IN: /" >"$FILE.tmp" &&
-               mv "$FILE.tmp" "$FILE" || return
+               sed -e "s/^ *[0-9][0-9]*[       ]*IN: /x IN: /" >"$FILE.tmp"
        done &&
-       test_cmp "$expect" "$actual"
+       test_cmp "$expect.tmp" "$actual.tmp" &&
+       rm "$expect.tmp" "$actual.tmp"
 }
 
 # Compare two files but exclude all `clean` invocations because Git can
@@ -56,10 +56,10 @@ test_cmp_exclude_clean () {
        actual=$2
        for FILE in "$expect" "$actual"
        do
-               grep -v "IN: clean" "$FILE" >"$FILE.tmp" &&
-               mv "$FILE.tmp" "$FILE"
+               grep -v "IN: clean" "$FILE" >"$FILE.tmp"
        done &&
-       test_cmp "$expect" "$actual"
+       test_cmp "$expect.tmp" "$actual.tmp" &&
+       rm "$expect.tmp" "$actual.tmp"
 }
 
 # Check that the contents of two files are equal and that their rot13 version
@@ -342,7 +342,7 @@ test_expect_success 'diff does not reuse worktree files that need cleaning' '
 '
 
 test_expect_success PERL 'required process filter should filter data' '
-       test_config_global filter.protocol.process "rot13-filter.pl clean smudge" &&
+       test_config_global filter.protocol.process "rot13-filter.pl debug.log clean smudge" &&
        test_config_global filter.protocol.required true &&
        rm -rf repo &&
        mkdir repo &&
@@ -375,7 +375,7 @@ test_expect_success PERL 'required process filter should filter data' '
                        IN: clean testsubdir/test3 '\''sq'\'',\$x=.r $S3 [OK] -- OUT: $S3 . [OK]
                        STOP
                EOF
-               test_cmp_count expected.log rot13-filter.log &&
+               test_cmp_count expected.log debug.log &&
 
                git commit -m "test commit 2" &&
                rm -f test2.r "testsubdir/test3 '\''sq'\'',\$x=.r" &&
@@ -388,7 +388,7 @@ test_expect_success PERL 'required process filter should filter data' '
                        IN: smudge testsubdir/test3 '\''sq'\'',\$x=.r $S3 [OK] -- OUT: $S3 . [OK]
                        STOP
                EOF
-               test_cmp_exclude_clean expected.log rot13-filter.log &&
+               test_cmp_exclude_clean expected.log debug.log &&
 
                filter_git checkout --quiet --no-progress empty-branch &&
                cat >expected.log <<-EOF &&
@@ -397,7 +397,7 @@ test_expect_success PERL 'required process filter should filter data' '
                        IN: clean test.r $S [OK] -- OUT: $S . [OK]
                        STOP
                EOF
-               test_cmp_exclude_clean expected.log rot13-filter.log &&
+               test_cmp_exclude_clean expected.log debug.log &&
 
                filter_git checkout --quiet --no-progress master &&
                cat >expected.log <<-EOF &&
@@ -409,7 +409,7 @@ test_expect_success PERL 'required process filter should filter data' '
                        IN: smudge testsubdir/test3 '\''sq'\'',\$x=.r $S3 [OK] -- OUT: $S3 . [OK]
                        STOP
                EOF
-               test_cmp_exclude_clean expected.log rot13-filter.log &&
+               test_cmp_exclude_clean expected.log debug.log &&
 
                test_cmp_committed_rot13 "$TEST_ROOT/test.o" test.r &&
                test_cmp_committed_rot13 "$TEST_ROOT/test2.o" test2.r &&
@@ -419,7 +419,7 @@ test_expect_success PERL 'required process filter should filter data' '
 
 test_expect_success PERL 'required process filter takes precedence' '
        test_config_global filter.protocol.clean false &&
-       test_config_global filter.protocol.process "rot13-filter.pl clean" &&
+       test_config_global filter.protocol.process "rot13-filter.pl debug.log clean" &&
        test_config_global filter.protocol.required true &&
        rm -rf repo &&
        mkdir repo &&
@@ -439,12 +439,12 @@ test_expect_success PERL 'required process filter takes precedence' '
                        IN: clean test.r $S [OK] -- OUT: $S . [OK]
                        STOP
                EOF
-               test_cmp_count expected.log rot13-filter.log
+               test_cmp_count expected.log debug.log
        )
 '
 
 test_expect_success PERL 'required process filter should be used only for "clean" operation only' '
-       test_config_global filter.protocol.process "rot13-filter.pl clean" &&
+       test_config_global filter.protocol.process "rot13-filter.pl debug.log clean" &&
        rm -rf repo &&
        mkdir repo &&
        (
@@ -462,7 +462,7 @@ test_expect_success PERL 'required process filter should be used only for "clean
                        IN: clean test.r $S [OK] -- OUT: $S . [OK]
                        STOP
                EOF
-               test_cmp_count expected.log rot13-filter.log &&
+               test_cmp_count expected.log debug.log &&
 
                rm test.r &&
 
@@ -474,12 +474,12 @@ test_expect_success PERL 'required process filter should be used only for "clean
                        init handshake complete
                        STOP
                EOF
-               test_cmp_exclude_clean expected.log rot13-filter.log
+               test_cmp_exclude_clean expected.log debug.log
        )
 '
 
 test_expect_success PERL 'required process filter should process multiple packets' '
-       test_config_global filter.protocol.process "rot13-filter.pl clean smudge" &&
+       test_config_global filter.protocol.process "rot13-filter.pl debug.log clean smudge" &&
        test_config_global filter.protocol.required true &&
 
        rm -rf repo &&
@@ -514,7 +514,7 @@ test_expect_success PERL 'required process filter should process multiple packet
                        IN: clean 3pkt_2+1.file $(($S*2+1)) [OK] -- OUT: $(($S*2+1)) ... [OK]
                        STOP
                EOF
-               test_cmp_count expected.log rot13-filter.log &&
+               test_cmp_count expected.log debug.log &&
 
                rm -f *.file &&
 
@@ -529,7 +529,7 @@ test_expect_success PERL 'required process filter should process multiple packet
                        IN: smudge 3pkt_2+1.file $(($S*2+1)) [OK] -- OUT: $(($S*2+1)) ... [OK]
                        STOP
                EOF
-               test_cmp_exclude_clean expected.log rot13-filter.log &&
+               test_cmp_exclude_clean expected.log debug.log &&
 
                for FILE in *.file
                do
@@ -539,7 +539,7 @@ test_expect_success PERL 'required process filter should process multiple packet
 '
 
 test_expect_success PERL 'required process filter with clean error should fail' '
-       test_config_global filter.protocol.process "rot13-filter.pl clean smudge" &&
+       test_config_global filter.protocol.process "rot13-filter.pl debug.log clean smudge" &&
        test_config_global filter.protocol.required true &&
        rm -rf repo &&
        mkdir repo &&
@@ -558,7 +558,7 @@ test_expect_success PERL 'required process filter with clean error should fail'
 '
 
 test_expect_success PERL 'process filter should restart after unexpected write failure' '
-       test_config_global filter.protocol.process "rot13-filter.pl clean smudge" &&
+       test_config_global filter.protocol.process "rot13-filter.pl debug.log clean smudge" &&
        rm -rf repo &&
        mkdir repo &&
        (
@@ -579,7 +579,7 @@ test_expect_success PERL 'process filter should restart after unexpected write f
                git add . &&
                rm -f *.r &&
 
-               rm -f rot13-filter.log &&
+               rm -f debug.log &&
                git checkout --quiet --no-progress . 2>git-stderr.log &&
 
                grep "smudge write error at" git-stderr.log &&
@@ -588,14 +588,14 @@ test_expect_success PERL 'process filter should restart after unexpected write f
                cat >expected.log <<-EOF &&
                        START
                        init handshake complete
-                       IN: smudge smudge-write-fail.r $SF [OK] -- OUT: $SF [WRITE FAIL]
+                       IN: smudge smudge-write-fail.r $SF [OK] -- [WRITE FAIL]
                        START
                        init handshake complete
                        IN: smudge test.r $S [OK] -- OUT: $S . [OK]
                        IN: smudge test2.r $S2 [OK] -- OUT: $S2 . [OK]
                        STOP
                EOF
-               test_cmp_exclude_clean expected.log rot13-filter.log &&
+               test_cmp_exclude_clean expected.log debug.log &&
 
                test_cmp_committed_rot13 "$TEST_ROOT/test.o" test.r &&
                test_cmp_committed_rot13 "$TEST_ROOT/test2.o" test2.r &&
@@ -609,7 +609,7 @@ test_expect_success PERL 'process filter should restart after unexpected write f
 '
 
 test_expect_success PERL 'process filter should not be restarted if it signals an error' '
-       test_config_global filter.protocol.process "rot13-filter.pl clean smudge" &&
+       test_config_global filter.protocol.process "rot13-filter.pl debug.log clean smudge" &&
        rm -rf repo &&
        mkdir repo &&
        (
@@ -634,12 +634,12 @@ test_expect_success PERL 'process filter should not be restarted if it signals a
                cat >expected.log <<-EOF &&
                        START
                        init handshake complete
-                       IN: smudge error.r $SE [OK] -- OUT: 0 [ERROR]
+                       IN: smudge error.r $SE [OK] -- [ERROR]
                        IN: smudge test.r $S [OK] -- OUT: $S . [OK]
                        IN: smudge test2.r $S2 [OK] -- OUT: $S2 . [OK]
                        STOP
                EOF
-               test_cmp_exclude_clean expected.log rot13-filter.log &&
+               test_cmp_exclude_clean expected.log debug.log &&
 
                test_cmp_committed_rot13 "$TEST_ROOT/test.o" test.r &&
                test_cmp_committed_rot13 "$TEST_ROOT/test2.o" test2.r &&
@@ -648,7 +648,7 @@ test_expect_success PERL 'process filter should not be restarted if it signals a
 '
 
 test_expect_success PERL 'process filter abort stops processing of all further files' '
-       test_config_global filter.protocol.process "rot13-filter.pl clean smudge" &&
+       test_config_global filter.protocol.process "rot13-filter.pl debug.log clean smudge" &&
        rm -rf repo &&
        mkdir repo &&
        (
@@ -673,10 +673,10 @@ test_expect_success PERL 'process filter abort stops processing of all further f
                cat >expected.log <<-EOF &&
                        START
                        init handshake complete
-                       IN: smudge abort.r $SA [OK] -- OUT: 0 [ABORT]
+                       IN: smudge abort.r $SA [OK] -- [ABORT]
                        STOP
                EOF
-               test_cmp_exclude_clean expected.log rot13-filter.log &&
+               test_cmp_exclude_clean expected.log debug.log &&
 
                test_cmp "$TEST_ROOT/test.o" test.r &&
                test_cmp "$TEST_ROOT/test2.o" test2.r &&
@@ -697,8 +697,124 @@ test_expect_success PERL 'invalid process filter must fail (and not hang!)' '
 
                cp "$TEST_ROOT/test.o" test.r &&
                test_must_fail git add . 2>git-stderr.log &&
-               grep "does not support filter protocol version" git-stderr.log
+               grep "expected git-filter-server" git-stderr.log
        )
 '
 
+test_expect_success PERL 'delayed checkout in process filter' '
+       test_config_global filter.a.process "rot13-filter.pl a.log clean smudge delay" &&
+       test_config_global filter.a.required true &&
+       test_config_global filter.b.process "rot13-filter.pl b.log clean smudge delay" &&
+       test_config_global filter.b.required true &&
+
+       rm -rf repo &&
+       mkdir repo &&
+       (
+               cd repo &&
+               git init &&
+               echo "*.a filter=a" >.gitattributes &&
+               echo "*.b filter=b" >>.gitattributes &&
+               cp "$TEST_ROOT/test.o" test.a &&
+               cp "$TEST_ROOT/test.o" test-delay10.a &&
+               cp "$TEST_ROOT/test.o" test-delay11.a &&
+               cp "$TEST_ROOT/test.o" test-delay20.a &&
+               cp "$TEST_ROOT/test.o" test-delay10.b &&
+               git add . &&
+               git commit -m "test commit"
+       ) &&
+
+       S=$(file_size "$TEST_ROOT/test.o") &&
+       cat >a.exp <<-EOF &&
+               START
+               init handshake complete
+               IN: smudge test.a $S [OK] -- OUT: $S . [OK]
+               IN: smudge test-delay10.a $S [OK] -- [DELAYED]
+               IN: smudge test-delay11.a $S [OK] -- [DELAYED]
+               IN: smudge test-delay20.a $S [OK] -- [DELAYED]
+               IN: list_available_blobs test-delay10.a test-delay11.a [OK]
+               IN: smudge test-delay10.a 0 [OK] -- OUT: $S . [OK]
+               IN: smudge test-delay11.a 0 [OK] -- OUT: $S . [OK]
+               IN: list_available_blobs test-delay20.a [OK]
+               IN: smudge test-delay20.a 0 [OK] -- OUT: $S . [OK]
+               IN: list_available_blobs [OK]
+               STOP
+       EOF
+       cat >b.exp <<-EOF &&
+               START
+               init handshake complete
+               IN: smudge test-delay10.b $S [OK] -- [DELAYED]
+               IN: list_available_blobs test-delay10.b [OK]
+               IN: smudge test-delay10.b 0 [OK] -- OUT: $S . [OK]
+               IN: list_available_blobs [OK]
+               STOP
+       EOF
+
+       rm -rf repo-cloned &&
+       filter_git clone repo repo-cloned &&
+       test_cmp_count a.exp repo-cloned/a.log &&
+       test_cmp_count b.exp repo-cloned/b.log &&
+
+       (
+               cd repo-cloned &&
+               test_cmp_committed_rot13 "$TEST_ROOT/test.o" test.a &&
+               test_cmp_committed_rot13 "$TEST_ROOT/test.o" test-delay10.a &&
+               test_cmp_committed_rot13 "$TEST_ROOT/test.o" test-delay11.a &&
+               test_cmp_committed_rot13 "$TEST_ROOT/test.o" test-delay20.a &&
+               test_cmp_committed_rot13 "$TEST_ROOT/test.o" test-delay10.b &&
+
+               rm *.a *.b &&
+               filter_git checkout . &&
+               test_cmp_count ../a.exp a.log &&
+               test_cmp_count ../b.exp b.log &&
+
+               test_cmp_committed_rot13 "$TEST_ROOT/test.o" test.a &&
+               test_cmp_committed_rot13 "$TEST_ROOT/test.o" test-delay10.a &&
+               test_cmp_committed_rot13 "$TEST_ROOT/test.o" test-delay11.a &&
+               test_cmp_committed_rot13 "$TEST_ROOT/test.o" test-delay20.a &&
+               test_cmp_committed_rot13 "$TEST_ROOT/test.o" test-delay10.b
+       )
+'
+
+test_expect_success PERL 'missing file in delayed checkout' '
+       test_config_global filter.bug.process "rot13-filter.pl bug.log clean smudge delay" &&
+       test_config_global filter.bug.required true &&
+
+       rm -rf repo &&
+       mkdir repo &&
+       (
+               cd repo &&
+               git init &&
+               echo "*.a filter=bug" >.gitattributes &&
+               cp "$TEST_ROOT/test.o" missing-delay.a
+               git add . &&
+               git commit -m "test commit"
+       ) &&
+
+       rm -rf repo-cloned &&
+       test_must_fail git clone repo repo-cloned 2>git-stderr.log &&
+       cat git-stderr.log &&
+       grep "error: .missing-delay\.a. was not filtered properly" git-stderr.log
+'
+
+test_expect_success PERL 'invalid file in delayed checkout' '
+       test_config_global filter.bug.process "rot13-filter.pl bug.log clean smudge delay" &&
+       test_config_global filter.bug.required true &&
+
+       rm -rf repo &&
+       mkdir repo &&
+       (
+               cd repo &&
+               git init &&
+               echo "*.a filter=bug" >.gitattributes &&
+               cp "$TEST_ROOT/test.o" invalid-delay.a &&
+               cp "$TEST_ROOT/test.o" unfiltered
+               git add . &&
+               git commit -m "test commit"
+       ) &&
+
+       rm -rf repo-cloned &&
+       test_must_fail git clone repo repo-cloned 2>git-stderr.log &&
+       grep "error: external filter .* signaled that .unfiltered. is now available although it has not been delayed earlier" git-stderr.log
+'
+
 test_done
index 617f581e56cac95191d6f1301566fa6671ecaf6f..ad685d92f8c7aa138cb29b0ef46e5d09e246f42c 100644 (file)
@@ -2,8 +2,9 @@
 # Example implementation for the Git filter protocol version 2
 # See Documentation/gitattributes.txt, section "Filter Protocol"
 #
-# The script takes the list of supported protocol capabilities as
-# arguments ("clean", "smudge", etc).
+# The first argument defines a debug log file that the script write to.
+# All remaining arguments define a list of supported protocol
+# capabilities ("clean", "smudge", etc).
 #
 # This implementation supports special test cases:
 # (1) If data with the pathname "clean-write-fail.r" is processed with
 #     operation then the filter signals that it cannot or does not want
 #     to process the file and any file after that is processed with the
 #     same command.
+# (5) If data with a pathname that is a key in the DELAY hash is
+#     requested (e.g. "test-delay10.a") then the filter responds with
+#     a "delay" status and sets the "requested" field in the DELAY hash.
+#     The filter will signal the availability of this object after
+#     "count" (field in DELAY hash) "list_available_blobs" commands.
+# (6) If data with the pathname "missing-delay.a" is processed that the
+#     filter will drop the path from the "list_available_blobs" response.
+# (7) If data with the pathname "invalid-delay.a" is processed that the
+#     filter will add the path "unfiltered" which was not delayed before
+#     to the "list_available_blobs" response.
 #
 
 use strict;
 use IO::File;
 
 my $MAX_PACKET_CONTENT_SIZE = 65516;
+my $log_file                = shift @ARGV;
 my @capabilities            = @ARGV;
 
-open my $debug, ">>", "rot13-filter.log" or die "cannot open log file: $!";
+open my $debug, ">>", $log_file or die "cannot open log file: $!";
+
+my %DELAY = (
+       'test-delay10.a' => { "requested" => 0, "count" => 1 },
+       'test-delay11.a' => { "requested" => 0, "count" => 1 },
+       'test-delay20.a' => { "requested" => 0, "count" => 2 },
+       'test-delay10.b' => { "requested" => 0, "count" => 1 },
+       'missing-delay.a' => { "requested" => 0, "count" => 1 },
+       'invalid-delay.a' => { "requested" => 0, "count" => 1 },
+);
 
 sub rot13 {
        my $str = shift;
@@ -64,7 +85,7 @@ sub packet_bin_read {
 
 sub packet_txt_read {
        my ( $res, $buf ) = packet_bin_read();
-       unless ( $buf =~ s/\n$// ) {
+       unless ( $buf eq '' or $buf =~ s/\n$// ) {
                die "A non-binary line MUST be terminated by an LF.";
        }
        return ( $res, $buf );
@@ -99,6 +120,7 @@ sub packet_flush {
 
 ( packet_txt_read() eq ( 0, "capability=clean" ) )  || die "bad capability";
 ( packet_txt_read() eq ( 0, "capability=smudge" ) ) || die "bad capability";
+( packet_txt_read() eq ( 0, "capability=delay" ) )  || die "bad capability";
 ( packet_bin_read() eq ( 1, "" ) )                  || die "bad capability end";
 
 foreach (@capabilities) {
@@ -109,88 +131,142 @@ sub packet_flush {
 $debug->flush();
 
 while (1) {
-       my ($command) = packet_txt_read() =~ /^command=(.+)$/;
+       my ( $command ) = packet_txt_read() =~ /^command=(.+)$/;
        print $debug "IN: $command";
        $debug->flush();
 
-       my ($pathname) = packet_txt_read() =~ /^pathname=(.+)$/;
-       print $debug " $pathname";
-       $debug->flush();
-
-       if ( $pathname eq "" ) {
-               die "bad pathname '$pathname'";
-       }
+       if ( $command eq "list_available_blobs" ) {
+               # Flush
+               packet_bin_read();
 
-       # Flush
-       packet_bin_read();
-
-       my $input = "";
-       {
-               binmode(STDIN);
-               my $buffer;
-               my $done = 0;
-               while ( !$done ) {
-                       ( $done, $buffer ) = packet_bin_read();
-                       $input .= $buffer;
+               foreach my $pathname ( sort keys %DELAY ) {
+                       if ( $DELAY{$pathname}{"requested"} >= 1 ) {
+                               $DELAY{$pathname}{"count"} = $DELAY{$pathname}{"count"} - 1;
+                               if ( $pathname eq "invalid-delay.a" ) {
+                                       # Send Git a pathname that was not delayed earlier
+                                       packet_txt_write("pathname=unfiltered");
+                               }
+                               if ( $pathname eq "missing-delay.a" ) {
+                                       # Do not signal Git that this file is available
+                               } elsif ( $DELAY{$pathname}{"count"} == 0 ) {
+                                       print $debug " $pathname";
+                                       packet_txt_write("pathname=$pathname");
+                               }
+                       }
                }
-               print $debug " " . length($input) . " [OK] -- ";
-               $debug->flush();
-       }
-
-       my $output;
-       if ( $pathname eq "error.r" or $pathname eq "abort.r" ) {
-               $output = "";
-       }
-       elsif ( $command eq "clean" and grep( /^clean$/, @capabilities ) ) {
-               $output = rot13($input);
-       }
-       elsif ( $command eq "smudge" and grep( /^smudge$/, @capabilities ) ) {
-               $output = rot13($input);
-       }
-       else {
-               die "bad command '$command'";
-       }
 
-       print $debug "OUT: " . length($output) . " ";
-       $debug->flush();
-
-       if ( $pathname eq "error.r" ) {
-               print $debug "[ERROR]\n";
-               $debug->flush();
-               packet_txt_write("status=error");
                packet_flush();
-       }
-       elsif ( $pathname eq "abort.r" ) {
-               print $debug "[ABORT]\n";
+
+               print $debug " [OK]\n";
                $debug->flush();
-               packet_txt_write("status=abort");
+               packet_txt_write("status=success");
                packet_flush();
        }
        else {
-               packet_txt_write("status=success");
-               packet_flush();
+               my ( $pathname ) = packet_txt_read() =~ /^pathname=(.+)$/;
+               print $debug " $pathname";
+               $debug->flush();
 
-               if ( $pathname eq "${command}-write-fail.r" ) {
-                       print $debug "[WRITE FAIL]\n";
+               if ( $pathname eq "" ) {
+                       die "bad pathname '$pathname'";
+               }
+
+               # Read until flush
+               my ( $done, $buffer ) = packet_txt_read();
+               while ( $buffer ne '' ) {
+                       if ( $buffer eq "can-delay=1" ) {
+                               if ( exists $DELAY{$pathname} and $DELAY{$pathname}{"requested"} == 0 ) {
+                                       $DELAY{$pathname}{"requested"} = 1;
+                               }
+                       } else {
+                               die "Unknown message '$buffer'";
+                       }
+
+                       ( $done, $buffer ) = packet_txt_read();
+               }
+
+               my $input = "";
+               {
+                       binmode(STDIN);
+                       my $buffer;
+                       my $done = 0;
+                       while ( !$done ) {
+                               ( $done, $buffer ) = packet_bin_read();
+                               $input .= $buffer;
+                       }
+                       print $debug " " . length($input) . " [OK] -- ";
                        $debug->flush();
-                       die "${command} write error";
                }
 
-               while ( length($output) > 0 ) {
-                       my $packet = substr( $output, 0, $MAX_PACKET_CONTENT_SIZE );
-                       packet_bin_write($packet);
-                       # dots represent the number of packets
-                       print $debug ".";
-                       if ( length($output) > $MAX_PACKET_CONTENT_SIZE ) {
-                               $output = substr( $output, $MAX_PACKET_CONTENT_SIZE );
+               my $output;
+               if ( exists $DELAY{$pathname} and exists $DELAY{$pathname}{"output"} ) {
+                       $output = $DELAY{$pathname}{"output"}
+               }
+               elsif ( $pathname eq "error.r" or $pathname eq "abort.r" ) {
+                       $output = "";
+               }
+               elsif ( $command eq "clean" and grep( /^clean$/, @capabilities ) ) {
+                       $output = rot13($input);
+               }
+               elsif ( $command eq "smudge" and grep( /^smudge$/, @capabilities ) ) {
+                       $output = rot13($input);
+               }
+               else {
+                       die "bad command '$command'";
+               }
+
+               if ( $pathname eq "error.r" ) {
+                       print $debug "[ERROR]\n";
+                       $debug->flush();
+                       packet_txt_write("status=error");
+                       packet_flush();
+               }
+               elsif ( $pathname eq "abort.r" ) {
+                       print $debug "[ABORT]\n";
+                       $debug->flush();
+                       packet_txt_write("status=abort");
+                       packet_flush();
+               }
+               elsif ( $command eq "smudge" and
+                       exists $DELAY{$pathname} and
+                       $DELAY{$pathname}{"requested"} == 1
+               ) {
+                       print $debug "[DELAYED]\n";
+                       $debug->flush();
+                       packet_txt_write("status=delayed");
+                       packet_flush();
+                       $DELAY{$pathname}{"requested"} = 2;
+                       $DELAY{$pathname}{"output"} = $output;
+               }
+               else {
+                       packet_txt_write("status=success");
+                       packet_flush();
+
+                       if ( $pathname eq "${command}-write-fail.r" ) {
+                               print $debug "[WRITE FAIL]\n";
+                               $debug->flush();
+                               die "${command} write error";
                        }
-                       else {
-                               $output = "";
+
+                       print $debug "OUT: " . length($output) . " ";
+                       $debug->flush();
+
+                       while ( length($output) > 0 ) {
+                               my $packet = substr( $output, 0, $MAX_PACKET_CONTENT_SIZE );
+                               packet_bin_write($packet);
+                               # dots represent the number of packets
+                               print $debug ".";
+                               if ( length($output) > $MAX_PACKET_CONTENT_SIZE ) {
+                                       $output = substr( $output, $MAX_PACKET_CONTENT_SIZE );
+                               }
+                               else {
+                                       $output = "";
+                               }
                        }
+                       packet_flush();
+                       print $debug " [OK]\n";
+                       $debug->flush();
+                       packet_flush();
                }
-               packet_flush();
-               print $debug " [OK]\n";
-               $debug->flush();
-               packet_flush();
        }
 }
index b9cb76654bd6cf0b7a910ec4c935c38a5f3bf9bc..6ac7734d79be21a82feeadff10064bb4ca7ad47b 100755 (executable)
@@ -171,14 +171,4 @@ test_expect_success 'reflog exists works' '
        ! git reflog exists refs/heads/nonexistent
 '
 
-# The behavior with two reflogs is buggy and the output is in flux; for now
-# we're just checking that the program works at all without segfaulting.
-test_expect_success 'showing multiple reflogs works' '
-       git log -g HEAD HEAD >actual
-'
-
-test_expect_success 'showing multiple reflogs with an old date' '
-       git log -g HEAD@{1979-01-01} HEAD >actual
-'
-
 test_done
diff --git a/t/t1414-reflog-walk.sh b/t/t1414-reflog-walk.sh
new file mode 100755 (executable)
index 0000000..feb1efd
--- /dev/null
@@ -0,0 +1,135 @@
+#!/bin/sh
+
+test_description='various tests of reflog walk (log -g) behavior'
+. ./test-lib.sh
+
+test_expect_success 'set up some reflog entries' '
+       test_commit one &&
+       test_commit two &&
+       git checkout -b side HEAD^ &&
+       test_commit three &&
+       git merge --no-commit master &&
+       echo evil-merge-content >>one.t &&
+       test_tick &&
+       git commit --no-edit -a
+'
+
+do_walk () {
+       git log -g --format="%gd %gs" "$@"
+}
+
+sq="'"
+test_expect_success 'set up expected reflog' '
+       cat >expect.all <<-EOF
+       HEAD@{0} commit (merge): Merge branch ${sq}master${sq} into side
+       HEAD@{1} commit: three
+       HEAD@{2} checkout: moving from master to side
+       HEAD@{3} commit: two
+       HEAD@{4} commit (initial): one
+       EOF
+'
+
+test_expect_success 'reflog walk shows expected logs' '
+       do_walk >actual &&
+       test_cmp expect.all actual
+'
+
+test_expect_success 'reflog can limit with --no-merges' '
+       grep -v merge expect.all >expect &&
+       do_walk --no-merges >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'reflog can limit with pathspecs' '
+       grep two expect.all >expect &&
+       do_walk -- two.t >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'pathspec limiting handles merges' '
+       # we pick up:
+       #   - the initial commit of one
+       #   - the checkout back to commit one
+       #   - the evil merge which touched one
+       sed -n "1p;3p;5p" expect.all >expect &&
+       do_walk -- one.t >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success '--parents shows true parents' '
+       # convert newlines to spaces
+       echo $(git rev-parse HEAD HEAD^1 HEAD^2) >expect &&
+       git rev-list -g --parents -1 HEAD >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'walking multiple reflogs shows all' '
+       # We expect to see all entries for all reflogs, but interleaved by
+       # date, with order on the command line breaking ties. We
+       # can use "sort" on the separate lists to generate this,
+       # but note two tricks:
+       #
+       #   1. We use "{" as the delimiter, which lets us skip to the reflog
+       #      date specifier as our second field, and then our "-n" numeric
+       #      sort ignores the bits after the timestamp.
+       #
+       #   2. POSIX leaves undefined whether this is a stable sort or not. So
+       #      we use "-k 1" to ensure that we see HEAD before master before
+       #      side when breaking ties.
+       {
+               do_walk --date=unix HEAD &&
+               do_walk --date=unix side &&
+               do_walk --date=unix master
+       } >expect.raw &&
+       sort -t "{" -k 2nr -k 1 <expect.raw >expect &&
+       do_walk --date=unix HEAD master side >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'date-limiting does not interfere with other logs' '
+       do_walk HEAD@{1979-01-01} HEAD >actual &&
+       test_cmp expect.all actual
+'
+
+test_expect_success 'min/max age uses entry date to limit' '
+       # Flip between commits one and two so each ref update actually
+       # does something (and does not get optimized out). We know
+       # that the timestamps of those commits will be before our "min".
+
+       git update-ref -m before refs/heads/minmax one &&
+
+       test_tick &&
+       min=$test_tick &&
+       git update-ref -m min refs/heads/minmax two &&
+
+       test_tick &&
+       max=$test_tick &&
+       git update-ref -m max refs/heads/minmax one &&
+
+       test_tick &&
+       git update-ref -m after refs/heads/minmax two &&
+
+       cat >expect <<-\EOF &&
+       max
+       min
+       EOF
+       git log -g --since=$min --until=$max --format=%gs minmax >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'walk prefers reflog to ref tip' '
+       head=$(git rev-parse HEAD) &&
+       one=$(git rev-parse one) &&
+       ident="$GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE" &&
+       echo "$head $one $ident broken reflog entry" >>.git/logs/HEAD &&
+
+       echo $one >expect &&
+       git log -g --format=%H -1 >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'rev-list -g complains when there are no reflogs' '
+       test_must_fail git rev-list -g
+'
+
+test_done
index bb89e1a5db293dd886bff9df668bcaf187a58d11..4087150db1b787540abc5a5f648839efbe4d78e3 100755 (executable)
@@ -608,6 +608,22 @@ test_expect_success 'fsck errors in packed objects' '
        ! grep corrupt out
 '
 
+test_expect_success 'fsck fails on corrupt packfile' '
+       hsh=$(git commit-tree -m mycommit HEAD^{tree}) &&
+       pack=$(echo $hsh | git pack-objects .git/objects/pack/pack) &&
+
+       # Corrupt the first byte of the first object. (It contains 3 type bits,
+       # at least one of which is not zero, so setting the first byte to 0 is
+       # sufficient.)
+       chmod a+w .git/objects/pack/pack-$pack.pack &&
+       printf '\0' | dd of=.git/objects/pack/pack-$pack.pack bs=1 conv=notrunc seek=12 &&
+
+       test_when_finished "rm -f .git/objects/pack/pack-$pack.*" &&
+       remove_object $hsh &&
+       test_must_fail git fsck 2>out &&
+       test_i18ngrep "checksum mismatch" out
+'
+
 test_expect_success 'fsck finds problems in duplicate loose objects' '
        rm -rf broken-duplicate &&
        git init broken-duplicate &&
index dd37ac47c5e16bc8df39bcc14e1a2861ab556374..9d707d2a40a457abcd85fb93d9f8195946d09d01 100755 (executable)
@@ -166,10 +166,9 @@ test_expect_success 'resulting reflog can be shown by log -g' '
        oid=$(git rev-parse HEAD) &&
        cat >expect <<-EOF &&
        HEAD@{0} $oid $msg
-       HEAD@{1} $oid $msg
        HEAD@{2} $oid checkout: moving from foo to baz
        EOF
-       git log -g --format="%gd %H %gs" -3 HEAD >actual &&
+       git log -g --format="%gd %H %gs" -2 HEAD >actual &&
        test_cmp expect actual
 '
 
index a428ae670369505476ab19338bf0f1da70018301..d2aec0f38b7913b27687b332029dc78be59bc182 100755 (executable)
@@ -2,6 +2,7 @@
 
 test_description='git branch display tests'
 . ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-terminal.sh
 
 test_expect_success 'make commits' '
        echo content >file &&
@@ -239,4 +240,34 @@ test_expect_success 'git branch --format option' '
        test_i18ncmp expect actual
 '
 
+test_expect_success "set up color tests" '
+       echo "<RED>master<RESET>" >expect.color &&
+       echo "master" >expect.bare &&
+       color_args="--format=%(color:red)%(refname:short) --list master"
+'
+
+test_expect_success '%(color) omitted without tty' '
+       TERM=vt100 git branch $color_args >actual.raw &&
+       test_decode_color <actual.raw >actual &&
+       test_cmp expect.bare actual
+'
+
+test_expect_success TTY '%(color) present with tty' '
+       test_terminal env TERM=vt100 git branch $color_args >actual.raw &&
+       test_decode_color <actual.raw >actual &&
+       test_cmp expect.color actual
+'
+
+test_expect_success 'color.branch=always overrides auto-color' '
+       git -c color.branch=always branch $color_args >actual.raw &&
+       test_decode_color <actual.raw >actual &&
+       test_cmp expect.color actual
+'
+
+test_expect_success '--color overrides auto-color' '
+       git branch --color $color_args >actual.raw &&
+       test_decode_color <actual.raw >actual &&
+       test_cmp expect.color actual
+'
+
 test_done
index b972296f0634144defe5a7a083c5607893a7ca10..60f040cab8ad5661b5b9b690798abba467748dd6 100755 (executable)
@@ -7,11 +7,6 @@ test_description='Test for "git log --decorate" colors'
 
 . ./test-lib.sh
 
-get_color ()
-{
-       git config --get-color no.such.slot "$1"
-}
-
 test_expect_success setup '
        git config diff.color.commit yellow &&
        git config color.decorate.branch green &&
@@ -20,14 +15,14 @@ test_expect_success setup '
        git config color.decorate.stash magenta &&
        git config color.decorate.HEAD cyan &&
 
-       c_reset=$(get_color reset) &&
+       c_reset="<RESET>" &&
 
-       c_commit=$(get_color yellow) &&
-       c_branch=$(get_color green) &&
-       c_remoteBranch=$(get_color red) &&
-       c_tag=$(get_color "reverse bold yellow") &&
-       c_stash=$(get_color magenta) &&
-       c_HEAD=$(get_color cyan) &&
+       c_commit="<YELLOW>" &&
+       c_branch="<GREEN>" &&
+       c_remoteBranch="<RED>" &&
+       c_tag="<BOLD;REVERSE;YELLOW>" &&
+       c_stash="<MAGENTA>" &&
+       c_HEAD="<CYAN>" &&
 
        test_commit A &&
        git clone . other &&
@@ -59,7 +54,8 @@ EOF
 # to this test since it does not contain any decoration, hence --first-parent
 test_expect_success 'Commit Decorations Colored Correctly' '
        git log --first-parent --abbrev=10 --all --decorate --oneline --color=always |
-       sed "s/[0-9a-f]\{10,10\}/COMMIT_ID/" >out &&
+       sed "s/[0-9a-f]\{10,10\}/COMMIT_ID/" |
+       test_decode_color >out &&
        test_cmp expected out
 '
 
index f15f7a332960f15c7af32a3c1e7a66f5a8a68989..59c4b778d3a455b6ef4575a4b07b860d1e84720d 100755 (executable)
@@ -305,7 +305,7 @@ test_expect_success '--rebase with conflicts shows advice' '
        test_tick &&
        git commit -m "Create conflict" seq.txt &&
        test_must_fail git pull --rebase . seq 2>err >out &&
-       test_i18ngrep "When you have resolved this problem" out
+       test_i18ngrep "Resolve all conflicts manually" out
 '
 
 test_expect_success 'failed --rebase shows advice' '
@@ -319,7 +319,7 @@ test_expect_success 'failed --rebase shows advice' '
        git checkout -f -b fails-to-rebase HEAD^ &&
        test_commit v2-without-cr file "2" file2-lf &&
        test_must_fail git pull --rebase . diverging 2>err >out &&
-       test_i18ngrep "When you have resolved this problem" out
+       test_i18ngrep "Resolve all conflicts manually" out
 '
 
 test_expect_success '--rebase fails with multiple branches' '
index 51c9669398a01bab0b59174ec6ec1be92c3f21fe..9c2798603b4d7b4a3db135febedc71e8cea23635 100755 (executable)
@@ -43,4 +43,9 @@ test_expect_success 'fetch through proxy works' '
        test_cmp expect actual
 '
 
+test_expect_success 'funny hostnames are rejected before running proxy' '
+       test_must_fail git fetch git://-remote/repo.git 2>stderr &&
+       ! grep "proxying for" stderr
+'
+
 test_done
index 563592d8a8a5f6fec7da160f292b2f8b8824327e..c1ef99b85c293e8a8bfc0872e3511fe8b7029213 100755 (executable)
@@ -11,4 +11,27 @@ test_expect_success 'setup repository to clone' '
 test_proto "file://" file "file://$PWD"
 test_proto "path" file .
 
+test_expect_success 'setup repo with dash' '
+       git init --bare repo.git &&
+       git push repo.git HEAD &&
+       mv repo.git "$PWD/-repo.git"
+'
+
+# This will fail even without our rejection because upload-pack will
+# complain about the bogus option. So let's make sure that GIT_TRACE
+# doesn't show us even running upload-pack.
+#
+# We must also be sure to use "fetch" and not "clone" here, as the latter
+# actually canonicalizes our input into an absolute path (which is fine
+# to allow).
+test_expect_success 'repo names starting with dash are rejected' '
+       rm -f trace.out &&
+       test_must_fail env GIT_TRACE="$PWD/trace.out" git fetch -- -repo.git &&
+       ! grep upload-pack trace.out
+'
+
+test_expect_success 'full paths still work' '
+       git fetch "$PWD/-repo.git"
+'
+
 test_done
index a954ead8af882002d3e8bbb6dad8c52190f794c7..3f084ee306517b2bc991365f6f15b76627e1d125 100755 (executable)
@@ -17,4 +17,27 @@ test_proto "host:path" ssh "remote:repo.git"
 test_proto "ssh://" ssh "ssh://remote$PWD/remote/repo.git"
 test_proto "git+ssh://" ssh "git+ssh://remote$PWD/remote/repo.git"
 
+# Don't even bother setting up a "-remote" directory, as ssh would generally
+# complain about the bogus option rather than completing our request. Our
+# fake wrapper actually _can_ handle this case, but it's more robust to
+# simply confirm from its output that it did not run at all.
+test_expect_success 'hostnames starting with dash are rejected' '
+       test_must_fail git clone ssh://-remote/repo.git dash-host 2>stderr &&
+       ! grep ^ssh: stderr
+'
+
+test_expect_success 'setup repo with dash' '
+       git init --bare remote/-repo.git &&
+       git push remote/-repo.git HEAD
+'
+
+test_expect_success 'repo names starting with dash are rejected' '
+       test_must_fail git clone remote:-repo.git dash-path 2>stderr &&
+       ! grep ^ssh: stderr
+'
+
+test_expect_success 'full paths still work' '
+       git clone "remote:$PWD/remote/-repo.git" dash-path
+'
+
 test_done
index a1dcdb81d789cfa2d0e8fcc178311a807a608771..b326d550f3e281e4b19ab669b95f08e8c63bf555 100755 (executable)
@@ -59,10 +59,14 @@ test_format () {
 }
 
 # Feed to --format to provide predictable colored sequences.
+BASIC_COLOR='%Credfoo%Creset'
+COLOR='%C(red)foo%C(reset)'
 AUTO_COLOR='%C(auto,red)foo%C(auto,reset)'
+ALWAYS_COLOR='%C(always,red)foo%C(always,reset)'
 has_color () {
-       printf '\033[31mfoo\033[m\n' >expect &&
-       test_cmp expect "$1"
+       test_decode_color <"$1" >decoded &&
+       echo "<RED>foo<RESET>" >expect &&
+       test_cmp expect decoded
 }
 
 has_no_color () {
@@ -170,62 +174,84 @@ $added
 
 EOF
 
-test_format colors %Credfoo%Cgreenbar%Cbluebaz%Cresetxyzzy <<EOF
-commit $head2
-\e[31mfoo\e[32mbar\e[34mbaz\e[mxyzzy
-commit $head1
-\e[31mfoo\e[32mbar\e[34mbaz\e[mxyzzy
-EOF
-
-test_format advanced-colors '%C(red yellow bold)foo%C(reset)' <<EOF
-commit $head2
-\e[1;31;43mfoo\e[m
-commit $head1
-\e[1;31;43mfoo\e[m
-EOF
-
-test_expect_success '%C(auto,...) does not enable color by default' '
-       git log --format=$AUTO_COLOR -1 >actual &&
-       has_no_color actual
+test_expect_success 'basic colors' '
+       cat >expect <<-EOF &&
+       commit $head2
+       <RED>foo<GREEN>bar<BLUE>baz<RESET>xyzzy
+       EOF
+       format="%Credfoo%Cgreenbar%Cbluebaz%Cresetxyzzy" &&
+       git rev-list --color --format="$format" -1 master >actual.raw &&
+       test_decode_color <actual.raw >actual &&
+       test_cmp expect actual
 '
 
-test_expect_success '%C(auto,...) enables colors for color.diff' '
-       git -c color.diff=always log --format=$AUTO_COLOR -1 >actual &&
-       has_color actual
+test_expect_success 'advanced colors' '
+       cat >expect <<-EOF &&
+       commit $head2
+       <BOLD;RED;BYELLOW>foo<RESET>
+       EOF
+       format="%C(red yellow bold)foo%C(reset)" &&
+       git rev-list --color --format="$format" -1 master >actual.raw &&
+       test_decode_color <actual.raw >actual &&
+       test_cmp expect actual
 '
 
-test_expect_success '%C(auto,...) enables colors for color.ui' '
-       git -c color.ui=always log --format=$AUTO_COLOR -1 >actual &&
-       has_color actual
-'
+for spec in \
+       "%Cred:$BASIC_COLOR" \
+       "%C(...):$COLOR" \
+       "%C(auto,...):$AUTO_COLOR"
+do
+       desc=${spec%%:*}
+       color=${spec#*:}
+       test_expect_success "$desc does not enable color by default" '
+               git log --format=$color -1 >actual &&
+               has_no_color actual
+       '
 
-test_expect_success '%C(auto,...) respects --color' '
-       git log --format=$AUTO_COLOR -1 --color >actual &&
-       has_color actual
-'
+       test_expect_success "$desc enables colors for color.diff" '
+               git -c color.diff=always log --format=$color -1 >actual &&
+               has_color actual
+       '
 
-test_expect_success '%C(auto,...) respects --no-color' '
-       git -c color.ui=always log --format=$AUTO_COLOR -1 --no-color >actual &&
-       has_no_color actual
-'
+       test_expect_success "$desc enables colors for color.ui" '
+               git -c color.ui=always log --format=$color -1 >actual &&
+               has_color actual
+       '
 
-test_expect_success TTY '%C(auto,...) respects --color=auto (stdout is tty)' '
-       test_terminal env TERM=vt100 \
-               git log --format=$AUTO_COLOR -1 --color=auto >actual &&
-       has_color actual
-'
+       test_expect_success "$desc respects --color" '
+               git log --format=$color -1 --color >actual &&
+               has_color actual
+       '
 
-test_expect_success '%C(auto,...) respects --color=auto (stdout not tty)' '
-       (
-               TERM=vt100 && export TERM &&
-               git log --format=$AUTO_COLOR -1 --color=auto >actual &&
+       test_expect_success "$desc respects --no-color" '
+               git -c color.ui=always log --format=$color -1 --no-color >actual &&
                has_no_color actual
-       )
+       '
+
+       test_expect_success TTY "$desc respects --color=auto (stdout is tty)" '
+               test_terminal env TERM=vt100 \
+                       git log --format=$color -1 --color=auto >actual &&
+               has_color actual
+       '
+
+       test_expect_success "$desc respects --color=auto (stdout not tty)" '
+               (
+                       TERM=vt100 && export TERM &&
+                       git log --format=$color -1 --color=auto >actual &&
+                       has_no_color actual
+               )
+       '
+done
+
+test_expect_success '%C(always,...) enables color even without tty' '
+       git log --format=$ALWAYS_COLOR -1 >actual &&
+       has_color actual
 '
 
 test_expect_success '%C(auto) respects --color' '
-       git log --color --format="%C(auto)%H" -1 >actual &&
-       printf "\\033[33m%s\\033[m\\n" $(git rev-parse HEAD) >expect &&
+       git log --color --format="%C(auto)%H" -1 >actual.raw &&
+       test_decode_color <actual.raw >actual &&
+       echo "<YELLOW>$(git rev-parse HEAD)<RESET>" >expect &&
        test_cmp expect actual
 '
 
@@ -235,6 +261,17 @@ test_expect_success '%C(auto) respects --no-color' '
        test_cmp expect actual
 '
 
+test_expect_success 'rev-list %C(auto,...) respects --color' '
+       git rev-list --color --format="%C(auto,green)foo%C(auto,reset)" \
+               -1 HEAD >actual.raw &&
+       test_decode_color <actual.raw >actual &&
+       cat >expect <<-EOF &&
+       commit $(git rev-parse HEAD)
+       <GREEN>foo<RESET>
+       EOF
+       test_cmp expect actual
+'
+
 iconv -f utf-8 -t $test_encoding > commit-msg <<EOF
 Test printing of complex bodies
 
index 834a9ed168fad35258955447326e7d3d1f09b7d1..2274a4b73310bfbc90886e0179a1cb12d9b6f3ed 100755 (executable)
@@ -7,6 +7,7 @@ test_description='for-each-ref test'
 
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-gpg.sh
+. "$TEST_DIRECTORY"/lib-terminal.sh
 
 # Mon Jul 3 23:18:43 2006 +0000
 datestamp=1151968723
@@ -412,21 +413,33 @@ test_expect_success 'Check for invalid refname format' '
        test_must_fail git for-each-ref --format="%(refname:INVALID)"
 '
 
-get_color ()
-{
-       git config --get-color no.such.slot "$1"
-}
+test_expect_success 'set up color tests' '
+       cat >expected.color <<-EOF &&
+       $(git rev-parse --short refs/heads/master) <GREEN>master<RESET>
+       $(git rev-parse --short refs/remotes/origin/master) <GREEN>origin/master<RESET>
+       $(git rev-parse --short refs/tags/testtag) <GREEN>testtag<RESET>
+       $(git rev-parse --short refs/tags/two) <GREEN>two<RESET>
+       EOF
+       sed "s/<[^>]*>//g" <expected.color >expected.bare &&
+       color_format="%(objectname:short) %(color:green)%(refname:short)"
+'
 
-cat >expected <<EOF
-$(git rev-parse --short refs/heads/master) $(get_color green)master$(get_color reset)
-$(git rev-parse --short refs/remotes/origin/master) $(get_color green)origin/master$(get_color reset)
-$(git rev-parse --short refs/tags/testtag) $(get_color green)testtag$(get_color reset)
-$(git rev-parse --short refs/tags/two) $(get_color green)two$(get_color reset)
-EOF
+test_expect_success TTY '%(color) shows color with a tty' '
+       test_terminal env TERM=vt100 \
+               git for-each-ref --format="$color_format" >actual.raw &&
+       test_decode_color <actual.raw >actual &&
+       test_cmp expected.color actual
+'
 
-test_expect_success 'Check %(color:...) ' '
-       git for-each-ref --format="%(objectname:short) %(color:green)%(refname:short)" >actual &&
-       test_cmp expected actual
+test_expect_success '%(color) does not show color without tty' '
+       TERM=vt100 git for-each-ref --format="$color_format" >actual &&
+       test_cmp expected.bare actual
+'
+
+test_expect_success 'color.ui=always can override tty check' '
+       git -c color.ui=always for-each-ref --format="$color_format" >actual.raw &&
+       test_decode_color <actual.raw >actual &&
+       test_cmp expected.color actual
 '
 
 cat >expected <<\EOF
index 0ef7b94394151da9a9a6d602952e7f2fa64cf6a4..dd5ba450ee4b33801dc39d0b57e4c4b08c1dfd62 100755 (executable)
@@ -9,6 +9,7 @@ Tests for operations with tags.'
 
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-gpg.sh
+. "$TEST_DIRECTORY"/lib-terminal.sh
 
 # creating and listing lightweight tags:
 
@@ -1900,6 +1901,30 @@ test_expect_success '--format should list tags as per format given' '
        test_cmp expect actual
 '
 
+test_expect_success "set up color tests" '
+       echo "<RED>v1.0<RESET>" >expect.color &&
+       echo "v1.0" >expect.bare &&
+       color_args="--format=%(color:red)%(refname:short) --list v1.0"
+'
+
+test_expect_success '%(color) omitted without tty' '
+       TERM=vt100 git tag $color_args >actual.raw &&
+       test_decode_color <actual.raw >actual &&
+       test_cmp expect.bare actual
+'
+
+test_expect_success TTY '%(color) present with tty' '
+       test_terminal env TERM=vt100 git tag $color_args >actual.raw &&
+       test_decode_color <actual.raw >actual &&
+       test_cmp expect.color actual
+'
+
+test_expect_success 'color.ui=always overrides auto-color' '
+       git -c color.ui=always tag $color_args >actual.raw &&
+       test_decode_color <actual.raw >actual &&
+       test_cmp expect.color actual
+'
+
 test_expect_success 'setup --merged test tags' '
        git tag mergetest-1 HEAD~2 &&
        git tag mergetest-2 HEAD~1 &&
index 3ae394e934d972d29286ecd25596eedd45bee902..556e1850e2b20c3f484ee43a975e5dcca8eac99e 100755 (executable)
@@ -472,4 +472,14 @@ test_expect_success 'git clean -id with prefix and path (ask)' '
 
 '
 
+test_expect_success 'git clean -i paints the header in HEADER color' '
+       >a.out &&
+       echo q |
+       git -c color.ui=always clean -i |
+       test_decode_color |
+       head -n 1 >header &&
+       # not i18ngrep
+       grep "^<BOLD>" header
+'
+
 test_done
index 92c8e792d166ee37d5463de2bce32f61cfa570a1..ae4b579d245caf568d07d1e452f917581dbfd355 100755 (executable)
@@ -12,22 +12,25 @@ test_expect_success 'setup' '
        echo c >>file &&
        echo d >>file &&
        test_tick &&
-       git commit -a -m two
+       git commit -a -m two &&
+       ID1=$(git rev-parse HEAD^) &&
+       shortID1="^$(git rev-parse HEAD^ |cut -c 1-17)" &&
+       ID2=$(git rev-parse HEAD) &&
+       shortID2="$(git rev-parse HEAD |cut -c 1-18)"
 '
 
-cat >expect <<'EOF'
-^baf5e0b (A U Thor 2005-04-07 15:13:13 -0700 1) a
-8825379d (A U Thor 2005-04-07 15:14:13 -0700 2) b
-8825379d (A U Thor 2005-04-07 15:14:13 -0700 3) c
-8825379d (A U Thor 2005-04-07 15:14:13 -0700 4) d
+cat >expect <<EOF
+$shortID1 (A U Thor 2005-04-07 15:13:13 -0700 1) a
+$shortID2 (A U Thor 2005-04-07 15:14:13 -0700 2) b
+$shortID2 (A U Thor 2005-04-07 15:14:13 -0700 3) c
+$shortID2 (A U Thor 2005-04-07 15:14:13 -0700 4) d
 EOF
 test_expect_success 'normal blame output' '
-       git blame file >actual &&
+       git blame --abbrev=17 file >actual &&
        test_cmp expect actual
 '
 
-ID1=baf5e0b3869e0b2b2beb395a3720c7b51eac94fc
-COMMIT1='author A U Thor
+COMMIT1="author A U Thor
 author-mail <author@example.com>
 author-time 1112911993
 author-tz -0700
@@ -37,9 +40,8 @@ committer-time 1112911993
 committer-tz -0700
 summary one
 boundary
-filename file'
-ID2=8825379dfb8a1267b58e8e5bcf69eec838f685ec
-COMMIT2='author A U Thor
+filename file"
+COMMIT2="author A U Thor
 author-mail <author@example.com>
 author-time 1112912053
 author-tz -0700
@@ -48,8 +50,8 @@ committer-mail <committer@example.com>
 committer-time 1112912053
 committer-tz -0700
 summary two
-previous baf5e0b3869e0b2b2beb395a3720c7b51eac94fc file
-filename file'
+previous $ID1 file
+filename file"
 
 cat >expect <<EOF
 $ID1 1 1 1
index 50a9a1d1c49e719d0ee65435b05171747e065259..1701fe2a06057530d845b91b4fd4cce99b4521a2 100644 (file)
@@ -42,6 +42,7 @@ test_decode_color () {
                function name(n) {
                        if (n == 0) return "RESET";
                        if (n == 1) return "BOLD";
+                       if (n == 7) return "REVERSE";
                        if (n == 30) return "BLACK";
                        if (n == 31) return "RED";
                        if (n == 32) return "GREEN";
diff --git a/tag.c b/tag.c
index 47f60ae151c2cfd9855d1b6f1660ec2ba178bec3..7e10acfb6ef1673e783e0a42e1b8810a6e2eff06 100644 (file)
--- a/tag.c
+++ b/tag.c
@@ -33,7 +33,7 @@ static int run_gpg_verify(const char *buf, unsigned long size, unsigned flags)
        return ret;
 }
 
-int gpg_verify_tag(const unsigned char *sha1, const char *name_to_report,
+int gpg_verify_tag(const struct object_id *oid, const char *name_to_report,
                unsigned flags)
 {
        enum object_type type;
@@ -41,20 +41,20 @@ int gpg_verify_tag(const unsigned char *sha1, const char *name_to_report,
        unsigned long size;
        int ret;
 
-       type = sha1_object_info(sha1, NULL);
+       type = sha1_object_info(oid->hash, NULL);
        if (type != OBJ_TAG)
                return error("%s: cannot verify a non-tag object of type %s.",
                                name_to_report ?
                                name_to_report :
-                               find_unique_abbrev(sha1, DEFAULT_ABBREV),
+                               find_unique_abbrev(oid->hash, DEFAULT_ABBREV),
                                typename(type));
 
-       buf = read_sha1_file(sha1, &type, &size);
+       buf = read_sha1_file(oid->hash, &type, &size);
        if (!buf)
                return error("%s: unable to read file.",
                                name_to_report ?
                                name_to_report :
-                               find_unique_abbrev(sha1, DEFAULT_ABBREV));
+                               find_unique_abbrev(oid->hash, DEFAULT_ABBREV));
 
        ret = run_gpg_verify(buf, size, flags);
 
diff --git a/tag.h b/tag.h
index fdfcb4a84aa16b8173f8f308f7faecf8e9f000c7..d469534e82a87b651abe752469d0547c2b560e10 100644 (file)
--- a/tag.h
+++ b/tag.h
@@ -17,7 +17,7 @@ extern int parse_tag_buffer(struct tag *item, const void *data, unsigned long si
 extern int parse_tag(struct tag *item);
 extern struct object *deref_tag(struct object *, const char *, int);
 extern struct object *deref_tag_noverify(struct object *);
-extern int gpg_verify_tag(const unsigned char *sha1,
+extern int gpg_verify_tag(const struct object_id *oid,
                const char *name_to_report, unsigned flags);
 
 #endif /* TAG_H */
index 86b8f227ecab874a4af98bc5ba3164d370e5e4b5..dc707e46eb86e6aa78487447d7f2c19fd3077c87 100755 (executable)
@@ -9,8 +9,8 @@
 #
 # To enable this hook, rename this file to "prepare-commit-msg".
 
-# This hook includes three examples.  The first comments out the
-# "Conflicts:" part of a merge commit.
+# This hook includes three examples. The first one removes the
+# "# Please enter the commit message..." help message.
 #
 # The second includes the output of "git diff --name-status -r"
 # into the message, just before the "git status" output.  It is
 # The third example adds a Signed-off-by line to the message, that can
 # still be edited.  This is rarely a good idea.
 
-case "$2,$3" in
-  merge,)
-    @PERL_PATH@ -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;;
+COMMIT_MSG_FILE=$1
+COMMIT_SOURCE=$2
+SHA1=$3
 
-# ,|template,)
-#   @PERL_PATH@ -i.bak -pe '
-#      print "\n" . `git diff --cached --name-status -r`
-#       if /^#/ && $first++ == 0' "$1" ;;
+@PERL_PATH@ -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE"
 
-  *) ;;
-esac
+# case "$COMMIT_SOURCE,$SHA1" in
+#  ,|template,)
+#    @PERL_PATH@ -i.bak -pe '
+#       print "\n" . `git diff --cached --name-status -r`
+#       if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;;
+#  *) ;;
+# esac
 
 # SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
-# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
+# git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE"
+# if test -z "$COMMIT_SOURCE"
+# then
+#   @PERL_PATH@ -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE"
+# fi
index 33cff38cc0b9b4a2d05b26544c9edda9caa33e9a..8f68d69a86bd919162b62514af0b1d1d55e204a1 100644 (file)
@@ -927,7 +927,7 @@ static int push_refs_with_export(struct transport *transport,
                struct object_id oid;
 
                private = apply_refspecs(data->refspecs, data->refspec_nr, ref->name);
-               if (private && !get_sha1(private, oid.hash)) {
+               if (private && !get_oid(private, &oid)) {
                        strbuf_addf(&buf, "^%s", private);
                        string_list_append(&revlist_args, strbuf_detach(&buf, NULL));
                        oidcpy(&ref->old_oid, &oid);
index bd6d65a40920a547b9f27512e31341231273fa75..2357f72899f8f47e497ffd1bb66a0d76d7dbe012 100644 (file)
@@ -421,8 +421,9 @@ static struct combine_diff_path *ll_diff_tree_paths(
         *   diff_tree_oid(parent, commit) )
         */
        for (i = 0; i < nparent; ++i)
-               tptree[i] = fill_tree_descriptor(&tp[i], parents_oid[i]->hash);
-       ttree = fill_tree_descriptor(&t, oid->hash);
+               tptree[i] = fill_tree_descriptor(&tp[i],
+                               parents_oid[i] ? parents_oid[i]->hash : NULL);
+       ttree = fill_tree_descriptor(&t, oid ? oid->hash : NULL);
 
        /* Enable recursion indefinitely */
        opt->pathspec.recursive = DIFF_OPT_TST(opt, RECURSIVE);
index dd535bc8497e5d8202a94923fd0a68c3f46907fd..862cfce661e57e50f7c6030dd5a8eda0add0cca5 100644 (file)
@@ -380,6 +380,7 @@ static int check_updates(struct unpack_trees_options *o)
        if (should_update_submodules() && o->update && !o->dry_run)
                reload_gitmodules_file(index, &state);
 
+       enable_delayed_checkout(&state);
        for (i = 0; i < index->cache_nr; i++) {
                struct cache_entry *ce = index->cache[i];
 
@@ -394,6 +395,7 @@ static int check_updates(struct unpack_trees_options *o)
                        }
                }
        }
+       errs |= finish_delayed_checkout(&state);
        stop_progress(&progress);
        if (o->update)
                git_attr_set_direction(GIT_ATTR_CHECKIN, NULL);