Merge branch 'jk/date-local'
authorJunio C Hamano <gitster@pobox.com>
Mon, 5 Oct 2015 19:30:12 +0000 (12:30 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 5 Oct 2015 19:30:13 +0000 (12:30 -0700)
"git log --date=local" used to only show the normal (default)
format in the local timezone. The command learned to take 'local'
as an instruction to use the local timezone with other formats,
e.g. "git show --date=rfc-local".

* jk/date-local:
t6300: add tests for "-local" date formats
t6300: make UTC and local dates different
date: make "local" orthogonal to date format
date: check for "local" before anything else
t6300: add test for "raw" date format
t6300: introduce test_date() helper
fast-import: switch crash-report date to iso8601
Documentation/rev-list: don't list date formats
Documentation/git-for-each-ref: don't list date formats
Documentation/config: don't list date formats
Documentation/blame-options: don't list date formats

1  2 
Documentation/config.txt
Documentation/git-for-each-ref.txt
Documentation/git-rev-list.txt
Documentation/rev-list-options.txt
builtin/blame.c
cache.h
fast-import.c
t/t6300-for-each-ref.sh
diff --combined Documentation/config.txt
index e935cbdc0058ce0ff629237d0f928bf5b5815bb3,e08be76b80c584c2136f9954e7d14faa88b7bb5b..4d3cb107f853463c92af67ba9da70cbf3485060f
@@@ -866,9 -866,9 +866,9 @@@ branch.<name>.rebase:
        "git pull" is run. See "pull.rebase" for doing this in a non
        branch-specific manner.
  +
 -      When preserve, also pass `--preserve-merges` along to 'git rebase'
 -      so that locally committed merge commits will not be flattened
 -      by running 'git pull'.
 +When preserve, also pass `--preserve-merges` along to 'git rebase'
 +so that locally committed merge commits will not be flattened
 +by running 'git pull'.
  +
  *NOTE*: this is a possibly dangerous operation; do *not* use
  it unless you understand the implications (see linkgit:git-rebase[1]
@@@ -1250,25 -1250,6 +1250,25 @@@ filter.<driver>.smudge:
        object to a worktree file upon checkout.  See
        linkgit:gitattributes[5] for details.
  
 +fsck.<msg-id>::
 +      Allows overriding the message type (error, warn or ignore) of a
 +      specific message ID such as `missingEmail`.
 ++
 +For convenience, fsck prefixes the error/warning with the message ID,
 +e.g.  "missingEmail: invalid author/committer line - missing email" means
 +that setting `fsck.missingEmail = ignore` will hide that issue.
 ++
 +This feature is intended to support working with legacy repositories
 +which cannot be repaired without disruptive changes.
 +
 +fsck.skipList::
 +      The path to a sorted list of object names (i.e. one SHA-1 per
 +      line) that are known to be broken in a non-fatal way and should
 +      be ignored. This feature is useful when an established project
 +      should be accepted despite early commits containing errors that
 +      can be safely ignored such as invalid committer email addresses.
 +      Note: corrupt objects cannot be skipped with this setting.
 +
  gc.aggressiveDepth::
        The depth parameter used in the delta compression
        algorithm used by 'git gc --aggressive'.  This defaults
@@@ -1307,34 -1288,28 +1307,34 @@@ gc.packRefs:
  gc.pruneExpire::
        When 'git gc' is run, it will call 'prune --expire 2.weeks.ago'.
        Override the grace period with this config variable.  The value
 -      "now" may be used to disable this  grace period and always prune
 -      unreachable objects immediately.
 -
 -gc.pruneWorktreesExpire::
 -      When 'git gc' is run, it will call
 -      'prune --worktrees --expire 3.months.ago'.
 -      Override the grace period with this config variable. The value
 -      "now" may be used to disable the grace period and prune
 -      $GIT_DIR/worktrees immediately.
 +      "now" may be used to disable this grace period and always prune
 +      unreachable objects immediately, or "never" may be used to
 +      suppress pruning.
 +
 +gc.worktreePruneExpire::
 +      When 'git gc' is run, it calls
 +      'git worktree prune --expire 3.months.ago'.
 +      This config variable can be used to set a different grace
 +      period. The value "now" may be used to disable the grace
 +      period and prune $GIT_DIR/worktrees immediately, or "never"
 +      may be used to suppress pruning.
  
  gc.reflogExpire::
  gc.<pattern>.reflogExpire::
        'git reflog expire' removes reflog entries older than
 -      this time; defaults to 90 days.  With "<pattern>" (e.g.
 +      this time; defaults to 90 days. The value "now" expires all
 +      entries immediately, and "never" suppresses expiration
 +      altogether. With "<pattern>" (e.g.
        "refs/stash") in the middle the setting applies only to
        the refs that match the <pattern>.
  
  gc.reflogExpireUnreachable::
 -gc.<ref>.reflogExpireUnreachable::
 +gc.<pattern>.reflogExpireUnreachable::
        'git reflog expire' removes reflog entries older than
        this time and are not reachable from the current tip;
 -      defaults to 30 days.  With "<pattern>" (e.g. "refs/stash")
 +      defaults to 30 days. The value "now" expires all entries
 +      immediately, and "never" suppresses expiration altogether.
 +      With "<pattern>" (e.g. "refs/stash")
        in the middle, the setting applies only to the refs that
        match the <pattern>.
  
@@@ -1609,29 -1584,6 +1609,29 @@@ http.saveCookies:
        If set, store cookies received during requests to the file specified by
        http.cookieFile. Has no effect if http.cookieFile is unset.
  
 +http.sslVersion::
 +      The SSL version to use when negotiating an SSL connection, if you
 +      want to force the default.  The available and default version
 +      depend on whether libcurl was built against NSS or OpenSSL and the
 +      particular configuration of the crypto library in use. Internally
 +      this sets the 'CURLOPT_SSL_VERSION' option; see the libcurl
 +      documentation for more details on the format of this option and
 +      for the ssl version supported. Actually the possible values of
 +      this option are:
 +
 +      - sslv2
 +      - sslv3
 +      - tlsv1
 +      - tlsv1.0
 +      - tlsv1.1
 +      - tlsv1.2
 +
 ++
 +Can be overridden by the 'GIT_SSL_VERSION' environment variable.
 +To force git to use libcurl's default ssl version and ignore any
 +explicit http.sslversion option, set 'GIT_SSL_VERSION' to the
 +empty string.
 +
  http.sslCipherList::
    A list of SSL ciphers to use when negotiating an SSL connection.
    The available ciphers depend on whether libcurl was built against
@@@ -1829,9 -1781,7 +1829,7 @@@ log.abbrevCommit:
  log.date::
        Set the default date-time mode for the 'log' command.
        Setting a value for log.date is similar to using 'git log''s
-       `--date` option.  Possible values are `relative`, `local`,
-       `default`, `iso`, `rfc`, and `short`; see linkgit:git-log[1]
-       for details.
+       `--date` option.  See linkgit:git-log[1] for details.
  
  log.decorate::
        Print out the ref names of any commits that are shown by the log
@@@ -1942,18 -1892,6 +1940,18 @@@ mergetool.writeToTemp:
  mergetool.prompt::
        Prompt before each invocation of the merge resolution program.
  
 +notes.mergeStrategy::
 +      Which merge strategy to choose by default when resolving notes
 +      conflicts.  Must be one of `manual`, `ours`, `theirs`, `union`, or
 +      `cat_sort_uniq`.  Defaults to `manual`.  See "NOTES MERGE STRATEGIES"
 +      section of linkgit:git-notes[1] for more information on each strategy.
 +
 +notes.<name>.mergeStrategy::
 +      Which merge strategy to choose when doing a notes merge into
 +      refs/notes/<name>.  This overrides the more general
 +      "notes.mergeStrategy".  See the "NOTES MERGE STRATEGIES" section in
 +      linkgit:git-notes[1] for more information on the available strategies.
 +
  notes.displayRef::
        The (fully qualified) refname from which to show notes when
        showing commit messages.  The value of this variable can be set
@@@ -1982,8 -1920,8 +1980,8 @@@ notes.rewriteMode:
        When copying notes during a rewrite (see the
        "notes.rewrite.<command>" option), determines what to do if
        the target commit already has a note.  Must be one of
 -      `overwrite`, `concatenate`, or `ignore`.  Defaults to
 -      `concatenate`.
 +      `overwrite`, `concatenate`, `cat_sort_uniq`, or `ignore`.
 +      Defaults to `concatenate`.
  +
  This setting can be overridden with the `GIT_NOTES_REWRITE_MODE`
  environment variable.
@@@ -2138,9 -2076,9 +2136,9 @@@ pull.rebase:
        pull" is run. See "branch.<name>.rebase" for setting this on a
        per-branch basis.
  +
 -      When preserve, also pass `--preserve-merges` along to 'git rebase'
 -      so that locally committed merge commits will not be flattened
 -      by running 'git pull'.
 +When preserve, also pass `--preserve-merges` along to 'git rebase'
 +so that locally committed merge commits will not be flattened
 +by running 'git pull'.
  +
  *NOTE*: this is a possibly dangerous operation; do *not* use
  it unless you understand the implications (see linkgit:git-rebase[1]
@@@ -2213,14 -2151,6 +2211,14 @@@ push.followTags:
        may override this configuration at time of push by specifying
        '--no-follow-tags'.
  
 +push.gpgSign::
 +      May be set to a boolean value, or the string 'if-asked'. A true
 +      value causes all pushes to be GPG signed, as if '--signed' is
 +      passed to linkgit:git-push[1]. The string 'if-asked' causes
 +      pushes to be signed if the server supports it, as if
 +      '--signed=if-asked' is passed to 'git push'. A false value may
 +      override a value from a lower-priority config file. An explicit
 +      command-line flag always overrides this config option.
  
  rebase.stat::
        Whether to show a diffstat of what changed upstream since the last
@@@ -2237,22 -2167,6 +2235,22 @@@ rebase.autoStash:
        successful rebase might result in non-trivial conflicts.
        Defaults to false.
  
 +rebase.missingCommitsCheck::
 +      If set to "warn", git rebase -i will print a warning if some
 +      commits are removed (e.g. a line was deleted), however the
 +      rebase will still proceed. If set to "error", it will print
 +      the previous warning and stop the rebase, 'git rebase
 +      --edit-todo' can then be used to correct the error. If set to
 +      "ignore", no checking is done.
 +      To drop a commit without warning or error, use the `drop`
 +      command in the todo-list.
 +      Defaults to "ignore".
 +
 +rebase.instructionFormat
 +      A format string, as specified in linkgit:git-log[1], to be used for
 +      the instruction list during an interactive rebase.  The format will automatically
 +      have the long commit hash prepended to the format.
 +
  receive.advertiseAtomic::
        By default, git-receive-pack will advertise the atomic push
        capability to its clients. If you don't want to this capability
@@@ -2289,28 -2203,6 +2287,28 @@@ receive.fsckObjects:
        Defaults to false. If not set, the value of `transfer.fsckObjects`
        is used instead.
  
 +receive.fsck.<msg-id>::
 +      When `receive.fsckObjects` is set to true, errors can be switched
 +      to warnings and vice versa by configuring the `receive.fsck.<msg-id>`
 +      setting where the `<msg-id>` is the fsck message ID and the value
 +      is one of `error`, `warn` or `ignore`. For convenience, fsck prefixes
 +      the error/warning with the message ID, e.g. "missingEmail: invalid
 +      author/committer line - missing email" means that setting
 +      `receive.fsck.missingEmail = ignore` will hide that issue.
 ++
 +This feature is intended to support working with legacy repositories
 +which would not pass pushing when `receive.fsckObjects = true`, allowing
 +the host to accept repositories with certain known issues but still catch
 +other issues.
 +
 +receive.fsck.skipList::
 +      The path to a sorted list of object names (i.e. one SHA-1 per
 +      line) that are known to be broken in a non-fatal way and should
 +      be ignored. This feature is useful when an established project
 +      should be accepted despite early commits containing errors that
 +      can be safely ignored such as invalid committer email addresses.
 +      Note: corrupt objects cannot be skipped with this setting.
 +
  receive.unpackLimit::
        If the number of objects received in a push is below this
        limit then the objects will be unpacked into loose object
@@@ -2356,10 -2248,13 +2354,10 @@@ receive.denyNonFastForwards:
        set when initializing a shared repository.
  
  receive.hideRefs::
 -      String(s) `receive-pack` uses to decide which refs to omit
 -      from its initial advertisement.  Use more than one
 -      definitions to specify multiple prefix strings. A ref that
 -      are under the hierarchies listed on the value of this
 -      variable is excluded, and is hidden when responding to `git
 -      push`, and an attempt to update or delete a hidden ref by
 -      `git push` is rejected.
 +      This variable is the same as `transfer.hideRefs`, but applies
 +      only to `receive-pack` (and so affects pushes, but not fetches).
 +      An attempt to update or delete a hidden ref by `git push` is
 +      rejected.
  
  receive.updateServerInfo::
        If set to true, git-receive-pack will run git-update-server-info
@@@ -2587,16 -2482,6 +2585,16 @@@ status.submoduleSummary:
        submodule summary' command, which shows a similar output but does
        not honor these settings.
  
 +stash.showPatch::
 +      If this is set to true, the `git stash show` command without an
 +      option will show the stash in patch form.  Defaults to false.
 +      See description of 'show' command in linkgit:git-stash[1].
 +
 +stash.showStat::
 +      If this is set to true, the `git stash show` command without an
 +      option will show diffstat of the stash.  Defaults to true.
 +      See description of 'show' command in linkgit:git-stash[1].
 +
  submodule.<name>.path::
  submodule.<name>.url::
        The path within this project and URL for a submodule. These
@@@ -2657,18 -2542,9 +2655,18 @@@ transfer.fsckObjects:
        Defaults to false.
  
  transfer.hideRefs::
 -      This variable can be used to set both `receive.hideRefs`
 -      and `uploadpack.hideRefs` at the same time to the same
 -      values.  See entries for these other variables.
 +      String(s) `receive-pack` and `upload-pack` use to decide which
 +      refs to omit from their initial advertisements.  Use more than
 +      one definition to specify multiple prefix strings. A ref that is
 +      under the hierarchies listed in the value of this variable is
 +      excluded, and is hidden when responding to `git push` or `git
 +      fetch`.  See `receive.hideRefs` and `uploadpack.hideRefs` for
 +      program-specific versions of this config.
 ++
 +You may also include a `!` in front of the ref name to negate the entry,
 +explicitly exposing it, even if an earlier entry marked it as hidden.
 +If you have multiple hideRefs values, later entries override earlier ones
 +(and entries in more-specific config files override less-specific ones).
  
  transfer.unpackLimit::
        When `fetch.unpackLimit` or `receive.unpackLimit` are
@@@ -2683,10 -2559,13 +2681,10 @@@ uploadarchive.allowUnreachable:
        `false`.
  
  uploadpack.hideRefs::
 -      String(s) `upload-pack` uses to decide which refs to omit
 -      from its initial advertisement.  Use more than one
 -      definitions to specify multiple prefix strings. A ref that
 -      are under the hierarchies listed on the value of this
 -      variable is excluded, and is hidden from `git ls-remote`,
 -      `git fetch`, etc.  An attempt to fetch a hidden ref by `git
 -      fetch` will fail.  See also `uploadpack.allowTipSHA1InWant`.
 +      This variable is the same as `transfer.hideRefs`, but applies
 +      only to `upload-pack` (and so affects only fetches, not pushes).
 +      An attempt to fetch a hidden ref by `git fetch` will fail.  See
 +      also `uploadpack.allowTipSHA1InWant`.
  
  uploadpack.allowTipSHA1InWant::
        When `uploadpack.hideRefs` is in effect, allow `upload-pack`
index e49d5782fc6f82289d0b71c720110b11e38cb8b0,d0626395570817e0469c26acda0ab18d60929bce..d6a1abcca5e8bb451595f4a2bc0d9852496584b7
@@@ -10,8 -10,6 +10,8 @@@ SYNOPSI
  [verse]
  'git for-each-ref' [--count=<count>] [--shell|--perl|--python|--tcl]
                   [(--sort=<key>)...] [--format=<format>] [<pattern>...]
 +                 [--points-at <object>] [(--merged | --no-merged) [<object>]]
 +                 [--contains [<object>]]
  
  DESCRIPTION
  -----------
@@@ -64,20 -62,6 +64,20 @@@ OPTION
        the specified host language.  This is meant to produce
        a scriptlet that can directly be `eval`ed.
  
 +--points-at <object>::
 +      Only list refs which points at the given object.
 +
 +--merged [<object>]::
 +      Only list refs whose tips are reachable from the
 +      specified commit (HEAD if not specified).
 +
 +--no-merged [<object>]::
 +      Only list refs whose tips are not reachable from the
 +      specified commit (HEAD if not specified).
 +
 +--contains [<object>]::
 +      Only list tags which contain the specified commit (HEAD if not
 +      specified).
  
  FIELD NAMES
  -----------
@@@ -150,9 -134,8 +150,8 @@@ the object referred by the ref does no
  returns an empty string instead.
  
  As a special case for the date-type fields, you may specify a format for
- the date by adding one of `:default`, `:relative`, `:short`, `:local`,
- `:iso8601`, `:rfc2822` or `:raw` to the end of the fieldname; e.g.
- `%(taggerdate:relative)`.
+ the date by adding `:` followed by date format name (see the
+ values the `--date` option to linkgit::git-rev-list[1] takes).
  
  
  EXAMPLES
index 7b49c85347ec583c4d9849a3f0bc878d776e9519,51c7d0720823406debe68b743ca388736203e02d..ef22f1775b634812a6d0595ca3d88ce0b0c51506
@@@ -45,7 -45,7 +45,7 @@@ SYNOPSI
             [ --regexp-ignore-case | -i ]
             [ --extended-regexp | -E ]
             [ --fixed-strings | -F ]
-            [ --date=(local|relative|default|iso|iso-strict|rfc|short) ]
+            [ --date=<format>]
             [ [ --objects | --objects-edge | --objects-edge-aggressive ]
               [ --unpacked ] ]
             [ --pretty | --header ]
@@@ -56,7 -56,6 +56,7 @@@
             [ --reverse ]
             [ --walk-reflogs ]
             [ --no-walk ] [ --do-walk ]
 +           [ --count ]
             [ --use-bitmap-index ]
             <commit>... [ \-- <paths>... ]
  
index f1c52208f08c3dc9f50e8d18f546a96276a47fec,359587c505a1845c52c28318a80ba298a4eee97e..4f009d44240e3725e25bc8a9a3acd999d69cc487
@@@ -58,11 -58,9 +58,11 @@@ endif::git-rev-list[
        more than one `--grep=<pattern>`, commits whose message
        matches any of the given patterns are chosen (but see
        `--all-match`).
 +ifndef::git-rev-list[]
  +
  When `--show-notes` is in effect, the message from the notes is
  matched as if it were part of the log message.
 +endif::git-rev-list[]
  
  --all-match::
        Limit the commits output to ones that match all given `--grep`,
@@@ -701,15 -699,19 +701,19 @@@ include::pretty-options.txt[
  --relative-date::
        Synonym for `--date=relative`.
  
- --date=(relative|local|default|iso|iso-strict|rfc|short|raw)::
+ --date=<format>::
        Only takes effect for dates shown in human-readable format, such
        as when using `--pretty`. `log.date` config variable sets a default
-       value for the log command's `--date` option.
+       value for the log command's `--date` option. By default, dates
+       are shown in the original time zone (either committer's or
+       author's). If `-local` is appended to the format (e.g.,
+       `iso-local`), the user's local time zone is used instead.
  +
  `--date=relative` shows dates relative to the current time,
- e.g. ``2 hours ago''.
+ e.g. ``2 hours ago''. The `-local` option cannot be used with
+ `--raw` or `--relative`.
  +
- `--date=local` shows timestamps in user's local time zone.
+ `--date=local` is an alias for `--date=default-local`.
  +
  `--date=iso` (or `--date=iso8601`) shows timestamps in a ISO 8601-like format.
  The differences to the strict ISO 8601 format are:
@@@ -732,10 -734,15 +736,15 @@@ format, often found in email messages
  `--date=format:...` feeds the format `...` to your system `strftime`.
  Use `--date=format:%c` to show the date in your system locale's
  preferred format.  See the `strftime` manual for a complete list of
- format placeholders.
+ format placeholders. When using `-local`, the correct syntax is
+ `--date=format-local:...`.
  +
- `--date=default` shows timestamps in the original time zone
- (either committer's or author's).
+ `--date=default` is the default format, and is similar to
+ `--date=rfc2822`, with a few exceptions:
+       - there is no comma after the day-of-week
+       - the time zone is omitted when the local time zone is used
  
  ifdef::git-rev-list[]
  --header::
diff --combined builtin/blame.c
index 4db01c195cd27719023eeb599e76428ad752c9c9,cb4ab204a9ecfc05889533512cc63a74e00a5554..6fd1a63fc7e45464ebb85d339f464f55f350ac8d
@@@ -6,7 -6,6 +6,7 @@@
   */
  
  #include "cache.h"
 +#include "refs.h"
  #include "builtin.h"
  #include "blob.h"
  #include "commit.h"
@@@ -2227,19 -2226,20 +2227,19 @@@ static struct commit_list **append_pare
  static void append_merge_parents(struct commit_list **tail)
  {
        int merge_head;
 -      const char *merge_head_file = git_path("MERGE_HEAD");
        struct strbuf line = STRBUF_INIT;
  
 -      merge_head = open(merge_head_file, O_RDONLY);
 +      merge_head = open(git_path_merge_head(), O_RDONLY);
        if (merge_head < 0) {
                if (errno == ENOENT)
                        return;
 -              die("cannot open '%s' for reading", merge_head_file);
 +              die("cannot open '%s' for reading", git_path_merge_head());
        }
  
        while (!strbuf_getwholeline_fd(&line, merge_head, '\n')) {
                unsigned char sha1[20];
                if (line.len < 40 || get_sha1_hex(line.buf, sha1))
 -                      die("unknown line in '%s': %s", merge_head_file, line.buf);
 +                      die("unknown line in '%s': %s", git_path_merge_head(), line.buf);
                tail = append_parent(tail, sha1);
        }
        close(merge_head);
@@@ -2600,7 -2600,6 +2600,6 @@@ parse_done
                   fewer display columns. */
                blame_date_width = utf8_strwidth(_("4 years, 11 months ago")) + 1; /* add the null */
                break;
-       case DATE_LOCAL:
        case DATE_NORMAL:
                blame_date_width = sizeof("Thu Oct 19 16:00:04 2006 -0700");
                break;
diff --combined cache.h
index 79066e57dc806d118366d9807e0af338b72e2fb2,ebb72568c2fdf04ee226c863afe1e9e03f39ff69..752031e84ab8231a3bf516951b05aa8a6434aa25
+++ b/cache.h
@@@ -397,7 -397,6 +397,7 @@@ static inline enum object_type object_t
  #define EXEC_PATH_ENVIRONMENT "GIT_EXEC_PATH"
  #define CEILING_DIRECTORIES_ENVIRONMENT "GIT_CEILING_DIRECTORIES"
  #define NO_REPLACE_OBJECTS_ENVIRONMENT "GIT_NO_REPLACE_OBJECTS"
 +#define GIT_REPLACE_REF_BASE_ENVIRONMENT "GIT_REPLACE_REF_BASE"
  #define GITATTRIBUTES_FILE ".gitattributes"
  #define INFOATTRIBUTES_FILE "info/attributes"
  #define ATTRIBUTE_MACRO_PREFIX "[attr]"
@@@ -447,17 -446,7 +447,17 @@@ extern int get_common_dir(struct strbu
  extern const char *get_git_namespace(void);
  extern const char *strip_namespace(const char *namespaced_ref);
  extern const char *get_git_work_tree(void);
 -extern const char *read_gitfile(const char *path);
 +
 +#define READ_GITFILE_ERR_STAT_FAILED 1
 +#define READ_GITFILE_ERR_NOT_A_FILE 2
 +#define READ_GITFILE_ERR_OPEN_FAILED 3
 +#define READ_GITFILE_ERR_READ_FAILED 4
 +#define READ_GITFILE_ERR_INVALID_FORMAT 5
 +#define READ_GITFILE_ERR_NO_PATH 6
 +#define READ_GITFILE_ERR_NOT_A_REPO 7
 +#define READ_GITFILE_ERR_TOO_LARGE 8
 +extern const char *read_gitfile_gently(const char *path, int *return_error_code);
 +#define read_gitfile(path) read_gitfile_gently((path), NULL)
  extern const char *resolve_gitdir(const char *suspect);
  extern void set_git_work_tree(const char *tree);
  
@@@ -596,6 -585,8 +596,6 @@@ extern void update_index_if_able(struc
  extern int hold_locked_index(struct lock_file *, int);
  extern void set_alternate_index_output(const char *);
  
 -extern int delete_ref(const char *, const unsigned char *sha1, unsigned int flags);
 -
  /* Environment bits from configuration mechanism */
  extern int trust_executable_bit;
  extern int trust_ctime;
@@@ -631,7 -622,6 +631,7 @@@ extern unsigned long pack_size_limit_cf
   * been sought but there were none.
   */
  extern int check_replace_refs;
 +extern char *git_replace_ref_base;
  
  extern int fsync_object_files;
  extern int core_preload_index;
@@@ -708,59 -698,22 +708,59 @@@ extern int check_repository_format(void
  #define DATA_CHANGED    0x0020
  #define TYPE_CHANGED    0x0040
  
 +/*
 + * Return a statically allocated filename, either generically (mkpath), in
 + * the repository directory (git_path), or in a submodule's repository
 + * directory (git_path_submodule). In all cases, note that the result
 + * may be overwritten by another call to _any_ of the functions. Consider
 + * using the safer "dup" or "strbuf" formats below (in some cases, the
 + * unsafe versions have already been removed).
 + */
 +extern const char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 +extern const char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 +
  extern char *mksnpath(char *buf, size_t n, const char *fmt, ...)
        __attribute__((format (printf, 3, 4)));
  extern void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
        __attribute__((format (printf, 2, 3)));
 +extern void strbuf_git_path_submodule(struct strbuf *sb, const char *path,
 +                                    const char *fmt, ...)
 +      __attribute__((format (printf, 3, 4)));
  extern char *git_pathdup(const char *fmt, ...)
        __attribute__((format (printf, 1, 2)));
  extern char *mkpathdup(const char *fmt, ...)
        __attribute__((format (printf, 1, 2)));
 -
 -/* Return a statically allocated filename matching the sha1 signature */
 -extern const char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 -extern const char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 -extern const char *git_path_submodule(const char *path, const char *fmt, ...)
 +extern char *git_pathdup_submodule(const char *path, const char *fmt, ...)
        __attribute__((format (printf, 2, 3)));
 +
  extern void report_linked_checkout_garbage(void);
  
 +/*
 + * You can define a static memoized git path like:
 + *
 + *    static GIT_PATH_FUNC(git_path_foo, "FOO");
 + *
 + * or use one of the global ones below.
 + */
 +#define GIT_PATH_FUNC(func, filename) \
 +      const char *func(void) \
 +      { \
 +              static char *ret; \
 +              if (!ret) \
 +                      ret = git_pathdup(filename); \
 +              return ret; \
 +      }
 +
 +const char *git_path_cherry_pick_head(void);
 +const char *git_path_revert_head(void);
 +const char *git_path_squash_msg(void);
 +const char *git_path_merge_msg(void);
 +const char *git_path_merge_rr(void);
 +const char *git_path_merge_mode(void);
 +const char *git_path_merge_head(void);
 +const char *git_path_fetch_head(void);
 +const char *git_path_shallow(void);
 +
  /*
   * Return the name of the file in the local object database that would
   * be used to store a loose object with the specified sha1.  The
@@@ -982,7 -935,7 +982,7 @@@ extern int do_check_packed_object_crc
  
  extern int check_sha1_signature(const unsigned char *sha1, void *buf, unsigned long size, const char *type);
  
 -extern int move_temp_to_file(const char *tmpfile, const char *filename);
 +extern int finalize_object_file(const char *tmpfile, const char *filename);
  
  extern int has_sha1_pack(const unsigned char *sha1);
  
@@@ -1067,10 -1020,76 +1067,10 @@@ extern int get_oid_hex(const char *hex
  
  extern char *sha1_to_hex(const unsigned char *sha1);  /* static buffer result! */
  extern char *oid_to_hex(const struct object_id *oid); /* same static buffer as sha1_to_hex */
 -extern int read_ref_full(const char *refname, int resolve_flags,
 -                       unsigned char *sha1, int *flags);
 -extern int read_ref(const char *refname, unsigned char *sha1);
  
 -/*
 - * Resolve a reference, recursively following symbolic refererences.
 - *
 - * Store the referred-to object's name in sha1 and return the name of
 - * the non-symbolic reference that ultimately pointed at it.  The
 - * return value, if not NULL, is a pointer into either a static buffer
 - * or the input ref.
 - *
 - * If the reference cannot be resolved to an object, the behavior
 - * depends on the RESOLVE_REF_READING flag:
 - *
 - * - If RESOLVE_REF_READING is set, return NULL.
 - *
 - * - If RESOLVE_REF_READING is not set, clear sha1 and return the name of
 - *   the last reference name in the chain, which will either be a non-symbolic
 - *   reference or an undefined reference.  If this is a prelude to
 - *   "writing" to the ref, the return value is the name of the ref
 - *   that will actually be created or changed.
 - *
 - * If the RESOLVE_REF_NO_RECURSE flag is passed, only resolves one
 - * level of symbolic reference.  The value stored in sha1 for a symbolic
 - * reference will always be null_sha1 in this case, and the return
 - * value is the reference that the symref refers to directly.
 - *
 - * If flags is non-NULL, set the value that it points to the
 - * combination of REF_ISPACKED (if the reference was found among the
 - * packed references), REF_ISSYMREF (if the initial reference was a
 - * symbolic reference), REF_BAD_NAME (if the reference name is ill
 - * formed --- see RESOLVE_REF_ALLOW_BAD_NAME below), and REF_ISBROKEN
 - * (if the ref is malformed or has a bad name). See refs.h for more detail
 - * on each flag.
 - *
 - * If ref is not a properly-formatted, normalized reference, return
 - * NULL.  If more than MAXDEPTH recursive symbolic lookups are needed,
 - * give up and return NULL.
 - *
 - * RESOLVE_REF_ALLOW_BAD_NAME allows resolving refs even when their
 - * name is invalid according to git-check-ref-format(1).  If the name
 - * is bad then the value stored in sha1 will be null_sha1 and the two
 - * flags REF_ISBROKEN and REF_BAD_NAME will be set.
 - *
 - * Even with RESOLVE_REF_ALLOW_BAD_NAME, names that escape the refs/
 - * directory and do not consist of all caps and underscores cannot be
 - * resolved. The function returns NULL for such ref names.
 - * Caps and underscores refers to the special refs, such as HEAD,
 - * FETCH_HEAD and friends, that all live outside of the refs/ directory.
 - */
 -#define RESOLVE_REF_READING 0x01
 -#define RESOLVE_REF_NO_RECURSE 0x02
 -#define RESOLVE_REF_ALLOW_BAD_NAME 0x04
 -extern const char *resolve_ref_unsafe(const char *ref, int resolve_flags, unsigned char *sha1, int *flags);
 -extern char *resolve_refdup(const char *ref, int resolve_flags, unsigned char *sha1, int *flags);
 -
 -extern int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref);
 -extern int dwim_log(const char *str, int len, unsigned char *sha1, char **ref);
  extern int interpret_branch_name(const char *str, int len, struct strbuf *);
  extern int get_sha1_mb(const char *str, unsigned char *sha1);
  
 -/*
 - * Return true iff abbrev_name is a possible abbreviation for
 - * full_name according to the rules defined by ref_rev_parse_rules in
 - * refs.c.
 - */
 -extern int refname_match(const char *abbrev_name, const char *full_name);
 -
 -extern int create_symref(const char *ref, const char *refs_heads_master, const char *logmsg);
  extern int validate_headref(const char *ref);
  
  extern int base_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
@@@ -1091,7 -1110,6 +1091,6 @@@ struct date_mode 
                DATE_NORMAL = 0,
                DATE_RELATIVE,
                DATE_SHORT,
-               DATE_LOCAL,
                DATE_ISO8601,
                DATE_ISO8601_STRICT,
                DATE_RFC2822,
                DATE_RAW
        } type;
        const char *strftime_fmt;
+       int local;
  };
  
  /*
@@@ -1429,7 -1448,6 +1429,7 @@@ extern int git_config_with_options(conf
                                   int respect_includes);
  extern int git_config_early(config_fn_t fn, void *, const char *repo_config);
  extern int git_parse_ulong(const char *, unsigned long *);
 +extern int git_parse_maybe_bool(const char *);
  extern int git_config_int(const char *, const char *);
  extern int64_t git_config_int64(const char *, const char *);
  extern unsigned long git_config_ulong(const char *, const char *);
@@@ -1441,7 -1459,6 +1441,7 @@@ extern int git_config_pathname(const ch
  extern int git_config_set_in_file(const char *, const char *, const char *);
  extern int git_config_set(const char *, const char *);
  extern int git_config_parse_key(const char *, char **, int *);
 +extern int git_config_key_is_valid(const char *key);
  extern int git_config_set_multivar(const char *, const char *, const char *, int);
  extern int git_config_set_multivar_in_file(const char *, const char *, const char *, const char *, int);
  extern int git_config_rename_section(const char *, const char *);
@@@ -1578,9 -1595,8 +1578,9 @@@ static inline ssize_t write_str_in_full
  {
        return write_in_full(fd, str, strlen(str));
  }
 -__attribute__((format (printf, 3, 4)))
 -extern int write_file(const char *path, int fatal, const char *fmt, ...);
 +
 +extern int write_file(const char *path, const char *fmt, ...);
 +extern int write_file_gently(const char *path, const char *fmt, ...);
  
  /* pager.c */
  extern void setup_pager(void);
diff --combined fast-import.c
index 6c7c3c9b669eb272f4da530aef459c9c39c4d294,1343865278ec69b394d7a9098650a0b4a26b11ad..adcbfc67dca7aecd8f1680f3e30b05dcfa400b59
@@@ -134,17 -134,16 +134,17 @@@ Format of STDIN stream
    ts    ::= # time since the epoch in seconds, ascii base10 notation;
    tz    ::= # GIT style timezone;
  
 -     # note: comments, ls and cat requests may appear anywhere
 -     # in the input, except within a data command.  Any form
 -     # of the data command always escapes the related input
 -     # from comment processing.
 +     # note: comments, get-mark, ls-tree, and cat-blob requests may
 +     # appear anywhere in the input, except within a data command. Any
 +     # form of the data command always escapes the related input from
 +     # comment processing.
       #
       # In case it is not clear, the '#' that starts the comment
       # must be the first character on that line (an lf
       # preceded it).
       #
  
 +  get_mark ::= 'get-mark' sp idnum lf;
    cat_blob ::= 'cat-blob' sp (hexsha1 | idnum) lf;
    ls_tree  ::= 'ls' sp (hexsha1 | idnum) sp path_str lf;
  
@@@ -373,7 -372,6 +373,7 @@@ static volatile sig_atomic_t checkpoint
  static int cat_blob_fd = STDOUT_FILENO;
  
  static void parse_argv(void);
 +static void parse_get_mark(const char *p);
  static void parse_cat_blob(const char *p);
  static void parse_ls(const char *p, struct branch *b);
  
@@@ -407,7 -405,7 +407,7 @@@ static void dump_marks_helper(FILE *, u
  
  static void write_crash_report(const char *err)
  {
 -      const char *loc = git_path("fast_import_crash_%"PRIuMAX, (uintmax_t) getpid());
 +      char *loc = git_pathdup("fast_import_crash_%"PRIuMAX, (uintmax_t) getpid());
        FILE *rpt = fopen(loc, "w");
        struct branch *b;
        unsigned long lu;
  
        if (!rpt) {
                error("can't write crash report %s: %s", loc, strerror(errno));
 +              free(loc);
                return;
        }
  
        fprintf(rpt, "fast-import crash report:\n");
        fprintf(rpt, "    fast-import process: %"PRIuMAX"\n", (uintmax_t) getpid());
        fprintf(rpt, "    parent process     : %"PRIuMAX"\n", (uintmax_t) getppid());
-       fprintf(rpt, "    at %s\n", show_date(time(NULL), 0, DATE_MODE(LOCAL)));
+       fprintf(rpt, "    at %s\n", show_date(time(NULL), 0, DATE_MODE(ISO8601)));
        fputc('\n', rpt);
  
        fputs("fatal: ", rpt);
        fputs("-------------------\n", rpt);
        fputs("END OF CRASH REPORT\n", rpt);
        fclose(rpt);
 +      free(loc);
  }
  
  static void end_packfile(void);
@@@ -925,12 -921,12 +925,12 @@@ static char *keep_pack(const char *curr
  
        snprintf(name, sizeof(name), "%s/pack/pack-%s.pack",
                 get_object_directory(), sha1_to_hex(pack_data->sha1));
 -      if (move_temp_to_file(pack_data->pack_name, name))
 +      if (finalize_object_file(pack_data->pack_name, name))
                die("cannot store pack file");
  
        snprintf(name, sizeof(name), "%s/pack/pack-%s.idx",
                 get_object_directory(), sha1_to_hex(pack_data->sha1));
 -      if (move_temp_to_file(curr_index_name, name))
 +      if (finalize_object_file(curr_index_name, name))
                die("cannot store index file");
        free((void *)curr_index_name);
        return name;
@@@ -1696,13 -1692,13 +1696,13 @@@ static int update_branch(struct branch 
        unsigned char old_sha1[20];
        struct strbuf err = STRBUF_INIT;
  
 -      if (read_ref(b->name, old_sha1))
 -              hashclr(old_sha1);
        if (is_null_sha1(b->sha1)) {
                if (b->delete)
 -                      delete_ref(b->name, old_sha1, 0);
 +                      delete_ref(b->name, NULL, 0);
                return 0;
        }
 +      if (read_ref(b->name, old_sha1))
 +              hashclr(old_sha1);
        if (!force_update && !is_null_sha1(old_sha1)) {
                struct commit *old_cmit, *new_cmit;
  
@@@ -1911,10 -1907,6 +1911,10 @@@ static int read_next_command(void
                        rc->prev->next = rc;
                        cmd_tail = rc;
                }
 +              if (skip_prefix(command_buf.buf, "get-mark ", &p)) {
 +                      parse_get_mark(p);
 +                      continue;
 +              }
                if (skip_prefix(command_buf.buf, "cat-blob ", &p)) {
                        parse_cat_blob(p);
                        continue;
@@@ -2596,12 -2588,14 +2596,12 @@@ static int parse_from(struct branch *b
  {
        const char *from;
        struct branch *s;
 +      unsigned char sha1[20];
  
        if (!skip_prefix(command_buf.buf, "from ", &from))
                return 0;
  
 -      if (b->branch_tree.tree) {
 -              release_tree_content_recursive(b->branch_tree.tree);
 -              b->branch_tree.tree = NULL;
 -      }
 +      hashcpy(sha1, b->branch_tree.versions[1].sha1);
  
        s = lookup_branch(from);
        if (b == s)
                struct object_entry *oe = find_mark(idnum);
                if (oe->type != OBJ_COMMIT)
                        die("Mark :%" PRIuMAX " not a commit", idnum);
 -              hashcpy(b->sha1, oe->idx.sha1);
 -              if (oe->pack_id != MAX_PACK_ID) {
 -                      unsigned long size;
 -                      char *buf = gfi_unpack_entry(oe, &size);
 -                      parse_from_commit(b, buf, size);
 -                      free(buf);
 -              } else
 -                      parse_from_existing(b);
 +              if (hashcmp(b->sha1, oe->idx.sha1)) {
 +                      hashcpy(b->sha1, oe->idx.sha1);
 +                      if (oe->pack_id != MAX_PACK_ID) {
 +                              unsigned long size;
 +                              char *buf = gfi_unpack_entry(oe, &size);
 +                              parse_from_commit(b, buf, size);
 +                              free(buf);
 +                      } else
 +                              parse_from_existing(b);
 +              }
        } else if (!get_sha1(from, b->sha1)) {
                parse_from_existing(b);
                if (is_null_sha1(b->sha1))
        else
                die("Invalid ref name or SHA1 expression: %s", from);
  
 +      if (b->branch_tree.tree && hashcmp(sha1, b->branch_tree.versions[1].sha1)) {
 +              release_tree_content_recursive(b->branch_tree.tree);
 +              b->branch_tree.tree = NULL;
 +      }
 +
        read_next_command();
        return 1;
  }
@@@ -2932,23 -2919,6 +2932,23 @@@ static void cat_blob(struct object_entr
                free(buf);
  }
  
 +static void parse_get_mark(const char *p)
 +{
 +      struct object_entry *oe = oe;
 +      char output[42];
 +
 +      /* get-mark SP <object> LF */
 +      if (*p != ':')
 +              die("Not a mark: %s", p);
 +
 +      oe = find_mark(parse_mark_ref_eol(p));
 +      if (!oe)
 +              die("Unknown mark: %s", command_buf.buf);
 +
 +      snprintf(output, sizeof(output), "%s\n", sha1_to_hex(oe->idx.sha1));
 +      cat_blob_write(output, 41);
 +}
 +
  static void parse_cat_blob(const char *p)
  {
        struct object_entry *oe = oe;
@@@ -3270,8 -3240,6 +3270,8 @@@ static int parse_one_feature(const cha
                option_import_marks(arg, from_stream, 1);
        } else if (skip_prefix(feature, "export-marks=", &arg)) {
                option_export_marks(arg);
 +      } else if (!strcmp(feature, "get-mark")) {
 +              ; /* Don't die - this feature is supported */
        } else if (!strcmp(feature, "cat-blob")) {
                ; /* Don't die - this feature is supported */
        } else if (!strcmp(feature, "relative-marks")) {
diff --combined t/t6300-for-each-ref.sh
index 7c9bec76302259beebeea7521b9c74acfe6de264,d6c9e627acd9d7ee997790ef71bd5aa7db53c90f..03873b09d1a4480549e1b8ab92fc3780fb874d89
@@@ -8,8 -8,8 +8,8 @@@ test_description='for-each-ref test
  . ./test-lib.sh
  . "$TEST_DIRECTORY"/lib-gpg.sh
  
- # Mon Jul 3 15:18:43 2006 +0000
- datestamp=1151939923
+ # Mon Jul 3 23:18:43 2006 +0000
+ datestamp=1151968723
  setdate_and_increment () {
      GIT_COMMITTER_DATE="$datestamp +0200"
      datestamp=$(expr "$datestamp" + 1)
@@@ -61,21 -61,21 +61,21 @@@ test_atom head object '
  test_atom head type ''
  test_atom head '*objectname' ''
  test_atom head '*objecttype' ''
- test_atom head author 'A U Thor <author@example.com> 1151939924 +0200'
+ test_atom head author 'A U Thor <author@example.com> 1151968724 +0200'
  test_atom head authorname 'A U Thor'
  test_atom head authoremail '<author@example.com>'
- test_atom head authordate 'Mon Jul 3 17:18:44 2006 +0200'
- test_atom head committer 'C O Mitter <committer@example.com> 1151939923 +0200'
+ test_atom head authordate 'Tue Jul 4 01:18:44 2006 +0200'
+ test_atom head committer 'C O Mitter <committer@example.com> 1151968723 +0200'
  test_atom head committername 'C O Mitter'
  test_atom head committeremail '<committer@example.com>'
- test_atom head committerdate 'Mon Jul 3 17:18:43 2006 +0200'
+ test_atom head committerdate 'Tue Jul 4 01:18:43 2006 +0200'
  test_atom head tag ''
  test_atom head tagger ''
  test_atom head taggername ''
  test_atom head taggeremail ''
  test_atom head taggerdate ''
- test_atom head creator 'C O Mitter <committer@example.com> 1151939923 +0200'
- test_atom head creatordate 'Mon Jul 3 17:18:43 2006 +0200'
+ test_atom head creator 'C O Mitter <committer@example.com> 1151968723 +0200'
+ test_atom head creatordate 'Tue Jul 4 01:18:43 2006 +0200'
  test_atom head subject 'Initial'
  test_atom head contents:subject 'Initial'
  test_atom head body ''
@@@ -96,7 -96,7 +96,7 @@@ test_atom tag parent '
  test_atom tag numparent ''
  test_atom tag object $(git rev-parse refs/tags/testtag^0)
  test_atom tag type 'commit'
- test_atom tag '*objectname' '67a36f10722846e891fbada1ba48ed035de75581'
+ test_atom tag '*objectname' 'ea122842f48be4afb2d1fc6a4b96c05885ab7463'
  test_atom tag '*objecttype' 'commit'
  test_atom tag author ''
  test_atom tag authorname ''
@@@ -107,18 -107,18 +107,18 @@@ test_atom tag committername '
  test_atom tag committeremail ''
  test_atom tag committerdate ''
  test_atom tag tag 'testtag'
- test_atom tag tagger 'C O Mitter <committer@example.com> 1151939925 +0200'
+ test_atom tag tagger 'C O Mitter <committer@example.com> 1151968725 +0200'
  test_atom tag taggername 'C O Mitter'
  test_atom tag taggeremail '<committer@example.com>'
- test_atom tag taggerdate 'Mon Jul 3 17:18:45 2006 +0200'
- test_atom tag creator 'C O Mitter <committer@example.com> 1151939925 +0200'
- test_atom tag creatordate 'Mon Jul 3 17:18:45 2006 +0200'
- test_atom tag subject 'Tagging at 1151939927'
- test_atom tag contents:subject 'Tagging at 1151939927'
+ test_atom tag taggerdate 'Tue Jul 4 01:18:45 2006 +0200'
+ test_atom tag creator 'C O Mitter <committer@example.com> 1151968725 +0200'
+ test_atom tag creatordate 'Tue Jul 4 01:18:45 2006 +0200'
+ test_atom tag subject 'Tagging at 1151968727'
+ test_atom tag contents:subject 'Tagging at 1151968727'
  test_atom tag body ''
  test_atom tag contents:body ''
  test_atom tag contents:signature ''
- test_atom tag contents 'Tagging at 1151939927
+ test_atom tag contents 'Tagging at 1151968727
  '
  test_atom tag HEAD ' '
  
@@@ -146,105 -146,123 +146,133 @@@ test_expect_success 'Check invalid form
        test_must_fail git for-each-ref --format="%(authordate:INVALID)" refs/heads
  '
  
- cat >expected <<\EOF
- 'refs/heads/master' 'Mon Jul 3 17:18:43 2006 +0200' 'Mon Jul 3 17:18:44 2006 +0200'
- 'refs/tags/testtag' 'Mon Jul 3 17:18:45 2006 +0200'
- EOF
+ test_date () {
+       f=$1 &&
+       committer_date=$2 &&
+       author_date=$3 &&
+       tagger_date=$4 &&
+       cat >expected <<-EOF &&
+       'refs/heads/master' '$committer_date' '$author_date'
+       'refs/tags/testtag' '$tagger_date'
+       EOF
+       (
+               git for-each-ref --shell \
+                       --format="%(refname) %(committerdate${f:+:$f}) %(authordate${f:+:$f})" \
+                       refs/heads &&
+               git for-each-ref --shell \
+                       --format="%(refname) %(taggerdate${f:+:$f})" \
+                       refs/tags
+       ) >actual &&
+       test_cmp expected actual
+ }
  
  test_expect_success 'Check unformatted date fields output' '
-       (git for-each-ref --shell --format="%(refname) %(committerdate) %(authordate)" refs/heads &&
-       git for-each-ref --shell --format="%(refname) %(taggerdate)" refs/tags) >actual &&
-       test_cmp expected actual
+       test_date "" \
+               "Tue Jul 4 01:18:43 2006 +0200" \
+               "Tue Jul 4 01:18:44 2006 +0200" \
+               "Tue Jul 4 01:18:45 2006 +0200"
  '
  
  test_expect_success 'Check format "default" formatted date fields output' '
-       f=default &&
-       (git for-each-ref --shell --format="%(refname) %(committerdate:$f) %(authordate:$f)" refs/heads &&
-       git for-each-ref --shell --format="%(refname) %(taggerdate:$f)" refs/tags) >actual &&
-       test_cmp expected actual
+       test_date default \
+               "Tue Jul 4 01:18:43 2006 +0200" \
+               "Tue Jul 4 01:18:44 2006 +0200" \
+               "Tue Jul 4 01:18:45 2006 +0200"
+ '
+ test_expect_success 'Check format "default-local" date fields output' '
+       test_date default-local "Mon Jul 3 23:18:43 2006" "Mon Jul 3 23:18:44 2006" "Mon Jul 3 23:18:45 2006"
  '
  
  # Don't know how to do relative check because I can't know when this script
  # is going to be run and can't fake the current time to git, and hence can't
  # provide expected output.  Instead, I'll just make sure that "relative"
  # doesn't exit in error
- #
- #cat >expected <<\EOF
- #
- #EOF
- #
  test_expect_success 'Check format "relative" date fields output' '
        f=relative &&
        (git for-each-ref --shell --format="%(refname) %(committerdate:$f) %(authordate:$f)" refs/heads &&
        git for-each-ref --shell --format="%(refname) %(taggerdate:$f)" refs/tags) >actual
  '
  
- cat >expected <<\EOF
- 'refs/heads/master' '2006-07-03' '2006-07-03'
- 'refs/tags/testtag' '2006-07-03'
- EOF
+ # We just check that this is the same as "relative" for now.
+ test_expect_success 'Check format "relative-local" date fields output' '
+       test_date relative-local \
+               "$(git for-each-ref --format="%(committerdate:relative)" refs/heads)" \
+               "$(git for-each-ref --format="%(authordate:relative)" refs/heads)" \
+               "$(git for-each-ref --format="%(taggerdate:relative)" refs/tags)"
+ '
  
  test_expect_success 'Check format "short" date fields output' '
-       f=short &&
-       (git for-each-ref --shell --format="%(refname) %(committerdate:$f) %(authordate:$f)" refs/heads &&
-       git for-each-ref --shell --format="%(refname) %(taggerdate:$f)" refs/tags) >actual &&
-       test_cmp expected actual
+       test_date short 2006-07-04 2006-07-04 2006-07-04
  '
  
- cat >expected <<\EOF
- 'refs/heads/master' 'Mon Jul 3 15:18:43 2006' 'Mon Jul 3 15:18:44 2006'
- 'refs/tags/testtag' 'Mon Jul 3 15:18:45 2006'
- EOF
+ test_expect_success 'Check format "short-local" date fields output' '
+       test_date short-local 2006-07-03 2006-07-03 2006-07-03
+ '
  
  test_expect_success 'Check format "local" date fields output' '
-       f=local &&
-       (git for-each-ref --shell --format="%(refname) %(committerdate:$f) %(authordate:$f)" refs/heads &&
-       git for-each-ref --shell --format="%(refname) %(taggerdate:$f)" refs/tags) >actual &&
-       test_cmp expected actual
+       test_date local \
+               "Mon Jul 3 23:18:43 2006" \
+               "Mon Jul 3 23:18:44 2006" \
+               "Mon Jul 3 23:18:45 2006"
  '
  
- cat >expected <<\EOF
- 'refs/heads/master' '2006-07-03 17:18:43 +0200' '2006-07-03 17:18:44 +0200'
- 'refs/tags/testtag' '2006-07-03 17:18:45 +0200'
- EOF
  test_expect_success 'Check format "iso8601" date fields output' '
-       f=iso8601 &&
-       (git for-each-ref --shell --format="%(refname) %(committerdate:$f) %(authordate:$f)" refs/heads &&
-       git for-each-ref --shell --format="%(refname) %(taggerdate:$f)" refs/tags) >actual &&
-       test_cmp expected actual
+       test_date iso8601 \
+               "2006-07-04 01:18:43 +0200" \
+               "2006-07-04 01:18:44 +0200" \
+               "2006-07-04 01:18:45 +0200"
  '
  
- cat >expected <<\EOF
- 'refs/heads/master' 'Mon, 3 Jul 2006 17:18:43 +0200' 'Mon, 3 Jul 2006 17:18:44 +0200'
- 'refs/tags/testtag' 'Mon, 3 Jul 2006 17:18:45 +0200'
- EOF
+ test_expect_success 'Check format "iso8601-local" date fields output' '
+       test_date iso8601-local "2006-07-03 23:18:43 +0000" "2006-07-03 23:18:44 +0000" "2006-07-03 23:18:45 +0000"
+ '
  
  test_expect_success 'Check format "rfc2822" date fields output' '
-       f=rfc2822 &&
-       (git for-each-ref --shell --format="%(refname) %(committerdate:$f) %(authordate:$f)" refs/heads &&
-       git for-each-ref --shell --format="%(refname) %(taggerdate:$f)" refs/tags) >actual &&
-       test_cmp expected actual
+       test_date rfc2822 \
+               "Tue, 4 Jul 2006 01:18:43 +0200" \
+               "Tue, 4 Jul 2006 01:18:44 +0200" \
+               "Tue, 4 Jul 2006 01:18:45 +0200"
+ '
+ test_expect_success 'Check format "rfc2822-local" date fields output' '
+       test_date rfc2822-local "Mon, 3 Jul 2006 23:18:43 +0000" "Mon, 3 Jul 2006 23:18:44 +0000" "Mon, 3 Jul 2006 23:18:45 +0000"
+ '
+ test_expect_success 'Check format "raw" date fields output' '
+       test_date raw "1151968723 +0200" "1151968724 +0200" "1151968725 +0200"
+ '
+ test_expect_success 'Check format "raw-local" date fields output' '
+       test_date raw-local "1151968723 +0000" "1151968724 +0000" "1151968725 +0000"
  '
  
  test_expect_success 'Check format of strftime date fields' '
-       echo "my date is 2006-07-03" >expected &&
+       echo "my date is 2006-07-04" >expected &&
        git for-each-ref \
          --format="%(authordate:format:my date is %Y-%m-%d)" \
          refs/heads >actual &&
        test_cmp expected actual
  '
  
+ test_expect_success 'Check format of strftime-local date fields' '
+       echo "my date is 2006-07-03" >expected &&
+       git for-each-ref \
+         --format="%(authordate:format-local:my date is %Y-%m-%d)" \
+         refs/heads >actual &&
+       test_cmp expected actual
+ '
 +test_expect_success 'exercise strftime with odd fields' '
 +      echo >expected &&
 +      git for-each-ref --format="%(authordate:format:)" refs/heads >actual &&
 +      test_cmp expected actual &&
 +      long="long format -- $_z40$_z40$_z40$_z40$_z40$_z40$_z40" &&
 +      echo $long >expected &&
 +      git for-each-ref --format="%(authordate:format:$long)" refs/heads >actual &&
 +      test_cmp expected actual
 +'
 +
  cat >expected <<\EOF
  refs/heads/master
  refs/remotes/origin/master
@@@ -546,8 -564,8 +574,8 @@@ body content
  $sig"
  
  cat >expected <<EOF
- $(git rev-parse refs/tags/master) <committer@example.com> refs/tags/master
  $(git rev-parse refs/tags/bogo) <committer@example.com> refs/tags/bogo
+ $(git rev-parse refs/tags/master) <committer@example.com> refs/tags/master
  EOF
  
  test_expect_success 'Verify sort with multiple keys' '