Merge branch 'mo/cvs-server-cleanup'
authorJeff King <peff@peff.net>
Fri, 9 Nov 2012 17:50:36 +0000 (12:50 -0500)
committerJeff King <peff@peff.net>
Fri, 9 Nov 2012 17:50:36 +0000 (12:50 -0500)
Cleanups to prepare for mo/cvs-server-updates.

* mo/cvs-server-cleanup:
Use character class for sed expression instead of \s
cvsserver status: provide real sticky info
cvsserver: cvs add: do not expand directory arguments
cvsserver: use whole CVS rev number in-process; don't strip "1." prefix
cvsserver: split up long lines in req_{status,diff,log}
cvsserver: clean up client request handler map comments
cvsserver: remove unused functions _headrev and gethistory
cvsserver update: comment about how we shouldn't remove a user-modified file
cvsserver: add comments about database schema/usage
cvsserver: removed unused sha1Or-k mode from kopts_from_path
cvsserver t9400: add basic 'cvs log' test

109 files changed:
.gitignore
Documentation/RelNotes/1.7.12.4.txt [new file with mode: 0644]
Documentation/RelNotes/1.8.0.txt
Documentation/config.txt
Documentation/diff-config.txt
Documentation/git-clone.txt
Documentation/git-commit.txt
Documentation/git-merge.txt
Documentation/git-push.txt
Documentation/git-remote-helpers.txt
Documentation/git-reset.txt
Documentation/git-rm.txt
Documentation/git-send-email.txt
Documentation/git-status.txt
Documentation/git-submodule.txt
Documentation/git-svn.txt
Documentation/git.txt
Documentation/gitattributes.txt
Documentation/gitmodules.txt
Documentation/gitrepository-layout.txt
Documentation/merge-config.txt
Documentation/rev-list-options.txt
Documentation/technical/api-argv-array.txt
GIT-VERSION-GEN
Makefile
argv-array.c
argv-array.h
attr.c
builtin/branch.c
builtin/commit.c
builtin/describe.c
builtin/grep.c
builtin/log.c
builtin/pack-objects.c
builtin/rm.c
builtin/show-ref.c
compat/mingw.c
compat/mingw.h
config.c
configure.ac
contrib/svn-fe/svn-fe.c
contrib/svn-fe/svnrdump_sim.py [new file with mode: 0755]
diff.c
dir.c
dir.h
git-compat-util.h
git-filter-branch.sh
git-gui/GIT-VERSION-GEN
git-gui/git-gui.sh
git-gui/lib/commit.tcl
git-gui/lib/status_bar.tcl
git-gui/macosx/AppMain.tcl
git-gui/po/de.po
git-gui/po/fr.po
git-gui/po/git-gui.pot
git-gui/po/hu.po
git-gui/po/it.po
git-gui/po/ja.po
git-gui/po/nb.po
git-gui/po/pt_br.po
git-gui/po/ru.po
git-gui/po/sv.po
git-pull.sh
git-send-email.perl
git-sh-setup.sh
git-submodule.sh
grep.c
grep.h
http.c
http.h
mailmap.c
mergetools/p4merge
pager.c
po/sv.po
po/vi.po
pretty.c
refs.c
remote-curl.c
remote-testsvn.c [new file with mode: 0644]
revision.c
run-command.c
run-command.h
strbuf.c
submodule.c
submodule.h
t/t0003-attributes.sh
t/t3001-ls-files-others-exclude.sh
t/t3200-branch.sh
t/t3600-rm.sh
t/t4014-format-patch.sh
t/t4055-diff-context.sh [new file with mode: 0755]
t/t4202-log.sh
t/t7003-filter-branch.sh
t/t7008-grep-binary.sh
t/t7400-submodule-basic.sh
t/t7406-submodule-update.sh
t/t9001-send-email.sh
t/t9020-remote-svn.sh [new file with mode: 0755]
t/t9200-git-cvsexportcommit.sh
t/test-lib.sh
test-svn-fe.c
transport-helper.c
upload-pack.c
utf8.c
vcs-svn/fast_export.c
vcs-svn/fast_export.h
vcs-svn/svndump.c
vcs-svn/svndump.h
write_or_die.c
index a188a82bb1d6ab080c434a7096bd263545169f3c..f702415c12c5a4a66180f7ffd697347e5343ac4a 100644 (file)
 /git-remote-fd
 /git-remote-ext
 /git-remote-testgit
+/git-remote-testsvn
 /git-repack
 /git-replace
 /git-repo-config
diff --git a/Documentation/RelNotes/1.7.12.4.txt b/Documentation/RelNotes/1.7.12.4.txt
new file mode 100644 (file)
index 0000000..c6da3cc
--- /dev/null
@@ -0,0 +1,23 @@
+Git 1.7.12.4 Release Notes
+==========================
+
+Fixes since v1.7.12.3
+---------------------
+
+ * "git fetch" over the dumb-http revision walker could segfault when
+   curl's multi interface was used.
+
+ * It was possible to give specific paths for "asciidoc" and other
+   tools in the documentation toolchain, but not for "xmlto".
+
+ * "gitweb" did not give the correct committer timezone in its feed
+   output due to a typo.
+
+ * The "-Xours" (and similarly -Xtheirs) backend option to "git
+   merge -s recursive" was ignored for binary files.  Now it is
+   honored.
+
+ * The "binary" synthetic attribute made "diff" to treat the path as
+   binary, but not "merge".
+
+Also contains many documentation updates.
index 9158899d60a394e998c8f011cea137b2fb4dae25..43883c14f08ac06b8cfa066e971135022837e218 100644 (file)
@@ -4,16 +4,18 @@ Git v1.8.0 Release Notes
 Backward compatibility notes
 ----------------------------
 
-In the next major release, we will change the behavior of the "git
-push" command.  When "git push [$there]" does not say what to push, we
-have used the traditional "matching" semantics so far (all your branches were
-sent to the remote as long as there already are branches of the same
-name over there).  We will now use the "simple" semantics, that pushes the
-current branch to the branch with the same name only when the current
+In the next major release (not *this* one), we will change the
+behavior of the "git push" command.
+
+When "git push [$there]" does not say what to push, we have used the
+traditional "matching" semantics so far (all your branches were sent
+to the remote as long as there already are branches of the same name
+over there).  We will use the "simple" semantics that pushes the
+current branch to the branch with the same name, only when the current
 branch is set to integrate with that remote branch.  There is a user
 preference configuration variable "push.default" to change this, and
 "git push" will warn about the upcoming change until you set this
-variable.
+variable in this release.
 
 "git branch --set-upstream" is deprecated and may be removed in a
 relatively distant future.  "git branch [-u|--set-upstream-to]" has
@@ -35,7 +37,7 @@ UI, Workflows & Features
 
  * When "git am" sanitizes the "Subject:" line, we strip the prefix from
    "Re: subject" and also from a less common "re: subject", but left
-   the even less common "RE: subject" intact. We strip that now, too.
+   the even less common "RE: subject" intact.  Now we strip that too.
 
  * It was tempting to say "git branch --set-upstream origin/master",
    but that tells Git to arrange the local branch "origin/master" to
@@ -62,6 +64,8 @@ UI, Workflows & Features
  * "git grep" learned to use a non-standard pattern type by default if
    a configuration variable tells it to.
 
+ * Accumulated updates to "git gui" has been merged.
+
  * "git log -g" learned the "--grep-reflog=<pattern>" option to limit
    its output to commits with a reflog message that matches the given
    pattern.
@@ -73,9 +77,6 @@ UI, Workflows & Features
    with the mergetool.$name.cmd configuration variable even for built-in
    mergetool backends.
 
- * The "-Xours" backend option to "git merge -s recursive" now takes
-   effect even on binary files.
-
  * "git rebase -i" learned the "--edit-todo" option to open an editor
    to edit the instruction sheet.
 
@@ -88,7 +89,7 @@ Foreign Interface
    encountering a conflict during "p4 submit".
 
 
-Performance, Internal Implementation, etc. (please report possible regressions)
+Performance, Internal Implementation, etc.
 
  * Git ships with a fall-back regexp implementation for platforms with
    buggy regexp library, but it was easy for people to keep using their
@@ -212,7 +213,6 @@ to them for details).
 
  * "git fetch" over the dumb-http revision walker could segfault when
    curl's multi interface was used.
-   (merge 188923f jk/maint-http-half-auth-push later to maint).
 
  * "git gc --auto" notified the user that auto-packing has triggered
     even under the "--quiet" option.
@@ -226,6 +226,9 @@ to them for details).
    --author or --committer, it showed commits that mention either A or
    B (or both) instead.
 
+ * The "-Xours" backend option to "git merge -s recursive" was ignored
+   for binary files.
+
  * "git p4", when "--use-client-spec" and "--detect-branches" are used
    together, misdetected branches.
 
index 11f320b96267e7bd11f23f13842ca9f92cac6f7f..9a0544cf1fba605bde7031c23016bc24db741417 100644 (file)
@@ -538,14 +538,14 @@ core.pager::
        `LESS` variable to some other value.  Alternately,
        these settings can be overridden on a project or
        global basis by setting the `core.pager` option.
-       Setting `core.pager` has no affect on the `LESS`
+       Setting `core.pager` has no effect on the `LESS`
        environment variable behaviour above, so if you want
        to override git's default settings this way, you need
        to be explicit.  For example, to disable the S option
        in a backward compatible manner, set `core.pager`
-       to `less -+$LESS -FRX`.  This will be passed to the
-       shell by git, which will translate the final command to
-       `LESS=FRSX less -+FRSX -FRX`.
+       to `less -+S`.  This will be passed to the shell by
+       git, which will translate the final command to
+       `LESS=FRSX less -+S`.
 
 core.whitespace::
        A comma separated list of common whitespace problems to
index 67a90a828c04b7277fc603c6518fd0ecd8247d32..75ab8a51ca17ce825d2f1faee5de14abc2fdb6f6 100644 (file)
@@ -56,6 +56,10 @@ diff.statGraphWidth::
        Limit the width of the graph part in --stat output. If set, applies
        to all commands generating --stat output except format-patch.
 
+diff.context::
+       Generate diffs with <n> lines of context instead of the default of
+       3. This value is overridden by the -U option.
+
 diff.external::
        If this config variable is set, diff generation is not
        performed using the internal diff machinery, but using the
index 6d98ef3d2ab8c8e63e026dbd7e242d3c3bc3c79a..7fefdb0384307d0029eb6016bdf37735e84ebdd8 100644 (file)
@@ -196,9 +196,9 @@ objects from the source repository into a pack in the cloned repository.
        `--no-single-branch` is given to fetch the histories near the
        tips of all branches.
        Further fetches into the resulting repository will only update the
-       remote tracking branch for the branch this option was used for the
+       remote-tracking branch for the branch this option was used for the
        initial cloning.  If the HEAD at the remote did not point at any
-       branch when `--single-branch` clone was made, no remote tracking
+       branch when `--single-branch` clone was made, no remote-tracking
        branch is created.
 
 --recursive::
index 9594ac8e9de9645be71b1528dcb94705f1695283..0295890621117ae3981485eec5872d3dcfb23af6 100644 (file)
@@ -13,7 +13,7 @@ SYNOPSIS
           [-F <file> | -m <msg>] [--reset-author] [--allow-empty]
           [--allow-empty-message] [--no-verify] [-e] [--author=<author>]
           [--date=<date>] [--cleanup=<mode>] [--status | --no-status]
-          [-i | -o] [--] [<file>...]
+          [-i | -o] [-S[<keyid>]] [--] [<file>...]
 
 DESCRIPTION
 -----------
@@ -109,6 +109,10 @@ OPTIONS
        format. See linkgit:git-status[1] for details. Implies
        `--dry-run`.
 
+--long::
+       When doing a dry-run, give the output in a the long-format.
+       Implies `--dry-run`.
+
 -z::
 --null::
        When showing `short` or `porcelain` status output, terminate
@@ -276,6 +280,10 @@ configuration variable documented in linkgit:git-config[1].
        commit message template when using an editor to prepare the
        default commit message.
 
+-S[<keyid>]::
+--gpg-sign[=<keyid>]::
+       GPG-sign commit.
+
 \--::
        Do not interpret any more arguments as options.
 
index 20f9228511e82ac9ced81889bcc66f41504710a3..d34ea3c50bae192cf0f43c782662a48a3df18f8c 100644 (file)
@@ -99,7 +99,7 @@ commit or stash your changes before running 'git merge'.
        more than two parents (affectionately called an Octopus merge).
 +
 If no commit is given from the command line, and if `merge.defaultToUpstream`
-configuration variable is set, merge the remote tracking branches
+configuration variable is set, merge the remote-tracking branches
 that the current branch is configured to use as its upstream.
 See also the configuration section of this manual page.
 
index 22d2580129538898933d19582b8c292f6463f6a8..fe46c4258a9c8a9dbab0b789215716065bef00ad 100644 (file)
@@ -175,7 +175,7 @@ useful if you write an alias or script around 'git push'.
 
 --recurse-submodules=check|on-demand::
        Make sure all submodule commits used by the revisions to be
-       pushed are available on a remote tracking branch. If 'check' is
+       pushed are available on a remote-tracking branch. If 'check' is
        used git will verify that all submodule commits that changed in
        the revisions to be pushed are available on at least one remote
        of the submodule. If any commits are missing the push will be
index f5836e46d080d8f1f9931a8cd1aa22d0654341ba..5ce4cda8e72ff27a46cd79ae66e8587a9cc2b7d8 100644 (file)
@@ -98,6 +98,20 @@ advertised with this capability must cover all refs reported by
 the list command.  If no 'refspec' capability is advertised,
 there is an implied `refspec *:*`.
 
+'bidi-import'::
+       The fast-import commands 'cat-blob' and 'ls' can be used by remote-helpers
+       to retrieve information about blobs and trees that already exist in
+       fast-import's memory. This requires a channel from fast-import to the
+       remote-helper.
+       If it is advertised in addition to "import", git establishes a pipe from
+       fast-import to the remote-helper's stdin.
+       It follows that git and fast-import are both connected to the
+       remote-helper's stdin. Because git can send multiple commands to
+       the remote-helper it is required that helpers that use 'bidi-import'
+       buffer all 'import' commands of a batch before sending data to fast-import.
+       This is to prevent mixing commands and fast-import responses on the
+       helper's stdin.
+
 Capabilities for Pushing
 ~~~~~~~~~~~~~~~~~~~~~~~~
 'connect'::
@@ -286,7 +300,12 @@ terminated with a blank line. For each batch of 'import', the remote
 helper should produce a fast-import stream terminated by a 'done'
 command.
 +
-Supported if the helper has the "import" capability.
+Note that if the 'bidi-import' capability is used the complete batch
+sequence has to be buffered before starting to send data to fast-import
+to prevent mixing of commands and fast-import responses on the helper's
+stdin.
++
+Supported if the helper has the 'import' capability.
 
 'connect' <service>::
        Connects to given service. Standard input and standard output
index 117e3743a62f59a1b6b57f8a36f4ee938f6e1848..978d8da50c150a695565958d89daade5434ce8e0 100644 (file)
@@ -10,7 +10,7 @@ SYNOPSIS
 [verse]
 'git reset' [-q] [<commit>] [--] <paths>...
 'git reset' (--patch | -p) [<commit>] [--] [<paths>...]
-'git reset' (--soft | --mixed | --hard | --merge | --keep) [-q] [<commit>]
+'git reset' [--soft | --mixed | --hard | --merge | --keep] [-q] [<commit>]
 
 DESCRIPTION
 -----------
@@ -43,11 +43,11 @@ This means that `git reset -p` is the opposite of `git add -p`, i.e.
 you can use it to selectively reset hunks. See the ``Interactive Mode''
 section of linkgit:git-add[1] to learn how to operate the `--patch` mode.
 
-'git reset' --<mode> [<commit>]::
+'git reset' [<mode>] [<commit>]::
        This form resets the current branch head to <commit> and
        possibly updates the index (resetting it to the tree of <commit>) and
-       the working tree depending on <mode>, which
-       must be one of the following:
+       the working tree depending on <mode>. If <mode> is omitted,
+       defaults to "--mixed". The <mode> must be one of the following:
 +
 --
 --soft::
index 5d31860eb1ddf57251d61d16b34693cebc4fd297..882cb1171bb361cd527cd71b8b06639237582dba 100644 (file)
@@ -107,6 +107,21 @@ as well as modifications of existing paths.
 Typically you would first remove all tracked files from the working
 tree using this command:
 
+Submodules
+~~~~~~~~~~
+Only submodules using a gitfile (which means they were cloned
+with a git version 1.7.8 or newer) will be removed from the work
+tree, as their repository lives inside the .git directory of the
+superproject. If a submodule (or one of those nested inside it)
+still uses a .git directory, `git rm` will fail - no matter if forced
+or not - to protect the submodule's history.
+
+A submodule is considered up-to-date when the HEAD is the same as
+recorded in the index, no tracked files are modified and no untracked
+files that aren't ignored are present in the submodules work tree.
+Ignored files are deemed expendable and won't stop a submodule's work
+tree from being removed.
+
 ----------------
 git ls-files -z | xargs -0 rm -f
 ----------------
index 324117072d55f831b07f96ca23d27be88b2abaa4..eeb561cf147bcd40a220c76599ceeb714a7c7bf7 100644 (file)
@@ -126,6 +126,10 @@ The --to option must be repeated for each user you want on the to list.
 +
 Note that no attempts whatsoever are made to validate the encoding.
 
+--compose-encoding=<encoding>::
+       Specify encoding of compose message. Default is the value of the
+       'sendemail.composeencoding'; if that is unspecified, UTF-8 is assumed.
+
 
 Sending
 ~~~~~~~
index 67e5f53a9ef00991954b6bf95286a418c7e4af23..9f1ef9a463a8f884ba69474fdf5e1f338cc43bb9 100644 (file)
@@ -38,6 +38,9 @@ OPTIONS
        across git versions and regardless of user configuration. See
        below for details.
 
+--long::
+       Give the output in the long-format. This is the default.
+
 -u[<mode>]::
 --untracked-files[=<mode>]::
        Show untracked files.
index b4683bba1bc0ea6561a2378c663cf431776a3f7a..1d6527ab9f46fb0eb5d52ef335c1c4b4c377a72b 100644 (file)
@@ -9,7 +9,7 @@ git-submodule - Initialize, update or inspect submodules
 SYNOPSIS
 --------
 [verse]
-'git submodule' [--quiet] add [-b branch] [-f|--force]
+'git submodule' [--quiet] add [-b branch] [-f|--force] [--name <name>]
              [--reference <repository>] [--] <repository> [<path>]
 'git submodule' [--quiet] status [--cached] [--recursive] [--] [<path>...]
 'git submodule' [--quiet] init [--] [<path>...]
@@ -265,6 +265,11 @@ OPTIONS
        Initialize all submodules for which "git submodule init" has not been
        called so far before updating.
 
+--name::
+       This option is only valid for the add command. It sets the submodule's
+       name to the given string instead of defaulting to its path. The name
+       must be valid as a directory name and may not end with a '/'.
+
 --reference <repository>::
        This option is only valid for add and update commands.  These
        commands sometimes need to clone a remote repository. In this case,
index cfe8d2b5df78b85b7a675423f77a3996ebe24092..8b0d3adfede9ebffbddc294d6f30eedea0e2dfa0 100644 (file)
@@ -146,6 +146,13 @@ Skip "branches" and "tags" of first level directories;;
 ------------------------------------------------------------------------
 --
 
+--log-window-size=<n>;;
+    Fetch <n> log entries per request when scanning Subversion history.
+    The default is 100. For very large Subversion repositories, larger
+    values may be needed for 'clone'/'fetch' to complete in reasonable
+    time. But overly large values may lead to higher memory usage and
+    request timeouts.
+
 'clone'::
        Runs 'init' and 'fetch'.  It will automatically create a
        directory based on the basename of the URL passed to it;
index d1d227a32d1b110239fc4a789839dd2dadc12d80..4a89a1251366ab8312cb20d77b73ecf40ca92349 100644 (file)
@@ -43,9 +43,15 @@ unreleased) version of git, that is available from 'master'
 branch of the `git.git` repository.
 Documentation for older releases are available here:
 
-* link:v1.7.12.3/git.html[documentation for release 1.7.12.3]
+* link:v1.8.0/git.html[documentation for release 1.8.0]
 
 * release notes for
+  link:RelNotes/1.8.0.txt[1.8.0],
+
+* link:v1.7.12.4/git.html[documentation for release 1.7.12.4]
+
+* release notes for
+  link:RelNotes/1.7.12.4.txt[1.7.12.4],
   link:RelNotes/1.7.12.3.txt[1.7.12.3],
   link:RelNotes/1.7.12.2.txt[1.7.12.2],
   link:RelNotes/1.7.12.1.txt[1.7.12.1],
index ba02d4de5901b4448411654ecdf76a1b1980e53b..2698f63cf9b492deb32b09e2a60c59f500c47f5c 100644 (file)
@@ -56,6 +56,7 @@ When more than one pattern matches the path, a later line
 overrides an earlier line.  This overriding is done per
 attribute.  The rules how the pattern matches paths are the
 same as in `.gitignore` files; see linkgit:gitignore[5].
+Unlike `.gitignore`, negative patterns are forbidden.
 
 When deciding what attributes are assigned to a path, git
 consults `$GIT_DIR/info/attributes` file (which has the highest
index 4effd789026e48085d6b0834cbef990968bedbb2..ab3e91c054ca7b4dcf7373b0aac839c18275a791 100644 (file)
@@ -18,7 +18,9 @@ working tree, is a text file with a syntax matching the requirements
 of linkgit:git-config[1].
 
 The file contains one subsection per submodule, and the subsection value
-is the name of the submodule. Each submodule section also contains the
+is the name of the submodule. The name is set to the path where the
+submodule has been added unless it was customized with the '--name'
+option of 'git submodule add'. Each submodule section also contains the
 following required keys:
 
 submodule.<name>.path::
index 5c891f1169b35e53bccc19f0423b5b7e98db720b..9f628862b4f571608c5bd9185e39cb240b137037 100644 (file)
@@ -93,6 +93,12 @@ refs/remotes/`name`::
        records tip-of-the-tree commit objects of branches copied
        from a remote repository.
 
+refs/replace/`<obj-sha1>`::
+       records the SHA1 of the object that replaces `<obj-sha1>`.
+       This is similar to info/grafts and is internally used and
+       maintained by linkgit:git-replace[1]. Such refs can be exchanged
+       between repositories while grafts are not.
+
 packed-refs::
        records the same information as refs/heads/, refs/tags/,
        and friends record in a more efficient way.  See
index 861bd6f55352a12db6d1d680508e1d02a8e90d12..9bb4956ccdbef507ab115ac19dfe8ad326afb7c2 100644 (file)
@@ -9,11 +9,11 @@ merge.conflictstyle::
 merge.defaultToUpstream::
        If merge is called without any commit argument, merge the upstream
        branches configured for the current branch by using their last
-       observed values stored in their remote tracking branches.
+       observed values stored in their remote-tracking branches.
        The values of the `branch.<current branch>.merge` that name the
        branches at the remote named by `branch.<current branch>.remote`
        are consulted, and then they are mapped via `remote.<remote>.fetch`
-       to their corresponding remote tracking branches, and the tips of
+       to their corresponding remote-tracking branches, and the tips of
        these tracking branches are merged.
 
 merge.ff::
index ee497430cb0f8dc0859b90b8773e6b8e28d5e361..1ec14a068e750b114ac5f1ad2f468de8d0664a16 100644 (file)
@@ -79,6 +79,11 @@ if it is part of the log message.
 
        Match the regexp limiting patterns without regard to letters case.
 
+--basic-regexp::
+
+       Consider the limiting patterns to be basic regular expressions;
+       this is the default.
+
 -E::
 --extended-regexp::
 
@@ -91,6 +96,11 @@ if it is part of the log message.
        Consider the limiting patterns to be fixed strings (don't interpret
        pattern as a regular expression).
 
+--perl-regexp::
+
+       Consider the limiting patterns to be Perl-compatible regexp.
+       Requires libpcre to be compiled in.
+
 --remove-empty::
 
        Stop when a given path disappears from the tree.
index 1a797812fb426189b03a814498dd7019c96607b4..a959517b2339847e92464c86a73f9c472bfdb2d0 100644 (file)
@@ -53,3 +53,11 @@ Functions
 `argv_array_clear`::
        Free all memory associated with the array and return it to the
        initial, empty state.
+
+`argv_array_detach`::
+       Detach the argv array from the `struct argv_array`, transfering
+       ownership of the allocated array and strings.
+
+`argv_array_free_detached`::
+       Free the memory allocated by a `struct argv_array` that was later
+       detached and is now no longer needed.
index 3c0e89c4cbd5665852ddc93c8a7515822dbaf19e..b09d264a865fc6ad4a2f0acd930d82150f0e1280 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v1.8.0-rc2
+DEF_VER=v1.8.0
 
 LF='
 '
index f69979e39e25bd0aae3dbdf21019d040aa1fd788..40829a9e994ef57e07bdcc16f0c6c8fd137f01fc 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -495,6 +495,7 @@ PROGRAM_OBJS += sh-i18n--envsubst.o
 PROGRAM_OBJS += shell.o
 PROGRAM_OBJS += show-index.o
 PROGRAM_OBJS += upload-pack.o
+PROGRAM_OBJS += remote-testsvn.o
 
 # Binary suffix, set to .exe for Windows builds
 X =
@@ -2449,6 +2450,10 @@ git-http-push$X: revision.o http.o http-push.o GIT-LDFLAGS $(GITLIBS)
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
                $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT)
 
+git-remote-testsvn$X: remote-testsvn.o GIT-LDFLAGS $(GITLIBS) $(VCSSVN_LIB)
+       $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) \
+       $(VCSSVN_LIB)
+
 $(REMOTE_CURL_ALIASES): $(REMOTE_CURL_PRIMARY)
        $(QUIET_LNCP)$(RM) $@ && \
        ln $< $@ 2>/dev/null || \
index 256741d2262b237c56b6730bea9d52c9b39b7ee3..9e960d549c158a4c761942bb17824c1d5e075d49 100644 (file)
@@ -68,3 +68,23 @@ void argv_array_clear(struct argv_array *array)
        }
        argv_array_init(array);
 }
+
+const char **argv_array_detach(struct argv_array *array, int *argc)
+{
+       const char **argv =
+               array->argv == empty_argv || array->argc == 0 ? NULL : array->argv;
+       if (argc)
+               *argc = array->argc;
+       argv_array_init(array);
+       return argv;
+}
+
+void argv_array_free_detached(const char **argv)
+{
+       if (argv) {
+               int i;
+               for (i = 0; argv[i]; i++)
+                       free((char **)argv[i]);
+               free(argv);
+       }
+}
index f4b98660f8a98e2cecdf70285d1d76205b3f4be7..40248d424c31662a3a574cfea13635084feb14f5 100644 (file)
@@ -18,5 +18,7 @@ void argv_array_pushf(struct argv_array *, const char *fmt, ...);
 void argv_array_pushl(struct argv_array *, ...);
 void argv_array_pop(struct argv_array *);
 void argv_array_clear(struct argv_array *);
+const char **argv_array_detach(struct argv_array *array, int *argc);
+void argv_array_free_detached(const char **argv);
 
 #endif /* ARGV_ARRAY_H */
diff --git a/attr.c b/attr.c
index 887a9ae46b7044489845abf2072339271caf2d4a..097ae87f3c2b4093fffe6586f036918367fa672e 100644 (file)
--- a/attr.c
+++ b/attr.c
@@ -115,6 +115,13 @@ struct attr_state {
        const char *setto;
 };
 
+struct pattern {
+       const char *pattern;
+       int patternlen;
+       int nowildcardlen;
+       int flags;              /* EXC_FLAG_* */
+};
+
 /*
  * One rule, as from a .gitattributes file.
  *
@@ -131,7 +138,7 @@ struct attr_state {
  */
 struct match_attr {
        union {
-               char *pattern;
+               struct pattern pat;
                struct git_attr *attr;
        } u;
        char is_macro;
@@ -241,9 +248,16 @@ static struct match_attr *parse_attr_line(const char *line, const char *src,
        if (is_macro)
                res->u.attr = git_attr_internal(name, namelen);
        else {
-               res->u.pattern = (char *)&(res->state[num_attr]);
-               memcpy(res->u.pattern, name, namelen);
-               res->u.pattern[namelen] = 0;
+               char *p = (char *)&(res->state[num_attr]);
+               memcpy(p, name, namelen);
+               res->u.pat.pattern = p;
+               parse_exclude_pattern(&res->u.pat.pattern,
+                                     &res->u.pat.patternlen,
+                                     &res->u.pat.flags,
+                                     &res->u.pat.nowildcardlen);
+               if (res->u.pat.flags & EXC_FLAG_NEGATIVE)
+                       die(_("Negative patterns are forbidden in git attributes\n"
+                             "Use '\\!' for literal leading exclamation."));
        }
        res->is_macro = is_macro;
        res->num_attr = num_attr;
@@ -277,6 +291,7 @@ static struct match_attr *parse_attr_line(const char *line, const char *src,
 static struct attr_stack {
        struct attr_stack *prev;
        char *origin;
+       size_t originlen;
        unsigned num_matches;
        unsigned alloc;
        struct match_attr **attrs;
@@ -535,6 +550,7 @@ static void bootstrap_attr_stack(void)
        if (!is_bare_repository() || direction == GIT_ATTR_INDEX) {
                elem = read_attr(GITATTRIBUTES_FILE, 1);
                elem->origin = xstrdup("");
+               elem->originlen = 0;
                elem->prev = attr_stack;
                attr_stack = elem;
                debug_push(elem);
@@ -628,7 +644,7 @@ static void prepare_attr_stack(const char *path)
                        strbuf_addstr(&pathbuf, GITATTRIBUTES_FILE);
                        elem = read_attr(pathbuf.buf, 0);
                        strbuf_setlen(&pathbuf, cp - path);
-                       elem->origin = strbuf_detach(&pathbuf, NULL);
+                       elem->origin = strbuf_detach(&pathbuf, &elem->originlen);
                        elem->prev = attr_stack;
                        attr_stack = elem;
                        debug_push(elem);
@@ -645,28 +661,22 @@ static void prepare_attr_stack(const char *path)
 }
 
 static int path_matches(const char *pathname, int pathlen,
-                       const char *pattern,
+                       const char *basename,
+                       const struct pattern *pat,
                        const char *base, int baselen)
 {
-       if (!strchr(pattern, '/')) {
-               /* match basename */
-               const char *basename = strrchr(pathname, '/');
-               basename = basename ? basename + 1 : pathname;
-               return (fnmatch_icase(pattern, basename, 0) == 0);
+       const char *pattern = pat->pattern;
+       int prefix = pat->nowildcardlen;
+
+       if (pat->flags & EXC_FLAG_NODIR) {
+               return match_basename(basename,
+                                     pathlen - (basename - pathname),
+                                     pattern, prefix,
+                                     pat->patternlen, pat->flags);
        }
-       /*
-        * match with FNM_PATHNAME; the pattern has base implicitly
-        * in front of it.
-        */
-       if (*pattern == '/')
-               pattern++;
-       if (pathlen < baselen ||
-           (baselen && pathname[baselen] != '/') ||
-           strncmp(pathname, base, baselen))
-               return 0;
-       if (baselen != 0)
-               baselen++;
-       return fnmatch_icase(pattern, pathname + baselen, FNM_PATHNAME) == 0;
+       return match_pathname(pathname, pathlen,
+                             base, baselen,
+                             pattern, prefix, pat->patternlen, pat->flags);
 }
 
 static int macroexpand_one(int attr_nr, int rem);
@@ -693,7 +703,8 @@ static int fill_one(const char *what, struct match_attr *a, int rem)
        return rem;
 }
 
-static int fill(const char *path, int pathlen, struct attr_stack *stk, int rem)
+static int fill(const char *path, int pathlen, const char *basename,
+               struct attr_stack *stk, int rem)
 {
        int i;
        const char *base = stk->origin ? stk->origin : "";
@@ -702,8 +713,8 @@ static int fill(const char *path, int pathlen, struct attr_stack *stk, int rem)
                struct match_attr *a = stk->attrs[i];
                if (a->is_macro)
                        continue;
-               if (path_matches(path, pathlen,
-                                a->u.pattern, base, strlen(base)))
+               if (path_matches(path, pathlen, basename,
+                                &a->u.pat, base, stk->originlen))
                        rem = fill_one("fill", a, rem);
        }
        return rem;
@@ -741,15 +752,19 @@ static void collect_all_attrs(const char *path)
 {
        struct attr_stack *stk;
        int i, pathlen, rem;
+       const char *basename;
 
        prepare_attr_stack(path);
        for (i = 0; i < attr_nr; i++)
                check_all_attr[i].value = ATTR__UNKNOWN;
 
+       basename = strrchr(path, '/');
+       basename = basename ? basename + 1 : path;
+
        pathlen = strlen(path);
        rem = attr_nr;
        for (stk = attr_stack; 0 < rem && stk; stk = stk->prev)
-               rem = fill(path, pathlen, stk, rem);
+               rem = fill(path, pathlen, basename, stk, rem);
 }
 
 int git_check_attr(const char *path, int num, struct git_attr_check *check)
index ffd26849c7ad20ff470323621486ae8a2aeb2501..1ec9c02612d0391984b484a5850f45c277a3e804 100644 (file)
@@ -154,10 +154,37 @@ static int branch_merged(int kind, const char *name,
        return merged;
 }
 
+static int check_branch_commit(const char *branchname, const char *refname,
+                              unsigned char *sha1, struct commit *head_rev,
+                              int kinds, int force)
+{
+       struct commit *rev = lookup_commit_reference(sha1);
+       if (!rev) {
+               error(_("Couldn't look up commit object for '%s'"), refname);
+               return -1;
+       }
+       if (!force && !branch_merged(kinds, branchname, rev, head_rev)) {
+               error(_("The branch '%s' is not fully merged.\n"
+                     "If you are sure you want to delete it, "
+                     "run 'git branch -D %s'."), branchname, branchname);
+               return -1;
+       }
+       return 0;
+}
+
+static void delete_branch_config(const char *branchname)
+{
+       struct strbuf buf = STRBUF_INIT;
+       strbuf_addf(&buf, "branch.%s", branchname);
+       if (git_config_rename_section(buf.buf, NULL) < 0)
+               warning(_("Update of config-file failed"));
+       strbuf_release(&buf);
+}
+
 static int delete_branches(int argc, const char **argv, int force, int kinds,
                           int quiet)
 {
-       struct commit *rev, *head_rev = NULL;
+       struct commit *head_rev = NULL;
        unsigned char sha1[20];
        char *name = NULL;
        const char *fmt;
@@ -187,6 +214,9 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
                        die(_("Couldn't look up commit object for HEAD"));
        }
        for (i = 0; i < argc; i++, strbuf_release(&bname)) {
+               const char *target;
+               int flags = 0;
+
                strbuf_branchname(&bname, argv[i]);
                if (kinds == REF_LOCAL_BRANCH && !strcmp(head, bname.buf)) {
                        error(_("Cannot delete the branch '%s' "
@@ -198,7 +228,9 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
                free(name);
 
                name = mkpathdup(fmt, bname.buf);
-               if (read_ref(name, sha1)) {
+               target = resolve_ref_unsafe(name, sha1, 0, &flags);
+               if (!target ||
+                   (!(flags & REF_ISSYMREF) && is_null_sha1(sha1))) {
                        error(remote_branch
                              ? _("remote branch '%s' not found.")
                              : _("branch '%s' not found."), bname.buf);
@@ -206,40 +238,31 @@ static int delete_branches(int argc, const char **argv, int force, int kinds,
                        continue;
                }
 
-               rev = lookup_commit_reference(sha1);
-               if (!rev) {
-                       error(_("Couldn't look up commit object for '%s'"), name);
-                       ret = 1;
-                       continue;
-               }
-
-               if (!force && !branch_merged(kinds, bname.buf, rev, head_rev)) {
-                       error(_("The branch '%s' is not fully merged.\n"
-                             "If you are sure you want to delete it, "
-                             "run 'git branch -D %s'."), bname.buf, bname.buf);
+               if (!(flags & REF_ISSYMREF) &&
+                   check_branch_commit(bname.buf, name, sha1, head_rev, kinds,
+                                       force)) {
                        ret = 1;
                        continue;
                }
 
-               if (delete_ref(name, sha1, 0)) {
+               if (delete_ref(name, sha1, REF_NODEREF)) {
                        error(remote_branch
                              ? _("Error deleting remote branch '%s'")
                              : _("Error deleting branch '%s'"),
                              bname.buf);
                        ret = 1;
-               } else {
-                       struct strbuf buf = STRBUF_INIT;
-                       if (!quiet)
-                               printf(remote_branch
-                                      ? _("Deleted remote branch %s (was %s).\n")
-                                      : _("Deleted branch %s (was %s).\n"),
-                                      bname.buf,
-                                      find_unique_abbrev(sha1, DEFAULT_ABBREV));
-                       strbuf_addf(&buf, "branch.%s", bname.buf);
-                       if (git_config_rename_section(buf.buf, NULL) < 0)
-                               warning(_("Update of config-file failed"));
-                       strbuf_release(&buf);
+                       continue;
+               }
+               if (!quiet) {
+                       printf(remote_branch
+                              ? _("Deleted remote branch %s (was %s).\n")
+                              : _("Deleted branch %s (was %s).\n"),
+                              bname.buf,
+                              (flags & REF_ISSYMREF)
+                              ? target
+                              : find_unique_abbrev(sha1, DEFAULT_ABBREV));
                }
+               delete_branch_config(bname.buf);
        }
 
        free(name);
index a17a5df4494e9414bd4b04fd008671d84d914ca0..1dd2ec5e6f878c02e2858d72f08d8b88d67bcd85 100644 (file)
@@ -112,10 +112,11 @@ static const char *only_include_assumed;
 static struct strbuf message = STRBUF_INIT;
 
 static enum {
+       STATUS_FORMAT_NONE = 0,
        STATUS_FORMAT_LONG,
        STATUS_FORMAT_SHORT,
        STATUS_FORMAT_PORCELAIN
-} status_format = STATUS_FORMAT_LONG;
+} status_format;
 
 static int opt_parse_m(const struct option *opt, const char *arg, int unset)
 {
@@ -454,6 +455,7 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int
        case STATUS_FORMAT_PORCELAIN:
                wt_porcelain_print(s);
                break;
+       case STATUS_FORMAT_NONE:
        case STATUS_FORMAT_LONG:
                wt_status_print(s);
                break;
@@ -1058,9 +1060,13 @@ static int parse_and_validate_options(int argc, const char *argv[],
        if (all && argc > 0)
                die(_("Paths with -a does not make sense."));
 
-       if (s->null_termination && status_format == STATUS_FORMAT_LONG)
-               status_format = STATUS_FORMAT_PORCELAIN;
-       if (status_format != STATUS_FORMAT_LONG)
+       if (s->null_termination) {
+               if (status_format == STATUS_FORMAT_NONE)
+                       status_format = STATUS_FORMAT_PORCELAIN;
+               else if (status_format == STATUS_FORMAT_LONG)
+                       die(_("--long and -z are incompatible"));
+       }
+       if (status_format != STATUS_FORMAT_NONE)
                dry_run = 1;
 
        return argc;
@@ -1159,6 +1165,9 @@ int cmd_status(int argc, const char **argv, const char *prefix)
                OPT_SET_INT(0, "porcelain", &status_format,
                            N_("machine-readable output"),
                            STATUS_FORMAT_PORCELAIN),
+               OPT_SET_INT(0, "long", &status_format,
+                           N_("show status in long format (default)"),
+                           STATUS_FORMAT_LONG),
                OPT_BOOLEAN('z', "null", &s.null_termination,
                            N_("terminate entries with NUL")),
                { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg,
@@ -1186,8 +1195,12 @@ int cmd_status(int argc, const char **argv, const char *prefix)
                             builtin_status_usage, 0);
        finalize_colopts(&s.colopts, -1);
 
-       if (s.null_termination && status_format == STATUS_FORMAT_LONG)
-               status_format = STATUS_FORMAT_PORCELAIN;
+       if (s.null_termination) {
+               if (status_format == STATUS_FORMAT_NONE)
+                       status_format = STATUS_FORMAT_PORCELAIN;
+               else if (status_format == STATUS_FORMAT_LONG)
+                       die(_("--long and -z are incompatible"));
+       }
 
        handle_untracked_files_arg(&s);
        if (show_ignored_in_status)
@@ -1216,6 +1229,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
        case STATUS_FORMAT_PORCELAIN:
                wt_porcelain_print(&s);
                break;
+       case STATUS_FORMAT_NONE:
        case STATUS_FORMAT_LONG:
                s.verbose = verbose;
                s.ignore_submodule_arg = ignore_submodule_arg;
@@ -1386,6 +1400,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
                OPT_BOOLEAN(0, "branch", &s.show_branch, N_("show branch information")),
                OPT_SET_INT(0, "porcelain", &status_format,
                            N_("machine-readable output"), STATUS_FORMAT_PORCELAIN),
+               OPT_SET_INT(0, "long", &status_format,
+                           N_("show status in long format (default)"),
+                           STATUS_FORMAT_LONG),
                OPT_BOOLEAN('z', "null", &s.null_termination,
                            N_("terminate entries with NUL")),
                OPT_BOOLEAN(0, "amend", &amend, N_("amend previous commit")),
index 9fe11ed9de7b9e5c13187a630c45d8e44f50c851..04c185b1fbdc51ba9958fdb83d1c6616bcb0c18e 100644 (file)
@@ -144,7 +144,7 @@ static int get_name(const char *path, const unsigned char *sha1, int flag, void
        if (!all && !might_be_tag)
                return 0;
 
-       if (!peel_ref(path, peeled) && !is_null_sha1(peeled)) {
+       if (!peel_ref(path, peeled)) {
                is_tag = !!hashcmp(sha1, peeled);
        } else {
                hashcpy(peeled, sha1);
index 82530a61b483738382c810bcb141e33b06729d6f..0e1b6c860e18c6c47f343fad885cbd24f641862e 100644 (file)
@@ -86,7 +86,7 @@ static pthread_cond_t cond_result;
 static int skip_first_line;
 
 static void add_work(struct grep_opt *opt, enum grep_source_type type,
-                    const char *name, const void *id)
+                    const char *name, const char *path, const void *id)
 {
        grep_lock();
 
@@ -94,7 +94,7 @@ static void add_work(struct grep_opt *opt, enum grep_source_type type,
                pthread_cond_wait(&cond_write, &grep_mutex);
        }
 
-       grep_source_init(&todo[todo_end].source, type, name, id);
+       grep_source_init(&todo[todo_end].source, type, name, path, id);
        if (opt->binary != GREP_BINARY_TEXT)
                grep_source_load_driver(&todo[todo_end].source);
        todo[todo_end].done = 0;
@@ -261,103 +261,12 @@ static int wait_all(void)
 }
 #endif
 
-static int parse_pattern_type_arg(const char *opt, const char *arg)
+static int grep_cmd_config(const char *var, const char *value, void *cb)
 {
-       if (!strcmp(arg, "default"))
-               return GREP_PATTERN_TYPE_UNSPECIFIED;
-       else if (!strcmp(arg, "basic"))
-               return GREP_PATTERN_TYPE_BRE;
-       else if (!strcmp(arg, "extended"))
-               return GREP_PATTERN_TYPE_ERE;
-       else if (!strcmp(arg, "fixed"))
-               return GREP_PATTERN_TYPE_FIXED;
-       else if (!strcmp(arg, "perl"))
-               return GREP_PATTERN_TYPE_PCRE;
-       die("bad %s argument: %s", opt, arg);
-}
-
-static void grep_pattern_type_options(const int pattern_type, struct grep_opt *opt)
-{
-       switch (pattern_type) {
-       case GREP_PATTERN_TYPE_UNSPECIFIED:
-               /* fall through */
-
-       case GREP_PATTERN_TYPE_BRE:
-               opt->fixed = 0;
-               opt->pcre = 0;
-               opt->regflags &= ~REG_EXTENDED;
-               break;
-
-       case GREP_PATTERN_TYPE_ERE:
-               opt->fixed = 0;
-               opt->pcre = 0;
-               opt->regflags |= REG_EXTENDED;
-               break;
-
-       case GREP_PATTERN_TYPE_FIXED:
-               opt->fixed = 1;
-               opt->pcre = 0;
-               opt->regflags &= ~REG_EXTENDED;
-               break;
-
-       case GREP_PATTERN_TYPE_PCRE:
-               opt->fixed = 0;
-               opt->pcre = 1;
-               opt->regflags &= ~REG_EXTENDED;
-               break;
-       }
-}
-
-static int grep_config(const char *var, const char *value, void *cb)
-{
-       struct grep_opt *opt = cb;
-       char *color = NULL;
-
-       if (userdiff_config(var, value) < 0)
-               return -1;
-
-       if (!strcmp(var, "grep.extendedregexp")) {
-               if (git_config_bool(var, value))
-                       opt->extended_regexp_option = 1;
-               else
-                       opt->extended_regexp_option = 0;
-               return 0;
-       }
-
-       if (!strcmp(var, "grep.patterntype")) {
-               opt->pattern_type_option = parse_pattern_type_arg(var, value);
-               return 0;
-  }
-
-       if (!strcmp(var, "grep.linenumber")) {
-               opt->linenum = git_config_bool(var, value);
-               return 0;
-       }
-
-       if (!strcmp(var, "color.grep"))
-               opt->color = git_config_colorbool(var, value);
-       else if (!strcmp(var, "color.grep.context"))
-               color = opt->color_context;
-       else if (!strcmp(var, "color.grep.filename"))
-               color = opt->color_filename;
-       else if (!strcmp(var, "color.grep.function"))
-               color = opt->color_function;
-       else if (!strcmp(var, "color.grep.linenumber"))
-               color = opt->color_lineno;
-       else if (!strcmp(var, "color.grep.match"))
-               color = opt->color_match;
-       else if (!strcmp(var, "color.grep.selected"))
-               color = opt->color_selected;
-       else if (!strcmp(var, "color.grep.separator"))
-               color = opt->color_sep;
-       else
-               return git_color_default_config(var, value, cb);
-       if (color) {
-               if (!value)
-                       return config_error_nonbool(var);
-               color_parse(value, var, color);
-       }
-       return 0;
+       int st = grep_config(var, value, cb);
+       if (git_color_default_config(var, value, cb) < 0)
+               st = -1;
+       return st;
 }
 
 static void *lock_and_read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size)
@@ -371,7 +280,8 @@ static void *lock_and_read_sha1_file(const unsigned char *sha1, enum object_type
 }
 
 static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1,
-                    const char *filename, int tree_name_len)
+                    const char *filename, int tree_name_len,
+                    const char *path)
 {
        struct strbuf pathbuf = STRBUF_INIT;
 
@@ -385,7 +295,7 @@ static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1,
 
 #ifndef NO_PTHREADS
        if (use_threads) {
-               add_work(opt, GREP_SOURCE_SHA1, pathbuf.buf, sha1);
+               add_work(opt, GREP_SOURCE_SHA1, pathbuf.buf, path, sha1);
                strbuf_release(&pathbuf);
                return 0;
        } else
@@ -394,7 +304,7 @@ static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1,
                struct grep_source gs;
                int hit;
 
-               grep_source_init(&gs, GREP_SOURCE_SHA1, pathbuf.buf, sha1);
+               grep_source_init(&gs, GREP_SOURCE_SHA1, pathbuf.buf, path, sha1);
                strbuf_release(&pathbuf);
                hit = grep_source(opt, &gs);
 
@@ -414,7 +324,7 @@ static int grep_file(struct grep_opt *opt, const char *filename)
 
 #ifndef NO_PTHREADS
        if (use_threads) {
-               add_work(opt, GREP_SOURCE_FILE, buf.buf, filename);
+               add_work(opt, GREP_SOURCE_FILE, buf.buf, filename, filename);
                strbuf_release(&buf);
                return 0;
        } else
@@ -423,7 +333,7 @@ static int grep_file(struct grep_opt *opt, const char *filename)
                struct grep_source gs;
                int hit;
 
-               grep_source_init(&gs, GREP_SOURCE_FILE, buf.buf, filename);
+               grep_source_init(&gs, GREP_SOURCE_FILE, buf.buf, filename, filename);
                strbuf_release(&buf);
                hit = grep_source(opt, &gs);
 
@@ -479,7 +389,7 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int
                if (cached || (ce->ce_flags & CE_VALID) || ce_skip_worktree(ce)) {
                        if (ce_stage(ce))
                                continue;
-                       hit |= grep_sha1(opt, ce->sha1, ce->name, 0);
+                       hit |= grep_sha1(opt, ce->sha1, ce->name, 0, ce->name);
                }
                else
                        hit |= grep_file(opt, ce->name);
@@ -497,7 +407,8 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int
 }
 
 static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
-                    struct tree_desc *tree, struct strbuf *base, int tn_len)
+                    struct tree_desc *tree, struct strbuf *base, int tn_len,
+                    int check_attr)
 {
        int hit = 0;
        enum interesting match = entry_not_interesting;
@@ -518,7 +429,8 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
                strbuf_add(base, entry.path, te_len);
 
                if (S_ISREG(entry.mode)) {
-                       hit |= grep_sha1(opt, entry.sha1, base->buf, tn_len);
+                       hit |= grep_sha1(opt, entry.sha1, base->buf, tn_len,
+                                        check_attr ? base->buf + tn_len : NULL);
                }
                else if (S_ISDIR(entry.mode)) {
                        enum object_type type;
@@ -533,7 +445,8 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
 
                        strbuf_addch(base, '/');
                        init_tree_desc(&sub, data, size);
-                       hit |= grep_tree(opt, pathspec, &sub, base, tn_len);
+                       hit |= grep_tree(opt, pathspec, &sub, base, tn_len,
+                                        check_attr);
                        free(data);
                }
                strbuf_setlen(base, old_baselen);
@@ -548,7 +461,7 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
                       struct object *obj, const char *name)
 {
        if (obj->type == OBJ_BLOB)
-               return grep_sha1(opt, obj->sha1, name, 0);
+               return grep_sha1(opt, obj->sha1, name, 0, NULL);
        if (obj->type == OBJ_COMMIT || obj->type == OBJ_TREE) {
                struct tree_desc tree;
                void *data;
@@ -571,7 +484,8 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
                        strbuf_addch(&base, ':');
                }
                init_tree_desc(&tree, data, size);
-               hit = grep_tree(opt, pathspec, &tree, &base, base.len);
+               hit = grep_tree(opt, pathspec, &tree, &base, base.len,
+                               obj->type == OBJ_COMMIT);
                strbuf_release(&base);
                free(data);
                return hit;
@@ -839,27 +753,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
        if (argc == 2 && !strcmp(argv[1], "-h"))
                usage_with_options(grep_usage, options);
 
-       memset(&opt, 0, sizeof(opt));
-       opt.prefix = prefix;
-       opt.prefix_length = (prefix && *prefix) ? strlen(prefix) : 0;
-       opt.relative = 1;
-       opt.pathname = 1;
-       opt.pattern_tail = &opt.pattern_list;
-       opt.header_tail = &opt.header_list;
-       opt.regflags = REG_NEWLINE;
-       opt.max_depth = -1;
-       opt.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED;
-       opt.extended_regexp_option = 0;
-
-       strcpy(opt.color_context, "");
-       strcpy(opt.color_filename, "");
-       strcpy(opt.color_function, "");
-       strcpy(opt.color_lineno, "");
-       strcpy(opt.color_match, GIT_COLOR_BOLD_RED);
-       strcpy(opt.color_selected, "");
-       strcpy(opt.color_sep, GIT_COLOR_CYAN);
-       opt.color = -1;
-       git_config(grep_config, &opt);
+       init_grep_defaults();
+       git_config(grep_cmd_config, NULL);
+       grep_init(&opt, prefix);
 
        /*
         * If there is no -- then the paths must exist in the working
@@ -875,13 +771,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                             PARSE_OPT_KEEP_DASHDASH |
                             PARSE_OPT_STOP_AT_NON_OPTION |
                             PARSE_OPT_NO_INTERNAL_HELP);
-
-       if (pattern_type_arg != GREP_PATTERN_TYPE_UNSPECIFIED)
-               grep_pattern_type_options(pattern_type_arg, &opt);
-       else if (opt.pattern_type_option != GREP_PATTERN_TYPE_UNSPECIFIED)
-               grep_pattern_type_options(opt.pattern_type_option, &opt);
-       else if (opt.extended_regexp_option)
-               grep_pattern_type_options(GREP_PATTERN_TYPE_ERE, &opt);
+       grep_commit_pattern_type(pattern_type_arg, &opt);
 
        if (use_index && !startup_info->have_repository)
                /* die the same way as if we did it at the beginning */
index 09cf43e6d40efc13f6b7bda2094fca5bdc1bbc87..e7b7db1cacf1934a9bb0b96beb98ddda15a66074 100644 (file)
@@ -351,7 +351,8 @@ static int git_log_config(const char *var, const char *value, void *cb)
        }
        if (!prefixcmp(var, "color.decorate."))
                return parse_decorate_color_config(var, 15, value);
-
+       if (grep_config(var, value, cb) < 0)
+               return -1;
        return git_diff_ui_config(var, value, cb);
 }
 
@@ -360,6 +361,7 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix)
        struct rev_info rev;
        struct setup_revision_opt opt;
 
+       init_grep_defaults();
        git_config(git_log_config, NULL);
 
        init_revisions(&rev, prefix);
@@ -450,6 +452,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
        struct pathspec match_all;
        int i, count, ret = 0;
 
+       init_grep_defaults();
        git_config(git_log_config, NULL);
 
        init_pathspec(&match_all, NULL);
@@ -530,6 +533,7 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix)
        struct rev_info rev;
        struct setup_revision_opt opt;
 
+       init_grep_defaults();
        git_config(git_log_config, NULL);
 
        init_revisions(&rev, prefix);
@@ -552,6 +556,7 @@ int cmd_log(int argc, const char **argv, const char *prefix)
        struct rev_info rev;
        struct setup_revision_opt opt;
 
+       init_grep_defaults();
        git_config(git_log_config, NULL);
 
        init_revisions(&rev, prefix);
@@ -1121,6 +1126,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
        extra_hdr.strdup_strings = 1;
        extra_to.strdup_strings = 1;
        extra_cc.strdup_strings = 1;
+       init_grep_defaults();
        git_config(git_format_config, NULL);
        init_revisions(&rev, prefix);
        rev.commit_format = CMIT_FMT_EMAIL;
index 5e140640947cd9c38da00a01d8db9f036e8babd7..f069462cb03bbae46dae8d6b97420b3726690c47 100644 (file)
@@ -2033,7 +2033,6 @@ static int add_ref_tag(const char *path, const unsigned char *sha1, int flag, vo
 
        if (!prefixcmp(path, "refs/tags/") && /* is a tag? */
            !peel_ref(path, peeled)        && /* peelable? */
-           !is_null_sha1(peeled)          && /* annotated tag? */
            locate_object_entry(peeled))      /* object packed? */
                add_object_entry(sha1, OBJ_TAG, NULL, 0);
        return 0;
index b384c4c3cfe973346b5b295416f3883ae2d73c94..2aea3b565318e11bdcc63f175631388f4f20ba44 100644 (file)
@@ -9,6 +9,7 @@
 #include "cache-tree.h"
 #include "tree-walk.h"
 #include "parse-options.h"
+#include "submodule.h"
 
 static const char * const builtin_rm_usage[] = {
        N_("git rm [options] [--] <file>..."),
@@ -17,9 +18,58 @@ static const char * const builtin_rm_usage[] = {
 
 static struct {
        int nr, alloc;
-       const char **name;
+       struct {
+               const char *name;
+               char is_submodule;
+       } *entry;
 } list;
 
+static int get_ours_cache_pos(const char *path, int pos)
+{
+       int i = -pos - 1;
+
+       while ((i < active_nr) && !strcmp(active_cache[i]->name, path)) {
+               if (ce_stage(active_cache[i]) == 2)
+                       return i;
+               i++;
+       }
+       return -1;
+}
+
+static int check_submodules_use_gitfiles(void)
+{
+       int i;
+       int errs = 0;
+
+       for (i = 0; i < list.nr; i++) {
+               const char *name = list.entry[i].name;
+               int pos;
+               struct cache_entry *ce;
+               struct stat st;
+
+               pos = cache_name_pos(name, strlen(name));
+               if (pos < 0) {
+                       pos = get_ours_cache_pos(name, pos);
+                       if (pos < 0)
+                               continue;
+               }
+               ce = active_cache[pos];
+
+               if (!S_ISGITLINK(ce->ce_mode) ||
+                   (lstat(ce->name, &st) < 0) ||
+                   is_empty_dir(name))
+                       continue;
+
+               if (!submodule_uses_gitfile(name))
+                       errs = error(_("submodule '%s' (or one of its nested "
+                                    "submodules) uses a .git directory\n"
+                                    "(use 'rm -rf' if you really want to remove "
+                                    "it including all of its history)"), name);
+       }
+
+       return errs;
+}
+
 static int check_local_mod(unsigned char *head, int index_only)
 {
        /*
@@ -37,15 +87,26 @@ static int check_local_mod(unsigned char *head, int index_only)
                struct stat st;
                int pos;
                struct cache_entry *ce;
-               const char *name = list.name[i];
+               const char *name = list.entry[i].name;
                unsigned char sha1[20];
                unsigned mode;
                int local_changes = 0;
                int staged_changes = 0;
 
                pos = cache_name_pos(name, strlen(name));
-               if (pos < 0)
-                       continue; /* removing unmerged entry */
+               if (pos < 0) {
+                       /*
+                        * Skip unmerged entries except for populated submodules
+                        * that could lose history when removed.
+                        */
+                       pos = get_ours_cache_pos(name, pos);
+                       if (pos < 0)
+                               continue;
+
+                       if (!S_ISGITLINK(active_cache[pos]->ce_mode) ||
+                           is_empty_dir(name))
+                               continue;
+               }
                ce = active_cache[pos];
 
                if (lstat(ce->name, &st) < 0) {
@@ -58,9 +119,10 @@ static int check_local_mod(unsigned char *head, int index_only)
                        /* if a file was removed and it is now a
                         * directory, that is the same as ENOENT as
                         * far as git is concerned; we do not track
-                        * directories.
+                        * directories unless they are submodules.
                         */
-                       continue;
+                       if (!S_ISGITLINK(ce->ce_mode))
+                               continue;
                }
 
                /*
@@ -80,8 +142,11 @@ static int check_local_mod(unsigned char *head, int index_only)
 
                /*
                 * Is the index different from the file in the work tree?
+                * If it's a submodule, is its work tree modified?
                 */
-               if (ce_match_stat(ce, &st, 0))
+               if (ce_match_stat(ce, &st, 0) ||
+                   (S_ISGITLINK(ce->ce_mode) &&
+                    !ok_to_remove_submodule(ce->name)))
                        local_changes = 1;
 
                /*
@@ -115,10 +180,18 @@ static int check_local_mod(unsigned char *head, int index_only)
                                errs = error(_("'%s' has changes staged in the index\n"
                                             "(use --cached to keep the file, "
                                             "or -f to force removal)"), name);
-                       if (local_changes)
-                               errs = error(_("'%s' has local modifications\n"
-                                            "(use --cached to keep the file, "
-                                            "or -f to force removal)"), name);
+                       if (local_changes) {
+                               if (S_ISGITLINK(ce->ce_mode) &&
+                                   !submodule_uses_gitfile(name)) {
+                                       errs = error(_("submodule '%s' (or one of its nested "
+                                                    "submodules) uses a .git directory\n"
+                                                    "(use 'rm -rf' if you really want to remove "
+                                                    "it including all of its history)"), name);
+                               } else
+                                       errs = error(_("'%s' has local modifications\n"
+                                                    "(use --cached to keep the file, "
+                                                    "or -f to force removal)"), name);
+                       }
                }
        }
        return errs;
@@ -173,8 +246,9 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
                struct cache_entry *ce = active_cache[i];
                if (!match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen))
                        continue;
-               ALLOC_GROW(list.name, list.nr + 1, list.alloc);
-               list.name[list.nr++] = ce->name;
+               ALLOC_GROW(list.entry, list.nr + 1, list.alloc);
+               list.entry[list.nr].name = ce->name;
+               list.entry[list.nr++].is_submodule = S_ISGITLINK(ce->ce_mode);
        }
 
        if (pathspec) {
@@ -215,6 +289,9 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
                        hashclr(sha1);
                if (check_local_mod(sha1, index_only))
                        exit(1);
+       } else if (!index_only) {
+               if (check_submodules_use_gitfiles())
+                       exit(1);
        }
 
        /*
@@ -222,7 +299,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
         * the index unless all of them succeed.
         */
        for (i = 0; i < list.nr; i++) {
-               const char *path = list.name[i];
+               const char *path = list.entry[i].name;
                if (!quiet)
                        printf("rm '%s'\n", path);
 
@@ -244,7 +321,25 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
        if (!index_only) {
                int removed = 0;
                for (i = 0; i < list.nr; i++) {
-                       const char *path = list.name[i];
+                       const char *path = list.entry[i].name;
+                       if (list.entry[i].is_submodule) {
+                               if (is_empty_dir(path)) {
+                                       if (!rmdir(path)) {
+                                               removed = 1;
+                                               continue;
+                                       }
+                               } else {
+                                       struct strbuf buf = STRBUF_INIT;
+                                       strbuf_addstr(&buf, path);
+                                       if (!remove_dir_recursively(&buf, 0)) {
+                                               removed = 1;
+                                               strbuf_release(&buf);
+                                               continue;
+                                       }
+                                       strbuf_release(&buf);
+                                       /* Fallthrough and let remove_path() fail. */
+                               }
+                       }
                        if (!remove_path(path)) {
                                removed = 1;
                                continue;
index 4eb016d6e53628f19d51a50aeb074bf424154026..8d9b76a02fd115c0285216c27c5232f345d0582d 100644 (file)
@@ -28,7 +28,6 @@ static void show_one(const char *refname, const unsigned char *sha1)
 
 static int show_ref(const char *refname, const unsigned char *sha1, int flag, void *cbdata)
 {
-       struct object *obj;
        const char *hex;
        unsigned char peeled[20];
 
@@ -79,25 +78,9 @@ static int show_ref(const char *refname, const unsigned char *sha1, int flag, vo
        if (!deref_tags)
                return 0;
 
-       if ((flag & REF_ISPACKED) && !peel_ref(refname, peeled)) {
-               if (!is_null_sha1(peeled)) {
-                       hex = find_unique_abbrev(peeled, abbrev);
-                       printf("%s %s^{}\n", hex, refname);
-               }
-       }
-       else {
-               obj = parse_object(sha1);
-               if (!obj)
-                       die("git show-ref: bad ref %s (%s)", refname,
-                           sha1_to_hex(sha1));
-               if (obj->type == OBJ_TAG) {
-                       obj = deref_tag(obj, refname, 0);
-                       if (!obj)
-                               die("git show-ref: bad tag at ref %s (%s)", refname,
-                                   sha1_to_hex(sha1));
-                       hex = find_unique_abbrev(obj->sha1, abbrev);
-                       printf("%s %s^{}\n", hex, refname);
-               }
+       if (!peel_ref(refname, peeled)) {
+               hex = find_unique_abbrev(peeled, abbrev);
+               printf("%s %s^{}\n", hex, refname);
        }
        return 0;
 }
index afc892d6b1837d807490f42790bf29686d074a10..4e6383898c59f03127ed698abcb86857d63a8eac 100644 (file)
@@ -335,6 +335,28 @@ FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
        return freopen(filename, otype, stream);
 }
 
+#undef fflush
+int mingw_fflush(FILE *stream)
+{
+       int ret = fflush(stream);
+
+       /*
+        * write() is used behind the scenes of stdio output functions.
+        * Since git code does not check for errors after each stdio write
+        * operation, it can happen that write() is called by a later
+        * stdio function even if an earlier write() call failed. In the
+        * case of a pipe whose readable end was closed, only the first
+        * call to write() reports EPIPE on Windows. Subsequent write()
+        * calls report EINVAL. It is impossible to notice whether this
+        * fflush invocation triggered such a case, therefore, we have to
+        * catch all EINVAL errors whole-sale.
+        */
+       if (ret && errno == EINVAL)
+               errno = EPIPE;
+
+       return ret;
+}
+
 /*
  * The unit of FILETIME is 100-nanoseconds since January 1, 1601, UTC.
  * Returns the 100-nanoseconds ("hekto nanoseconds") since the epoch.
index 61a652138ac7b7ef412bbc15e6ce479db158b181..eeb08d120bab73154afe282873514c920628eab2 100644 (file)
@@ -185,6 +185,9 @@ FILE *mingw_fopen (const char *filename, const char *otype);
 FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream);
 #define freopen mingw_freopen
 
+int mingw_fflush(FILE *stream);
+#define fflush mingw_fflush
+
 char *mingw_getcwd(char *pointer, int len);
 #define getcwd mingw_getcwd
 
index 08e47e2e48a5bd310025752ee5ecdce81721b34d..fff8a43bc0378d7d7ee6d7ab3deee228c87b1d5c 100644 (file)
--- a/config.c
+++ b/config.c
@@ -10,8 +10,6 @@
 #include "strbuf.h"
 #include "quote.h"
 
-#define MAXNAME (256)
-
 typedef struct config_file {
        struct config_file *prev;
        FILE *f;
@@ -19,7 +17,7 @@ typedef struct config_file {
        int linenr;
        int eof;
        struct strbuf value;
-       char var[MAXNAME];
+       struct strbuf var;
 } config_file;
 
 static config_file *cf;
@@ -260,7 +258,7 @@ static inline int iskeychar(int c)
        return isalnum(c) || c == '-';
 }
 
-static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
+static int get_value(config_fn_t fn, void *data, struct strbuf *name)
 {
        int c;
        char *value;
@@ -272,11 +270,9 @@ static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
                        break;
                if (!iskeychar(c))
                        break;
-               name[len++] = tolower(c);
-               if (len >= MAXNAME)
-                       return -1;
+               strbuf_addch(name, tolower(c));
        }
-       name[len] = 0;
+
        while (c == ' ' || c == '\t')
                c = get_next_char();
 
@@ -288,10 +284,10 @@ static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
                if (!value)
                        return -1;
        }
-       return fn(name, value, data);
+       return fn(name->buf, value, data);
 }
 
-static int get_extended_base_var(char *name, int baselen, int c)
+static int get_extended_base_var(struct strbuf *name, int c)
 {
        do {
                if (c == '\n')
@@ -302,7 +298,7 @@ static int get_extended_base_var(char *name, int baselen, int c)
        /* We require the format to be '[base "extension"]' */
        if (c != '"')
                return -1;
-       name[baselen++] = '.';
+       strbuf_addch(name, '.');
 
        for (;;) {
                int c = get_next_char();
@@ -315,37 +311,31 @@ static int get_extended_base_var(char *name, int baselen, int c)
                        if (c == '\n')
                                goto error_incomplete_line;
                }
-               name[baselen++] = c;
-               if (baselen > MAXNAME / 2)
-                       return -1;
+               strbuf_addch(name, c);
        }
 
        /* Final ']' */
        if (get_next_char() != ']')
                return -1;
-       return baselen;
+       return 0;
 error_incomplete_line:
        cf->linenr--;
        return -1;
 }
 
-static int get_base_var(char *name)
+static int get_base_var(struct strbuf *name)
 {
-       int baselen = 0;
-
        for (;;) {
                int c = get_next_char();
                if (cf->eof)
                        return -1;
                if (c == ']')
-                       return baselen;
+                       return 0;
                if (isspace(c))
-                       return get_extended_base_var(name, baselen, c);
+                       return get_extended_base_var(name, c);
                if (!iskeychar(c) && c != '.')
                        return -1;
-               if (baselen > MAXNAME / 2)
-                       return -1;
-               name[baselen++] = tolower(c);
+               strbuf_addch(name, tolower(c));
        }
 }
 
@@ -353,7 +343,7 @@ static int git_parse_file(config_fn_t fn, void *data)
 {
        int comment = 0;
        int baselen = 0;
-       char *var = cf->var;
+       struct strbuf *var = &cf->var;
 
        /* U+FEFF Byte Order Mark in UTF8 */
        static const unsigned char *utf8_bom = (unsigned char *) "\xef\xbb\xbf";
@@ -389,17 +379,24 @@ static int git_parse_file(config_fn_t fn, void *data)
                        continue;
                }
                if (c == '[') {
-                       baselen = get_base_var(var);
-                       if (baselen <= 0)
+                       /* Reset prior to determining a new stem */
+                       strbuf_reset(var);
+                       if (get_base_var(var) < 0 || var->len < 1)
                                break;
-                       var[baselen++] = '.';
-                       var[baselen] = 0;
+                       strbuf_addch(var, '.');
+                       baselen = var->len;
                        continue;
                }
                if (!isalpha(c))
                        break;
-               var[baselen] = tolower(c);
-               if (get_value(fn, data, var, baselen+1) < 0)
+               /*
+                * Truncate the var name back to the section header
+                * stem prior to grabbing the suffix part of the name
+                * and the value.
+                */
+               strbuf_setlen(var, baselen);
+               strbuf_addch(var, tolower(c));
+               if (get_value(fn, data, var) < 0)
                        break;
        }
        die("bad config file line %d in %s", cf->linenr, cf->name);
@@ -899,12 +896,14 @@ int git_config_from_file(config_fn_t fn, const char *filename, void *data)
                top.linenr = 1;
                top.eof = 0;
                strbuf_init(&top.value, 1024);
+               strbuf_init(&top.var, 1024);
                cf = &top;
 
                ret = git_parse_file(fn, data);
 
                /* pop config-file parsing state stack */
                strbuf_release(&top.value);
+               strbuf_release(&top.var);
                cf = top.prev;
 
                fclose(f);
index c85888c851c39d4ac88e1ba8b1a35a6f14a97ca7..ad215cc4a10ed95804e7cec929f003c985d25a3d 100644 (file)
@@ -1024,7 +1024,7 @@ elif test -z "$PTHREAD_CFLAGS"; then
   for opt in -mt -pthread -lpthread; do
      old_CFLAGS="$CFLAGS"
      CFLAGS="$opt $CFLAGS"
-     AC_MSG_CHECKING([Checking for POSIX Threads with '$opt'])
+     AC_MSG_CHECKING([for POSIX Threads with '$opt'])
      AC_LINK_IFELSE([PTHREADTEST_SRC],
        [AC_MSG_RESULT([yes])
                NO_PTHREADS=
@@ -1044,7 +1044,7 @@ elif test -z "$PTHREAD_CFLAGS"; then
 else
   old_CFLAGS="$CFLAGS"
   CFLAGS="$PTHREAD_CFLAGS $CFLAGS"
-  AC_MSG_CHECKING([Checking for POSIX Threads with '$PTHREAD_CFLAGS'])
+  AC_MSG_CHECKING([for POSIX Threads with '$PTHREAD_CFLAGS'])
   AC_LINK_IFELSE([PTHREADTEST_SRC],
        [AC_MSG_RESULT([yes])
                NO_PTHREADS=
index 35db24f5eae600a973391915ceb61c4635941aec..f363505abb278f89a94413874099e0e80ee8192c 100644 (file)
@@ -10,7 +10,8 @@ int main(int argc, char **argv)
 {
        if (svndump_init(NULL))
                return 1;
-       svndump_read((argc > 1) ? argv[1] : NULL);
+       svndump_read((argc > 1) ? argv[1] : NULL, "refs/heads/master",
+                       "refs/notes/svn/revs");
        svndump_deinit();
        svndump_reset();
        return 0;
diff --git a/contrib/svn-fe/svnrdump_sim.py b/contrib/svn-fe/svnrdump_sim.py
new file mode 100755 (executable)
index 0000000..1cfac4a
--- /dev/null
@@ -0,0 +1,53 @@
+#!/usr/bin/python
+"""
+Simulates svnrdump by replaying an existing dump from a file, taking care
+of the specified revision range.
+To simulate incremental imports the environment variable SVNRMAX can be set
+to the highest revision that should be available.
+"""
+import sys, os
+
+
+def getrevlimit():
+        var = 'SVNRMAX'
+        if os.environ.has_key(var):
+                return os.environ[var]
+        return None
+
+def writedump(url, lower, upper):
+        if url.startswith('sim://'):
+                filename = url[6:]
+                if filename[-1] == '/': filename = filename[:-1] #remove terminating slash
+        else:
+                raise ValueError('sim:// url required')
+        f = open(filename, 'r');
+        state = 'header'
+        wroterev = False
+        while(True):
+                l = f.readline()
+                if l == '': break
+                if state == 'header' and l.startswith('Revision-number: '):
+                        state = 'prefix'
+                if state == 'prefix' and l == 'Revision-number: %s\n' % lower:
+                        state = 'selection'
+                if not upper == 'HEAD' and state == 'selection' and l == 'Revision-number: %s\n' % upper:
+                        break;
+
+                if state == 'header' or state == 'selection':
+                        if state == 'selection': wroterev = True
+                        sys.stdout.write(l)
+        return wroterev
+
+if __name__ == "__main__":
+        if not (len(sys.argv) in (3, 4, 5)):
+                print "usage: %s dump URL -rLOWER:UPPER"
+                sys.exit(1)
+        if not sys.argv[1] == 'dump': raise NotImplementedError('only "dump" is suppported.')
+        url = sys.argv[2]
+        r = ('0', 'HEAD')
+        if len(sys.argv) == 4 and sys.argv[3][0:2] == '-r':
+                r = sys.argv[3][2:].lstrip().split(':')
+        if not getrevlimit() is None: r[1] = getrevlimit()
+        if writedump(url, r[0], r[1]): ret = 0
+        else: ret = 1
+        sys.exit(ret)
diff --git a/diff.c b/diff.c
index 35d3f073859acf66dbd38c6096c0cc47bd26b6e2..7fef69d85c33faaaaf23cbff536ca0639ab2f1c6 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -15,6 +15,7 @@
 #include "sigchain.h"
 #include "submodule.h"
 #include "ll-merge.h"
+#include "string-list.h"
 
 #ifdef NO_FAST_WORKING_DIRECTORY
 #define FAST_WORKING_DIRECTORY 0
@@ -26,6 +27,7 @@ static int diff_detect_rename_default;
 static int diff_rename_limit_default = 400;
 static int diff_suppress_blank_empty;
 static int diff_use_color_default = -1;
+static int diff_context_default = 3;
 static const char *diff_word_regex_cfg;
 static const char *external_diff_cmd_cfg;
 int diff_auto_refresh_index = 1;
@@ -68,26 +70,30 @@ static int parse_diff_color_slot(const char *var, int ofs)
        return -1;
 }
 
-static int parse_dirstat_params(struct diff_options *options, const char *params,
+static int parse_dirstat_params(struct diff_options *options, const char *params_string,
                                struct strbuf *errmsg)
 {
-       const char *p = params;
-       int p_len, ret = 0;
+       char *params_copy = xstrdup(params_string);
+       struct string_list params = STRING_LIST_INIT_NODUP;
+       int ret = 0;
+       int i;
 
-       while (*p) {
-               p_len = strchrnul(p, ',') - p;
-               if (!memcmp(p, "changes", p_len)) {
+       if (*params_copy)
+               string_list_split_in_place(&params, params_copy, ',', -1);
+       for (i = 0; i < params.nr; i++) {
+               const char *p = params.items[i].string;
+               if (!strcmp(p, "changes")) {
                        DIFF_OPT_CLR(options, DIRSTAT_BY_LINE);
                        DIFF_OPT_CLR(options, DIRSTAT_BY_FILE);
-               } else if (!memcmp(p, "lines", p_len)) {
+               } else if (!strcmp(p, "lines")) {
                        DIFF_OPT_SET(options, DIRSTAT_BY_LINE);
                        DIFF_OPT_CLR(options, DIRSTAT_BY_FILE);
-               } else if (!memcmp(p, "files", p_len)) {
+               } else if (!strcmp(p, "files")) {
                        DIFF_OPT_CLR(options, DIRSTAT_BY_LINE);
                        DIFF_OPT_SET(options, DIRSTAT_BY_FILE);
-               } else if (!memcmp(p, "noncumulative", p_len)) {
+               } else if (!strcmp(p, "noncumulative")) {
                        DIFF_OPT_CLR(options, DIRSTAT_CUMULATIVE);
-               } else if (!memcmp(p, "cumulative", p_len)) {
+               } else if (!strcmp(p, "cumulative")) {
                        DIFF_OPT_SET(options, DIRSTAT_CUMULATIVE);
                } else if (isdigit(*p)) {
                        char *end;
@@ -99,24 +105,21 @@ static int parse_dirstat_params(struct diff_options *options, const char *params
                                while (isdigit(*++end))
                                        ; /* nothing */
                        }
-                       if (end - p == p_len)
+                       if (!*end)
                                options->dirstat_permille = permille;
                        else {
-                               strbuf_addf(errmsg, _("  Failed to parse dirstat cut-off percentage '%.*s'\n"),
-                                           p_len, p);
+                               strbuf_addf(errmsg, _("  Failed to parse dirstat cut-off percentage '%s'\n"),
+                                           p);
                                ret++;
                        }
                } else {
-                       strbuf_addf(errmsg, _("  Unknown dirstat parameter '%.*s'\n"),
-                                   p_len, p);
+                       strbuf_addf(errmsg, _("  Unknown dirstat parameter '%s'\n"), p);
                        ret++;
                }
 
-               p += p_len;
-
-               if (*p)
-                       p++; /* more parameters, swallow separator */
        }
+       string_list_clear(&params, 0);
+       free(params_copy);
        return ret;
 }
 
@@ -141,6 +144,12 @@ int git_diff_ui_config(const char *var, const char *value, void *cb)
                diff_use_color_default = git_config_colorbool(var, value);
                return 0;
        }
+       if (!strcmp(var, "diff.context")) {
+               diff_context_default = git_config_int(var, value);
+               if (diff_context_default < 0)
+                       return -1;
+               return 0;
+       }
        if (!strcmp(var, "diff.renames")) {
                diff_detect_rename_default = git_config_rename(var, value);
                return 0;
@@ -3170,7 +3179,7 @@ void diff_setup(struct diff_options *options)
        options->break_opt = -1;
        options->rename_limit = -1;
        options->dirstat_permille = diff_dirstat_permille_default;
-       options->context = 3;
+       options->context = diff_context_default;
        DIFF_OPT_SET(options, RENAME_EMPTY);
 
        options->change = diff_change;
diff --git a/dir.c b/dir.c
index 486833986ed4b4e7d05d2086d53b15ec63905dd0..5a83aa7897f270279c403778f43aea6db1efc5af 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -308,42 +308,69 @@ static int no_wildcard(const char *string)
        return string[simple_length(string)] == '\0';
 }
 
+void parse_exclude_pattern(const char **pattern,
+                          int *patternlen,
+                          int *flags,
+                          int *nowildcardlen)
+{
+       const char *p = *pattern;
+       size_t i, len;
+
+       *flags = 0;
+       if (*p == '!') {
+               *flags |= EXC_FLAG_NEGATIVE;
+               p++;
+       }
+       len = strlen(p);
+       if (len && p[len - 1] == '/') {
+               len--;
+               *flags |= EXC_FLAG_MUSTBEDIR;
+       }
+       for (i = 0; i < len; i++) {
+               if (p[i] == '/')
+                       break;
+       }
+       if (i == len)
+               *flags |= EXC_FLAG_NODIR;
+       *nowildcardlen = simple_length(p);
+       /*
+        * we should have excluded the trailing slash from 'p' too,
+        * but that's one more allocation. Instead just make sure
+        * nowildcardlen does not exceed real patternlen
+        */
+       if (*nowildcardlen > len)
+               *nowildcardlen = len;
+       if (*p == '*' && no_wildcard(p + 1))
+               *flags |= EXC_FLAG_ENDSWITH;
+       *pattern = p;
+       *patternlen = len;
+}
+
 void add_exclude(const char *string, const char *base,
                 int baselen, struct exclude_list *which)
 {
        struct exclude *x;
-       size_t len;
-       int to_exclude = 1;
-       int flags = 0;
+       int patternlen;
+       int flags;
+       int nowildcardlen;
 
-       if (*string == '!') {
-               to_exclude = 0;
-               string++;
-       }
-       len = strlen(string);
-       if (len && string[len - 1] == '/') {
+       parse_exclude_pattern(&string, &patternlen, &flags, &nowildcardlen);
+       if (flags & EXC_FLAG_MUSTBEDIR) {
                char *s;
-               x = xmalloc(sizeof(*x) + len);
+               x = xmalloc(sizeof(*x) + patternlen + 1);
                s = (char *)(x+1);
-               memcpy(s, string, len - 1);
-               s[len - 1] = '\0';
-               string = s;
+               memcpy(s, string, patternlen);
+               s[patternlen] = '\0';
                x->pattern = s;
-               flags = EXC_FLAG_MUSTBEDIR;
        } else {
                x = xmalloc(sizeof(*x));
                x->pattern = string;
        }
-       x->to_exclude = to_exclude;
-       x->patternlen = strlen(string);
+       x->patternlen = patternlen;
+       x->nowildcardlen = nowildcardlen;
        x->base = base;
        x->baselen = baselen;
        x->flags = flags;
-       if (!strchr(string, '/'))
-               x->flags |= EXC_FLAG_NODIR;
-       x->nowildcardlen = simple_length(string);
-       if (*string == '*' && no_wildcard(string+1))
-               x->flags |= EXC_FLAG_ENDSWITH;
        ALLOC_GROW(which->excludes, which->nr + 1, which->alloc);
        which->excludes[which->nr++] = x;
 }
@@ -505,6 +532,72 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
        dir->basebuf[baselen] = '\0';
 }
 
+int match_basename(const char *basename, int basenamelen,
+                  const char *pattern, int prefix, int patternlen,
+                  int flags)
+{
+       if (prefix == patternlen) {
+               if (!strcmp_icase(pattern, basename))
+                       return 1;
+       } else if (flags & EXC_FLAG_ENDSWITH) {
+               if (patternlen - 1 <= basenamelen &&
+                   !strcmp_icase(pattern + 1,
+                                 basename + basenamelen - patternlen + 1))
+                       return 1;
+       } else {
+               if (fnmatch_icase(pattern, basename, 0) == 0)
+                       return 1;
+       }
+       return 0;
+}
+
+int match_pathname(const char *pathname, int pathlen,
+                  const char *base, int baselen,
+                  const char *pattern, int prefix, int patternlen,
+                  int flags)
+{
+       const char *name;
+       int namelen;
+
+       /*
+        * match with FNM_PATHNAME; the pattern has base implicitly
+        * in front of it.
+        */
+       if (*pattern == '/') {
+               pattern++;
+               prefix--;
+       }
+
+       /*
+        * baselen does not count the trailing slash. base[] may or
+        * may not end with a trailing slash though.
+        */
+       if (pathlen < baselen + 1 ||
+           (baselen && pathname[baselen] != '/') ||
+           strncmp_icase(pathname, base, baselen))
+               return 0;
+
+       namelen = baselen ? pathlen - baselen - 1 : pathlen;
+       name = pathname + pathlen - namelen;
+
+       if (prefix) {
+               /*
+                * if the non-wildcard part is longer than the
+                * remaining pathname, surely it cannot match.
+                */
+               if (prefix > namelen)
+                       return 0;
+
+               if (strncmp_icase(pattern, name, prefix))
+                       return 0;
+               pattern += prefix;
+               name    += prefix;
+               namelen -= prefix;
+       }
+
+       return fnmatch_icase(pattern, name, FNM_PATHNAME) == 0;
+}
+
 /* Scan the list and let the last match determine the fate.
  * Return 1 for exclude, 0 for include and -1 for undecided.
  */
@@ -519,9 +612,9 @@ int excluded_from_list(const char *pathname,
 
        for (i = el->nr - 1; 0 <= i; i--) {
                struct exclude *x = el->excludes[i];
-               const char *name, *exclude = x->pattern;
-               int to_exclude = x->to_exclude;
-               int namelen, prefix = x->nowildcardlen;
+               const char *exclude = x->pattern;
+               int to_exclude = x->flags & EXC_FLAG_NEGATIVE ? 0 : 1;
+               int prefix = x->nowildcardlen;
 
                if (x->flags & EXC_FLAG_MUSTBEDIR) {
                        if (*dtype == DT_UNKNOWN)
@@ -531,51 +624,18 @@ int excluded_from_list(const char *pathname,
                }
 
                if (x->flags & EXC_FLAG_NODIR) {
-                       /* match basename */
-                       if (prefix == x->patternlen) {
-                               if (!strcmp_icase(exclude, basename))
-                                       return to_exclude;
-                       } else if (x->flags & EXC_FLAG_ENDSWITH) {
-                               if (x->patternlen - 1 <= pathlen &&
-                                   !strcmp_icase(exclude + 1, pathname + pathlen - x->patternlen + 1))
-                                       return to_exclude;
-                       } else {
-                               if (fnmatch_icase(exclude, basename, 0) == 0)
-                                       return to_exclude;
-                       }
-                       continue;
-               }
-
-               /* match with FNM_PATHNAME:
-                * exclude has base (baselen long) implicitly in front of it.
-                */
-               if (*exclude == '/') {
-                       exclude++;
-                       prefix--;
-               }
-
-               if (pathlen < x->baselen ||
-                   (x->baselen && pathname[x->baselen-1] != '/') ||
-                   strncmp_icase(pathname, x->base, x->baselen))
+                       if (match_basename(basename,
+                                          pathlen - (basename - pathname),
+                                          exclude, prefix, x->patternlen,
+                                          x->flags))
+                               return to_exclude;
                        continue;
-
-               namelen = x->baselen ? pathlen - x->baselen : pathlen;
-               name = pathname + pathlen  - namelen;
-
-               /* if the non-wildcard part is longer than the
-                  remaining pathname, surely it cannot match */
-               if (prefix > namelen)
-                       continue;
-
-               if (prefix) {
-                       if (strncmp_icase(exclude, name, prefix))
-                               continue;
-                       exclude += prefix;
-                       name    += prefix;
-                       namelen -= prefix;
                }
 
-               if (!namelen || !fnmatch_icase(exclude, name, FNM_PATHNAME))
+               assert(x->baselen == 0 || x->base[x->baselen - 1] == '/');
+               if (match_pathname(pathname, pathlen,
+                                  x->base, x->baselen ? x->baselen - 1 : 0,
+                                  exclude, prefix, x->patternlen, x->flags))
                        return to_exclude;
        }
        return -1; /* undecided */
diff --git a/dir.h b/dir.h
index 893465a1e89d17cf5f94d3e68be1371f03e6163d..f5c89e3b80143f2508ac5b69d432aa82a4254751 100644 (file)
--- a/dir.h
+++ b/dir.h
@@ -11,6 +11,7 @@ struct dir_entry {
 #define EXC_FLAG_NODIR 1
 #define EXC_FLAG_ENDSWITH 4
 #define EXC_FLAG_MUSTBEDIR 8
+#define EXC_FLAG_NEGATIVE 16
 
 struct exclude_list {
        int nr;
@@ -21,7 +22,6 @@ struct exclude_list {
                int nowildcardlen;
                const char *base;
                int baselen;
-               int to_exclude;
                int flags;
        } **excludes;
 };
@@ -80,6 +80,16 @@ extern int excluded_from_list(const char *pathname, int pathlen, const char *bas
                              int *dtype, struct exclude_list *el);
 struct dir_entry *dir_add_ignored(struct dir_struct *dir, const char *pathname, int len);
 
+/*
+ * these implement the matching logic for dir.c:excluded_from_list and
+ * attr.c:path_matches()
+ */
+extern int match_basename(const char *, int,
+                         const char *, int, int, int);
+extern int match_pathname(const char *, int,
+                         const char *, int,
+                         const char *, int, int, int);
+
 /*
  * The excluded() API is meant for callers that check each level of leading
  * directory hierarchies with excluded() to avoid recursing into excluded
@@ -97,6 +107,7 @@ extern int path_excluded(struct path_exclude_check *, const char *, int namelen,
 extern int add_excludes_from_file_to_list(const char *fname, const char *base, int baselen,
                                          char **buf_p, struct exclude_list *which, int check_index);
 extern void add_excludes_from_file(struct dir_struct *, const char *fname);
+extern void parse_exclude_pattern(const char **string, int *patternlen, int *flags, int *nowildcardlen);
 extern void add_exclude(const char *string, const char *base,
                        int baselen, struct exclude_list *which);
 extern void free_excludes(struct exclude_list *el);
index 2fbf1fd8b14a57e065674ffec238406f09b71639..2e79b8a2f379d7c72a0934b36c7538db2143c722 100644 (file)
@@ -506,6 +506,7 @@ extern const char tolower_trans_tbl[256];
 #undef isdigit
 #undef isalpha
 #undef isalnum
+#undef isprint
 #undef islower
 #undef isupper
 #undef tolower
@@ -523,6 +524,7 @@ extern unsigned char sane_ctype[256];
 #define isdigit(x) sane_istest(x,GIT_DIGIT)
 #define isalpha(x) sane_istest(x,GIT_ALPHA)
 #define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
+#define isprint(x) ((x) >= 0x20 && (x) <= 0x7e)
 #define islower(x) sane_iscase(x, 1)
 #define isupper(x) sane_iscase(x, 0)
 #define is_glob_special(x) sane_istest(x,GIT_GLOB_SPECIAL)
index 178e45305d2b66bbe5a0c0902d989ea66888869b..53142492afcfb92f0453359af9a00a045c51e7e9 100755 (executable)
@@ -64,37 +64,19 @@ EOF
 
 eval "$functions"
 
-# When piped a commit, output a script to set the ident of either
-# "author" or "committer
+finish_ident() {
+       # Ensure non-empty id name.
+       echo "case \"\$GIT_$1_NAME\" in \"\") GIT_$1_NAME=\"\${GIT_$1_EMAIL%%@*}\" && export GIT_$1_NAME;; esac"
+       # And make sure everything is exported.
+       echo "export GIT_$1_NAME"
+       echo "export GIT_$1_EMAIL"
+       echo "export GIT_$1_DATE"
+}
 
 set_ident () {
-       lid="$(echo "$1" | tr "[A-Z]" "[a-z]")"
-       uid="$(echo "$1" | tr "[a-z]" "[A-Z]")"
-       pick_id_script='
-               /^'$lid' /{
-                       s/'\''/'\''\\'\'\''/g
-                       h
-                       s/^'$lid' \([^<]*\) <[^>]*> .*$/\1/
-                       s/'\''/'\''\'\'\''/g
-                       s/.*/GIT_'$uid'_NAME='\''&'\''; export GIT_'$uid'_NAME/p
-
-                       g
-                       s/^'$lid' [^<]* <\([^>]*\)> .*$/\1/
-                       s/'\''/'\''\'\'\''/g
-                       s/.*/GIT_'$uid'_EMAIL='\''&'\''; export GIT_'$uid'_EMAIL/p
-
-                       g
-                       s/^'$lid' [^<]* <[^>]*> \(.*\)$/@\1/
-                       s/'\''/'\''\'\'\''/g
-                       s/.*/GIT_'$uid'_DATE='\''&'\''; export GIT_'$uid'_DATE/p
-
-                       q
-               }
-       '
-
-       LANG=C LC_ALL=C sed -ne "$pick_id_script"
-       # Ensure non-empty id name.
-       echo "case \"\$GIT_${uid}_NAME\" in \"\") GIT_${uid}_NAME=\"\${GIT_${uid}_EMAIL%%@*}\" && export GIT_${uid}_NAME;; esac"
+       parse_ident_from_commit author AUTHOR committer COMMITTER
+       finish_ident AUTHOR
+       finish_ident COMMITTER
 }
 
 USAGE="[--env-filter <command>] [--tree-filter <command>]
@@ -320,10 +302,8 @@ while read commit parents; do
        git cat-file commit "$commit" >../commit ||
                die "Cannot read commit $commit"
 
-       eval "$(set_ident AUTHOR <../commit)" ||
-               die "setting author failed for commit $commit"
-       eval "$(set_ident COMMITTER <../commit)" ||
-               die "setting committer failed for commit $commit"
+       eval "$(set_ident <../commit)" ||
+               die "setting author/committer failed for commit $commit"
        eval "$filter_env" < /dev/null ||
                die "env filter failed: $filter_env"
 
index 65709437ff06a2b371fe70fd846922c73ebc23b0..49b62ea6ebc61c4af16d7d740e5b423e5787b915 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=0.16.GITGUI
+DEF_VER=0.17.GITGUI
 
 LF='
 '
index ba4e5c1330c84f54a6809991eec22aa2e8e25ddd..89f636f4963cf7933639f6a23b3be2e8fd4c0964 100755 (executable)
@@ -154,6 +154,7 @@ set _trace [lsearch -exact $argv --trace]
 if {$_trace >= 0} {
        set argv [lreplace $argv $_trace $_trace]
        set _trace 1
+       if {[tk windowingsystem] eq "win32"} { console show }
 } else {
        set _trace 0
 }
@@ -1463,7 +1464,7 @@ proc rescan {after {honor_trustmtime 1}} {
                (![$ui_comm edit modified]
                || [string trim [$ui_comm get 0.0 end]] eq {})} {
                if {[string match amend* $commit_type]} {
-               } elseif {[load_message GITGUI_MSG]} {
+               } elseif {[load_message GITGUI_MSG utf-8]} {
                } elseif {[run_prepare_commit_msg_hook]} {
                } elseif {[load_message MERGE_MSG]} {
                } elseif {[load_message SQUASH_MSG]} {
@@ -1549,7 +1550,7 @@ proc rescan_stage2 {fd after} {
        fileevent $fd_lo readable [list read_ls_others $fd_lo $after]
 }
 
-proc load_message {file} {
+proc load_message {file {encoding {}}} {
        global ui_comm
 
        set f [gitdir $file]
@@ -1558,6 +1559,9 @@ proc load_message {file} {
                        return 0
                }
                fconfigure $fd -eofchar {}
+               if {$encoding ne {}} {
+                       fconfigure $fd -encoding $encoding
+               }
                set content [string trim [read $fd]]
                close $fd
                regsub -all -line {[ \r\t]+$} $content {} content
@@ -2266,6 +2270,7 @@ proc do_quit {{rc {1}}} {
                                && $msg ne {}} {
                                catch {
                                        set fd [open $save w]
+                                       fconfigure $fd -encoding utf-8
                                        puts -nonewline $fd $msg
                                        close $fd
                                }
@@ -2998,10 +3003,19 @@ blame {
        set jump_spec {}
        set is_path 0
        foreach a $argv {
-               if {$is_path || [file exists $_prefix$a]} {
+               if {[file exists $a]} {
+                       if {$path ne {}} usage
+                       set path [normalize_relpath $a]
+                       break
+               } elseif {[file exists $_prefix$a]} {
                        if {$path ne {}} usage
                        set path [normalize_relpath $_prefix$a]
                        break
+               }
+
+               if {$is_path} {
+                       if {$path ne {}} usage
+                       break
                } elseif {$a eq {--}} {
                        if {$path ne {}} {
                                if {$head ne {}} usage
@@ -3023,8 +3037,13 @@ blame {
        unset is_path
 
        if {$head ne {} && $path eq {}} {
-               set path [normalize_relpath $_prefix$head]
-               set head {}
+               if {[string index $head 0] eq {/}} {
+                       set path [normalize_relpath $head]
+                       set head {}
+               } else {
+                       set path [normalize_relpath $_prefix$head]
+                       set head {}
+               }
        }
 
        if {$head eq {}} {
@@ -3710,6 +3729,8 @@ bind $ui_diff <$M1B-Key-v> {break}
 bind $ui_diff <$M1B-Key-V> {break}
 bind $ui_diff <$M1B-Key-a> {%W tag add sel 0.0 end;break}
 bind $ui_diff <$M1B-Key-A> {%W tag add sel 0.0 end;break}
+bind $ui_diff <$M1B-Key-j> {do_revert_selection;break}
+bind $ui_diff <$M1B-Key-J> {do_revert_selection;break}
 bind $ui_diff <Key-Up>     {catch {%W yview scroll -1 units};break}
 bind $ui_diff <Key-Down>   {catch {%W yview scroll  1 units};break}
 bind $ui_diff <Key-Left>   {catch {%W xview scroll -1 units};break}
@@ -3742,6 +3763,8 @@ bind .   <$M1B-Key-s> do_signoff
 bind .   <$M1B-Key-S> do_signoff
 bind .   <$M1B-Key-t> do_add_selection
 bind .   <$M1B-Key-T> do_add_selection
+bind .   <$M1B-Key-u> do_unstage_selection
+bind .   <$M1B-Key-U> do_unstage_selection
 bind .   <$M1B-Key-j> do_revert_selection
 bind .   <$M1B-Key-J> do_revert_selection
 bind .   <$M1B-Key-i> do_add_all
@@ -3835,7 +3858,7 @@ if {[is_enabled transport]} {
 }
 
 if {[winfo exists $ui_comm]} {
-       set GITGUI_BCK_exists [load_message GITGUI_BCK]
+       set GITGUI_BCK_exists [load_message GITGUI_BCK utf-8]
 
        # -- If both our backup and message files exist use the
        #    newer of the two files to initialize the buffer.
@@ -3872,6 +3895,7 @@ if {[winfo exists $ui_comm]} {
                        } elseif {$m} {
                                catch {
                                        set fd [open [gitdir GITGUI_BCK] w]
+                                       fconfigure $fd -encoding utf-8
                                        puts -nonewline $fd $msg
                                        close $fd
                                        set GITGUI_BCK_exists 1
index 0d81432af53ba873d89421fa4767243818ab1f0a..864b687057c9759f2b06a9a83e3ca18c51113d92 100644 (file)
@@ -268,7 +268,7 @@ proc commit_commitmsg {curHEAD msg_p} {
            &&  [is_config_true gui.warndetachedcommit]} {
                set msg [mc "You are about to commit on a detached head.\
 This is a potentially dangerous thing to do because if you switch\
-to another branch you will loose your changes and it can be difficult\
+to another branch you will lose your changes and it can be difficult\
 to retrieve them later from the reflog. You should probably cancel this\
 commit and create a new branch to continue.\n\
 \n\
@@ -409,6 +409,7 @@ A rescan will be automatically started now.
        catch {file delete [gitdir MERGE_MSG]}
        catch {file delete [gitdir SQUASH_MSG]}
        catch {file delete [gitdir GITGUI_MSG]}
+       catch {file delete [gitdir CHERRY_PICK_HEAD]}
 
        # -- Let rerere do its thing.
        #
index 95cb44991fc5b018805d6091c4f98ce7ae0ccf52..02111a1742f92eff7efc6b8e54323919029867bc 100644 (file)
@@ -77,6 +77,7 @@ method start {msg uds} {
 
 method update {have total} {
        set pdone 0
+       set cdone 0
        if {$total > 0} {
                set pdone [expr {100 * $have / $total}]
                set cdone [expr {[winfo width $w_c] * $have / $total}]
index ddbe6334a258dae46b6c333d53590f3b920a9cab..738bdd03ed8a3940ae9bec362ddcfd16a3c48e9c 100644 (file)
@@ -12,7 +12,9 @@ if {[file tail [lindex $argv 0]] eq {gitk}} {
 } else {
        set argv0 [file join $gitexecdir [file tail [lindex $argv 0]]]
        set AppMain_source [file join $gitguilib git-gui.tcl]
-       if {[pwd] eq {/}} {
+       if {[info exists env(PWD)]} {
+               cd $env(PWD)
+       } elseif {[pwd] eq {/}} {
                cd $env(HOME)
        }
 }
index 44c5ddc8b67cbdb5dbec19e779394745d8f2e6ad..baebff2ffff7f84d5765c809cd44bc8bf93e766e 100644 (file)
@@ -72,7 +72,7 @@ msgstr ""
 
 #: git-gui.sh:1154
 msgid "Cannot use bare repository:"
-msgstr "Leeres Projektarchiv kann nicht benutzt werden:"
+msgstr "Bloßes Projektarchiv kann nicht benutzt werden:"
 
 #: git-gui.sh:1162
 msgid "No working directory"
@@ -88,7 +88,7 @@ msgstr "Nach geänderten Dateien suchen..."
 
 #: git-gui.sh:1454
 msgid "Calling prepare-commit-msg hook..."
-msgstr "Aufrufen der Eintragen-Vorbereiten-Kontrolle..."
+msgstr "Aufrufen der Eintragen-Vorbereiten-Kontrolle (»prepare-commit hook«)..."
 
 #: git-gui.sh:1471
 msgid "Commit declined by prepare-commit-msg hook."
@@ -188,7 +188,7 @@ msgstr "Zusammenführen"
 
 #: git-gui.sh:2465 lib/choose_rev.tcl:557
 msgid "Remote"
-msgstr "Andere Archive"
+msgstr "Externe Archive"
 
 #: git-gui.sh:2468
 msgid "Tools"
@@ -478,7 +478,7 @@ msgstr "Zusammenführungswerkzeug"
 
 #: git-gui.sh:3328
 msgid "Use Remote Version"
-msgstr "Entfernte Version benutzen"
+msgstr "Externe Version benutzen"
 
 #: git-gui.sh:3332
 msgid "Use Local Version"
@@ -771,7 +771,7 @@ msgstr "Bitte wählen Sie einen Übernahmezweig."
 #: lib/branch_create.tcl:140
 #, tcl-format
 msgid "Tracking branch %s is not a branch in the remote repository."
-msgstr "Übernahmezweig »%s« ist kein Zweig im anderen Projektarchiv."
+msgstr "Übernahmezweig »%s« ist kein Zweig im externen Projektarchiv."
 
 #: lib/branch_create.tcl:153 lib/branch_rename.tcl:86
 msgid "Please supply a branch name."
@@ -1446,7 +1446,7 @@ msgstr ""
 
 #: lib/commit.tcl:234
 msgid "Calling pre-commit hook..."
-msgstr "Aufrufen der Vor-Eintragen-Kontrolle..."
+msgstr "Aufrufen der Vor-Eintragen-Kontrolle (»pre-commit hook«)..."
 
 #: lib/commit.tcl:249
 msgid "Commit declined by pre-commit hook."
@@ -1454,7 +1454,7 @@ msgstr "Eintragen abgelehnt durch Vor-Eintragen-Kontrolle (»pre-commit hook«).
 
 #: lib/commit.tcl:272
 msgid "Calling commit-msg hook..."
-msgstr "Aufrufen der Versionsbeschreibungs-Kontrolle..."
+msgstr "Aufrufen der Versionsbeschreibungs-Kontrolle (»commit-message hook«)..."
 
 #: lib/commit.tcl:287
 msgid "Commit declined by commit-msg hook."
@@ -2134,11 +2134,11 @@ msgstr "Optionen konnten nicht gespeichert werden:"
 
 #: lib/remote_add.tcl:19
 msgid "Add Remote"
-msgstr "Anderes Archiv hinzufügen"
+msgstr "Externes Archiv hinzufügen"
 
 #: lib/remote_add.tcl:24
 msgid "Add New Remote"
-msgstr "Neues anderes Archiv hinzufügen"
+msgstr "Neues externes Archiv hinzufügen"
 
 #: lib/remote_add.tcl:28 lib/tools_dlg.tcl:36
 msgid "Add"
@@ -2146,7 +2146,7 @@ msgstr "Hinzufügen"
 
 #: lib/remote_add.tcl:37
 msgid "Remote Details"
-msgstr "Einzelheiten des anderen Archivs"
+msgstr "Einzelheiten des externen Archivs"
 
 #: lib/remote_add.tcl:50
 msgid "Location:"
@@ -2162,7 +2162,7 @@ msgstr "Gleich anfordern"
 
 #: lib/remote_add.tcl:71
 msgid "Initialize Remote Repository and Push"
-msgstr "Anderes Archiv initialisieren und dahin versenden"
+msgstr "Externes Archiv initialisieren und dahin versenden"
 
 #: lib/remote_add.tcl:77
 msgid "Do Nothing Else Now"
@@ -2170,17 +2170,17 @@ msgstr "Nichts tun"
 
 #: lib/remote_add.tcl:101
 msgid "Please supply a remote name."
-msgstr "Bitte geben Sie einen Namen des anderen Archivs an."
+msgstr "Bitte geben Sie einen Namen des externen Archivs an."
 
 #: lib/remote_add.tcl:114
 #, tcl-format
 msgid "'%s' is not an acceptable remote name."
-msgstr "»%s« ist kein zulässiger Name eines anderen Archivs."
+msgstr "»%s« ist kein zulässiger Name eines externen Archivs."
 
 #: lib/remote_add.tcl:125
 #, tcl-format
 msgid "Failed to add remote '%s' of location '%s'."
-msgstr "Fehler beim Hinzufügen des anderen Archivs »%s« aus Herkunftsort »%s«."
+msgstr "Fehler beim Hinzufügen des externen Archivs »%s« aus Herkunftsort »%s«."
 
 #: lib/remote_add.tcl:133 lib/transport.tcl:6
 #, tcl-format
@@ -2195,7 +2195,7 @@ msgstr "»%s« anfordern"
 #: lib/remote_add.tcl:157
 #, tcl-format
 msgid "Do not know how to initialize repository at location '%s'."
-msgstr "Initialisieren eines anderen Archivs an Adresse »%s« ist nicht möglich."
+msgstr "Initialisieren eines externen Archivs an Adresse »%s« ist nicht möglich."
 
 #: lib/remote_add.tcl:163 lib/transport.tcl:25 lib/transport.tcl:63
 #: lib/transport.tcl:81
@@ -2210,7 +2210,7 @@ msgstr "Einrichten von »%s« an »%s«"
 
 #: lib/remote_branch_delete.tcl:29 lib/remote_branch_delete.tcl:34
 msgid "Delete Branch Remotely"
-msgstr "Zweig in anderem Archiv löschen"
+msgstr "Zweig in externem Archiv löschen"
 
 #: lib/remote_branch_delete.tcl:47
 msgid "From Repository"
@@ -2218,7 +2218,7 @@ msgstr "In Projektarchiv"
 
 #: lib/remote_branch_delete.tcl:50 lib/transport.tcl:134
 msgid "Remote:"
-msgstr "Anderes Archiv:"
+msgstr "Externes Archiv:"
 
 #: lib/remote_branch_delete.tcl:66 lib/transport.tcl:149
 msgid "Arbitrary Location:"
@@ -2281,7 +2281,7 @@ msgstr "»%s« laden..."
 
 #: lib/remote.tcl:163
 msgid "Remove Remote"
-msgstr "Anderes Archiv entfernen"
+msgstr "Externes Archiv entfernen"
 
 #: lib/remote.tcl:168
 msgid "Prune from"
@@ -2397,7 +2397,7 @@ msgid "Generation failed."
 msgstr "Schlüsselerzeugung fehlgeschlagen."
 
 #: lib/sshkey.tcl:118
-msgid "Generation succeded, but no keys found."
+msgid "Generation succeeded, but no keys found."
 msgstr "Schlüsselerzeugung erfolgreich, aber keine Schlüssel gefunden."
 
 #: lib/sshkey.tcl:121
index 81706965f377787f8048bc5705ab8da10af55586..40441dbb0da4fe5a62776054aa2d5d2d30d9af8f 100644 (file)
@@ -2399,7 +2399,7 @@ msgid "Generation failed."
 msgstr "La génération a échoué."
 
 #: lib/sshkey.tcl:118
-msgid "Generation succeded, but no keys found."
+msgid "Generation succeeded, but no keys found."
 msgstr "La génération a réussi, mais aucune clé n'a été trouvée."
 
 #: lib/sshkey.tcl:121
index 1ae2aaa0b3bb46302a9a4876dbbb1be00d2c2ddf..0c94f9c2c6df3a5d7088d5669138aaebdad0974c 100644 (file)
@@ -2203,7 +2203,7 @@ msgid "Generation failed."
 msgstr ""
 
 #: lib/sshkey.tcl:118
-msgid "Generation succeded, but no keys found."
+msgid "Generation succeeded, but no keys found."
 msgstr ""
 
 #: lib/sshkey.tcl:121
index 0f87bc1cbeedca8d9040777a5484500d1071c2e6..d106dadac89b01ba27170e95aa2d1ef02fa8b940 100644 (file)
@@ -2354,7 +2354,7 @@ msgid "Generation failed."
 msgstr "A generálás nem sikerült."
 
 #: lib/sshkey.tcl:118
-msgid "Generation succeded, but no keys found."
+msgid "Generation succeeded, but no keys found."
 msgstr "A generálás sikeres, de egy kulcs se található."
 
 #: lib/sshkey.tcl:121
index aa15a204d85c5fdffbb74a5882c759c36f547184..1bd8b8e04f716d46627ded00997a0f9ca85f7b60 100644 (file)
@@ -2397,7 +2397,7 @@ msgid "Generation failed."
 msgstr "Errore durante la creazione della chiave."
 
 #: lib/sshkey.tcl:118
-msgid "Generation succeded, but no keys found."
+msgid "Generation succeeded, but no keys found."
 msgstr "La chiave è stata creata con successo, ma non è stata trovata."
 
 #: lib/sshkey.tcl:121
index 15017985e5f3a731cd9b16f1d71442b22e67f771..9aff249d5f533638170e7e14e03930a560978f46 100644 (file)
@@ -2362,7 +2362,7 @@ msgid "Generation failed."
 msgstr "生成に失敗しました。"
 
 #: lib/sshkey.tcl:118
-msgid "Generation succeded, but no keys found."
+msgid "Generation succeeded, but no keys found."
 msgstr "生成には成功しましたが、鍵が見つかりません。"
 
 #: lib/sshkey.tcl:121
index 6de93c28c2e2b7cb0413521c987161c4a4fcb59d..d66aa5026391fbba38ff8b02c50c363965927131 100644 (file)
@@ -2286,7 +2286,7 @@ msgid "Generation failed."
 msgstr "Generering feilet."
 
 #: lib/sshkey.tcl:118
-msgid "Generation succeded, but no keys found."
+msgid "Generation succeeded, but no keys found."
 msgstr "Generering vellykket, men ingen nøkler er funnet."
 
 #: lib/sshkey.tcl:121
index b175b9791ecb83c761d360e38ff2526717ad3deb..bad116c78038936b59e88b714de8a37ce02739c9 100644 (file)
@@ -2375,7 +2375,7 @@ msgid "Generation failed."
 msgstr "A geração da chave falhou."
 
 #: lib/sshkey.tcl:118
-msgid "Generation succeded, but no keys found."
+msgid "Generation succeeded, but no keys found."
 msgstr "A geração da chave foi bem-sucedida, mas nenhuma chave foi encontrada."
 
 #: lib/sshkey.tcl:121
index 30f4b77dac08d9c69ea3d0009ec97d30b9349be8..ca4343b40cd9a166fc9c3526d68b6182057e71a3 100644 (file)
@@ -2370,7 +2370,7 @@ msgid "Generation failed."
 msgstr "Ключ не создан."
 
 #: lib/sshkey.tcl:118
-msgid "Generation succeded, but no keys found."
+msgid "Generation succeeded, but no keys found."
 msgstr "Создание ключа завершилось, но результат не был найден"
 
 #: lib/sshkey.tcl:121
index 24cc4e3675e05e9bd3bf7ea17335a67a3aa5166b..fcb063ffa6436271968f7991cccad1a2303fd8c0 100644 (file)
@@ -2382,7 +2382,7 @@ msgid "Generation failed."
 msgstr "Misslyckades med att skapa."
 
 #: lib/sshkey.tcl:120
-msgid "Generation succeded, but no keys found."
+msgid "Generation succeeded, but no keys found."
 msgstr "Lyckades skapa nyckeln, men hittar inte någon nyckel."
 
 #: lib/sshkey.tcl:123
index 2a10047eb710011213024bd0acc57eec87a6f965..266e682f6c518ab72dc710d52ed4f1dbe22881b5 100755 (executable)
@@ -200,6 +200,7 @@ test true = "$rebase" && {
                require_clean_work_tree "pull with rebase" "Please commit or stash them."
        fi
        oldremoteref= &&
+       test -n "$curr_branch" &&
        . git-parse-remote &&
        remoteref="$(get_remote_merge_branch "$@" 2>/dev/null)" &&
        oldremoteref="$(git rev-parse -q --verify "$remoteref")" &&
index aea66a0d47a9ad64fe805351c631fe5fddbf6182..5a7c29db9324df48c9da68b08a946e5a357f0a78 100755 (executable)
@@ -56,6 +56,7 @@ sub usage {
     --in-reply-to           <str>  * Email "In-Reply-To:"
     --annotate                     * Review each patch that will be sent in an editor.
     --compose                      * Open an editor for introduction.
+    --compose-encoding      <str>  * Encoding to assume for introduction.
     --8bit-encoding         <str>  * Encoding to assume 8bit mails if undeclared
 
   Sending:
@@ -198,6 +199,7 @@ sub do_edit {
 my ($validate, $confirm);
 my (@suppress_cc);
 my ($auto_8bit_encoding);
+my ($compose_encoding);
 
 my ($debug_net_smtp) = 0;              # Net::SMTP, see send_message()
 
@@ -231,6 +233,7 @@ sub do_edit {
     "confirm"   => \$confirm,
     "from" => \$sender,
     "assume8bitencoding" => \$auto_8bit_encoding,
+    "composeencoding" => \$compose_encoding,
 );
 
 my %config_path_settings = (
@@ -315,6 +318,7 @@ sub signal_handler {
                    "validate!" => \$validate,
                    "format-patch!" => \$format_patch,
                    "8bit-encoding=s" => \$auto_8bit_encoding,
+                   "compose-encoding=s" => \$compose_encoding,
                    "force" => \$force,
         );
 
@@ -632,6 +636,9 @@ sub get_patch_subject {
        my $need_8bit_cte = file_has_nonascii($compose_filename);
        my $in_body = 0;
        my $summary_empty = 1;
+       if (!defined $compose_encoding) {
+               $compose_encoding = "UTF-8";
+       }
        while(<$c>) {
                next if m/^GIT:/;
                if ($in_body) {
@@ -641,7 +648,7 @@ sub get_patch_subject {
                        if ($need_8bit_cte) {
                                print $c2 "MIME-Version: 1.0\n",
                                         "Content-Type: text/plain; ",
-                                          "charset=UTF-8\n",
+                                          "charset=$compose_encoding\n",
                                         "Content-Transfer-Encoding: 8bit\n";
                        }
                } elsif (/^MIME-Version:/i) {
@@ -650,9 +657,7 @@ sub get_patch_subject {
                        $initial_subject = $1;
                        my $subject = $initial_subject;
                        $_ = "Subject: " .
-                               ($subject =~ /[^[:ascii:]]/ ?
-                                quote_rfc2047($subject) :
-                                $subject) .
+                               quote_subject($subject, $compose_encoding) .
                                "\n";
                } elsif (/^In-Reply-To:\s*(.+)\s*$/i) {
                        $initial_reply_to = $1;
@@ -900,6 +905,22 @@ sub is_rfc2047_quoted {
        $s =~ m/^(?:"[[:ascii:]]*"|=\?$token\?$token\?$encoded_text\?=)$/o;
 }
 
+sub subject_needs_rfc2047_quoting {
+       my $s = shift;
+
+       return ($s =~ /[^[:ascii:]]/) || ($s =~ /=\?/);
+}
+
+sub quote_subject {
+       local $subject = shift;
+       my $encoding = shift || 'UTF-8';
+
+       if (subject_needs_rfc2047_quoting($subject)) {
+               return quote_rfc2047($subject, $encoding);
+       }
+       return $subject;
+}
+
 # use the simplest quoting being able to handle the recipient
 sub sanitize_address {
        my ($recipient) = @_;
@@ -1321,7 +1342,7 @@ sub send_message {
        }
 
        if ($broken_encoding{$t} && !is_rfc2047_quoted($subject)) {
-               $subject = quote_rfc2047($subject, $auto_8bit_encoding);
+               $subject = quote_subject($subject, $auto_8bit_encoding);
        }
 
        if (defined $author and $author ne $sender) {
index ee0e0bc045bb7d92045a3afb0a042748834e6163..22f0aed6db366c3d4a291b3ae646c45002ff86c1 100644 (file)
@@ -191,28 +191,52 @@ require_clean_work_tree () {
        fi
 }
 
+# Generate a sed script to parse identities from a commit.
+#
+# Reads the commit from stdin, which should be in raw format (e.g., from
+# cat-file or "--pretty=raw").
+#
+# The first argument specifies the ident line to parse (e.g., "author"), and
+# the second specifies the environment variable to put it in (e.g., "AUTHOR"
+# for "GIT_AUTHOR_*"). Multiple pairs can be given to parse author and
+# committer.
+pick_ident_script () {
+       while test $# -gt 0
+       do
+               lid=$1; shift
+               uid=$1; shift
+               printf '%s' "
+               /^$lid /{
+                       s/'/'\\\\''/g
+                       h
+                       s/^$lid "'\([^<]*\) <[^>]*> .*$/\1/'"
+                       s/.*/GIT_${uid}_NAME='&'/p
+
+                       g
+                       s/^$lid "'[^<]* <\([^>]*\)> .*$/\1/'"
+                       s/.*/GIT_${uid}_EMAIL='&'/p
+
+                       g
+                       s/^$lid "'[^<]* <[^>]*> \(.*\)$/@\1/'"
+                       s/.*/GIT_${uid}_DATE='&'/p
+               }
+               "
+       done
+       echo '/^$/q'
+}
+
+# Create a pick-script as above and feed it to sed. Stdout is suitable for
+# feeding to eval.
+parse_ident_from_commit () {
+       LANG=C LC_ALL=C sed -ne "$(pick_ident_script "$@")"
+}
+
+# Parse the author from a commit given as an argument. Stdout is suitable for
+# feeding to eval to set the usual GIT_* ident variables.
 get_author_ident_from_commit () {
-       pick_author_script='
-       /^author /{
-               s/'\''/'\''\\'\'\''/g
-               h
-               s/^author \([^<]*\) <[^>]*> .*$/\1/
-               s/.*/GIT_AUTHOR_NAME='\''&'\''/p
-
-               g
-               s/^author [^<]* <\([^>]*\)> .*$/\1/
-               s/.*/GIT_AUTHOR_EMAIL='\''&'\''/p
-
-               g
-               s/^author [^<]* <[^>]*> \(.*\)$/@\1/
-               s/.*/GIT_AUTHOR_DATE='\''&'\''/p
-
-               q
-       }
-       '
        encoding=$(git config i18n.commitencoding || echo UTF-8)
        git show -s --pretty=raw --encoding="$encoding" "$1" -- |
-       LANG=C LC_ALL=C sed -ne "$pick_author_script"
+       parse_ident_from_commit author AUTHOR
 }
 
 # Clear repo-local GIT_* environment variables. Useful when switching to
index ab6b1107b6090494f192f361471ed5748ffa7dc1..3d1617fa9eb490463f9a4a4218082de168e1491a 100755 (executable)
@@ -5,7 +5,7 @@
 # Copyright (c) 2007 Lars Hjemli
 
 dashless=$(basename "$0" | sed -e 's/-/ /')
-USAGE="[--quiet] add [-b branch] [-f|--force] [--reference <repository>] [--] <repository> [<path>]
+USAGE="[--quiet] add [-b branch] [-f|--force] [--name <name>] [--reference <repository>] [--] <repository> [<path>]
    or: $dashless [--quiet] status [--cached] [--recursive] [--] [<path>...]
    or: $dashless [--quiet] init [--] [<path>...]
    or: $dashless [--quiet] update [--init] [-N|--no-fetch] [-f|--force] [--rebase] [--reference <repository>] [--merge] [--recursive] [--] [<path>...]
@@ -29,6 +29,7 @@ files=
 nofetch=
 update=
 prefix=
+custom_name=
 
 # The function takes at most 2 arguments. The first argument is the
 # URL that navigates to the submodule origin repo. When relative, this URL
@@ -179,8 +180,9 @@ module_name()
 module_clone()
 {
        sm_path=$1
-       url=$2
-       reference="$3"
+       name=$2
+       url=$3
+       reference="$4"
        quiet=
        if test -n "$GIT_QUIET"
        then
@@ -189,8 +191,6 @@ module_clone()
 
        gitdir=
        gitdir_base=
-       name=$(module_name "$sm_path" 2>/dev/null)
-       test -n "$name" || name="$sm_path"
        base_name=$(dirname "$name")
 
        gitdir=$(git rev-parse --git-dir)
@@ -270,6 +270,10 @@ cmd_add()
                        ;;
                --reference=*)
                        reference="$1"
+                       ;;
+               --name)
+                       case "$2" in '') usage ;; esac
+                       custom_name=$2
                        shift
                        ;;
                --)
@@ -336,6 +340,13 @@ Use -f if you really want to add it." >&2
                exit 1
        fi
 
+       if test -n "$custom_name"
+       then
+               sm_name="$custom_name"
+       else
+               sm_name="$sm_path"
+       fi
+
        # perhaps the path exists and is already a git repo, else clone it
        if test -e "$sm_path"
        then
@@ -347,8 +358,21 @@ Use -f if you really want to add it." >&2
                fi
 
        else
-
-               module_clone "$sm_path" "$realrepo" "$reference" || exit
+               if test -d ".git/modules/$sm_name"
+               then
+                       if test -z "$force"
+                       then
+                               echo >&2 "$(eval_gettext "A git directory for '\$sm_name' is found locally with remote(s):")"
+                               GIT_DIR=".git/modules/$sm_name" GIT_WORK_TREE=. git remote -v | grep '(fetch)' | sed -e s,^,"  ", -e s,' (fetch)',, >&2
+                               echo >&2 "$(eval_gettext "If you want to reuse this local git directory instead of cloning again from")"
+                               echo >&2 "  $realrepo"
+                               echo >&2 "$(eval_gettext "use the '--force' option. If the local git directory is not the correct repo")"
+                               die "$(eval_gettext "or you are unsure what this means choose another name with the '--name' option.")"
+                       else
+                               echo "$(eval_gettext "Reactivating local git directory for submodule '\$sm_name'.")"
+                       fi
+               fi
+               module_clone "$sm_path" "$sm_name" "$realrepo" "$reference" || exit
                (
                        clear_local_git_env
                        cd "$sm_path" &&
@@ -359,13 +383,13 @@ Use -f if you really want to add it." >&2
                        esac
                ) || die "$(eval_gettext "Unable to checkout submodule '\$sm_path'")"
        fi
-       git config submodule."$sm_path".url "$realrepo"
+       git config submodule."$sm_name".url "$realrepo"
 
        git add $force "$sm_path" ||
        die "$(eval_gettext "Failed to add submodule '\$sm_path'")"
 
-       git config -f .gitmodules submodule."$sm_path".path "$sm_path" &&
-       git config -f .gitmodules submodule."$sm_path".url "$repo" &&
+       git config -f .gitmodules submodule."$sm_name".path "$sm_path" &&
+       git config -f .gitmodules submodule."$sm_name".url "$repo" &&
        git add --force .gitmodules ||
        die "$(eval_gettext "Failed to register submodule '\$sm_path'")"
 }
@@ -594,7 +618,7 @@ Maybe you want to use 'update --init'?")"
 
                if ! test -d "$sm_path"/.git -o -f "$sm_path"/.git
                then
-                       module_clone "$sm_path" "$url" "$reference"|| exit
+                       module_clone "$sm_path" "$name" "$url" "$reference" || exit
                        cloned_modules="$cloned_modules;$name"
                        subsha1=
                else
diff --git a/grep.c b/grep.c
index edc7776677ed201dbe117c207a680e1f832737e3..4bd1b8b1dd67e4f5c2223536b435198ce67463ba 100644 (file)
--- a/grep.c
+++ b/grep.c
@@ -6,6 +6,183 @@
 static int grep_source_load(struct grep_source *gs);
 static int grep_source_is_binary(struct grep_source *gs);
 
+static struct grep_opt grep_defaults;
+
+/*
+ * Initialize the grep_defaults template with hardcoded defaults.
+ * We could let the compiler do this, but without C99 initializers
+ * the code gets unwieldy and unreadable, so...
+ */
+void init_grep_defaults(void)
+{
+       struct grep_opt *opt = &grep_defaults;
+       static int run_once;
+
+       if (run_once)
+               return;
+       run_once++;
+
+       memset(opt, 0, sizeof(*opt));
+       opt->relative = 1;
+       opt->pathname = 1;
+       opt->regflags = REG_NEWLINE;
+       opt->max_depth = -1;
+       opt->pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED;
+       opt->extended_regexp_option = 0;
+       strcpy(opt->color_context, "");
+       strcpy(opt->color_filename, "");
+       strcpy(opt->color_function, "");
+       strcpy(opt->color_lineno, "");
+       strcpy(opt->color_match, GIT_COLOR_BOLD_RED);
+       strcpy(opt->color_selected, "");
+       strcpy(opt->color_sep, GIT_COLOR_CYAN);
+       opt->color = -1;
+}
+
+static int parse_pattern_type_arg(const char *opt, const char *arg)
+{
+       if (!strcmp(arg, "default"))
+               return GREP_PATTERN_TYPE_UNSPECIFIED;
+       else if (!strcmp(arg, "basic"))
+               return GREP_PATTERN_TYPE_BRE;
+       else if (!strcmp(arg, "extended"))
+               return GREP_PATTERN_TYPE_ERE;
+       else if (!strcmp(arg, "fixed"))
+               return GREP_PATTERN_TYPE_FIXED;
+       else if (!strcmp(arg, "perl"))
+               return GREP_PATTERN_TYPE_PCRE;
+       die("bad %s argument: %s", opt, arg);
+}
+
+/*
+ * Read the configuration file once and store it in
+ * the grep_defaults template.
+ */
+int grep_config(const char *var, const char *value, void *cb)
+{
+       struct grep_opt *opt = &grep_defaults;
+       char *color = NULL;
+
+       if (userdiff_config(var, value) < 0)
+               return -1;
+
+       if (!strcmp(var, "grep.extendedregexp")) {
+               if (git_config_bool(var, value))
+                       opt->extended_regexp_option = 1;
+               else
+                       opt->extended_regexp_option = 0;
+               return 0;
+       }
+
+       if (!strcmp(var, "grep.patterntype")) {
+               opt->pattern_type_option = parse_pattern_type_arg(var, value);
+               return 0;
+       }
+
+       if (!strcmp(var, "grep.linenumber")) {
+               opt->linenum = git_config_bool(var, value);
+               return 0;
+       }
+
+       if (!strcmp(var, "color.grep"))
+               opt->color = git_config_colorbool(var, value);
+       else if (!strcmp(var, "color.grep.context"))
+               color = opt->color_context;
+       else if (!strcmp(var, "color.grep.filename"))
+               color = opt->color_filename;
+       else if (!strcmp(var, "color.grep.function"))
+               color = opt->color_function;
+       else if (!strcmp(var, "color.grep.linenumber"))
+               color = opt->color_lineno;
+       else if (!strcmp(var, "color.grep.match"))
+               color = opt->color_match;
+       else if (!strcmp(var, "color.grep.selected"))
+               color = opt->color_selected;
+       else if (!strcmp(var, "color.grep.separator"))
+               color = opt->color_sep;
+
+       if (color) {
+               if (!value)
+                       return config_error_nonbool(var);
+               color_parse(value, var, color);
+       }
+       return 0;
+}
+
+/*
+ * Initialize one instance of grep_opt and copy the
+ * default values from the template we read the configuration
+ * information in an earlier call to git_config(grep_config).
+ */
+void grep_init(struct grep_opt *opt, const char *prefix)
+{
+       struct grep_opt *def = &grep_defaults;
+
+       memset(opt, 0, sizeof(*opt));
+       opt->prefix = prefix;
+       opt->prefix_length = (prefix && *prefix) ? strlen(prefix) : 0;
+       opt->pattern_tail = &opt->pattern_list;
+       opt->header_tail = &opt->header_list;
+
+       opt->color = def->color;
+       opt->extended_regexp_option = def->extended_regexp_option;
+       opt->pattern_type_option = def->pattern_type_option;
+       opt->linenum = def->linenum;
+       opt->max_depth = def->max_depth;
+       opt->pathname = def->pathname;
+       opt->regflags = def->regflags;
+       opt->relative = def->relative;
+
+       strcpy(opt->color_context, def->color_context);
+       strcpy(opt->color_filename, def->color_filename);
+       strcpy(opt->color_function, def->color_function);
+       strcpy(opt->color_lineno, def->color_lineno);
+       strcpy(opt->color_match, def->color_match);
+       strcpy(opt->color_selected, def->color_selected);
+       strcpy(opt->color_sep, def->color_sep);
+}
+
+void grep_commit_pattern_type(enum grep_pattern_type pattern_type, struct grep_opt *opt)
+{
+       if (pattern_type != GREP_PATTERN_TYPE_UNSPECIFIED)
+               grep_set_pattern_type_option(pattern_type, opt);
+       else if (opt->pattern_type_option != GREP_PATTERN_TYPE_UNSPECIFIED)
+               grep_set_pattern_type_option(opt->pattern_type_option, opt);
+       else if (opt->extended_regexp_option)
+               grep_set_pattern_type_option(GREP_PATTERN_TYPE_ERE, opt);
+}
+
+void grep_set_pattern_type_option(enum grep_pattern_type pattern_type, struct grep_opt *opt)
+{
+       switch (pattern_type) {
+       case GREP_PATTERN_TYPE_UNSPECIFIED:
+               /* fall through */
+
+       case GREP_PATTERN_TYPE_BRE:
+               opt->fixed = 0;
+               opt->pcre = 0;
+               opt->regflags &= ~REG_EXTENDED;
+               break;
+
+       case GREP_PATTERN_TYPE_ERE:
+               opt->fixed = 0;
+               opt->pcre = 0;
+               opt->regflags |= REG_EXTENDED;
+               break;
+
+       case GREP_PATTERN_TYPE_FIXED:
+               opt->fixed = 1;
+               opt->pcre = 0;
+               opt->regflags &= ~REG_EXTENDED;
+               break;
+
+       case GREP_PATTERN_TYPE_PCRE:
+               opt->fixed = 0;
+               opt->pcre = 1;
+               opt->regflags &= ~REG_EXTENDED;
+               break;
+       }
+}
 
 static struct grep_pat *create_grep_pat(const char *pat, size_t patlen,
                                        const char *origin, int no,
@@ -1373,7 +1550,7 @@ int grep_buffer(struct grep_opt *opt, char *buf, unsigned long size)
        struct grep_source gs;
        int r;
 
-       grep_source_init(&gs, GREP_SOURCE_BUF, NULL, NULL);
+       grep_source_init(&gs, GREP_SOURCE_BUF, NULL, NULL, NULL);
        gs.buf = buf;
        gs.size = size;
 
@@ -1384,10 +1561,12 @@ int grep_buffer(struct grep_opt *opt, char *buf, unsigned long size)
 }
 
 void grep_source_init(struct grep_source *gs, enum grep_source_type type,
-                     const char *name, const void *identifier)
+                     const char *name, const char *path,
+                     const void *identifier)
 {
        gs->type = type;
        gs->name = name ? xstrdup(name) : NULL;
+       gs->path = path ? xstrdup(path) : NULL;
        gs->buf = NULL;
        gs->size = 0;
        gs->driver = NULL;
@@ -1409,6 +1588,8 @@ void grep_source_clear(struct grep_source *gs)
 {
        free(gs->name);
        gs->name = NULL;
+       free(gs->path);
+       gs->path = NULL;
        free(gs->identifier);
        gs->identifier = NULL;
        grep_source_clear_data(gs);
@@ -1501,7 +1682,8 @@ void grep_source_load_driver(struct grep_source *gs)
                return;
 
        grep_attr_lock();
-       gs->driver = userdiff_find_by_path(gs->name);
+       if (gs->path)
+               gs->driver = userdiff_find_by_path(gs->path);
        if (!gs->driver)
                gs->driver = userdiff_find_by_name("default");
        grep_attr_unlock();
diff --git a/grep.h b/grep.h
index c256ac6e15b22e153623ae3395fb6ffc732b20b9..8fc854f400802c3329fc3c028942de55b820ac90 100644 (file)
--- a/grep.h
+++ b/grep.h
@@ -138,6 +138,12 @@ struct grep_opt {
        void *output_priv;
 };
 
+extern void init_grep_defaults(void);
+extern int grep_config(const char *var, const char *value, void *);
+extern void grep_init(struct grep_opt *, const char *prefix);
+void grep_set_pattern_type_option(enum grep_pattern_type, struct grep_opt *opt);
+void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt);
+
 extern void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t);
 extern void append_grep_pattern(struct grep_opt *opt, const char *pat, const char *origin, int no, enum grep_pat_token t);
 extern void append_header_grep_pattern(struct grep_opt *, enum grep_header_field, const char *);
@@ -158,11 +164,13 @@ struct grep_source {
        char *buf;
        unsigned long size;
 
+       char *path; /* for attribute lookups */
        struct userdiff_driver *driver;
 };
 
 void grep_source_init(struct grep_source *gs, enum grep_source_type type,
-                     const char *name, const void *identifier);
+                     const char *name, const char *path,
+                     const void *identifier);
 void grep_source_clear_data(struct grep_source *gs);
 void grep_source_clear(struct grep_source *gs);
 void grep_source_load_driver(struct grep_source *gs);
diff --git a/http.c b/http.c
index df9bb710863e30ba98d7661f84e872b30ed4449e..98c0b2b362c531234ac9d02d922d23958f6d90cf 100644 (file)
--- a/http.c
+++ b/http.c
@@ -745,8 +745,7 @@ char *get_remote_object_url(const char *url, const char *hex,
        return strbuf_detach(&buf, NULL);
 }
 
-int handle_curl_result(struct active_request_slot *slot,
-                      struct slot_results *results)
+int handle_curl_result(struct slot_results *results)
 {
        if (results->curl_result == CURLE_OK) {
                credential_approve(&http_auth);
@@ -759,7 +758,6 @@ int handle_curl_result(struct active_request_slot *slot,
                        return HTTP_NOAUTH;
                } else {
                        credential_fill(&http_auth);
-                       init_curl_http_auth(slot->curl);
                        return HTTP_REAUTH;
                }
        } else {
@@ -821,7 +819,7 @@ static int http_request(const char *url, void *result, int target, int options)
 
        if (start_active_slot(slot)) {
                run_active_slot(slot);
-               ret = handle_curl_result(slot, &results);
+               ret = handle_curl_result(&results);
        } else {
                error("Unable to start HTTP request for %s", url);
                ret = HTTP_START_FAILED;
diff --git a/http.h b/http.h
index 0bd1e849e1406c8c8a822c6ecc6de84d4b5e1798..0a80d303e369b4adf77ca131c732ba39a990610d 100644 (file)
--- a/http.h
+++ b/http.h
@@ -78,8 +78,7 @@ extern int start_active_slot(struct active_request_slot *slot);
 extern void run_active_slot(struct active_request_slot *slot);
 extern void finish_active_slot(struct active_request_slot *slot);
 extern void finish_all_active_slots(void);
-extern int handle_curl_result(struct active_request_slot *slot,
-                             struct slot_results *results);
+extern int handle_curl_result(struct slot_results *results);
 
 #ifdef USE_CURL_MULTI
 extern void fill_active_slots(void);
index 47aa41924507f7603aab5e35abb51b3956a33dad..ea4b471edeb5ca9b29a8138f6f831a5e6a15a9e8 100644 (file)
--- a/mailmap.c
+++ b/mailmap.c
@@ -118,7 +118,7 @@ static char *parse_name_and_email(char *buffer, char **name,
        while (isspace(*nstart) && nstart < left)
                ++nstart;
        nend = left-1;
-       while (isspace(*nend) && nend > nstart)
+       while (nend > nstart && isspace(*nend))
                --nend;
 
        *name = (nstart < nend ? nstart : NULL);
index 1a45c1b0c5128335fc340e7d6409b4e772419a07..295361a8aa7d075bbb9fdb8173858e37f9a43211 100644 (file)
@@ -1,5 +1,30 @@
 diff_cmd () {
+       # p4merge does not like /dev/null
+       rm_local=
+       rm_remote=
+       if test "/dev/null" = "$LOCAL"
+       then
+               LOCAL="./p4merge-dev-null.LOCAL.$$"
+               >"$LOCAL"
+               rm_local=true
+       fi
+       if test "/dev/null" = "$REMOTE"
+       then
+               REMOTE="./p4merge-dev-null.REMOTE.$$"
+               >"$REMOTE"
+               rm_remote=true
+       fi
+
        "$merge_tool_path" "$LOCAL" "$REMOTE"
+
+       if test -n "$rm_local"
+       then
+               rm -f "$LOCAL"
+       fi
+       if test -n "$rm_remote"
+       then
+               rm -f "$REMOTE"
+       fi
 }
 
 merge_cmd () {
diff --git a/pager.c b/pager.c
index 4dcb08d9674c252cbe2c2725f92eca2a0350dc93..c0b4387d969476232a4e00a7acf9b06dc4ef6edc 100644 (file)
--- a/pager.c
+++ b/pager.c
  * something different on Windows.
  */
 
-#ifndef WIN32
-static void pager_preexec(void)
-{
-       /*
-        * Work around bug in "less" by not starting it until we
-        * have real input
-        */
-       fd_set in;
-
-       FD_ZERO(&in);
-       FD_SET(0, &in);
-       select(1, &in, NULL, &in, NULL);
-}
-#endif
-
 static const char *pager_argv[] = { NULL, NULL };
 static struct child_process pager_process;
 
@@ -93,9 +78,6 @@ void setup_pager(void)
                static const char *env[] = { "LESS=FRSX", NULL };
                pager_process.env = env;
        }
-#ifndef WIN32
-       pager_process.preexec_cb = pager_preexec;
-#endif
        if (start_command(&pager_process))
                return;
 
index 7ce7e581d9afdb111503767362fc1458c0adb8cc..9b3aa744bc781cb3963e7eefd91bda8a754a8a47 100644 (file)
--- a/po/sv.po
+++ b/po/sv.po
@@ -7,8 +7,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: git 1.7.12\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2012-09-15 10:21+0800\n"
-"PO-Revision-Date: 2012-10-02 08:15+0100\n"
+"POT-Creation-Date: 2012-10-16 08:38+0800\n"
+"PO-Revision-Date: 2012-10-16 08:36+0100\n"
 "Last-Translator: Peter Krefting <peter@softwolves.pp.se>\n"
 "Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n"
 "Language: sv\n"
@@ -73,12 +73,11 @@ msgstr "prefix"
 msgid "prepend prefix to each pathname in the archive"
 msgstr "lägg till prefix till varje sökväg i arkivet"
 
-# %s är ett verb ("Untracked"/"Ignored"); lägg till ett -e.
-#: archive.c:325 builtin/archive.c:91 builtin/blame.c:2332
-#: builtin/blame.c:2333 builtin/config.c:56 builtin/fast-export.c:642
-#: builtin/fast-export.c:644 builtin/grep.c:800 builtin/hash-object.c:77
-#: builtin/ls-files.c:494 builtin/ls-files.c:497 builtin/notes.c:537
-#: builtin/notes.c:694 builtin/read-tree.c:107 parse-options.h:149
+#: archive.c:325 builtin/archive.c:91 builtin/blame.c:2389
+#: builtin/blame.c:2390 builtin/config.c:56 builtin/fast-export.c:642
+#: builtin/fast-export.c:644 builtin/grep.c:801 builtin/hash-object.c:77
+#: builtin/ls-files.c:494 builtin/ls-files.c:497 builtin/notes.c:540
+#: builtin/notes.c:697 builtin/read-tree.c:107 parse-options.h:149
 msgid "file"
 msgstr "fil"
 
@@ -118,7 +117,7 @@ msgstr "arkiv"
 msgid "retrieve the archive from remote repository <repo>"
 msgstr "hämta arkivet från fjärrarkivet <arkiv>"
 
-#: archive.c:346 builtin/archive.c:95 builtin/notes.c:616
+#: archive.c:346 builtin/archive.c:95 builtin/notes.c:619
 msgid "command"
 msgstr "kommando"
 
@@ -136,7 +135,7 @@ msgstr "'%s' ser inte ut som en v2-bundle-fil"
 msgid "unrecognized header: %s%s (%d)"
 msgstr "okänt huvud: %s%s (%d)"
 
-#: bundle.c:89 builtin/commit.c:714
+#: bundle.c:89 builtin/commit.c:672
 #, c-format
 msgid "could not open '%s'"
 msgstr "kunde inte öppna \"%s\""
@@ -145,7 +144,7 @@ msgstr "kunde inte öppna \"%s\""
 msgid "Repository lacks these prerequisite commits:"
 msgstr "Arkivet saknar dessa nödvändiga incheckningar:"
 
-#: bundle.c:164 sequencer.c:557 sequencer.c:989 builtin/log.c:290
+#: bundle.c:164 sequencer.c:562 sequencer.c:994 builtin/log.c:290
 #: builtin/log.c:727 builtin/log.c:1313 builtin/log.c:1529 builtin/merge.c:347
 #: builtin/shortlog.c:181
 msgid "revision walk setup failed"
@@ -204,12 +203,12 @@ msgstr "kan inte skapa \"%s\""
 msgid "index-pack died"
 msgstr "index-pack dog"
 
-#: commit.c:48
+#: commit.c:50
 #, c-format
 msgid "could not parse %s"
 msgstr "kunde inte tolka %s"
 
-#: commit.c:50
+#: commit.c:52
 #, c-format
 msgid "%s %s is not a commit!"
 msgstr "%s %s är inte en incheckning!"
@@ -318,32 +317,7 @@ msgstr ""
 "Hittade fel i konfigurationsvariabeln \"diff.dirstat\":\n"
 "%s"
 
-#: diff.c:1401
-msgid " 0 files changed"
-msgstr " 0 filer ändrade"
-
-#: diff.c:1405
-#, c-format
-msgid " %d file changed"
-msgid_plural " %d files changed"
-msgstr[0] " %d fil ändrad"
-msgstr[1] " %d filer ändrade"
-
-#: diff.c:1422
-#, c-format
-msgid ", %d insertion(+)"
-msgid_plural ", %d insertions(+)"
-msgstr[0] ", %d tillägg(+)"
-msgstr[1] ", %d tillägg(+)"
-
-#: diff.c:1433
-#, c-format
-msgid ", %d deletion(-)"
-msgid_plural ", %d deletions(-)"
-msgstr[0] ", %d borttagning(-)"
-msgstr[1] ", %d borttagningar(-)"
-
-#: diff.c:3460
+#: diff.c:3458
 #, c-format
 msgid ""
 "Failed to parse --dirstat/-X option parameter:\n"
@@ -364,17 +338,17 @@ msgstr "gpg godtog inte data"
 msgid "gpg failed to sign the data"
 msgstr "gpg misslyckades signera data"
 
-#: grep.c:1320
+#: grep.c:1441
 #, c-format
 msgid "'%s': unable to read %s"
 msgstr "\"%s\" kunde inte läsa %s"
 
-#: grep.c:1337
+#: grep.c:1458
 #, c-format
 msgid "'%s': %s"
 msgstr "\"%s\": %s"
 
-#: grep.c:1348
+#: grep.c:1469
 #, c-format
 msgid "'%s': short read %s"
 msgstr "\"%s\": kort läsning %s"
@@ -741,19 +715,19 @@ msgstr[1] ""
 "Din gren och \"%s\" har divergerat,\n"
 "och har %d respektive %d olika incheckningar.\n"
 
-#: sequencer.c:121 builtin/merge.c:864 builtin/merge.c:977
+#: sequencer.c:123 builtin/merge.c:864 builtin/merge.c:977
 #: builtin/merge.c:1087 builtin/merge.c:1097
 #, c-format
 msgid "Could not open '%s' for writing"
 msgstr "Kunde inte öppna \"%s\" för skrivning"
 
-#: sequencer.c:123 builtin/merge.c:333 builtin/merge.c:867
+#: sequencer.c:125 builtin/merge.c:333 builtin/merge.c:867
 #: builtin/merge.c:1089 builtin/merge.c:1102
 #, c-format
 msgid "Could not write to '%s'"
 msgstr "Kunde inte skriva till \"%s\""
 
-#: sequencer.c:144
+#: sequencer.c:146
 msgid ""
 "after resolving the conflicts, mark the corrected paths\n"
 "with 'git add <paths>' or 'git rm <paths>'"
@@ -761,7 +735,7 @@ msgstr ""
 "efter att ha löst konflikterna, markera de rättade sökvägarna\n"
 "med \"git add <sökvägar>\" eller \"git rm <sökvägar>\""
 
-#: sequencer.c:147
+#: sequencer.c:149
 msgid ""
 "after resolving the conflicts, mark the corrected paths\n"
 "with 'git add <paths>' or 'git rm <paths>'\n"
@@ -771,214 +745,214 @@ msgstr ""
 "med \"git add <sökvägar>\" eller \"git rm <sökvägar>\"\n"
 "och checka in resultatet med \"git commit\""
 
-#: sequencer.c:160 sequencer.c:765 sequencer.c:848
+#: sequencer.c:162 sequencer.c:770 sequencer.c:853
 #, c-format
 msgid "Could not write to %s"
 msgstr "Kunde inte skriva till %s"
 
-#: sequencer.c:163
+#: sequencer.c:165
 #, c-format
 msgid "Error wrapping up %s"
 msgstr "Fel vid ombrytning av %s"
 
-#: sequencer.c:178
+#: sequencer.c:180
 msgid "Your local changes would be overwritten by cherry-pick."
 msgstr "Dina lokala ändringar skulle skrivas över av \"cherry-pick\"."
 
-#: sequencer.c:180
+#: sequencer.c:182
 msgid "Your local changes would be overwritten by revert."
 msgstr "Dina lokala ändringar skulle skrivas över av \"revert\"."
 
-#: sequencer.c:183
+#: sequencer.c:185
 msgid "Commit your changes or stash them to proceed."
 msgstr "Checka in dina ändringar eller använd \"stash\" för att fortsätta."
 
 #. TRANSLATORS: %s will be "revert" or "cherry-pick"
-#: sequencer.c:233
+#: sequencer.c:235
 #, c-format
 msgid "%s: Unable to write new index file"
 msgstr "%s: Kunde inte skriva ny indexfil"
 
-#: sequencer.c:261
+#: sequencer.c:266
 msgid "Could not resolve HEAD commit\n"
 msgstr "Kunde inte bestämma HEAD:s incheckning\n"
 
-#: sequencer.c:282
+#: sequencer.c:287
 msgid "Unable to update cache tree\n"
 msgstr "Kan inte uppdatera cacheträd\n"
 
-#: sequencer.c:327
+#: sequencer.c:332
 #, c-format
 msgid "Could not parse commit %s\n"
 msgstr "Kunde inte tolka incheckningen %s\n"
 
-#: sequencer.c:332
+#: sequencer.c:337
 #, c-format
 msgid "Could not parse parent commit %s\n"
 msgstr "Kunde inte tolka föräldraincheckningen %s\n"
 
-#: sequencer.c:398
+#: sequencer.c:403
 msgid "Your index file is unmerged."
 msgstr "Din indexfil har inte slagits ihop."
 
-#: sequencer.c:401
+#: sequencer.c:406
 msgid "You do not have a valid HEAD"
 msgstr "Du har ingen giltig HEAD"
 
-#: sequencer.c:416
+#: sequencer.c:421
 #, c-format
 msgid "Commit %s is a merge but no -m option was given."
 msgstr "Incheckning %s är en sammanslagning, men flaggan -m angavs inte."
 
-#: sequencer.c:424
+#: sequencer.c:429
 #, c-format
 msgid "Commit %s does not have parent %d"
 msgstr "Incheckning %s har inte förälder %d"
 
-#: sequencer.c:428
+#: sequencer.c:433
 #, c-format
 msgid "Mainline was specified but commit %s is not a merge."
 msgstr "Huvudlinje angavs, men incheckningen %s är inte en sammanslagning"
 
 #. TRANSLATORS: The first %s will be "revert" or
 #. "cherry-pick", the second %s a SHA1
-#: sequencer.c:439
+#: sequencer.c:444
 #, c-format
 msgid "%s: cannot parse parent commit %s"
 msgstr "%s: kan inte tolka föräldraincheckningen %s"
 
-#: sequencer.c:443
+#: sequencer.c:448
 #, c-format
 msgid "Cannot get commit message for %s"
 msgstr "Kan inte hämta incheckningsmeddelande för %s"
 
-#: sequencer.c:527
+#: sequencer.c:532
 #, c-format
 msgid "could not revert %s... %s"
 msgstr "kunde inte ångra %s... %s"
 
-#: sequencer.c:528
+#: sequencer.c:533
 #, c-format
 msgid "could not apply %s... %s"
 msgstr "kunde inte tillämpa %s... %s"
 
-#: sequencer.c:560
+#: sequencer.c:565
 msgid "empty commit set passed"
 msgstr "den angivna uppsättningen incheckningar är tom"
 
-#: sequencer.c:568
+#: sequencer.c:573
 #, c-format
 msgid "git %s: failed to read the index"
 msgstr "git %s: misslyckades läsa indexet"
 
-#: sequencer.c:573
+#: sequencer.c:578
 #, c-format
 msgid "git %s: failed to refresh the index"
 msgstr "git %s: misslyckades uppdatera indexet"
 
-#: sequencer.c:631
+#: sequencer.c:636
 #, c-format
 msgid "Cannot %s during a %s"
 msgstr "kan inte %s under en %s"
 
-#: sequencer.c:653
+#: sequencer.c:658
 #, c-format
 msgid "Could not parse line %d."
 msgstr "Kan inte tolka rad %d."
 
-#: sequencer.c:658
+#: sequencer.c:663
 msgid "No commits parsed."
 msgstr "Inga incheckningar lästes."
 
-#: sequencer.c:671
+#: sequencer.c:676
 #, c-format
 msgid "Could not open %s"
 msgstr "Kunde inte öppna %s"
 
-#: sequencer.c:675
+#: sequencer.c:680
 #, c-format
 msgid "Could not read %s."
 msgstr "kunde inte läsa %s."
 
-#: sequencer.c:682
+#: sequencer.c:687
 #, c-format
 msgid "Unusable instruction sheet: %s"
 msgstr "Oanvändbart manus: %s"
 
-#: sequencer.c:710
+#: sequencer.c:715
 #, c-format
 msgid "Invalid key: %s"
 msgstr "Felaktig nyckel: %s"
 
-#: sequencer.c:713
+#: sequencer.c:718
 #, c-format
 msgid "Invalid value for %s: %s"
 msgstr "Felaktigt värde för %s: %s"
 
-#: sequencer.c:725
+#: sequencer.c:730
 #, c-format
 msgid "Malformed options sheet: %s"
 msgstr "Trasigt manus: %s"
 
-#: sequencer.c:746
+#: sequencer.c:751
 msgid "a cherry-pick or revert is already in progress"
 msgstr "en \"cherry-pick\" eller \"revert\" pågår redan"
 
-#: sequencer.c:747
+#: sequencer.c:752
 msgid "try \"git cherry-pick (--continue | --quit | --abort)\""
 msgstr "testa \"git cherry-pick (--continue | --quit | --abort)\""
 
-#: sequencer.c:751
+#: sequencer.c:756
 #, c-format
 msgid "Could not create sequencer directory %s"
 msgstr "Kunde inte skapa \"sequencer\"-katalogen \"%s\""
 
-#: sequencer.c:767 sequencer.c:852
+#: sequencer.c:772 sequencer.c:857
 #, c-format
 msgid "Error wrapping up %s."
 msgstr "Fel vid ombrytning av %s."
 
-#: sequencer.c:786 sequencer.c:920
+#: sequencer.c:791 sequencer.c:925
 msgid "no cherry-pick or revert in progress"
 msgstr "ingen \"cherry-pick\" eller \"revert\" pågår"
 
-#: sequencer.c:788
+#: sequencer.c:793
 msgid "cannot resolve HEAD"
 msgstr "kan inte bestämma HEAD"
 
-#: sequencer.c:790
+#: sequencer.c:795
 msgid "cannot abort from a branch yet to be born"
 msgstr "kan inte avbryta från en gren som ännu inte är född"
 
-#: sequencer.c:812 builtin/apply.c:4005
+#: sequencer.c:817 builtin/apply.c:4005
 #, c-format
 msgid "cannot open %s: %s"
 msgstr "kan inte öppna %s: %s"
 
-#: sequencer.c:815
+#: sequencer.c:820
 #, c-format
 msgid "cannot read %s: %s"
 msgstr "kan inte läsa %s: %s"
 
-#: sequencer.c:816
+#: sequencer.c:821
 msgid "unexpected end of file"
 msgstr "oväntat filslut"
 
-#: sequencer.c:822
+#: sequencer.c:827
 #, c-format
 msgid "stored pre-cherry-pick HEAD file '%s' is corrupt"
 msgstr "sparad HEAD-fil från före \"cherry-pick\", \"%s\", är trasig"
 
-#: sequencer.c:845
+#: sequencer.c:850
 #, c-format
 msgid "Could not format %s."
 msgstr "Kunde inte formatera %s."
 
-#: sequencer.c:1007
+#: sequencer.c:1012
 msgid "Can't revert as initial commit"
 msgstr "Kan inte ångra som första incheckning"
 
-#: sequencer.c:1008
+#: sequencer.c:1013
 msgid "Can't cherry-pick into empty head"
 msgstr "Kan inte göra \"cherry-pick\" i ett tomt huvud"
 
@@ -1374,7 +1348,7 @@ msgstr "git add [flaggor] [--] <filmönster>..."
 msgid "unexpected diff status %c"
 msgstr "diff-status %c förväntades inte"
 
-#: builtin/add.c:67 builtin/commit.c:229
+#: builtin/add.c:67 builtin/commit.c:230
 msgid "updating files failed"
 msgstr "misslyckades uppdatera filer"
 
@@ -1439,7 +1413,7 @@ msgstr "Följande sökvägar ignoreras av en av dina .gitignore-filer:\n"
 msgid "dry run"
 msgstr "testkörning"
 
-#: builtin/add.c:320 builtin/apply.c:4354 builtin/commit.c:1187
+#: builtin/add.c:320 builtin/apply.c:4354 builtin/commit.c:1154
 #: builtin/count-objects.c:82 builtin/fsck.c:613 builtin/log.c:1477
 #: builtin/mv.c:62 builtin/read-tree.c:112
 msgid "be verbose"
@@ -1516,7 +1490,7 @@ msgstr "Inget angivet, inget tillagt.\n"
 msgid "Maybe you wanted to say 'git add .'?\n"
 msgstr "Kanske menade du att skriva \"git add .\"?\n"
 
-#: builtin/add.c:421 builtin/clean.c:95 builtin/commit.c:289 builtin/mv.c:82
+#: builtin/add.c:421 builtin/clean.c:95 builtin/commit.c:290 builtin/mv.c:82
 #: builtin/rm.c:162
 msgid "index file corrupt"
 msgstr "indexfilen trasig"
@@ -2057,95 +2031,95 @@ msgstr "git blame [flaggor] [rev-flaggor] [rev] [--] fil"
 msgid "[rev-opts] are documented in git-rev-list(1)"
 msgstr "[rev-flaggor] dokumenteras i git-rev-list(1)"
 
-#: builtin/blame.c:2316
+#: builtin/blame.c:2373
 msgid "Show blame entries as we find them, incrementally"
 msgstr "Visa klandringsposter när vi hittar dem, interaktivt"
 
-#: builtin/blame.c:2317
+#: builtin/blame.c:2374
 msgid "Show blank SHA-1 for boundary commits (Default: off)"
 msgstr "Visa blank SHA-1 för gränsincheckningar (Standard: av)"
 
-#: builtin/blame.c:2318
+#: builtin/blame.c:2375
 msgid "Do not treat root commits as boundaries (Default: off)"
 msgstr "Behandla inte rotincheckningar som gränser (Standard: av)"
 
-#: builtin/blame.c:2319
+#: builtin/blame.c:2376
 msgid "Show work cost statistics"
 msgstr "Visa statistik över arbetskostnad"
 
-#: builtin/blame.c:2320
+#: builtin/blame.c:2377
 msgid "Show output score for blame entries"
 msgstr "Visa utdatapoäng för klandringsposter"
 
-#: builtin/blame.c:2321
+#: builtin/blame.c:2378
 msgid "Show original filename (Default: auto)"
 msgstr "Visa originalfilnamn (Standard: auto)"
 
-#: builtin/blame.c:2322
+#: builtin/blame.c:2379
 msgid "Show original linenumber (Default: off)"
 msgstr "Visa ursprungligt radnummer (Standard: av)"
 
-#: builtin/blame.c:2323
+#: builtin/blame.c:2380
 msgid "Show in a format designed for machine consumption"
 msgstr "Visa i ett format avsett för maskinkonsumtion"
 
-#: builtin/blame.c:2324
+#: builtin/blame.c:2381
 msgid "Show porcelain format with per-line commit information"
 msgstr "Visa porslinsformat med per-rad-incheckningsinformation"
 
-#: builtin/blame.c:2325
+#: builtin/blame.c:2382
 msgid "Use the same output mode as git-annotate (Default: off)"
 msgstr "Använd samma utdataläge som git-annotate (Standard: av)"
 
-#: builtin/blame.c:2326
+#: builtin/blame.c:2383
 msgid "Show raw timestamp (Default: off)"
 msgstr "Visa rå tidsstämpel (Standard: av)"
 
-#: builtin/blame.c:2327
+#: builtin/blame.c:2384
 msgid "Show long commit SHA1 (Default: off)"
 msgstr "Visa lång inchecknings-SHA1 (Standard: av)"
 
-#: builtin/blame.c:2328
+#: builtin/blame.c:2385
 msgid "Suppress author name and timestamp (Default: off)"
 msgstr "Undertryck författarnamn och tidsstämpel (Standard: av)"
 
-#: builtin/blame.c:2329
+#: builtin/blame.c:2386
 msgid "Show author email instead of name (Default: off)"
 msgstr "Visa författarens e-post istället för namn (Standard: av)"
 
-#: builtin/blame.c:2330
+#: builtin/blame.c:2387
 msgid "Ignore whitespace differences"
 msgstr "Ignorera ändringar i blanksteg"
 
-#: builtin/blame.c:2331
+#: builtin/blame.c:2388
 msgid "Spend extra cycles to find better match"
 msgstr "Slösa extra cykler med att hitta bättre träff"
 
-#: builtin/blame.c:2332
+#: builtin/blame.c:2389
 msgid "Use revisions from <file> instead of calling git-rev-list"
 msgstr "Använd revisioner från <fil> istället för att anropa git-rev-list"
 
-#: builtin/blame.c:2333
+#: builtin/blame.c:2390
 msgid "Use <file>'s contents as the final image"
 msgstr "Använd <fil>s innehåll som slutgiltig bild"
 
-#: builtin/blame.c:2334 builtin/blame.c:2335
+#: builtin/blame.c:2391 builtin/blame.c:2392
 msgid "score"
 msgstr "poäng"
 
-#: builtin/blame.c:2334
+#: builtin/blame.c:2391
 msgid "Find line copies within and across files"
 msgstr "Hitta kopierade rader inuti och mellan filer"
 
-#: builtin/blame.c:2335
+#: builtin/blame.c:2392
 msgid "Find line movements within and across files"
 msgstr "Hitta flyttade rader inuti och mellan filer"
 
-#: builtin/blame.c:2336
+#: builtin/blame.c:2393
 msgid "n,m"
 msgstr "n,m"
 
-#: builtin/blame.c:2336
+#: builtin/blame.c:2393
 msgid "Process only line range n,m, counting from 1"
 msgstr "Behandla endast radintervallet n,m, med början på 1"
 
@@ -2354,8 +2328,8 @@ msgid "act on remote-tracking branches"
 msgstr "arbeta på fjärrspårande grenar"
 
 #: builtin/branch.c:738 builtin/branch.c:744 builtin/branch.c:765
-#: builtin/branch.c:771 builtin/commit.c:1395 builtin/commit.c:1396
-#: builtin/commit.c:1397 builtin/commit.c:1398 builtin/tag.c:470
+#: builtin/branch.c:771 builtin/commit.c:1362 builtin/commit.c:1363
+#: builtin/commit.c:1364 builtin/commit.c:1365 builtin/tag.c:470
 msgid "commit"
 msgstr "incheckning"
 
@@ -2531,8 +2505,8 @@ msgid "git check-attr [-a | --all | attr...] [--] pathname..."
 msgstr "git check-attr [-a | --all | attr...] [--] sökväg..."
 
 #: builtin/check-attr.c:12
-msgid "git check-attr --stdin [-a | --all | attr...] < <list-of-paths>"
-msgstr "git check-attr --stdin [-a | --all | attr...] < <sökvägslista>"
+msgid "git check-attr --stdin [-z] [-a | --all | attr...] < <list-of-paths>"
+msgstr "git check-attr --stdin [-z] [-a | --all | attr...] < <sökvägslista>"
 
 #: builtin/check-attr.c:19
 msgid "report all attributes set on file"
@@ -2912,7 +2886,7 @@ msgstr "tvinga"
 msgid "remove whole directories"
 msgstr "ta bort hela kataloger"
 
-#: builtin/clean.c:56 builtin/describe.c:413 builtin/grep.c:802
+#: builtin/clean.c:56 builtin/describe.c:413 builtin/grep.c:803
 #: builtin/ls-files.c:491 builtin/name-rev.c:231 builtin/show-ref.c:199
 msgid "pattern"
 msgstr "mönster"
@@ -3038,7 +3012,7 @@ msgstr "checka ut <gren> istället för fjärrens HEAD"
 msgid "path to git-upload-pack on the remote"
 msgstr "sökväg till git-upload-pack på fjärren"
 
-#: builtin/clone.c:93 builtin/fetch.c:83 builtin/grep.c:747
+#: builtin/clone.c:93 builtin/fetch.c:83 builtin/grep.c:748
 msgid "depth"
 msgstr "djup"
 
@@ -3116,69 +3090,69 @@ msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n"
 msgstr ""
 "HEAD hos fjärren pekar på en obefintlig referens, kan inte checka ut.\n"
 
-#: builtin/clone.c:642
+#: builtin/clone.c:690
 msgid "Too many arguments."
 msgstr "För många argument."
 
-#: builtin/clone.c:646
+#: builtin/clone.c:694
 msgid "You must specify a repository to clone."
 msgstr "Du måste ange ett arkiv att klona."
 
-#: builtin/clone.c:657
+#: builtin/clone.c:705
 #, c-format
 msgid "--bare and --origin %s options are incompatible."
 msgstr "flaggorna --bare och --origin %s är inkompatibla."
 
-#: builtin/clone.c:671
+#: builtin/clone.c:719
 #, c-format
 msgid "repository '%s' does not exist"
 msgstr "arkivet \"%s\" finns inte"
 
-#: builtin/clone.c:676
+#: builtin/clone.c:724
 msgid "--depth is ignored in local clones; use file:// instead."
 msgstr "--depth ignoreras i lokala kloningar; använd file:// istället"
 
-#: builtin/clone.c:686
+#: builtin/clone.c:734
 #, c-format
 msgid "destination path '%s' already exists and is not an empty directory."
 msgstr "destinationssökvägen \"%s\" finns redan och är inte en tom katalog."
 
-#: builtin/clone.c:696
+#: builtin/clone.c:744
 #, c-format
 msgid "working tree '%s' already exists."
 msgstr "arbetsträdet \"%s\" finns redan."
 
-#: builtin/clone.c:709 builtin/clone.c:723
+#: builtin/clone.c:757 builtin/clone.c:771
 #, c-format
 msgid "could not create leading directories of '%s'"
 msgstr "kunde inte skapa inledande kataloger för \"%s\""
 
-#: builtin/clone.c:712
+#: builtin/clone.c:760
 #, c-format
 msgid "could not create work tree dir '%s'."
 msgstr "kunde inte skapa arbetskatalogen \"%s\""
 
-#: builtin/clone.c:731
+#: builtin/clone.c:779
 #, c-format
 msgid "Cloning into bare repository '%s'...\n"
 msgstr "Klonar till ett naket arkiv \"%s\"...\n"
 
-#: builtin/clone.c:733
+#: builtin/clone.c:781
 #, c-format
 msgid "Cloning into '%s'...\n"
 msgstr "Klonar till \"%s\"...\n"
 
-#: builtin/clone.c:789
+#: builtin/clone.c:823
 #, c-format
 msgid "Don't know how to clone %s"
 msgstr "Vet inte hur man klonar %s"
 
-#: builtin/clone.c:838
+#: builtin/clone.c:872
 #, c-format
 msgid "Remote branch %s not found in upstream %s"
 msgstr "Fjärrgrenen %s hittades inte i uppströmsarkivet %s"
 
-#: builtin/clone.c:845
+#: builtin/clone.c:879
 msgid "You appear to have cloned an empty repository."
 msgstr "Du verkar ha klonat ett tomt arkiv."
 
@@ -3214,15 +3188,15 @@ msgstr "Spaltfyllnad mellan spalter"
 msgid "--command must be the first argument"
 msgstr "--command måste vara första argument"
 
-#: builtin/commit.c:33
+#: builtin/commit.c:34
 msgid "git commit [options] [--] <filepattern>..."
 msgstr "git commit [flaggor] [--] <filmöster>..."
 
-#: builtin/commit.c:38
+#: builtin/commit.c:39
 msgid "git status [options] [--] <filepattern>..."
 msgstr "git status [flaggor] [--] <filmönster>..."
 
-#: builtin/commit.c:43
+#: builtin/commit.c:44
 msgid ""
 "Your name and email address were configured automatically based\n"
 "on your username and hostname. Please check that they are accurate.\n"
@@ -3247,7 +3221,7 @@ msgstr ""
 "\n"
 "    git commit --amend --reset-author\n"
 
-#: builtin/commit.c:55
+#: builtin/commit.c:56
 msgid ""
 "You asked to amend the most recent commit, but doing so would make\n"
 "it empty. You can repeat your command with --allow-empty, or you can\n"
@@ -3257,7 +3231,7 @@ msgstr ""
 "blir den tom. Du kan köra kommandot på nytt med --allow-empty, eller\n"
 "så kan du ta bort incheckningen helt med \"git reset HEAD^\".\n"
 
-#: builtin/commit.c:60
+#: builtin/commit.c:61
 msgid ""
 "The previous cherry-pick is now empty, possibly due to conflict resolution.\n"
 "If you wish to commit it anyway, use:\n"
@@ -3273,93 +3247,93 @@ msgstr ""
 "\n"
 "Annars använder du \"git reset\"\n"
 
-#: builtin/commit.c:256
+#: builtin/commit.c:257
 msgid "failed to unpack HEAD tree object"
 msgstr "misslyckades packa upp HEAD:s trädobjekt"
 
-#: builtin/commit.c:298
+#: builtin/commit.c:299
 msgid "unable to create temporary index"
 msgstr "kunde inte skapa temporär indexfil"
 
-#: builtin/commit.c:304
+#: builtin/commit.c:305
 msgid "interactive add failed"
 msgstr "interaktiv tilläggning misslyckades"
 
-#: builtin/commit.c:337 builtin/commit.c:358 builtin/commit.c:408
+#: builtin/commit.c:338 builtin/commit.c:359 builtin/commit.c:409
 msgid "unable to write new_index file"
 msgstr "kunde inte skriva filen new_index"
 
-#: builtin/commit.c:389
+#: builtin/commit.c:390
 msgid "cannot do a partial commit during a merge."
 msgstr "kan inte utföra en delvis incheckning under en sammanslagning."
 
-#: builtin/commit.c:391
+#: builtin/commit.c:392
 msgid "cannot do a partial commit during a cherry-pick."
 msgstr "kan inte utföra en delvis incheckning under en cherry-pick."
 
-#: builtin/commit.c:401
+#: builtin/commit.c:402
 msgid "cannot read the index"
 msgstr "kan inte läsa indexet"
 
-#: builtin/commit.c:421
+#: builtin/commit.c:422
 msgid "unable to write temporary index file"
 msgstr "kunde inte skriva temporär indexfil"
 
-#: builtin/commit.c:510 builtin/commit.c:516
+#: builtin/commit.c:509 builtin/commit.c:515
 #, c-format
 msgid "invalid commit: %s"
 msgstr "felaktig incheckning: %s"
 
-#: builtin/commit.c:539
+#: builtin/commit.c:538
 msgid "malformed --author parameter"
 msgstr "felformad \"--author\"-flagga"
 
-#: builtin/commit.c:600
+#: builtin/commit.c:558
 #, c-format
 msgid "Malformed ident string: '%s'"
 msgstr "Felaktig indragningssträng: \"%s\""
 
-#: builtin/commit.c:638 builtin/commit.c:671 builtin/commit.c:985
+#: builtin/commit.c:596 builtin/commit.c:629 builtin/commit.c:952
 #, c-format
 msgid "could not lookup commit %s"
 msgstr "kunde inte slå upp incheckningen %s"
 
-#: builtin/commit.c:650 builtin/shortlog.c:296
+#: builtin/commit.c:608 builtin/shortlog.c:296
 #, c-format
 msgid "(reading log message from standard input)\n"
 msgstr "(läser loggmeddelande från standard in)\n"
 
-#: builtin/commit.c:652
+#: builtin/commit.c:610
 msgid "could not read log from standard input"
 msgstr "kunde inte läsa logg från standard in"
 
-#: builtin/commit.c:656
+#: builtin/commit.c:614
 #, c-format
 msgid "could not read log file '%s'"
 msgstr "kunde inte läsa loggfilen \"%s\""
 
-#: builtin/commit.c:662
+#: builtin/commit.c:620
 msgid "commit has empty message"
 msgstr "incheckningen har ett tomt meddelande"
 
-#: builtin/commit.c:678
+#: builtin/commit.c:636
 msgid "could not read MERGE_MSG"
 msgstr "kunde inte läsa MERGE_MSG"
 
-#: builtin/commit.c:682
+#: builtin/commit.c:640
 msgid "could not read SQUASH_MSG"
 msgstr "kunde inte läsa SQUASH_MSG"
 
-#: builtin/commit.c:686
+#: builtin/commit.c:644
 #, c-format
 msgid "could not read '%s'"
 msgstr "kunde inte läsa \"%s\""
 
-#: builtin/commit.c:738
+#: builtin/commit.c:705
 msgid "could not write commit template"
 msgstr "kunde inte skriva incheckningsmall"
 
-#: builtin/commit.c:749
+#: builtin/commit.c:716
 #, c-format
 msgid ""
 "\n"
@@ -3374,7 +3348,7 @@ msgstr ""
 "\t%s\n"
 "och försöker igen.\n"
 
-#: builtin/commit.c:754
+#: builtin/commit.c:721
 #, c-format
 msgid ""
 "\n"
@@ -3389,7 +3363,7 @@ msgstr ""
 "\t%s\n"
 "och försöker igen.\n"
 
-#: builtin/commit.c:766
+#: builtin/commit.c:733
 msgid ""
 "Please enter the commit message for your changes. Lines starting\n"
 "with '#' will be ignored, and an empty message aborts the commit.\n"
@@ -3397,7 +3371,7 @@ msgstr ""
 "Ange incheckningsmeddelandet för dina ändringar. Rader som inleds\n"
 "med \"#\" kommer ignoreras, och ett tomt meddelande avbryter incheckningen.\n"
 
-#: builtin/commit.c:771
+#: builtin/commit.c:738
 msgid ""
 "Please enter the commit message for your changes. Lines starting\n"
 "with '#' will be kept; you may remove them yourself if you want to.\n"
@@ -3407,131 +3381,131 @@ msgstr ""
 "med \"#\" kommer behållas; du kan själv ta bort dem om du vill.\n"
 "Ett tomt meddelande avbryter incheckningen.\n"
 
-#: builtin/commit.c:784
+#: builtin/commit.c:751
 #, c-format
 msgid "%sAuthor:    %s"
 msgstr "%sFörfattare: %s"
 
-#: builtin/commit.c:791
+#: builtin/commit.c:758
 #, c-format
 msgid "%sCommitter: %s"
 msgstr "%sIncheckare: %s"
 
-#: builtin/commit.c:811
+#: builtin/commit.c:778
 msgid "Cannot read index"
 msgstr "Kan inte läsa indexet"
 
-#: builtin/commit.c:848
+#: builtin/commit.c:815
 msgid "Error building trees"
 msgstr "Fel vid byggande av träd"
 
-#: builtin/commit.c:863 builtin/tag.c:361
+#: builtin/commit.c:830 builtin/tag.c:361
 #, c-format
 msgid "Please supply the message using either -m or -F option.\n"
 msgstr "Ange meddelandet en av flaggorna -m eller -F.\n"
 
-#: builtin/commit.c:960
+#: builtin/commit.c:927
 #, c-format
 msgid "No existing author found with '%s'"
 msgstr "Hittade ingen befintlig författare med \"%s\""
 
-#: builtin/commit.c:975 builtin/commit.c:1175
+#: builtin/commit.c:942 builtin/commit.c:1142
 #, c-format
 msgid "Invalid untracked files mode '%s'"
 msgstr "Ogiltigt läge för ospårade filer: \"%s\""
 
-#: builtin/commit.c:1015
+#: builtin/commit.c:982
 msgid "Using both --reset-author and --author does not make sense"
 msgstr "Kan inte använda både --reset-author och --author"
 
-#: builtin/commit.c:1026
+#: builtin/commit.c:993
 msgid "You have nothing to amend."
 msgstr "Du har inget att utöka."
 
-#: builtin/commit.c:1029
+#: builtin/commit.c:996
 msgid "You are in the middle of a merge -- cannot amend."
 msgstr "Du är i mitten av en sammanslagning -- kan inte utöka."
 
-#: builtin/commit.c:1031
+#: builtin/commit.c:998
 msgid "You are in the middle of a cherry-pick -- cannot amend."
 msgstr "Du är i mitten av en cherry-pick -- kan inte utöka."
 
-#: builtin/commit.c:1034
+#: builtin/commit.c:1001
 msgid "Options --squash and --fixup cannot be used together"
 msgstr "Flaggorna --squash och --fixup kan inte användas samtidigt"
 
-#: builtin/commit.c:1044
+#: builtin/commit.c:1011
 msgid "Only one of -c/-C/-F/--fixup can be used."
 msgstr "Endast en av -c/-C/-F/--fixup kan användas."
 
-#: builtin/commit.c:1046
+#: builtin/commit.c:1013
 msgid "Option -m cannot be combined with -c/-C/-F/--fixup."
 msgstr "Flaggan -m kan inte kombineras med -c/-C/-F/--fixup."
 
-#: builtin/commit.c:1054
+#: builtin/commit.c:1021
 msgid "--reset-author can be used only with -C, -c or --amend."
 msgstr "--reset-author kan endast användas med -C, -c eller --amend."
 
-#: builtin/commit.c:1071
+#: builtin/commit.c:1038
 msgid "Only one of --include/--only/--all/--interactive/--patch can be used."
 msgstr ""
 "Endast en av --include/--only/--all/--interactive/--patch kan användas."
 
-#: builtin/commit.c:1073
+#: builtin/commit.c:1040
 msgid "No paths with --include/--only does not make sense."
 msgstr "Du måste ange sökvägar tillsammans med --include/--only."
 
-#: builtin/commit.c:1075
+#: builtin/commit.c:1042
 msgid "Clever... amending the last one with dirty index."
 msgstr "Smart... utöka den senaste med smutsigt index."
 
-#: builtin/commit.c:1077
+#: builtin/commit.c:1044
 msgid "Explicit paths specified without -i nor -o; assuming --only paths..."
 msgstr "Explicita sökvägar angavs utan -i eller -o; antar --only sökvägar..."
 
-#: builtin/commit.c:1087 builtin/tag.c:577
+#: builtin/commit.c:1054 builtin/tag.c:577
 #, c-format
 msgid "Invalid cleanup mode %s"
 msgstr "Felaktigt städningsläge %s"
 
-#: builtin/commit.c:1092
+#: builtin/commit.c:1059
 msgid "Paths with -a does not make sense."
 msgstr "Kan inte ange sökvägar med -a."
 
-#: builtin/commit.c:1189 builtin/commit.c:1417
+#: builtin/commit.c:1156 builtin/commit.c:1384
 msgid "show status concisely"
 msgstr "vis koncis status"
 
-#: builtin/commit.c:1191 builtin/commit.c:1419
+#: builtin/commit.c:1158 builtin/commit.c:1386
 msgid "show branch information"
 msgstr "visa information om gren"
 
-#: builtin/commit.c:1193 builtin/commit.c:1421 builtin/push.c:389
+#: builtin/commit.c:1160 builtin/commit.c:1388 builtin/push.c:389
 msgid "machine-readable output"
 msgstr "maskinläsbar utdata"
 
-#: builtin/commit.c:1196 builtin/commit.c:1423
+#: builtin/commit.c:1163 builtin/commit.c:1390
 msgid "terminate entries with NUL"
 msgstr "terminera poster med NUL"
 
-#: builtin/commit.c:1198 builtin/commit.c:1426 builtin/fast-export.c:636
+#: builtin/commit.c:1165 builtin/commit.c:1393 builtin/fast-export.c:636
 #: builtin/fast-export.c:639 builtin/tag.c:461
 msgid "mode"
 msgstr "läge"
 
-#: builtin/commit.c:1199 builtin/commit.c:1426
+#: builtin/commit.c:1166 builtin/commit.c:1393
 msgid "show untracked files, optional modes: all, normal, no. (Default: all)"
 msgstr "visa ospårade filer, valfria lägen: alla, normal, no. (Standard: all)"
 
-#: builtin/commit.c:1202
+#: builtin/commit.c:1169
 msgid "show ignored files"
 msgstr "visa ignorerade filer"
 
-#: builtin/commit.c:1203 parse-options.h:151
+#: builtin/commit.c:1170 parse-options.h:151
 msgid "when"
 msgstr "när"
 
-#: builtin/commit.c:1204
+#: builtin/commit.c:1171
 msgid ""
 "ignore changes to submodules, optional when: all, dirty, untracked. "
 "(Default: all)"
@@ -3539,217 +3513,217 @@ msgstr ""
 "ignorera ändringar i undermoduler, valfritt när: all, dirty, untracked. "
 "(Default: all)"
 
-#: builtin/commit.c:1206
+#: builtin/commit.c:1173
 msgid "list untracked files in columns"
 msgstr "visa ospårade filer i spalter"
 
-#: builtin/commit.c:1275
+#: builtin/commit.c:1242
 msgid "couldn't look up newly created commit"
 msgstr "kunde inte slå upp en precis skapad incheckning"
 
-#: builtin/commit.c:1277
+#: builtin/commit.c:1244
 msgid "could not parse newly created commit"
 msgstr "kunde inte tolka en precis skapad incheckning"
 
-#: builtin/commit.c:1318
+#: builtin/commit.c:1285
 msgid "detached HEAD"
 msgstr "frånkopplad HEAD"
 
-#: builtin/commit.c:1320
+#: builtin/commit.c:1287
 msgid " (root-commit)"
 msgstr " (rotincheckning)"
 
-#: builtin/commit.c:1387
+#: builtin/commit.c:1354
 msgid "suppress summary after successful commit"
 msgstr "undertryck sammanfattning efter framgångsrik incheckning"
 
-#: builtin/commit.c:1388
+#: builtin/commit.c:1355
 msgid "show diff in commit message template"
 msgstr "visa diff i mallen för incheckningsmeddelandet"
 
-#: builtin/commit.c:1390
+#: builtin/commit.c:1357
 msgid "Commit message options"
 msgstr "Alternativ för incheckningsmeddelande"
 
-#: builtin/commit.c:1391 builtin/tag.c:459
+#: builtin/commit.c:1358 builtin/tag.c:459
 msgid "read message from file"
 msgstr "läs meddelande från fil"
 
-#: builtin/commit.c:1392
+#: builtin/commit.c:1359
 msgid "author"
 msgstr "författare"
 
-#: builtin/commit.c:1392
+#: builtin/commit.c:1359
 msgid "override author for commit"
 msgstr "överstyr författare för incheckningen"
 
-#: builtin/commit.c:1393 builtin/gc.c:178
+#: builtin/commit.c:1360 builtin/gc.c:178
 msgid "date"
 msgstr "datum"
 
-#: builtin/commit.c:1393
+#: builtin/commit.c:1360
 msgid "override date for commit"
 msgstr "överstyr datum för inchecknignen"
 
-#: builtin/commit.c:1394 builtin/merge.c:206 builtin/notes.c:534
-#: builtin/notes.c:691 builtin/tag.c:457
+#: builtin/commit.c:1361 builtin/merge.c:206 builtin/notes.c:537
+#: builtin/notes.c:694 builtin/tag.c:457
 msgid "message"
 msgstr "meddelande"
 
-#: builtin/commit.c:1394
+#: builtin/commit.c:1361
 msgid "commit message"
 msgstr "incheckningsmeddelande"
 
-#: builtin/commit.c:1395
+#: builtin/commit.c:1362
 msgid "reuse and edit message from specified commit"
 msgstr "återanvänd och redigera meddelande från angiven incheckning"
 
-#: builtin/commit.c:1396
+#: builtin/commit.c:1363
 msgid "reuse message from specified commit"
 msgstr "återanvänd meddelande från angiven incheckning"
 
-#: builtin/commit.c:1397
+#: builtin/commit.c:1364
 msgid "use autosquash formatted message to fixup specified commit"
 msgstr ""
 "använd autosquash-formaterat meddelande för att fixa angiven incheckning"
 
-#: builtin/commit.c:1398
+#: builtin/commit.c:1365
 msgid "use autosquash formatted message to squash specified commit"
 msgstr ""
 "använd autosquash-formaterat meddelande för att slå ihop med angiven "
 "incheckning"
 
-#: builtin/commit.c:1399
+#: builtin/commit.c:1366
 msgid "the commit is authored by me now (used with -C/-c/--amend)"
 msgstr "jag är nu författare av incheckningen (används med -C/-c/--amend)"
 
-#: builtin/commit.c:1400 builtin/log.c:1068 builtin/revert.c:109
+#: builtin/commit.c:1367 builtin/log.c:1068 builtin/revert.c:109
 msgid "add Signed-off-by:"
 msgstr "lägg till Signed-off-by:"
 
-#: builtin/commit.c:1401
+#: builtin/commit.c:1368
 msgid "use specified template file"
 msgstr "använd angiven mallfil"
 
-#: builtin/commit.c:1402
+#: builtin/commit.c:1369
 msgid "force edit of commit"
 msgstr "tvinga redigering av incheckning"
 
-#: builtin/commit.c:1403
+#: builtin/commit.c:1370
 msgid "default"
 msgstr "standard"
 
-#: builtin/commit.c:1403 builtin/tag.c:462
+#: builtin/commit.c:1370 builtin/tag.c:462
 msgid "how to strip spaces and #comments from message"
 msgstr "hur blanksteg och #kommentarer skall tas bort från meddelande"
 
-#: builtin/commit.c:1404
+#: builtin/commit.c:1371
 msgid "include status in commit message template"
 msgstr "inkludera status i mallen för incheckningsmeddelandet"
 
-#: builtin/commit.c:1405 builtin/merge.c:213 builtin/tag.c:463
+#: builtin/commit.c:1372 builtin/merge.c:213 builtin/tag.c:463
 msgid "key id"
 msgstr "nyckel-id"
 
-#: builtin/commit.c:1406 builtin/merge.c:214
+#: builtin/commit.c:1373 builtin/merge.c:214
 msgid "GPG sign commit"
 msgstr "GPG-signera incheckning"
 
 #. end commit message options
-#: builtin/commit.c:1409
+#: builtin/commit.c:1376
 msgid "Commit contents options"
 msgstr "Alternativ för incheckningens innehåll"
 
-#: builtin/commit.c:1410
+#: builtin/commit.c:1377
 msgid "commit all changed files"
 msgstr "checka in alla ändrade filer"
 
-#: builtin/commit.c:1411
+#: builtin/commit.c:1378
 msgid "add specified files to index for commit"
 msgstr "lägg till angivna filer till indexet för incheckning"
 
-#: builtin/commit.c:1412
+#: builtin/commit.c:1379
 msgid "interactively add files"
 msgstr "lägg till filer interaktivt"
 
-#: builtin/commit.c:1413
+#: builtin/commit.c:1380
 msgid "interactively add changes"
 msgstr "lägg till ändringar interaktivt"
 
-#: builtin/commit.c:1414
+#: builtin/commit.c:1381
 msgid "commit only specified files"
 msgstr "checka endast in angivna filer"
 
-#: builtin/commit.c:1415
+#: builtin/commit.c:1382
 msgid "bypass pre-commit hook"
 msgstr "förbigå pre-commit-krok"
 
-#: builtin/commit.c:1416
+#: builtin/commit.c:1383
 msgid "show what would be committed"
 msgstr "visa vad som skulle checkas in"
 
-#: builtin/commit.c:1424
+#: builtin/commit.c:1391
 msgid "amend previous commit"
 msgstr "lägg till föregående incheckning"
 
-#: builtin/commit.c:1425
+#: builtin/commit.c:1392
 msgid "bypass post-rewrite hook"
 msgstr "förbigå post-rewrite-krok"
 
-#: builtin/commit.c:1430
+#: builtin/commit.c:1397
 msgid "ok to record an empty change"
 msgstr "ok att registrera en tom ändring"
 
-#: builtin/commit.c:1433
+#: builtin/commit.c:1400
 msgid "ok to record a change with an empty message"
 msgstr "ok att registrera en ändring med tomt meddelande"
 
-#: builtin/commit.c:1464
+#: builtin/commit.c:1432
 msgid "could not parse HEAD commit"
 msgstr "kunde inte tolka HEAD:s incheckning"
 
-#: builtin/commit.c:1502 builtin/merge.c:508
+#: builtin/commit.c:1470 builtin/merge.c:508
 #, c-format
 msgid "could not open '%s' for reading"
 msgstr "kunde inte öppna \"%s\" för läsning"
 
-#: builtin/commit.c:1509
+#: builtin/commit.c:1477
 #, c-format
 msgid "Corrupt MERGE_HEAD file (%s)"
 msgstr "Trasig MERGE_HEAD-fil (%s)"
 
-#: builtin/commit.c:1516
+#: builtin/commit.c:1484
 msgid "could not read MERGE_MODE"
 msgstr "kunde inte läsa MERGE_MODE"
 
-#: builtin/commit.c:1535
+#: builtin/commit.c:1503
 #, c-format
 msgid "could not read commit message: %s"
 msgstr "kunde inte läsa incheckningsmeddelande: %s"
 
-#: builtin/commit.c:1549
+#: builtin/commit.c:1517
 #, c-format
 msgid "Aborting commit; you did not edit the message.\n"
 msgstr "Avbryter incheckning; meddelandet inte redigerat.\n"
 
-#: builtin/commit.c:1554
+#: builtin/commit.c:1522
 #, c-format
 msgid "Aborting commit due to empty commit message.\n"
 msgstr "Avbryter på grund av tomt incheckningsmeddelande.\n"
 
-#: builtin/commit.c:1569 builtin/merge.c:935 builtin/merge.c:960
+#: builtin/commit.c:1537 builtin/merge.c:935 builtin/merge.c:960
 msgid "failed to write commit object"
 msgstr "kunde inte skriva incheckningsobjekt"
 
-#: builtin/commit.c:1590
+#: builtin/commit.c:1558
 msgid "cannot lock HEAD ref"
 msgstr "kunde inte låsa HEAD-referens"
 
-#: builtin/commit.c:1594
+#: builtin/commit.c:1562
 msgid "cannot update HEAD ref"
 msgstr "kunde inte uppdatera HEAD-referens"
 
-#: builtin/commit.c:1605
+#: builtin/commit.c:1573
 msgid ""
 "Repository has been updated, but unable to write\n"
 "new_index file. Check that disk is not full or quota is\n"
@@ -4179,67 +4153,67 @@ msgstr "Kunde inte hitta fjärr-referensen HEAD"
 msgid "object %s not found"
 msgstr "objektet %s hittades inte"
 
-#: builtin/fetch.c:260
+#: builtin/fetch.c:259
 msgid "[up to date]"
 msgstr "[àjour]"
 
-#: builtin/fetch.c:274
+#: builtin/fetch.c:273
 #, c-format
 msgid "! %-*s %-*s -> %s  (can't fetch in current branch)"
 msgstr "! %-*s %-*s -> %s  (kan inte hämta i aktuell gren)"
 
-#: builtin/fetch.c:275 builtin/fetch.c:361
+#: builtin/fetch.c:274 builtin/fetch.c:360
 msgid "[rejected]"
 msgstr "[refuserad]"
 
-#: builtin/fetch.c:286
+#: builtin/fetch.c:285
 msgid "[tag update]"
 msgstr "[uppdaterad tagg]"
 
-#: builtin/fetch.c:288 builtin/fetch.c:323 builtin/fetch.c:341
+#: builtin/fetch.c:287 builtin/fetch.c:322 builtin/fetch.c:340
 msgid "  (unable to update local ref)"
 msgstr "  (kunde inte uppdatera lokal ref)"
 
-#: builtin/fetch.c:306
+#: builtin/fetch.c:305
 msgid "[new tag]"
 msgstr "[ny tagg]"
 
-#: builtin/fetch.c:309
+#: builtin/fetch.c:308
 msgid "[new branch]"
 msgstr "[ny gren]"
 
-#: builtin/fetch.c:312
+#: builtin/fetch.c:311
 msgid "[new ref]"
 msgstr "[ny ref]"
 
-#: builtin/fetch.c:357
+#: builtin/fetch.c:356
 msgid "unable to update local ref"
 msgstr "kunde inte uppdatera lokal ref"
 
-#: builtin/fetch.c:357
+#: builtin/fetch.c:356
 msgid "forced update"
 msgstr "tvingad uppdatering"
 
-#: builtin/fetch.c:363
+#: builtin/fetch.c:362
 msgid "(non-fast-forward)"
 msgstr "(ej snabbspolad)"
 
-#: builtin/fetch.c:394 builtin/fetch.c:686
+#: builtin/fetch.c:393 builtin/fetch.c:685
 #, c-format
 msgid "cannot open %s: %s\n"
 msgstr "kan inte öppna %s: %s\n"
 
-#: builtin/fetch.c:403
+#: builtin/fetch.c:402
 #, c-format
 msgid "%s did not send all necessary objects\n"
 msgstr "%s sände inte alla nödvändiga objekt\n"
 
-#: builtin/fetch.c:489
+#: builtin/fetch.c:488
 #, c-format
 msgid "From %.*s\n"
 msgstr "Från %.*s\n"
 
-#: builtin/fetch.c:500
+#: builtin/fetch.c:499
 #, c-format
 msgid ""
 "some local refs could not be updated; try running\n"
@@ -4248,55 +4222,55 @@ msgstr ""
 "vissa lokala referenser kunde inte uppdateras; testa att köra\n"
 " \"git remote prune %s\" för att ta bort gamla grenar som står i konflikt"
 
-#: builtin/fetch.c:550
+#: builtin/fetch.c:549
 #, c-format
 msgid "   (%s will become dangling)"
 msgstr "   (%s kommer bli dinglande)"
 
-#: builtin/fetch.c:551
+#: builtin/fetch.c:550
 #, c-format
 msgid "   (%s has become dangling)"
 msgstr "   (%s har blivit dinglande)"
 
-#: builtin/fetch.c:558
+#: builtin/fetch.c:557
 msgid "[deleted]"
 msgstr "[borttagen]"
 
-#: builtin/fetch.c:559 builtin/remote.c:1055
+#: builtin/fetch.c:558 builtin/remote.c:1055
 msgid "(none)"
 msgstr "(ingen)"
 
-#: builtin/fetch.c:676
+#: builtin/fetch.c:675
 #, c-format
 msgid "Refusing to fetch into current branch %s of non-bare repository"
 msgstr "Vägrar hämta till aktuell gren %s i ett icke-naket arkiv"
 
-#: builtin/fetch.c:710
+#: builtin/fetch.c:709
 #, c-format
 msgid "Don't know how to fetch from %s"
 msgstr "Vet inte hur man hämtar från %s"
 
-#: builtin/fetch.c:787
+#: builtin/fetch.c:786
 #, c-format
 msgid "Option \"%s\" value \"%s\" is not valid for %s"
 msgstr "Flaggan \"%s\" och värdet \"%s\" är inte giltigt för %s"
 
-#: builtin/fetch.c:790
+#: builtin/fetch.c:789
 #, c-format
 msgid "Option \"%s\" is ignored for %s\n"
 msgstr "Flaggan \"%s\" ignoreras för %s\n"
 
-#: builtin/fetch.c:892
+#: builtin/fetch.c:891
 #, c-format
 msgid "Fetching %s\n"
 msgstr "Hämtar %s\n"
 
-#: builtin/fetch.c:894 builtin/remote.c:100
+#: builtin/fetch.c:893 builtin/remote.c:100
 #, c-format
 msgid "Could not fetch %s"
 msgstr "Kunde inte hämta %s"
 
-#: builtin/fetch.c:913
+#: builtin/fetch.c:912
 msgid ""
 "No remote repository specified.  Please, specify either a URL or a\n"
 "remote name from which new revisions should be fetched."
@@ -4304,24 +4278,24 @@ msgstr ""
 "Inget fjärrarkiv angavs. Ange antingen en URL eller namnet på ett\n"
 "fjärrarkiv som nya incheckningar skall hämtas från."
 
-#: builtin/fetch.c:933
+#: builtin/fetch.c:932
 msgid "You need to specify a tag name."
 msgstr "Du måste ange namnet på en tagg."
 
-#: builtin/fetch.c:985
+#: builtin/fetch.c:984
 msgid "fetch --all does not take a repository argument"
 msgstr "fetch --all tar inte namnet på ett arkiv som argument"
 
-#: builtin/fetch.c:987
+#: builtin/fetch.c:986
 msgid "fetch --all does not make sense with refspecs"
 msgstr "fetch --all kan inte anges med referensspecifikationer"
 
-#: builtin/fetch.c:998
+#: builtin/fetch.c:997
 #, c-format
 msgid "No such remote or remote group: %s"
 msgstr "Fjärren eller fjärrgruppen finns inte: %s"
 
-#: builtin/fetch.c:1006
+#: builtin/fetch.c:1005
 msgid "Fetching a group and specifying refspecs does not make sense"
 msgstr "Kan inte hämta från grupp och ange referensspecifikationer"
 
@@ -4330,7 +4304,7 @@ msgid "git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]"
 msgstr ""
 "git fmt-merge-msg [-m <meddelande>] [--log[=<n>]|--no-log] [--file <fil>]"
 
-#: builtin/fmt-merge-msg.c:653 builtin/fmt-merge-msg.c:656 builtin/grep.c:786
+#: builtin/fmt-merge-msg.c:653 builtin/fmt-merge-msg.c:656 builtin/grep.c:787
 #: builtin/merge.c:188 builtin/show-branch.c:656 builtin/show-ref.c:192
 #: builtin/tag.c:448 parse-options.h:133 parse-options.h:235
 msgid "n"
@@ -4466,12 +4440,7 @@ msgstr "var mer grundlig (ökar körtiden)"
 msgid "enable auto-gc mode"
 msgstr "aktivera auto-gc-läge"
 
-#: builtin/gc.c:221
-#, c-format
-msgid "Auto packing the repository for optimum performance.\n"
-msgstr "Packar arkivet automatiskt för optimal prestanda.\n"
-
-#: builtin/gc.c:224
+#: builtin/gc.c:222
 #, c-format
 msgid ""
 "Auto packing the repository for optimum performance. You may also\n"
@@ -4480,7 +4449,7 @@ msgstr ""
 "Packar arkivet automatiskt för optimal prestanda. Du kan även\n"
 "köra \"git gc\" manuellt. Se \"git help gc\" för mer information.\n"
 
-#: builtin/gc.c:251
+#: builtin/gc.c:249
 msgid ""
 "There are too many unreachable loose objects; run 'git prune' to remove them."
 msgstr ""
@@ -4491,227 +4460,230 @@ msgstr ""
 msgid "git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]"
 msgstr "git grep [flaggor] [-e] <mönster> [<rev>...] [[--] <sökväg>...]"
 
-#: builtin/grep.c:216
+#: builtin/grep.c:217
 #, c-format
 msgid "grep: failed to create thread: %s"
 msgstr "grep: misslyckades skapa tråd. %s"
 
-#: builtin/grep.c:454
+#: builtin/grep.c:455
 #, c-format
 msgid "Failed to chdir: %s"
 msgstr "Kunde inte byta katalog (chdir): %s"
 
-#: builtin/grep.c:530 builtin/grep.c:564
+#: builtin/grep.c:531 builtin/grep.c:565
 #, c-format
 msgid "unable to read tree (%s)"
 msgstr "kunde inte läsa träd (%s)"
 
-#: builtin/grep.c:578
+#: builtin/grep.c:579
 #, c-format
 msgid "unable to grep from object of type %s"
 msgstr "Kunde inte \"grep\" från objekt av typen %s"
 
-#: builtin/grep.c:636
+#: builtin/grep.c:637
 #, c-format
 msgid "switch `%c' expects a numerical value"
 msgstr "flaggan \"%c\" antar ett numeriskt värde"
 
-#: builtin/grep.c:653
+#: builtin/grep.c:654
 #, c-format
 msgid "cannot open '%s'"
 msgstr "kan inte öppna \"%s\""
 
-#: builtin/grep.c:728
+#: builtin/grep.c:729
 msgid "search in index instead of in the work tree"
 msgstr "sök i indexet istället för i arbetskatalogen"
 
-#: builtin/grep.c:730
+#: builtin/grep.c:731
 msgid "find in contents not managed by git"
 msgstr "sök i innehål som inte hanteras av git"
 
-#: builtin/grep.c:732
+#: builtin/grep.c:733
 msgid "search in both tracked and untracked files"
 msgstr "sök i både spårade och ospårade filer"
 
-#: builtin/grep.c:734
+#: builtin/grep.c:735
 msgid "search also in ignored files"
 msgstr "sök även i ignorerade filer"
 
-#: builtin/grep.c:737
+#: builtin/grep.c:738
 msgid "show non-matching lines"
 msgstr "vis rader som inte träffas"
 
-#: builtin/grep.c:739
+#: builtin/grep.c:740
 msgid "case insensitive matching"
 msgstr "skiftlägesokänslig sökning"
 
-#: builtin/grep.c:741
+#: builtin/grep.c:742
 msgid "match patterns only at word boundaries"
 msgstr "matcha endast mönster vid ordgränser"
 
-#: builtin/grep.c:743
+#: builtin/grep.c:744
 msgid "process binary files as text"
 msgstr "hantera binärfiler som text"
 
-#: builtin/grep.c:745
+#: builtin/grep.c:746
 msgid "don't match patterns in binary files"
 msgstr "träffa inte mönster i binärfiler"
 
-#: builtin/grep.c:748
+#: builtin/grep.c:749
 msgid "descend at most <depth> levels"
 msgstr "gå som mest ned <djup> nivåer"
 
-#: builtin/grep.c:752
+#: builtin/grep.c:753
 msgid "use extended POSIX regular expressions"
 msgstr "använd utökade POSIX-reguljära uttryck"
 
-#: builtin/grep.c:755
+#: builtin/grep.c:756
 msgid "use basic POSIX regular expressions (default)"
 msgstr "använd grundläggande POSIX-reguljära uttryck (standard)"
 
-#: builtin/grep.c:758
+#: builtin/grep.c:759
 msgid "interpret patterns as fixed strings"
 msgstr "tolka mönster som fixerade strängar"
 
-#: builtin/grep.c:761
+#: builtin/grep.c:762
 msgid "use Perl-compatible regular expressions"
 msgstr "använd Perlkompatibla reguljära uttryck"
 
-#: builtin/grep.c:764
+#: builtin/grep.c:765
 msgid "show line numbers"
 msgstr "visa radnummer"
 
-#: builtin/grep.c:765
+#: builtin/grep.c:766
 msgid "don't show filenames"
 msgstr "visa inte filnamn"
 
-# %s är ett verb ("Untracked"/"Ignored"); lägg till ett -e.
-#: builtin/grep.c:766
+#: builtin/grep.c:767
 msgid "show filenames"
 msgstr "visa filnamn"
 
-#: builtin/grep.c:768
+#: builtin/grep.c:769
 msgid "show filenames relative to top directory"
 msgstr "visa filnamn relativa till toppkatalogen"
 
-#: builtin/grep.c:770
+#: builtin/grep.c:771
 msgid "show only filenames instead of matching lines"
 msgstr "visa endast filnamn istället för träffade rader"
 
-#: builtin/grep.c:772
+#: builtin/grep.c:773
 msgid "synonym for --files-with-matches"
 msgstr "synonym för --files-with-matches"
 
-#: builtin/grep.c:775
+#: builtin/grep.c:776
 msgid "show only the names of files without match"
 msgstr "visa endast namn på filer utan träffar"
 
-#: builtin/grep.c:777
+#: builtin/grep.c:778
 msgid "print NUL after filenames"
 msgstr "skriv NUL efter filnamn"
 
-#: builtin/grep.c:779
+#: builtin/grep.c:780
 msgid "show the number of matches instead of matching lines"
 msgstr "visa antal träffar istället för träffade rader"
 
-#: builtin/grep.c:780
+#: builtin/grep.c:781
 msgid "highlight matches"
 msgstr "ljusmarkera träffar"
 
-#: builtin/grep.c:782
+#: builtin/grep.c:783
 msgid "print empty line between matches from different files"
 msgstr "skriv tomma rader mellan träffar från olika filer"
 
-#: builtin/grep.c:784
+#: builtin/grep.c:785
 msgid "show filename only once above matches from same file"
 msgstr "visa filnamn endast en gång ovanför träffar från samma fil"
 
-#: builtin/grep.c:787
+#: builtin/grep.c:788
 msgid "show <n> context lines before and after matches"
 msgstr "visa <n> rader sammanhang före och efter träffar"
 
-#: builtin/grep.c:790
+#: builtin/grep.c:791
 msgid "show <n> context lines before matches"
 msgstr "visa <n> rader sammanhang före träffar"
 
-#: builtin/grep.c:792
+#: builtin/grep.c:793
 msgid "show <n> context lines after matches"
 msgstr "visa <n> rader sammanhang efter träffar"
 
-#: builtin/grep.c:793
+#: builtin/grep.c:794
 msgid "shortcut for -C NUM"
 msgstr "genväg för -C NUM"
 
-#: builtin/grep.c:796
+#: builtin/grep.c:797
 msgid "show a line with the function name before matches"
 msgstr "visa en rad med funktionsnamnet före träffen"
 
-#: builtin/grep.c:798
+#: builtin/grep.c:799
 msgid "show the surrounding function"
 msgstr "visa den omkringliggande funktionen"
 
-#: builtin/grep.c:801
+#: builtin/grep.c:802
 msgid "read patterns from file"
 msgstr "läs mönster från fil"
 
-#: builtin/grep.c:803
+#: builtin/grep.c:804
 msgid "match <pattern>"
 msgstr "träffa <mönster>"
 
-#: builtin/grep.c:805
+#: builtin/grep.c:806
 msgid "combine patterns specified with -e"
 msgstr "kombinera mönster som anges med -e"
 
-#: builtin/grep.c:817
+#: builtin/grep.c:818
 msgid "indicate hit with exit status without output"
 msgstr "ange träff med slutstatuskod utan utdata"
 
-#: builtin/grep.c:819
+#: builtin/grep.c:820
 msgid "show only matches from files that match all patterns"
 msgstr "visa endast träffar från filer som träffar alla mönster"
 
 #: builtin/grep.c:822
+msgid "show parse tree for grep expression"
+msgstr "visa analysträd för grep-uttryck"
+
+#: builtin/grep.c:826
 msgid "pager"
 msgstr "bläddrare"
 
-#: builtin/grep.c:822
+#: builtin/grep.c:826
 msgid "show matching files in the pager"
 msgstr "visa träffade filer i filbläddraren"
 
-#: builtin/grep.c:825
+#: builtin/grep.c:829
 msgid "allow calling of grep(1) (ignored by this build)"
 msgstr "tillåt anropa grep(1) (ignoreras av detta bygge)"
 
-#: builtin/grep.c:826 builtin/show-ref.c:201
+#: builtin/grep.c:830 builtin/show-ref.c:201
 msgid "show usage"
 msgstr "visa användning"
 
-#: builtin/grep.c:917
+#: builtin/grep.c:921
 msgid "no pattern given."
 msgstr "inget mönster angavs."
 
-#: builtin/grep.c:931
+#: builtin/grep.c:935
 #, c-format
 msgid "bad object %s"
 msgstr "felaktigt objekt %s"
 
-#: builtin/grep.c:972
+#: builtin/grep.c:976
 msgid "--open-files-in-pager only works on the worktree"
 msgstr "--open-files-in-pager fungerar endast i arbetskatalogen"
 
-#: builtin/grep.c:995
+#: builtin/grep.c:999
 msgid "--cached or --untracked cannot be used with --no-index."
 msgstr "--cached och --untracked kan inte användas med --no-index."
 
-#: builtin/grep.c:1000
+#: builtin/grep.c:1004
 msgid "--no-index or --untracked cannot be used with revs."
 msgstr "--no-index och --untracked kan inte användas med revisioner."
 
-#: builtin/grep.c:1003
+#: builtin/grep.c:1007
 msgid "--[no-]exclude-standard cannot be used for tracked contents."
 msgstr "--[no-]exclude-standard kan inte användas för spårat innehåll."
 
-#: builtin/grep.c:1011
+#: builtin/grep.c:1015
 msgid "both --cached and trees are given."
 msgstr "både --cached och träd angavs."
 
@@ -5718,7 +5690,7 @@ msgstr "tillåt snabbspolning (standard)"
 msgid "abort if fast-forward is not possible"
 msgstr "avbryt om snabbspolning inte är möjlig"
 
-#: builtin/merge.c:202 builtin/notes.c:867 builtin/revert.c:112
+#: builtin/merge.c:202 builtin/notes.c:870 builtin/revert.c:112
 msgid "strategy"
 msgstr "strategi"
 
@@ -6181,11 +6153,11 @@ msgstr "läs från standard in"
 msgid "allow to print `undefined` names"
 msgstr "tillåt att skriva \"odefinierade\" namn"
 
-#: builtin/notes.c:23
+#: builtin/notes.c:26
 msgid "git notes [--ref <notes_ref>] [list [<object>]]"
 msgstr "git notes [--ref <anteckningsref>] [list [<objekt>]]"
 
-#: builtin/notes.c:24
+#: builtin/notes.c:27
 msgid ""
 "git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) "
 "<object>] [<object>]"
@@ -6193,12 +6165,12 @@ msgstr ""
 "git notes [--ref <anteckningsref>] add [-f] [-m <medd> | -F <fil> | (-c | -"
 "C) <objekt>] [<objekt>]"
 
-#: builtin/notes.c:25
+#: builtin/notes.c:28
 msgid "git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>"
 msgstr ""
 "git notes [--ref <anteckningsref>] copy [-f] <från-objekt> <till-objekt>"
 
-#: builtin/notes.c:26
+#: builtin/notes.c:29
 msgid ""
 "git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) "
 "<object>] [<object>]"
@@ -6206,226 +6178,226 @@ msgstr ""
 "git notes [--ref <anteckningsref>] append [-m <medd> | -F <fil> | (-c | -C) "
 "<objekt>] [<objekt>]"
 
-#: builtin/notes.c:27
+#: builtin/notes.c:30
 msgid "git notes [--ref <notes_ref>] edit [<object>]"
 msgstr "git notes [--ref <anteckningsref>] edit [<objekt>]"
 
-#: builtin/notes.c:28
+#: builtin/notes.c:31
 msgid "git notes [--ref <notes_ref>] show [<object>]"
 msgstr "git notes [--ref <anteckningsref>] show [<objekt>]"
 
-#: builtin/notes.c:29
+#: builtin/notes.c:32
 msgid ""
 "git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>"
 msgstr ""
 "git notes [--ref <anteckningsref>] merge [-v | -q] [-s <strategi> ] "
 "<anteckningsref>"
 
-#: builtin/notes.c:30
+#: builtin/notes.c:33
 msgid "git notes merge --commit [-v | -q]"
 msgstr "git notes merge --commit [-v | -q]"
 
-#: builtin/notes.c:31
+#: builtin/notes.c:34
 msgid "git notes merge --abort [-v | -q]"
 msgstr "git notes merge --abort [-v | -q]"
 
-#: builtin/notes.c:32
+#: builtin/notes.c:35
 msgid "git notes [--ref <notes_ref>] remove [<object>...]"
 msgstr "git notes [--ref <anteckningsref>] remove [<objekt>...]"
 
-#: builtin/notes.c:33
+#: builtin/notes.c:36
 msgid "git notes [--ref <notes_ref>] prune [-n | -v]"
 msgstr "git notes [--ref <anteckningsref>] prune [-n | -v]"
 
-#: builtin/notes.c:34
+#: builtin/notes.c:37
 msgid "git notes [--ref <notes_ref>] get-ref"
 msgstr "git notes [--ref <anteckningsref>] get-ref"
 
-#: builtin/notes.c:39
+#: builtin/notes.c:42
 msgid "git notes [list [<object>]]"
 msgstr "git notes [list [<objekt>]]"
 
-#: builtin/notes.c:44
+#: builtin/notes.c:47
 msgid "git notes add [<options>] [<object>]"
 msgstr "git notes add [<flaggor>] [<objekt>]"
 
-#: builtin/notes.c:49
+#: builtin/notes.c:52
 msgid "git notes copy [<options>] <from-object> <to-object>"
 msgstr "git notes copy [<flaggor>] <från-objekt> <till-objekt>"
 
-#: builtin/notes.c:50
+#: builtin/notes.c:53
 msgid "git notes copy --stdin [<from-object> <to-object>]..."
 msgstr "git notes copy --stdin [<från-objekt> <till-objekt>]..."
 
-#: builtin/notes.c:55
+#: builtin/notes.c:58
 msgid "git notes append [<options>] [<object>]"
 msgstr "git notes append [<flaggor>] [<objekt>]"
 
-#: builtin/notes.c:60
+#: builtin/notes.c:63
 msgid "git notes edit [<object>]"
 msgstr "git notes edit [<objekt>]"
 
-#: builtin/notes.c:65
+#: builtin/notes.c:68
 msgid "git notes show [<object>]"
 msgstr "git notes show [<objekt>]"
 
-#: builtin/notes.c:70
+#: builtin/notes.c:73
 msgid "git notes merge [<options>] <notes_ref>"
 msgstr "git notes merge [<flaggor>] <anteckningsref>"
 
-#: builtin/notes.c:71
+#: builtin/notes.c:74
 msgid "git notes merge --commit [<options>]"
 msgstr "git notes merge --commit [<flaggor>]"
 
-#: builtin/notes.c:72
+#: builtin/notes.c:75
 msgid "git notes merge --abort [<options>]"
 msgstr "git notes merge --abort [<flaggor>]"
 
-#: builtin/notes.c:77
+#: builtin/notes.c:80
 msgid "git notes remove [<object>]"
 msgstr "git notes remove [<objekt>]"
 
-#: builtin/notes.c:82
+#: builtin/notes.c:85
 msgid "git notes prune [<options>]"
 msgstr "git notes prune [<flaggor>]"
 
-#: builtin/notes.c:87
+#: builtin/notes.c:90
 msgid "git notes get-ref"
 msgstr "git notes get-ref"
 
-#: builtin/notes.c:139
+#: builtin/notes.c:142
 #, c-format
 msgid "unable to start 'show' for object '%s'"
 msgstr "kunde inte starta \"show\" för objektet \"%s\""
 
-#: builtin/notes.c:145
+#: builtin/notes.c:148
 msgid "can't fdopen 'show' output fd"
 msgstr "kunde inte öppna (fdopen) \"show\"-utdata-filhandtag"
 
-#: builtin/notes.c:155
+#: builtin/notes.c:158
 #, c-format
 msgid "failed to close pipe to 'show' for object '%s'"
 msgstr "kunde inte stänga röret till \"show\" för objektet \"%s\""
 
-#: builtin/notes.c:158
+#: builtin/notes.c:161
 #, c-format
 msgid "failed to finish 'show' for object '%s'"
 msgstr "kunde inte avsluta \"show\" för objektet \"%s\""
 
-#: builtin/notes.c:175 builtin/tag.c:347
+#: builtin/notes.c:178 builtin/tag.c:347
 #, c-format
 msgid "could not create file '%s'"
 msgstr "kunde inte skapa filen \"%s\""
 
-#: builtin/notes.c:189
+#: builtin/notes.c:192
 msgid "Please supply the note contents using either -m or -F option"
 msgstr "Ange innehåll för anteckningen med antingen -m eller -F"
 
-#: builtin/notes.c:210 builtin/notes.c:973
+#: builtin/notes.c:213 builtin/notes.c:976
 #, c-format
 msgid "Removing note for object %s\n"
 msgstr "Tar bort anteckning för objektet %s\n"
 
-#: builtin/notes.c:215
+#: builtin/notes.c:218
 msgid "unable to write note object"
 msgstr "kunde inte skriva anteckningsobjekt"
 
-#: builtin/notes.c:217
+#: builtin/notes.c:220
 #, c-format
 msgid "The note contents has been left in %s"
 msgstr "Anteckningens innehåll har lämnats kvar i %s"
 
-#: builtin/notes.c:251 builtin/tag.c:542
+#: builtin/notes.c:254 builtin/tag.c:542
 #, c-format
 msgid "cannot read '%s'"
 msgstr "kunde inte läsa \"%s\""
 
-#: builtin/notes.c:253 builtin/tag.c:545
+#: builtin/notes.c:256 builtin/tag.c:545
 #, c-format
 msgid "could not open or read '%s'"
 msgstr "kunde inte öppna eller läsa \"%s\""
 
-#: builtin/notes.c:272 builtin/notes.c:445 builtin/notes.c:447
-#: builtin/notes.c:507 builtin/notes.c:561 builtin/notes.c:644
-#: builtin/notes.c:649 builtin/notes.c:724 builtin/notes.c:766
-#: builtin/notes.c:968 builtin/reset.c:293 builtin/tag.c:558
+#: builtin/notes.c:275 builtin/notes.c:448 builtin/notes.c:450
+#: builtin/notes.c:510 builtin/notes.c:564 builtin/notes.c:647
+#: builtin/notes.c:652 builtin/notes.c:727 builtin/notes.c:769
+#: builtin/notes.c:971 builtin/reset.c:293 builtin/tag.c:558
 #, c-format
 msgid "Failed to resolve '%s' as a valid ref."
 msgstr "Kunde inte slå upp \"%s\" som en giltig referens."
 
-#: builtin/notes.c:275
+#: builtin/notes.c:278
 #, c-format
 msgid "Failed to read object '%s'."
 msgstr "Kunde inte läsa objektet \"%s\"."
 
-#: builtin/notes.c:299
+#: builtin/notes.c:302
 msgid "Cannot commit uninitialized/unreferenced notes tree"
 msgstr "Kan inte checka in oinitierat/orefererat anteckningsträd"
 
-#: builtin/notes.c:340
+#: builtin/notes.c:343
 #, c-format
 msgid "Bad notes.rewriteMode value: '%s'"
 msgstr "Felaktigt värde för notes.rewriteMode: '%s'"
 
-#: builtin/notes.c:350
+#: builtin/notes.c:353
 #, c-format
 msgid "Refusing to rewrite notes in %s (outside of refs/notes/)"
 msgstr "Vägrar skriva över anteckningar i %s (utanför refs/notes/)"
 
 #. TRANSLATORS: The first %s is the name of the
 #. environment variable, the second %s is its value
-#: builtin/notes.c:377
+#: builtin/notes.c:380
 #, c-format
 msgid "Bad %s value: '%s'"
 msgstr "Felaktigt värde på %s: \"%s\""
 
-#: builtin/notes.c:441
+#: builtin/notes.c:444
 #, c-format
 msgid "Malformed input line: '%s'."
 msgstr "Felaktig indatarad: \"%s\"."
 
-#: builtin/notes.c:456
+#: builtin/notes.c:459
 #, c-format
 msgid "Failed to copy notes from '%s' to '%s'"
 msgstr "Misslyckades kopiera anteckningar från \"%s\" till \"%s\""
 
-#: builtin/notes.c:500 builtin/notes.c:554 builtin/notes.c:627
-#: builtin/notes.c:639 builtin/notes.c:712 builtin/notes.c:759
-#: builtin/notes.c:1033
+#: builtin/notes.c:503 builtin/notes.c:557 builtin/notes.c:630
+#: builtin/notes.c:642 builtin/notes.c:715 builtin/notes.c:762
+#: builtin/notes.c:1036
 msgid "too many parameters"
 msgstr "för många parametrar"
 
-#: builtin/notes.c:513 builtin/notes.c:772
+#: builtin/notes.c:516 builtin/notes.c:775
 #, c-format
 msgid "No note found for object %s."
 msgstr "Inga anteckningar hittades för objektet %s."
 
-#: builtin/notes.c:535 builtin/notes.c:692
+#: builtin/notes.c:538 builtin/notes.c:695
 msgid "note contents as a string"
 msgstr "anteckningsinnehåll som sträng"
 
-#: builtin/notes.c:538 builtin/notes.c:695
+#: builtin/notes.c:541 builtin/notes.c:698
 msgid "note contents in a file"
 msgstr "anteckningsinnehåll i en fil"
 
-#: builtin/notes.c:540 builtin/notes.c:543 builtin/notes.c:697
-#: builtin/notes.c:700 builtin/tag.c:476
+#: builtin/notes.c:543 builtin/notes.c:546 builtin/notes.c:700
+#: builtin/notes.c:703 builtin/tag.c:476
 msgid "object"
 msgstr "objekt"
 
-#: builtin/notes.c:541 builtin/notes.c:698
+#: builtin/notes.c:544 builtin/notes.c:701
 msgid "reuse and edit specified note object"
 msgstr "återanvänd och redigera angivet anteckningsobjekt"
 
-#: builtin/notes.c:544 builtin/notes.c:701
+#: builtin/notes.c:547 builtin/notes.c:704
 msgid "reuse specified note object"
 msgstr "återanvänd angivet anteckningsobjekt"
 
-#: builtin/notes.c:546 builtin/notes.c:614
+#: builtin/notes.c:549 builtin/notes.c:617
 msgid "replace existing notes"
 msgstr "ersätt befintliga anteckningar"
 
-#: builtin/notes.c:580
+#: builtin/notes.c:583
 #, c-format
 msgid ""
 "Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite "
@@ -6434,24 +6406,24 @@ msgstr ""
 "Kan inte lägga till anteckningar. Hittade befintliga anteckningar för "
 "objektet %s. Använd \"-f\" för att skriva över befintliga anteckningar"
 
-#: builtin/notes.c:585 builtin/notes.c:662
+#: builtin/notes.c:588 builtin/notes.c:665
 #, c-format
 msgid "Overwriting existing notes for object %s\n"
 msgstr "Skriver över befintliga anteckningar för objektet %s\n"
 
-#: builtin/notes.c:615
+#: builtin/notes.c:618
 msgid "read objects from stdin"
 msgstr "läs objekt från standard in"
 
-#: builtin/notes.c:617
+#: builtin/notes.c:620
 msgid "load rewriting config for <command> (implies --stdin)"
 msgstr "läs omskrivningsinställning för <kommando> (implicerar --stdin)"
 
-#: builtin/notes.c:635
+#: builtin/notes.c:638
 msgid "too few parameters"
 msgstr "för få parametrar"
 
-#: builtin/notes.c:656
+#: builtin/notes.c:659
 #, c-format
 msgid ""
 "Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite "
@@ -6460,12 +6432,12 @@ msgstr ""
 "Kan inte kopiera anteckningar. Hittade befintliga anteckningar för objektet "
 "%s. Använd \"-f\" för att skriva över befintliga anteckningar"
 
-#: builtin/notes.c:668
+#: builtin/notes.c:671
 #, c-format
 msgid "Missing notes on source object %s. Cannot copy."
 msgstr "Anteckningar på källobjektet %s saknas. Kan inte kopiera."
 
-#: builtin/notes.c:717
+#: builtin/notes.c:720
 #, c-format
 msgid ""
 "The -m/-F/-c/-C options have been deprecated for the 'edit' subcommand.\n"
@@ -6474,15 +6446,15 @@ msgstr ""
 "Flaggorna -m/-F/-c/-C rekommenderas inte för underkommandot \"edit\".\n"
 "Använd \"git notes add -f -m/-F/-c/-C\" istället.\n"
 
-#: builtin/notes.c:864
+#: builtin/notes.c:867
 msgid "General options"
 msgstr "Allmänna flaggor"
 
-#: builtin/notes.c:866
+#: builtin/notes.c:869
 msgid "Merge options"
 msgstr "Flaggor för sammanslagning"
 
-#: builtin/notes.c:868
+#: builtin/notes.c:871
 msgid ""
 "resolve notes conflicts using the given strategy (manual/ours/theirs/union/"
 "cat_sort_uniq)"
@@ -6490,46 +6462,46 @@ msgstr ""
 "läs konflikter i anteckningar med angiven strategi (manual/ours/theirs/union/"
 "cat_sort_uniq)"
 
-#: builtin/notes.c:870
+#: builtin/notes.c:873
 msgid "Committing unmerged notes"
 msgstr "Checkar in ej sammanslagna anteckningar"
 
-#: builtin/notes.c:872
+#: builtin/notes.c:875
 msgid "finalize notes merge by committing unmerged notes"
 msgstr ""
 "färdigställ sammanslagning av anteckningar genom att checka in ej "
 "sammanslagna anteckningar"
 
-#: builtin/notes.c:874
+#: builtin/notes.c:877
 msgid "Aborting notes merge resolution"
 msgstr "Avbryt lösning av sammanslagning av anteckningar"
 
-#: builtin/notes.c:876
+#: builtin/notes.c:879
 msgid "abort notes merge"
 msgstr "avbryt sammanslagning av anteckningar"
 
-#: builtin/notes.c:971
+#: builtin/notes.c:974
 #, c-format
 msgid "Object %s has no note\n"
 msgstr "Objektet %s har ingen anteckning\n"
 
-#: builtin/notes.c:983
+#: builtin/notes.c:986
 msgid "attempt to remove non-existent note is not an error"
 msgstr "försök att ta bort icke-existerande anteckningar är inte ett fel"
 
-#: builtin/notes.c:986
+#: builtin/notes.c:989
 msgid "read object names from the standard input"
 msgstr "läs objektnamn från standard in"
 
-#: builtin/notes.c:1067
+#: builtin/notes.c:1070
 msgid "notes_ref"
 msgstr "anteckningar-ref"
 
-#: builtin/notes.c:1068
+#: builtin/notes.c:1071
 msgid "use notes from <notes_ref>"
 msgstr "använd anteckningar från <anteckningsref>"
 
-#: builtin/notes.c:1103 builtin/remote.c:1598
+#: builtin/notes.c:1106 builtin/remote.c:1598
 #, c-format
 msgid "Unknown subcommand: %s"
 msgstr "Okänt underkommando: %s"
@@ -8935,7 +8907,7 @@ msgstr "Kan inte slå ihop flera grenar i ett tomt huvud."
 msgid "Cannot rebase onto multiple branches"
 msgstr "Kan inte utföra en \"rebase\" ovanpå flera grenar"
 
-#: git-rebase.sh:52
+#: git-rebase.sh:53
 msgid ""
 "When you have resolved this problem, run \"git rebase --continue\".\n"
 "If you prefer to skip this patch, run \"git rebase --skip\" instead.\n"
@@ -8946,27 +8918,31 @@ msgstr ""
 "Om du vill hoppa över patchen kör du istället \"git rebase --skip\".\n"
 "För att återställa originalgrenen och avbryta kör du \"git rebase --abort\"."
 
-#: git-rebase.sh:159
+#: git-rebase.sh:160
 msgid "The pre-rebase hook refused to rebase."
 msgstr "Kroken pre-rebase vägrade ombaseringen."
 
-#: git-rebase.sh:164
+#: git-rebase.sh:165
 msgid "It looks like git-am is in progress. Cannot rebase."
 msgstr "Det verkar som en git-am körs. Kan inte ombasera."
 
-#: git-rebase.sh:295
+#: git-rebase.sh:296
 msgid "The --exec option must be used with the --interactive option"
 msgstr "Flaggan --exec måste användas tillsammans med flaggan --interactive"
 
-#: git-rebase.sh:300
+#: git-rebase.sh:301
 msgid "No rebase in progress?"
 msgstr "Ingen ombasering pågår?"
 
-#: git-rebase.sh:313
+#: git-rebase.sh:312
+msgid "The --edit-todo action can only be used during interactive rebase."
+msgstr "Åtgärden --edit-todo kan endast användas under interaktiv ombasering."
+
+#: git-rebase.sh:319
 msgid "Cannot read HEAD"
 msgstr "Kan inte läsa HEAD"
 
-#: git-rebase.sh:316
+#: git-rebase.sh:322
 msgid ""
 "You must edit all merge conflicts and then\n"
 "mark them as resolved using git add"
@@ -8974,12 +8950,12 @@ msgstr ""
 "Du måste redigera alla sammanslagningskonflikter och\n"
 "därefter markera dem som lösta med git add"
 
-#: git-rebase.sh:334
+#: git-rebase.sh:340
 #, sh-format
 msgid "Could not move back to $head_name"
 msgstr "Kunde inte flytta tillbaka till $head_name"
 
-#: git-rebase.sh:350
+#: git-rebase.sh:359
 #, sh-format
 msgid ""
 "It seems that there is already a $state_dir_base directory, and\n"
@@ -9000,57 +8976,57 @@ msgstr ""
 "och kör programmet igen. Jag avslutar ifall du fortfarande har\n"
 "något av värde där."
 
-#: git-rebase.sh:395
+#: git-rebase.sh:404
 #, sh-format
 msgid "invalid upstream $upstream_name"
 msgstr "ogiltig uppström $upstream_name"
 
-#: git-rebase.sh:419
+#: git-rebase.sh:428
 #, sh-format
 msgid "$onto_name: there are more than one merge bases"
 msgstr "$onto_name: mer än en sammanslagningsbas finns"
 
-#: git-rebase.sh:422 git-rebase.sh:426
+#: git-rebase.sh:431 git-rebase.sh:435
 #, sh-format
 msgid "$onto_name: there is no merge base"
 msgstr "$onto_name: ingen sammanslagningsbas finns"
 
-#: git-rebase.sh:431
+#: git-rebase.sh:440
 #, sh-format
 msgid "Does not point to a valid commit: $onto_name"
 msgstr "Peka på en giltig incheckning: $onto_name"
 
-#: git-rebase.sh:454
+#: git-rebase.sh:463
 #, sh-format
 msgid "fatal: no such branch: $branch_name"
 msgstr "ödesdigert: ingen sådan gren: $branch_name"
 
-#: git-rebase.sh:474
+#: git-rebase.sh:483
 msgid "Please commit or stash them."
 msgstr "Checka in eller använd \"stash\" på dem."
 
-#: git-rebase.sh:492
+#: git-rebase.sh:501
 #, sh-format
 msgid "Current branch $branch_name is up to date."
 msgstr "Aktuell gren $branch_name är à jour."
 
-#: git-rebase.sh:495
+#: git-rebase.sh:504
 #, sh-format
 msgid "Current branch $branch_name is up to date, rebase forced."
 msgstr "Aktuell gren $branch_name är à jour, ombasering framtvingad."
 
-#: git-rebase.sh:506
+#: git-rebase.sh:515
 #, sh-format
 msgid "Changes from $mb to $onto:"
 msgstr "Ändringar från $mb till $onto:"
 
 #. Detach HEAD and reset the tree
-#: git-rebase.sh:515
+#: git-rebase.sh:524
 msgid "First, rewinding head to replay your work on top of it..."
 msgstr ""
 "Först, spolar tillbaka huvudet för att spela av ditt arbete ovanpå det..."
 
-#: git-rebase.sh:523
+#: git-rebase.sh:532
 #, sh-format
 msgid "Fast-forwarded $branch_name to $onto_name."
 msgstr "Snabbspolade $branch_name till $onto_name."
@@ -9379,6 +9355,27 @@ msgstr "# Undermodulers ändringar att checka in:"
 msgid "Synchronizing submodule url for '$name'"
 msgstr "Synkroniserar undermodul-url för \"$name\""
 
+#~ msgid " 0 files changed"
+#~ msgstr " 0 filer ändrade"
+
+#~ msgid " %d file changed"
+#~ msgid_plural " %d files changed"
+#~ msgstr[0] " %d fil ändrad"
+#~ msgstr[1] " %d filer ändrade"
+
+#~ msgid ", %d insertion(+)"
+#~ msgid_plural ", %d insertions(+)"
+#~ msgstr[0] ", %d tillägg(+)"
+#~ msgstr[1] ", %d tillägg(+)"
+
+#~ msgid ", %d deletion(-)"
+#~ msgid_plural ", %d deletions(-)"
+#~ msgstr[0] ", %d borttagning(-)"
+#~ msgstr[1] ", %d borttagningar(-)"
+
+#~ msgid "Auto packing the repository for optimum performance.\n"
+#~ msgstr "Packar arkivet automatiskt för optimal prestanda.\n"
+
 #~ msgid " (use \"git add\" to track)"
 #~ msgstr " (spåra med \"git add\")"
 
index 1fca3217286a642d69d54634649228bfb1a4fa22..ca617a3ca087db1cde72adf060b24c71dbef11cf 100644 (file)
--- a/po/vi.po
+++ b/po/vi.po
@@ -6,10 +6,10 @@
 #
 msgid ""
 msgstr ""
-"Project-Id-Version: git-v1.7.12-437-g1084f\n"
+"Project-Id-Version: git-v1.8.0-rc2-4-g42e55\n"
 "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2012-09-15 10:21+0800\n"
-"PO-Revision-Date: 2012-10-15 14:34+0700\n"
+"POT-Creation-Date: 2012-10-16 08:38+0800\n"
+"PO-Revision-Date: 2012-10-17 08:09+0700\n"
 "Last-Translator: Trần Ngọc Quân <vnwildman@gmail.com>\n"
 "Language-Team: Vietnamese <translation-team-vi@lists.sourceforge.net>\n"
 "Language: vi\n"
@@ -37,9 +37,9 @@ msgid ""
 "or use 'git commit -a'."
 msgstr ""
 "Sửa chúng trong cây làm việc,\n"
-"và sau đó dùng lệnh 'git add/rm <tập-tin>'\n"
+"và sau đó dùng lệnh `git add/rm <tập-tin>'\n"
 "dành riêng cho việc đánh dấu cần giải quyết và tạo lần chuyển giao,\n"
-"hoặc là dùng lệnh 'git commit -a'."
+"hoặc là dùng lệnh `git commit -a'."
 
 #: archive.c:10
 msgid "git archive [options] <tree-ish> [<path>...]"
@@ -76,11 +76,11 @@ msgstr "tiền tố"
 msgid "prepend prefix to each pathname in the archive"
 msgstr "nối thêm tiền tố vào từng đường dẫn tập tin trong kho lưu"
 
-#: archive.c:325 builtin/archive.c:91 builtin/blame.c:2332
-#: builtin/blame.c:2333 builtin/config.c:56 builtin/fast-export.c:642
-#: builtin/fast-export.c:644 builtin/grep.c:800 builtin/hash-object.c:77
-#: builtin/ls-files.c:494 builtin/ls-files.c:497 builtin/notes.c:537
-#: builtin/notes.c:694 builtin/read-tree.c:107 parse-options.h:149
+#: archive.c:325 builtin/archive.c:91 builtin/blame.c:2389
+#: builtin/blame.c:2390 builtin/config.c:56 builtin/fast-export.c:642
+#: builtin/fast-export.c:644 builtin/grep.c:801 builtin/hash-object.c:77
+#: builtin/ls-files.c:494 builtin/ls-files.c:497 builtin/notes.c:540
+#: builtin/notes.c:697 builtin/read-tree.c:107 parse-options.h:149
 msgid "file"
 msgstr "tập-tin"
 
@@ -120,7 +120,7 @@ msgstr "kho"
 msgid "retrieve the archive from remote repository <repo>"
 msgstr "nhận kho lưu từ kho chứa <kho> trên máy chủ"
 
-#: archive.c:346 builtin/archive.c:95 builtin/notes.c:616
+#: archive.c:346 builtin/archive.c:95 builtin/notes.c:619
 msgid "command"
 msgstr "lệnh"
 
@@ -138,7 +138,7 @@ msgstr "`%s' không giống như tập tin v2 bundle (cụm)"
 msgid "unrecognized header: %s%s (%d)"
 msgstr "phần đầu (header) không được thừa nhận: %s%s (%d)"
 
-#: bundle.c:89 builtin/commit.c:714
+#: bundle.c:89 builtin/commit.c:672
 #, c-format
 msgid "could not open '%s'"
 msgstr "không thể mở `%s'"
@@ -147,7 +147,7 @@ msgstr "không thể mở `%s'"
 msgid "Repository lacks these prerequisite commits:"
 msgstr "Khó chứa thiếu những lần chuyển giao (commit) cần trước hết này:"
 
-#: bundle.c:164 sequencer.c:557 sequencer.c:989 builtin/log.c:290
+#: bundle.c:164 sequencer.c:562 sequencer.c:994 builtin/log.c:290
 #: builtin/log.c:727 builtin/log.c:1313 builtin/log.c:1529 builtin/merge.c:347
 #: builtin/shortlog.c:181
 msgid "revision walk setup failed"
@@ -206,12 +206,12 @@ msgstr "không thể tạo `%s'"
 msgid "index-pack died"
 msgstr "index-pack đã chết"
 
-#: commit.c:48
+#: commit.c:50
 #, c-format
 msgid "could not parse %s"
 msgstr "không thể phân tích %s"
 
-#: commit.c:50
+#: commit.c:52
 #, c-format
 msgid "%s %s is not a commit!"
 msgstr "%s %s không phải là một lần commit!"
@@ -222,7 +222,7 @@ msgstr "cạn bộ nhớ"
 
 #: connected.c:39
 msgid "Could not run 'git rev-list'"
-msgstr "Không thể chạy 'git rev-list'"
+msgstr "Không thể chạy `git rev-list'"
 
 #: connected.c:48
 #, c-format
@@ -320,32 +320,7 @@ msgstr ""
 "Tìm thấy các lỗi trong biến cấu hình 'diff.dirstat':\n"
 "%s"
 
-#: diff.c:1401
-msgid " 0 files changed"
-msgstr " 0 có tập tin nào thay đổi cả"
-
-#: diff.c:1405
-#, c-format
-msgid " %d file changed"
-msgid_plural " %d files changed"
-msgstr[0] " %d tập tin thay đổi"
-msgstr[1] " %d tập tin thay đổi"
-
-#: diff.c:1422
-#, c-format
-msgid ", %d insertion(+)"
-msgid_plural ", %d insertions(+)"
-msgstr[0] ", %d thêm(+)"
-msgstr[1] ", %d thêm(+)"
-
-#: diff.c:1433
-#, c-format
-msgid ", %d deletion(-)"
-msgid_plural ", %d deletions(-)"
-msgstr[0] ", %d xóa(-)"
-msgstr[1] ", %d xóa(-)"
-
-#: diff.c:3460
+#: diff.c:3458
 #, c-format
 msgid ""
 "Failed to parse --dirstat/-X option parameter:\n"
@@ -366,17 +341,17 @@ msgstr "gpg đã không đồng ý dữ liệu"
 msgid "gpg failed to sign the data"
 msgstr "gpg gặp lỗi khi ký dữ liệu"
 
-#: grep.c:1320
+#: grep.c:1441
 #, c-format
 msgid "'%s': unable to read %s"
 msgstr "`%s': không thể đọc %s"
 
-#: grep.c:1337
+#: grep.c:1458
 #, c-format
 msgid "'%s': %s"
 msgstr "`%s': %s"
 
-#: grep.c:1348
+#: grep.c:1469
 #, c-format
 msgid "'%s': short read %s"
 msgstr "`%s': đọc ngắn %s"
@@ -748,103 +723,103 @@ msgstr[1] ""
 "Your branch and `%s' have diverged,\n"
 "and have %d and %d different commit each, respectively.\n"
 
-#: sequencer.c:121 builtin/merge.c:864 builtin/merge.c:977
+#: sequencer.c:123 builtin/merge.c:864 builtin/merge.c:977
 #: builtin/merge.c:1087 builtin/merge.c:1097
 #, c-format
 msgid "Could not open '%s' for writing"
 msgstr "Không thể mở %s' để ghi"
 
-#: sequencer.c:123 builtin/merge.c:333 builtin/merge.c:867
+#: sequencer.c:125 builtin/merge.c:333 builtin/merge.c:867
 #: builtin/merge.c:1089 builtin/merge.c:1102
 #, c-format
 msgid "Could not write to '%s'"
 msgstr "Không thể ghi vào `%s'"
 
-#: sequencer.c:144
+#: sequencer.c:146
 msgid ""
 "after resolving the conflicts, mark the corrected paths\n"
 "with 'git add <paths>' or 'git rm <paths>'"
 msgstr ""
 "sau khi giải quyết các xung đột, đánh dấu đường dẫn đã sửa\n"
-"với lệnh 'git add <đường_dẫn>' hoặc 'git rm <đường_dẫn>'"
+"với lệnh `git add <đường_dẫn>' hoặc `git rm <đường_dẫn>'"
 
-#: sequencer.c:147
+#: sequencer.c:149
 msgid ""
 "after resolving the conflicts, mark the corrected paths\n"
 "with 'git add <paths>' or 'git rm <paths>'\n"
 "and commit the result with 'git commit'"
 msgstr ""
 "sau khi giải quyết các xung đột, đánh dấu đường dẫn đã sửa\n"
-"với lệnh 'git add <đường_dẫn>' hoặc 'git rm <đường_dẫn>'\n"
-"và chuyển giao (commit) kết quả bằng lệnh 'git commit'"
+"với lệnh `git add <đường_dẫn>' hoặc `git rm <đường_dẫn>'\n"
+"và chuyển giao (commit) kết quả bằng lệnh `git commit'"
 
-#: sequencer.c:160 sequencer.c:765 sequencer.c:848
+#: sequencer.c:162 sequencer.c:770 sequencer.c:853
 #, c-format
 msgid "Could not write to %s"
 msgstr "Không thể ghi vào %s"
 
-#: sequencer.c:163
+#: sequencer.c:165
 #, c-format
 msgid "Error wrapping up %s"
 msgstr "Lỗi bao bọc %s"
 
-#: sequencer.c:178
+#: sequencer.c:180
 msgid "Your local changes would be overwritten by cherry-pick."
 msgstr "Các thay đổi nội bộ của bạn có thể bị ghi đè bởi lệnh cherry-pick."
 
-#: sequencer.c:180
+#: sequencer.c:182
 msgid "Your local changes would be overwritten by revert."
 msgstr "Các thay đổi nội bộ của bạn có thể bị ghi đè bởi lệnh revert."
 
-#: sequencer.c:183
+#: sequencer.c:185
 msgid "Commit your changes or stash them to proceed."
 msgstr "Chuyển giao (commit) các thay đổi của bạn hay stash chúng để xử lý."
 
 #. TRANSLATORS: %s will be "revert" or "cherry-pick"
-#: sequencer.c:233
+#: sequencer.c:235
 #, c-format
 msgid "%s: Unable to write new index file"
 msgstr "%s: Không thể ghi tập tin lưu bảng mục lục mới"
 
-#: sequencer.c:261
+#: sequencer.c:266
 msgid "Could not resolve HEAD commit\n"
 msgstr "Không thể phân giải commit (lần chuyển giao) HEAD\n"
 
-#: sequencer.c:282
+#: sequencer.c:287
 msgid "Unable to update cache tree\n"
 msgstr "Không thể cập nhật cây bộ nhớ đệm\n"
 
-#: sequencer.c:327
+#: sequencer.c:332
 #, c-format
 msgid "Could not parse commit %s\n"
 msgstr "Không thể phân tích commit (lần chuyển giao) %s\n"
 
-#: sequencer.c:332
+#: sequencer.c:337
 #, c-format
 msgid "Could not parse parent commit %s\n"
 msgstr "Không thể phân tích commit (lần chuyển giao) cha mẹ %s\n"
 
-#: sequencer.c:398
+#: sequencer.c:403
 msgid "Your index file is unmerged."
 msgstr "Tập tin lưu mục lục của bạn không được hòa trộn."
 
-#: sequencer.c:401
+#: sequencer.c:406
 msgid "You do not have a valid HEAD"
 msgstr "Bạn không có HEAD nào hợp lệ"
 
-#: sequencer.c:416
+#: sequencer.c:421
 #, c-format
 msgid "Commit %s is a merge but no -m option was given."
 msgstr ""
 "Lần chuyển giao (commit) %s là một lần hòa trộn nhưng không đưa ra tùy chọn -"
 "m."
 
-#: sequencer.c:424
+#: sequencer.c:429
 #, c-format
 msgid "Commit %s does not have parent %d"
 msgstr "Lần chuyển giao (commit) %s không có cha mẹ %d"
 
-#: sequencer.c:428
+#: sequencer.c:433
 #, c-format
 msgid "Mainline was specified but commit %s is not a merge."
 msgstr ""
@@ -853,143 +828,143 @@ msgstr ""
 
 #. TRANSLATORS: The first %s will be "revert" or
 #. "cherry-pick", the second %s a SHA1
-#: sequencer.c:439
+#: sequencer.c:444
 #, c-format
 msgid "%s: cannot parse parent commit %s"
 msgstr "%s: không thể phân tích lần chuyển giao mẹ của %s"
 
-#: sequencer.c:443
+#: sequencer.c:448
 #, c-format
 msgid "Cannot get commit message for %s"
 msgstr "Không thể lấy thông điệp lần chuyển giao (commit) cho %s"
 
-#: sequencer.c:527
+#: sequencer.c:532
 #, c-format
 msgid "could not revert %s... %s"
 msgstr "không thể revert %s... %s"
 
-#: sequencer.c:528
+#: sequencer.c:533
 #, c-format
 msgid "could not apply %s... %s"
 msgstr "không thể apply (áp dụng miếng vá) %s... %s"
 
-#: sequencer.c:560
+#: sequencer.c:565
 msgid "empty commit set passed"
 msgstr "lần chuyển giao (commit) trống rỗng đặt là hợp quy cách"
 
-#: sequencer.c:568
+#: sequencer.c:573
 #, c-format
 msgid "git %s: failed to read the index"
 msgstr "git %s: gặp lỗi đọc bảng mục lục"
 
-#: sequencer.c:573
+#: sequencer.c:578
 #, c-format
 msgid "git %s: failed to refresh the index"
 msgstr "git %s: gặp lỗi khi làm tươi mới bảng mục lục"
 
-#: sequencer.c:631
+#: sequencer.c:636
 #, c-format
 msgid "Cannot %s during a %s"
 msgstr "Không thể %s trong khi %s"
 
-#: sequencer.c:653
+#: sequencer.c:658
 #, c-format
 msgid "Could not parse line %d."
 msgstr "Không phân tích được dòng %d."
 
-#: sequencer.c:658
+#: sequencer.c:663
 msgid "No commits parsed."
 msgstr "Không có lần chuyển giao (commit) nào được phân tích."
 
-#: sequencer.c:671
+#: sequencer.c:676
 #, c-format
 msgid "Could not open %s"
 msgstr "Không thể mở %s"
 
-#: sequencer.c:675
+#: sequencer.c:680
 #, c-format
 msgid "Could not read %s."
 msgstr "Không thể đọc %s."
 
-#: sequencer.c:682
+#: sequencer.c:687
 #, c-format
 msgid "Unusable instruction sheet: %s"
 msgstr "Bảng chỉ thị không thể dùng được: %s"
 
-#: sequencer.c:710
+#: sequencer.c:715
 #, c-format
 msgid "Invalid key: %s"
 msgstr "Khóa không đúng: %s"
 
-#: sequencer.c:713
+#: sequencer.c:718
 #, c-format
 msgid "Invalid value for %s: %s"
 msgstr "Giá trị không hợp lệ %s: %s"
 
-#: sequencer.c:725
+#: sequencer.c:730
 #, c-format
 msgid "Malformed options sheet: %s"
 msgstr "Bảng tùy chọn dị hình: %s"
 
-#: sequencer.c:746
+#: sequencer.c:751
 msgid "a cherry-pick or revert is already in progress"
 msgstr "một thao tác cherry-pick hoặc revert đang được thực hiện"
 
-#: sequencer.c:747
+#: sequencer.c:752
 msgid "try \"git cherry-pick (--continue | --quit | --abort)\""
 msgstr "hãy thử \"git cherry-pick (--continue | --quit | --abort)\""
 
-#: sequencer.c:751
+#: sequencer.c:756
 #, c-format
 msgid "Could not create sequencer directory %s"
 msgstr "Không thể tạo thư mục xếp dãy %s"
 
-#: sequencer.c:767 sequencer.c:852
+#: sequencer.c:772 sequencer.c:857
 #, c-format
 msgid "Error wrapping up %s."
 msgstr "Lỗi bao bọc %s."
 
-#: sequencer.c:786 sequencer.c:920
+#: sequencer.c:791 sequencer.c:925
 msgid "no cherry-pick or revert in progress"
 msgstr "không cherry-pick hay revert trong tiến trình"
 
-#: sequencer.c:788
+#: sequencer.c:793
 msgid "cannot resolve HEAD"
 msgstr "không thể phân giải HEAD"
 
-#: sequencer.c:790
+#: sequencer.c:795
 msgid "cannot abort from a branch yet to be born"
 msgstr "không thể hủy bỏ từ một nhánh mà nó còn chưa được tạo ra"
 
-#: sequencer.c:812 builtin/apply.c:4005
+#: sequencer.c:817 builtin/apply.c:4005
 #, c-format
 msgid "cannot open %s: %s"
 msgstr "không thể mở %s: %s"
 
-#: sequencer.c:815
+#: sequencer.c:820
 #, c-format
 msgid "cannot read %s: %s"
 msgstr "không thể đọc %s: %s"
 
-#: sequencer.c:816
+#: sequencer.c:821
 msgid "unexpected end of file"
 msgstr "kết thúc tập tin đột xuất"
 
-#: sequencer.c:822
+#: sequencer.c:827
 #, c-format
 msgid "stored pre-cherry-pick HEAD file '%s' is corrupt"
 msgstr "tập tin HEAD 'pre-cherry-pick' đã lưu `%s' bị hỏng"
 
-#: sequencer.c:845
+#: sequencer.c:850
 #, c-format
 msgid "Could not format %s."
 msgstr "Không thể định dạng %s."
 
-#: sequencer.c:1007
+#: sequencer.c:1012
 msgid "Can't revert as initial commit"
 msgstr "Không thể revert một lần chuyển giao (commit) khởi tạo"
 
-#: sequencer.c:1008
+#: sequencer.c:1013
 msgid "Can't cherry-pick into empty head"
 msgstr "Không thể cherry-pick vào một đầu (head) trống rỗng"
 
@@ -1404,7 +1379,7 @@ msgstr "git add [các-tùy-chọn] [--] <mẫu-tập-tin>..."
 msgid "unexpected diff status %c"
 msgstr "trạng thái lệnh diff không như mong đợi %c"
 
-#: builtin/add.c:67 builtin/commit.c:229
+#: builtin/add.c:67 builtin/commit.c:230
 msgid "updating files failed"
 msgstr "Cập nhật tập tin gặp lỗi"
 
@@ -1472,7 +1447,7 @@ msgstr ""
 msgid "dry run"
 msgstr "chạy thử"
 
-#: builtin/add.c:320 builtin/apply.c:4354 builtin/commit.c:1187
+#: builtin/add.c:320 builtin/apply.c:4354 builtin/commit.c:1154
 #: builtin/count-objects.c:82 builtin/fsck.c:613 builtin/log.c:1477
 #: builtin/mv.c:62 builtin/read-tree.c:112
 msgid "be verbose"
@@ -1550,9 +1525,9 @@ msgstr "Không có gì được chỉ ra, không có gì được thêm vào.\n"
 #: builtin/add.c:415
 #, c-format
 msgid "Maybe you wanted to say 'git add .'?\n"
-msgstr "Có lẽ bạn muốn nói là 'git add .' phải không?\n"
+msgstr "Có lẽ bạn muốn là `git add .' phải không?\n"
 
-#: builtin/add.c:421 builtin/clean.c:95 builtin/commit.c:289 builtin/mv.c:82
+#: builtin/add.c:421 builtin/clean.c:95 builtin/commit.c:290 builtin/mv.c:82
 #: builtin/rm.c:162
 msgid "index file corrupt"
 msgstr "tập tin ghi bảng mục lục bị hỏng"
@@ -2087,7 +2062,7 @@ msgstr "git bisect--helper --next-all [--no-checkout]"
 
 #: builtin/bisect--helper.c:17
 msgid "perform 'git bisect next'"
-msgstr "thực hiện 'git bisect next'"
+msgstr "thực hiện `git bisect next'"
 
 #: builtin/bisect--helper.c:19
 msgid "update BISECT_HEAD instead of checking out the current commit"
@@ -2103,97 +2078,97 @@ msgstr "git blame [các-tùy-chọn] [rev-opts] [rev] [--] tập-tin"
 msgid "[rev-opts] are documented in git-rev-list(1)"
 msgstr "[rev-opts] được mô tả trong git-rev-list(1)"
 
-#: builtin/blame.c:2316
+#: builtin/blame.c:2373
 msgid "Show blame entries as we find them, incrementally"
 msgstr "Hiển thị các mục `blame' như là chúng ta thấy chúng, tăng dần"
 
-#: builtin/blame.c:2317
+#: builtin/blame.c:2374
 msgid "Show blank SHA-1 for boundary commits (Default: off)"
 msgstr ""
 "Hiển thị SHA-1 trống cho những lần chuyển giao biên giới (Mặc định: off)"
 
-#: builtin/blame.c:2318
+#: builtin/blame.c:2375
 msgid "Do not treat root commits as boundaries (Default: off)"
 msgstr "Không coi các lần chuyển giao gốc là giới hạn (Mặc định: off)"
 
-#: builtin/blame.c:2319
+#: builtin/blame.c:2376
 msgid "Show work cost statistics"
 msgstr "Hiển thị thống kê công sức làm việc"
 
-#: builtin/blame.c:2320
+#: builtin/blame.c:2377
 msgid "Show output score for blame entries"
 msgstr "Hiển thị kết xuất điểm số có các mục tin `blame'"
 
-#: builtin/blame.c:2321
+#: builtin/blame.c:2378
 msgid "Show original filename (Default: auto)"
 msgstr "Hiển thị tên tập tin gốc (Mặc định: auto)"
 
-#: builtin/blame.c:2322
+#: builtin/blame.c:2379
 msgid "Show original linenumber (Default: off)"
 msgstr "Hiển thị số dòng gốc (Mặc định: off)"
 
-#: builtin/blame.c:2323
+#: builtin/blame.c:2380
 msgid "Show in a format designed for machine consumption"
 msgstr "Hiển thị ở định dạng đã thiết kế cho sự tiêu dùng bằng máy"
 
-#: builtin/blame.c:2324
+#: builtin/blame.c:2381
 msgid "Show porcelain format with per-line commit information"
 msgstr "Hiển thị định dạng 'porcelain' với thông tin chuyển giao mỗi dòng"
 
-#: builtin/blame.c:2325
+#: builtin/blame.c:2382
 msgid "Use the same output mode as git-annotate (Default: off)"
 msgstr "Dùng cùng chế độ xuất ra vóigit-annotate (Mặc định: off)"
 
-#: builtin/blame.c:2326
+#: builtin/blame.c:2383
 msgid "Show raw timestamp (Default: off)"
 msgstr "Hiển thị dấu vết thời gian dạng thô (Mặc định: off)"
 
-#: builtin/blame.c:2327
+#: builtin/blame.c:2384
 msgid "Show long commit SHA1 (Default: off)"
 msgstr "Hiển thị SHA1 của lần chuyển giao (commit) dạng dài (Mặc định: off)"
 
-#: builtin/blame.c:2328
+#: builtin/blame.c:2385
 msgid "Suppress author name and timestamp (Default: off)"
 msgstr "Không hiển thị tên tác giả và dấu vết thời gian (Mặc định: off)"
 
-#: builtin/blame.c:2329
+#: builtin/blame.c:2386
 msgid "Show author email instead of name (Default: off)"
 msgstr "Hiển thị thư điện tử của tác giả thay vì tên (Mặc định: off)"
 
-#: builtin/blame.c:2330
+#: builtin/blame.c:2387
 msgid "Ignore whitespace differences"
 msgstr "Bỏ qua các khác biệt do khoảng trắng gây ra"
 
-#: builtin/blame.c:2331
+#: builtin/blame.c:2388
 msgid "Spend extra cycles to find better match"
 msgstr "Tiêu thụ thêm năng tài nguyên máy móc để tìm kiếm tốt hơn nữa"
 
-#: builtin/blame.c:2332
+#: builtin/blame.c:2389
 msgid "Use revisions from <file> instead of calling git-rev-list"
 msgstr ""
 "Sử dụng điểm xét duyệt (revision) từ <tập tin> thay vì gọi `git-rev-list'"
 
-#: builtin/blame.c:2333
+#: builtin/blame.c:2390
 msgid "Use <file>'s contents as the final image"
 msgstr "Sử dụng nội dung của <tập tin> như là ảnh cuối cùng"
 
-#: builtin/blame.c:2334 builtin/blame.c:2335
+#: builtin/blame.c:2391 builtin/blame.c:2392
 msgid "score"
 msgstr "điểm số"
 
-#: builtin/blame.c:2334
+#: builtin/blame.c:2391
 msgid "Find line copies within and across files"
 msgstr "Tìm các bản sao chép dòng trong và ngang qua tập tin"
 
-#: builtin/blame.c:2335
+#: builtin/blame.c:2392
 msgid "Find line movements within and across files"
 msgstr "Tìm các di chuyển dòng trong và ngang qua tập tin"
 
-#: builtin/blame.c:2336
+#: builtin/blame.c:2393
 msgid "n,m"
 msgstr "n,m"
 
-#: builtin/blame.c:2336
+#: builtin/blame.c:2393
 msgid "Process only line range n,m, counting from 1"
 msgstr "Xử lý chỉ dòng vùng n,m, tính từ 1"
 
@@ -2401,8 +2376,8 @@ msgid "act on remote-tracking branches"
 msgstr "thao tác trên nhánh `remote-tracking'"
 
 #: builtin/branch.c:738 builtin/branch.c:744 builtin/branch.c:765
-#: builtin/branch.c:771 builtin/commit.c:1395 builtin/commit.c:1396
-#: builtin/commit.c:1397 builtin/commit.c:1398 builtin/tag.c:470
+#: builtin/branch.c:771 builtin/commit.c:1362 builtin/commit.c:1363
+#: builtin/commit.c:1364 builtin/commit.c:1365 builtin/tag.c:470
 msgid "commit"
 msgstr "commit"
 
@@ -2579,8 +2554,9 @@ msgid "git check-attr [-a | --all | attr...] [--] pathname..."
 msgstr "git check-attr [-a | --all | attr...] [--] tên-đường-dẫn..."
 
 #: builtin/check-attr.c:12
-msgid "git check-attr --stdin [-a | --all | attr...] < <list-of-paths>"
-msgstr "git check-attr --stdin [-a | --all | attr...] < <danh-sách-đường-dẫn>"
+msgid "git check-attr --stdin [-z] [-a | --all | attr...] < <list-of-paths>"
+msgstr ""
+"git check-attr --stdin [-z] [-a | --all | attr...] < <danh-sách-đường-dẫn>"
 
 #: builtin/check-attr.c:19
 msgid "report all attributes set on file"
@@ -2967,7 +2943,7 @@ msgstr "ép buộc"
 msgid "remove whole directories"
 msgstr "gỡ bỏ toàn bộ thư mục"
 
-#: builtin/clean.c:56 builtin/describe.c:413 builtin/grep.c:802
+#: builtin/clean.c:56 builtin/describe.c:413 builtin/grep.c:803
 #: builtin/ls-files.c:491 builtin/name-rev.c:231 builtin/show-ref.c:199
 msgid "pattern"
 msgstr "mẫu"
@@ -3093,7 +3069,7 @@ msgstr "lấy ra nhánh (checkout <nhánh>) thay vì HEAD của máy chủ"
 msgid "path to git-upload-pack on the remote"
 msgstr "đường dẫn đến git-upload-pack trên máy chủ"
 
-#: builtin/clone.c:93 builtin/fetch.c:83 builtin/grep.c:747
+#: builtin/clone.c:93 builtin/fetch.c:83 builtin/grep.c:748
 msgid "depth"
 msgstr "độ sâu"
 
@@ -3170,69 +3146,69 @@ msgstr "Không tìm thấy nhánh máy chủ %s để nhân bản (clone)."
 msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n"
 msgstr "refers HEAD máy chủ  chỉ đến ref không tồn tại, không thể checkout.\n"
 
-#: builtin/clone.c:642
+#: builtin/clone.c:690
 msgid "Too many arguments."
 msgstr "Có quá nhiều đối số."
 
-#: builtin/clone.c:646
+#: builtin/clone.c:694
 msgid "You must specify a repository to clone."
 msgstr "Bạn phải chỉ định một kho để mà nhân bản (clone)."
 
-#: builtin/clone.c:657
+#: builtin/clone.c:705
 #, c-format
 msgid "--bare and --origin %s options are incompatible."
 msgstr "tùy chọn --bare và --origin %s xung khắc nhau."
 
-#: builtin/clone.c:671
+#: builtin/clone.c:719
 #, c-format
 msgid "repository '%s' does not exist"
 msgstr "kho chứa `%s' chưa tồn tại"
 
-#: builtin/clone.c:676
+#: builtin/clone.c:724
 msgid "--depth is ignored in local clones; use file:// instead."
 msgstr "--depth bị lờ đi khi nhân bản nội bộ; hãy sử dụng file:// để thay thế."
 
-#: builtin/clone.c:686
+#: builtin/clone.c:734
 #, c-format
 msgid "destination path '%s' already exists and is not an empty directory."
 msgstr "đường dẫn đích `%s' đã có từ trước và không phải là một thư mục rỗng."
 
-#: builtin/clone.c:696
+#: builtin/clone.c:744
 #, c-format
 msgid "working tree '%s' already exists."
 msgstr "cây làm việc `%s' đã sẵn tồn tại rồi."
 
-#: builtin/clone.c:709 builtin/clone.c:723
+#: builtin/clone.c:757 builtin/clone.c:771
 #, c-format
 msgid "could not create leading directories of '%s'"
 msgstr "không thể tạo các thư mục dẫn đầu của `%s'"
 
-#: builtin/clone.c:712
+#: builtin/clone.c:760
 #, c-format
 msgid "could not create work tree dir '%s'."
 msgstr "không thể tạo cây thư mục làm việc dir `%s'."
 
-#: builtin/clone.c:731
+#: builtin/clone.c:779
 #, c-format
 msgid "Cloning into bare repository '%s'...\n"
 msgstr "Đang nhân bản thành kho chứa bare `%s'...\n"
 
-#: builtin/clone.c:733
+#: builtin/clone.c:781
 #, c-format
 msgid "Cloning into '%s'...\n"
 msgstr "Đang nhân bản thành `%s'...\n"
 
-#: builtin/clone.c:789
+#: builtin/clone.c:823
 #, c-format
 msgid "Don't know how to clone %s"
 msgstr "Không biết làm cách nào để nhân bản (clone) %s"
 
-#: builtin/clone.c:838
+#: builtin/clone.c:872
 #, c-format
 msgid "Remote branch %s not found in upstream %s"
 msgstr "Nhánh máy chủ %s không tìm thấy trong thượng nguồn (upstream) %s"
 
-#: builtin/clone.c:845
+#: builtin/clone.c:879
 msgid "You appear to have cloned an empty repository."
 msgstr "Bạn hình như là đã nhân bản một kho trống rỗng."
 
@@ -3268,15 +3244,15 @@ msgstr "Chèn thêm khoảng trắng giữa các cột"
 msgid "--command must be the first argument"
 msgstr "--command phải là đối số đầu tiên"
 
-#: builtin/commit.c:33
+#: builtin/commit.c:34
 msgid "git commit [options] [--] <filepattern>..."
 msgstr "git commit [các-tùy-chọn] [--] <mẫu-tập-tin>..."
 
-#: builtin/commit.c:38
+#: builtin/commit.c:39
 msgid "git status [options] [--] <filepattern>..."
 msgstr "git status [các-tùy-chọn] [--] <mẫu-tập-tin>..."
 
-#: builtin/commit.c:43
+#: builtin/commit.c:44
 msgid ""
 "Your name and email address were configured automatically based\n"
 "on your username and hostname. Please check that they are accurate.\n"
@@ -3304,7 +3280,7 @@ msgstr ""
 "\n"
 "    git commit --amend --reset-author\n"
 
-#: builtin/commit.c:55
+#: builtin/commit.c:56
 msgid ""
 "You asked to amend the most recent commit, but doing so would make\n"
 "it empty. You can repeat your command with --allow-empty, or you can\n"
@@ -3317,7 +3293,7 @@ msgstr ""
 "hoặc là bạn gỡ bỏ các lần chuyển giao một cách hoàn toàn bằng lệnh:\n"
 "\"git reset HEAD^\".\n"
 
-#: builtin/commit.c:60
+#: builtin/commit.c:61
 msgid ""
 "The previous cherry-pick is now empty, possibly due to conflict resolution.\n"
 "If you wish to commit it anyway, use:\n"
@@ -3334,97 +3310,97 @@ msgstr ""
 "\n"
 "Nếu không, hãy thử dùng `git reset'\n"
 
-#: builtin/commit.c:256
+#: builtin/commit.c:257
 msgid "failed to unpack HEAD tree object"
 msgstr "gặp lỗi khi tháo dỡ HEAD đối tượng cây"
 
-#: builtin/commit.c:298
+#: builtin/commit.c:299
 msgid "unable to create temporary index"
 msgstr "không thể tạo bảng mục lục tạm thời"
 
-#: builtin/commit.c:304
+#: builtin/commit.c:305
 msgid "interactive add failed"
 msgstr "việc thêm tương tác gặp lỗi"
 
-#: builtin/commit.c:337 builtin/commit.c:358 builtin/commit.c:408
+#: builtin/commit.c:338 builtin/commit.c:359 builtin/commit.c:409
 msgid "unable to write new_index file"
 msgstr "không thể ghi tập tin lưu bảng mục lục mới (new_index)"
 
-#: builtin/commit.c:389
+#: builtin/commit.c:390
 msgid "cannot do a partial commit during a merge."
 msgstr ""
 "không thể thực hiện việc chuyển giao (commit) cục bộ trong khi đang được hòa "
 "trộn."
 
-#: builtin/commit.c:391
+#: builtin/commit.c:392
 msgid "cannot do a partial commit during a cherry-pick."
 msgstr ""
 "không thể thực hiện việc chuyển giao (commit) bộ phận trong khi đang cherry-"
 "pick."
 
-#: builtin/commit.c:401
+#: builtin/commit.c:402
 msgid "cannot read the index"
 msgstr "không đọc được bảng mục lục"
 
-#: builtin/commit.c:421
+#: builtin/commit.c:422
 msgid "unable to write temporary index file"
 msgstr "không thể ghi tập tin lưu bảng mục lục tạm thời"
 
-#: builtin/commit.c:510 builtin/commit.c:516
+#: builtin/commit.c:509 builtin/commit.c:515
 #, c-format
 msgid "invalid commit: %s"
 msgstr "lần chuyển giao (commit) không hợp lệ: %s"
 
-#: builtin/commit.c:539
+#: builtin/commit.c:538
 msgid "malformed --author parameter"
 msgstr "đối số --author bị dị hình"
 
-#: builtin/commit.c:600
+#: builtin/commit.c:558
 #, c-format
 msgid "Malformed ident string: '%s'"
 msgstr "Chuỗi thụt lề đầu dòng dị hình: `%s'"
 
-#: builtin/commit.c:638 builtin/commit.c:671 builtin/commit.c:985
+#: builtin/commit.c:596 builtin/commit.c:629 builtin/commit.c:952
 #, c-format
 msgid "could not lookup commit %s"
 msgstr "không thể tìm kiếm commit (lần chuyển giao) %s"
 
-#: builtin/commit.c:650 builtin/shortlog.c:296
+#: builtin/commit.c:608 builtin/shortlog.c:296
 #, c-format
 msgid "(reading log message from standard input)\n"
 msgstr "(đang đọc thông điệp nhật ký từ đầu vào tiêu chuẩn)\n"
 
-#: builtin/commit.c:652
+#: builtin/commit.c:610
 msgid "could not read log from standard input"
 msgstr "không thể đọc nhật ký từ đầu vào tiêu chuẩn"
 
-#: builtin/commit.c:656
+#: builtin/commit.c:614
 #, c-format
 msgid "could not read log file '%s'"
 msgstr "không đọc được tệp nhật ký `%s'"
 
-#: builtin/commit.c:662
+#: builtin/commit.c:620
 msgid "commit has empty message"
 msgstr "lần chuyển giao (commit) có ghi chú trống rỗng"
 
-#: builtin/commit.c:678
+#: builtin/commit.c:636
 msgid "could not read MERGE_MSG"
 msgstr "không thể đọc MERGE_MSG"
 
-#: builtin/commit.c:682
+#: builtin/commit.c:640
 msgid "could not read SQUASH_MSG"
 msgstr "không thể đọc SQUASH_MSG"
 
-#: builtin/commit.c:686
+#: builtin/commit.c:644
 #, c-format
 msgid "could not read '%s'"
 msgstr "Không thể đọc `%s'."
 
-#: builtin/commit.c:738
+#: builtin/commit.c:705
 msgid "could not write commit template"
 msgstr "không thể ghi mẫu commit"
 
-#: builtin/commit.c:749
+#: builtin/commit.c:716
 #, c-format
 msgid ""
 "\n"
@@ -3439,7 +3415,7 @@ msgstr ""
 "\t%s\n"
 "và thử lại.\n"
 
-#: builtin/commit.c:754
+#: builtin/commit.c:721
 #, c-format
 msgid ""
 "\n"
@@ -3454,7 +3430,7 @@ msgstr ""
 "\t%s\n"
 "và thử lại.\n"
 
-#: builtin/commit.c:766
+#: builtin/commit.c:733
 msgid ""
 "Please enter the commit message for your changes. Lines starting\n"
 "with '#' will be ignored, and an empty message aborts the commit.\n"
@@ -3464,7 +3440,7 @@ msgstr ""
 "bắt đầu bằng `#' sẽ được bỏ qua, phần chú thích này nếu rỗng sẽ làm hủy bỏ "
 "lần chuyển giao (commit).\n"
 
-#: builtin/commit.c:771
+#: builtin/commit.c:738
 msgid ""
 "Please enter the commit message for your changes. Lines starting\n"
 "with '#' will be kept; you may remove them yourself if you want to.\n"
@@ -3475,140 +3451,140 @@ msgstr ""
 "bắt đầu bằng `#' sẽ được bỏ qua; bạn có thể xóa chúng đi nếu muốn.\n"
 "Phần chú thích này nếu rỗng sẽ làm hủy bỏ lần chuyển giao (commit).\n"
 
-#: builtin/commit.c:784
+#: builtin/commit.c:751
 #, c-format
 msgid "%sAuthor:    %s"
 msgstr "%sTác giả:    %s"
 
-#: builtin/commit.c:791
+#: builtin/commit.c:758
 #, c-format
 msgid "%sCommitter: %s"
 msgstr "%sNgười chuyển giao (commit): %s"
 
-#: builtin/commit.c:811
+#: builtin/commit.c:778
 msgid "Cannot read index"
 msgstr "không đọc được bảng mục lục"
 
-#: builtin/commit.c:848
+#: builtin/commit.c:815
 msgid "Error building trees"
 msgstr "Gặp lỗi khi xây dựng cây"
 
-#: builtin/commit.c:863 builtin/tag.c:361
+#: builtin/commit.c:830 builtin/tag.c:361
 #, c-format
 msgid "Please supply the message using either -m or -F option.\n"
 msgstr "Xin hãy áp dụng thông điệp sử dụng hoặc là tùy chọn -m hoặc là -F.\n"
 
-#: builtin/commit.c:960
+#: builtin/commit.c:927
 #, c-format
 msgid "No existing author found with '%s'"
 msgstr "Không tìm thấy tác giả có sẵn với `%s'"
 
-#: builtin/commit.c:975 builtin/commit.c:1175
+#: builtin/commit.c:942 builtin/commit.c:1142
 #, c-format
 msgid "Invalid untracked files mode '%s'"
 msgstr "Chế độ cho các tập tin không bị theo vết không hợp lệ `%s'"
 
-#: builtin/commit.c:1015
+#: builtin/commit.c:982
 msgid "Using both --reset-author and --author does not make sense"
 msgstr "Sử dụng cả hai tùy chọn --reset-author và --author không hợp lý"
 
-#: builtin/commit.c:1026
+#: builtin/commit.c:993
 msgid "You have nothing to amend."
 msgstr "Không có gì để amend (tu bổ) cả."
 
-#: builtin/commit.c:1029
+#: builtin/commit.c:996
 msgid "You are in the middle of a merge -- cannot amend."
 msgstr ""
 "Bạn đang ở giữa của quá trình hòa trộn -- không thể thực hiện amend (tu bổ)."
 
-#: builtin/commit.c:1031
+#: builtin/commit.c:998
 msgid "You are in the middle of a cherry-pick -- cannot amend."
 msgstr ""
 "Bạn đang ở giữa của quá trình cherry-pick -- không thể thực hiện amend (tu "
 "bổ)."
 
-#: builtin/commit.c:1034
+#: builtin/commit.c:1001
 msgid "Options --squash and --fixup cannot be used together"
 msgstr "Các tùy chọn --squash và --fixup không thể sử dụng cùng với nhau"
 
-#: builtin/commit.c:1044
+#: builtin/commit.c:1011
 msgid "Only one of -c/-C/-F/--fixup can be used."
 msgstr "Chỉ một tùy chọn trong số -c/-C/-F/--fixup được sử dụng"
 
-#: builtin/commit.c:1046
+#: builtin/commit.c:1013
 msgid "Option -m cannot be combined with -c/-C/-F/--fixup."
 msgstr "Tùy chọn -m không thể được tổ hợp cùng với -c/-C/-F/--fixup."
 
-#: builtin/commit.c:1054
+#: builtin/commit.c:1021
 msgid "--reset-author can be used only with -C, -c or --amend."
 msgstr ""
 "--reset-author chỉ có thể được sử dụng với tùy chọn -C, -c hay --amend."
 
-#: builtin/commit.c:1071
+#: builtin/commit.c:1038
 msgid "Only one of --include/--only/--all/--interactive/--patch can be used."
 msgstr ""
 "Chỉ một trong các tùy chọn --include/--only/--all/--interactive/--patch được "
 "sử dụng."
 
-#: builtin/commit.c:1073
+#: builtin/commit.c:1040
 msgid "No paths with --include/--only does not make sense."
 msgstr "Không đường dẫn với các tùy chọn --include/--only không hợp lý."
 
-#: builtin/commit.c:1075
+#: builtin/commit.c:1042
 msgid "Clever... amending the last one with dirty index."
 msgstr "Giỏi...  tu bổ cái cuối với bảng mục lục phi nghĩa."
 
-#: builtin/commit.c:1077
+#: builtin/commit.c:1044
 msgid "Explicit paths specified without -i nor -o; assuming --only paths..."
 msgstr ""
 "Những đường dẫn rõ ràng được chỉ ra không có tùy chọn -i cũng không -o; đang "
 "giả định --only những-đường-dẫn..."
 
-#: builtin/commit.c:1087 builtin/tag.c:577
+#: builtin/commit.c:1054 builtin/tag.c:577
 #, c-format
 msgid "Invalid cleanup mode %s"
 msgstr "Chế độ dọn dẹp không hợp lệ %s"
 
-#: builtin/commit.c:1092
+#: builtin/commit.c:1059
 msgid "Paths with -a does not make sense."
 msgstr "Các đường dẫn với tùy chọn -a không hợp lý."
 
-#: builtin/commit.c:1189 builtin/commit.c:1417
+#: builtin/commit.c:1156 builtin/commit.c:1384
 msgid "show status concisely"
 msgstr "hiển thị trạng thái ở dạng súc tích"
 
-#: builtin/commit.c:1191 builtin/commit.c:1419
+#: builtin/commit.c:1158 builtin/commit.c:1386
 msgid "show branch information"
 msgstr "hiển thị thông tin nhánh"
 
-#: builtin/commit.c:1193 builtin/commit.c:1421 builtin/push.c:389
+#: builtin/commit.c:1160 builtin/commit.c:1388 builtin/push.c:389
 msgid "machine-readable output"
 msgstr "kết xuất dạng máy-có-thể-đọc"
 
-#: builtin/commit.c:1196 builtin/commit.c:1423
+#: builtin/commit.c:1163 builtin/commit.c:1390
 msgid "terminate entries with NUL"
 msgstr "chấm dứt các mục bằng NUL"
 
-#: builtin/commit.c:1198 builtin/commit.c:1426 builtin/fast-export.c:636
+#: builtin/commit.c:1165 builtin/commit.c:1393 builtin/fast-export.c:636
 #: builtin/fast-export.c:639 builtin/tag.c:461
 msgid "mode"
 msgstr "chế độ"
 
-#: builtin/commit.c:1199 builtin/commit.c:1426
+#: builtin/commit.c:1166 builtin/commit.c:1393
 msgid "show untracked files, optional modes: all, normal, no. (Default: all)"
 msgstr ""
 "hiển thị các tập tin chưa được theo dõi  dấu vết, các chế độ tùy chọn:  all, "
 "normal, no. (Mặc định: all)"
 
-#: builtin/commit.c:1202
+#: builtin/commit.c:1169
 msgid "show ignored files"
 msgstr "hiển thị các tập tin ẩn"
 
-#: builtin/commit.c:1203 parse-options.h:151
+#: builtin/commit.c:1170 parse-options.h:151
 msgid "when"
 msgstr "khi"
 
-#: builtin/commit.c:1204
+#: builtin/commit.c:1171
 msgid ""
 "ignore changes to submodules, optional when: all, dirty, untracked. "
 "(Default: all)"
@@ -3616,223 +3592,223 @@ msgstr ""
 "bỏ qua các thay đổi trong mô-đun con, tùy chọn khi: all, dirty, untracked. "
 "(Mặc định: all)"
 
-#: builtin/commit.c:1206
+#: builtin/commit.c:1173
 msgid "list untracked files in columns"
 msgstr "hiển thị danh sách các tập-tin chưa được theo dõi trong các cột"
 
-#: builtin/commit.c:1275
+#: builtin/commit.c:1242
 msgid "couldn't look up newly created commit"
 msgstr "không thể tìm thấy lần chuyển giao (commit) mới hơn đã được tạo"
 
-#: builtin/commit.c:1277
+#: builtin/commit.c:1244
 msgid "could not parse newly created commit"
 msgstr ""
 "không thể phân tích cú pháp của đối tượng chuyển giao mới hơn đã được tạo"
 
-#: builtin/commit.c:1318
+#: builtin/commit.c:1285
 msgid "detached HEAD"
 msgstr "đã rời khỏi HEAD"
 
-#: builtin/commit.c:1320
+#: builtin/commit.c:1287
 msgid " (root-commit)"
 msgstr " (root-commit)"
 
-#: builtin/commit.c:1387
+#: builtin/commit.c:1354
 msgid "suppress summary after successful commit"
 msgstr "không hiển thị tổng kết sau khi chuyển giao thành công"
 
-#: builtin/commit.c:1388
+#: builtin/commit.c:1355
 msgid "show diff in commit message template"
 msgstr "hiển thị sự khác biệt trong mẫu tin nhắn chuyển giao"
 
-#: builtin/commit.c:1390
+#: builtin/commit.c:1357
 msgid "Commit message options"
 msgstr "Các tùy chọn ghi chú commit"
 
-#: builtin/commit.c:1391 builtin/tag.c:459
+#: builtin/commit.c:1358 builtin/tag.c:459
 msgid "read message from file"
 msgstr "đọc chú thích từ tập tin"
 
-#: builtin/commit.c:1392
+#: builtin/commit.c:1359
 msgid "author"
 msgstr "tác giả"
 
-#: builtin/commit.c:1392
+#: builtin/commit.c:1359
 msgid "override author for commit"
 msgstr "ghi đè tác giả cho commit"
 
-#: builtin/commit.c:1393 builtin/gc.c:178
+#: builtin/commit.c:1360 builtin/gc.c:178
 msgid "date"
 msgstr "ngày tháng"
 
-#: builtin/commit.c:1393
+#: builtin/commit.c:1360
 msgid "override date for commit"
 msgstr "ghi đè ngày tháng cho commit"
 
-#: builtin/commit.c:1394 builtin/merge.c:206 builtin/notes.c:534
-#: builtin/notes.c:691 builtin/tag.c:457
+#: builtin/commit.c:1361 builtin/merge.c:206 builtin/notes.c:537
+#: builtin/notes.c:694 builtin/tag.c:457
 msgid "message"
 msgstr "thông điệp"
 
-#: builtin/commit.c:1394
+#: builtin/commit.c:1361
 msgid "commit message"
 msgstr "chú thích của lần commit"
 
-#: builtin/commit.c:1395
+#: builtin/commit.c:1362
 msgid "reuse and edit message from specified commit"
 msgstr ""
 "dùng lại các ghi chú từ lần chuyển giao (commit) đã cho nhưng có cho sửa chữa"
 
-#: builtin/commit.c:1396
+#: builtin/commit.c:1363
 msgid "reuse message from specified commit"
 msgstr "dùng lại các ghi chú từ lần chuyển giao (commit) đã cho"
 
-#: builtin/commit.c:1397
+#: builtin/commit.c:1364
 msgid "use autosquash formatted message to fixup specified commit"
 msgstr ""
 "dùng ghi chú có định dạng autosquash để sửa chữa lần chuyển giao đã chỉ ra"
 
-#: builtin/commit.c:1398
+#: builtin/commit.c:1365
 msgid "use autosquash formatted message to squash specified commit"
 msgstr ""
 "dùng lời nhắn có định dạng tự động nén để nén lại các lần chuyển giao đã chỉ "
 "ra"
 
-#: builtin/commit.c:1399
+#: builtin/commit.c:1366
 msgid "the commit is authored by me now (used with -C/-c/--amend)"
 msgstr ""
 "lần chuyển giao nhận tôi là tác giả (được dùng với tùy chọn -C/-c/--amend)"
 
-#: builtin/commit.c:1400 builtin/log.c:1068 builtin/revert.c:109
+#: builtin/commit.c:1367 builtin/log.c:1068 builtin/revert.c:109
 msgid "add Signed-off-by:"
 msgstr "thêm dòng Signed-off-by:"
 
-#: builtin/commit.c:1401
+#: builtin/commit.c:1368
 msgid "use specified template file"
 msgstr "sử dụng tập tin mẫu đã cho"
 
-#: builtin/commit.c:1402
+#: builtin/commit.c:1369
 msgid "force edit of commit"
 msgstr "ép buộc sửa lần commit"
 
-#: builtin/commit.c:1403
+#: builtin/commit.c:1370
 msgid "default"
 msgstr "mặc định"
 
-#: builtin/commit.c:1403 builtin/tag.c:462
+#: builtin/commit.c:1370 builtin/tag.c:462
 msgid "how to strip spaces and #comments from message"
 msgstr "làm thế nào để cắt bỏ khoảng trắng và #ghichú từ mẩu tin nhắn"
 
-#: builtin/commit.c:1404
+#: builtin/commit.c:1371
 msgid "include status in commit message template"
 msgstr "bao gồm các trạng thái ghi mẫu ghi chú chuyển giao (commit)"
 
-#: builtin/commit.c:1405 builtin/merge.c:213 builtin/tag.c:463
+#: builtin/commit.c:1372 builtin/merge.c:213 builtin/tag.c:463
 msgid "key id"
 msgstr "id khóa"
 
-#: builtin/commit.c:1406 builtin/merge.c:214
+#: builtin/commit.c:1373 builtin/merge.c:214
 msgid "GPG sign commit"
 msgstr "ký lần commit dùng GPG"
 
 #. end commit message options
-#: builtin/commit.c:1409
+#: builtin/commit.c:1376
 msgid "Commit contents options"
 msgstr "Các tùy nội dung ghi chú commit"
 
-#: builtin/commit.c:1410
+#: builtin/commit.c:1377
 msgid "commit all changed files"
 msgstr "chuyển giao tất cả các tập tin có thay đổi"
 
-#: builtin/commit.c:1411
+#: builtin/commit.c:1378
 msgid "add specified files to index for commit"
 msgstr "thêm các tập tin đã chỉ ra vào bảng mục lục để chuyển giao (commit)"
 
-#: builtin/commit.c:1412
+#: builtin/commit.c:1379
 msgid "interactively add files"
 msgstr "thêm các tập-tin bằng tương tác"
 
-#: builtin/commit.c:1413
+#: builtin/commit.c:1380
 msgid "interactively add changes"
 msgstr "thêm các thay đổi bằng tương tác"
 
-#: builtin/commit.c:1414
+#: builtin/commit.c:1381
 msgid "commit only specified files"
 msgstr "chỉ chuyển giao các tập tin đã chỉ ra"
 
-#: builtin/commit.c:1415
+#: builtin/commit.c:1382
 msgid "bypass pre-commit hook"
 msgstr "vòng qua móc (hook) pre-commit"
 
-#: builtin/commit.c:1416
+#: builtin/commit.c:1383
 msgid "show what would be committed"
 msgstr "hiển thị xem cái gì có thể được chuyển giao"
 
-#: builtin/commit.c:1424
+#: builtin/commit.c:1391
 msgid "amend previous commit"
 msgstr "tu bổ (amend) lần commit trước"
 
-#: builtin/commit.c:1425
+#: builtin/commit.c:1392
 msgid "bypass post-rewrite hook"
 msgstr "vòng qua móc (hook) post-rewrite"
 
-#: builtin/commit.c:1430
+#: builtin/commit.c:1397
 msgid "ok to record an empty change"
 msgstr "ok để ghi lại một thay đổi trống rỗng"
 
-#: builtin/commit.c:1433
+#: builtin/commit.c:1400
 msgid "ok to record a change with an empty message"
 msgstr "ok để ghi các thay đổi với lời nhắn trống rỗng"
 
-#: builtin/commit.c:1464
+#: builtin/commit.c:1432
 msgid "could not parse HEAD commit"
 msgstr "không thể phân tích commit (lần chuyển giao) HEAD"
 
-#: builtin/commit.c:1502 builtin/merge.c:508
+#: builtin/commit.c:1470 builtin/merge.c:508
 #, c-format
 msgid "could not open '%s' for reading"
 msgstr "không thể mở `%s' để đọc"
 
-#: builtin/commit.c:1509
+#: builtin/commit.c:1477
 #, c-format
 msgid "Corrupt MERGE_HEAD file (%s)"
 msgstr "Tập tin MERGE_HEAD sai hỏng (%s)"
 
-#: builtin/commit.c:1516
+#: builtin/commit.c:1484
 msgid "could not read MERGE_MODE"
 msgstr "không thể đọc MERGE_MODE"
 
-#: builtin/commit.c:1535
+#: builtin/commit.c:1503
 #, c-format
 msgid "could not read commit message: %s"
 msgstr "không thể đọc thông điệp (message) commit (lần chuyển giao): %s"
 
-#: builtin/commit.c:1549
+#: builtin/commit.c:1517
 #, c-format
 msgid "Aborting commit; you did not edit the message.\n"
 msgstr ""
 "Đang bỏ qua việc chuyển giao (commit); bạn đã không biên soạn thông điệp "
 "(message).\n"
 
-#: builtin/commit.c:1554
+#: builtin/commit.c:1522
 #, c-format
 msgid "Aborting commit due to empty commit message.\n"
 msgstr ""
 "Đang bỏ qua lần chuyển giao (commit) bởi vì thông điệp của nó trống rỗng.\n"
 
-#: builtin/commit.c:1569 builtin/merge.c:935 builtin/merge.c:960
+#: builtin/commit.c:1537 builtin/merge.c:935 builtin/merge.c:960
 msgid "failed to write commit object"
 msgstr "gặp lỗi khi ghi đối tượng chuyển giao (commit)"
 
-#: builtin/commit.c:1590
+#: builtin/commit.c:1558
 msgid "cannot lock HEAD ref"
 msgstr "không thể khóa HEAD ref (tham chiếu)"
 
-#: builtin/commit.c:1594
+#: builtin/commit.c:1562
 msgid "cannot update HEAD ref"
 msgstr "không thể cập nhật ref (tham chiếu) HEAD"
 
-#: builtin/commit.c:1605
+#: builtin/commit.c:1573
 msgid ""
 "Repository has been updated, but unable to write\n"
 "new_index file. Check that disk is not full or quota is\n"
@@ -4264,126 +4240,126 @@ msgstr "Không thể tìm thấy máy chủ cho tham chiếu HEAD"
 msgid "object %s not found"
 msgstr "Không tìm thấy đối tượng %s"
 
-#: builtin/fetch.c:260
+#: builtin/fetch.c:259
 msgid "[up to date]"
 msgstr "[đã cập nhật]"
 
-#: builtin/fetch.c:274
+#: builtin/fetch.c:273
 #, c-format
 msgid "! %-*s %-*s -> %s  (can't fetch in current branch)"
 msgstr "! %-*s %-*s -> %s  (không thể fetch (lấy) về nhánh hiện hành)"
 
-#: builtin/fetch.c:275 builtin/fetch.c:361
+#: builtin/fetch.c:274 builtin/fetch.c:360
 msgid "[rejected]"
 msgstr "[Bị từ chối]"
 
-#: builtin/fetch.c:286
+#: builtin/fetch.c:285
 msgid "[tag update]"
 msgstr "[cập nhật thẻ]"
 
-#: builtin/fetch.c:288 builtin/fetch.c:323 builtin/fetch.c:341
+#: builtin/fetch.c:287 builtin/fetch.c:322 builtin/fetch.c:340
 msgid "  (unable to update local ref)"
 msgstr "  (không thể cập nhật tham chiếu (ref) nội bộ)"
 
-#: builtin/fetch.c:306
+#: builtin/fetch.c:305
 msgid "[new tag]"
 msgstr "[thẻ mới]"
 
-#: builtin/fetch.c:309
+#: builtin/fetch.c:308
 msgid "[new branch]"
 msgstr "[nhánh mới]"
 
-#: builtin/fetch.c:312
+#: builtin/fetch.c:311
 msgid "[new ref]"
 msgstr "[ref (tham chiếu) mới]"
 
-#: builtin/fetch.c:357
+#: builtin/fetch.c:356
 msgid "unable to update local ref"
 msgstr "không thể cập nhật tham chiếu (ref) nội bộ"
 
-#: builtin/fetch.c:357
+#: builtin/fetch.c:356
 msgid "forced update"
 msgstr "cưỡng bức cập nhật"
 
-#: builtin/fetch.c:363
+#: builtin/fetch.c:362
 msgid "(non-fast-forward)"
 msgstr "(non-fast-forward)"
 
-#: builtin/fetch.c:394 builtin/fetch.c:686
+#: builtin/fetch.c:393 builtin/fetch.c:685
 #, c-format
 msgid "cannot open %s: %s\n"
 msgstr "không thể mở %s: %s\n"
 
-#: builtin/fetch.c:403
+#: builtin/fetch.c:402
 #, c-format
 msgid "%s did not send all necessary objects\n"
 msgstr "%s đã không gửi tất cả các đối tượng cần thiết\n"
 
-#: builtin/fetch.c:489
+#: builtin/fetch.c:488
 #, c-format
 msgid "From %.*s\n"
 msgstr "Từ %.*s\n"
 
-#: builtin/fetch.c:500
+#: builtin/fetch.c:499
 #, c-format
 msgid ""
 "some local refs could not be updated; try running\n"
 " 'git remote prune %s' to remove any old, conflicting branches"
 msgstr ""
 "một số tham chiếu (refs) nội bộ không thể được cập nhật; hãy thử chạy\n"
-" 'git remote prune %s' để bỏ đi những nhánh cũ, hay bị xung đột"
+" `git remote prune %s' để bỏ đi những nhánh cũ, hay bị xung đột"
 
-#: builtin/fetch.c:550
+#: builtin/fetch.c:549
 #, c-format
 msgid "   (%s will become dangling)"
 msgstr "   (%s sẽ trở thành không đầu (không được quản lý))"
 
-#: builtin/fetch.c:551
+#: builtin/fetch.c:550
 #, c-format
 msgid "   (%s has become dangling)"
 msgstr "   (%s đã trở thành không đầu (không được quản lý))"
 
-#: builtin/fetch.c:558
+#: builtin/fetch.c:557
 msgid "[deleted]"
 msgstr "[đã xóa]"
 
-#: builtin/fetch.c:559 builtin/remote.c:1055
+#: builtin/fetch.c:558 builtin/remote.c:1055
 msgid "(none)"
 msgstr "(không)"
 
-#: builtin/fetch.c:676
+#: builtin/fetch.c:675
 #, c-format
 msgid "Refusing to fetch into current branch %s of non-bare repository"
 msgstr ""
 "Từ chối việc lấy (fetch) vào trong nhánh hiện tại %s của một kho chứa không "
 "phải kho trần (bare)"
 
-#: builtin/fetch.c:710
+#: builtin/fetch.c:709
 #, c-format
 msgid "Don't know how to fetch from %s"
 msgstr "Không biết làm cách nào để lấy về (fetch) từ %s"
 
-#: builtin/fetch.c:787
+#: builtin/fetch.c:786
 #, c-format
 msgid "Option \"%s\" value \"%s\" is not valid for %s"
 msgstr "Tùy chọn \"%s\" có giá trị \"%s\" là không hợp lệ cho %s"
 
-#: builtin/fetch.c:790
+#: builtin/fetch.c:789
 #, c-format
 msgid "Option \"%s\" is ignored for %s\n"
 msgstr "Tùy chọn \"%s\" bị bỏ qua với %s\n"
 
-#: builtin/fetch.c:892
+#: builtin/fetch.c:891
 #, c-format
 msgid "Fetching %s\n"
 msgstr "Đang lấy (fetch) %s\n"
 
-#: builtin/fetch.c:894 builtin/remote.c:100
+#: builtin/fetch.c:893 builtin/remote.c:100
 #, c-format
 msgid "Could not fetch %s"
 msgstr "không thể fetch (lấy) %s"
 
-#: builtin/fetch.c:913
+#: builtin/fetch.c:912
 msgid ""
 "No remote repository specified.  Please, specify either a URL or a\n"
 "remote name from which new revisions should be fetched."
@@ -4391,24 +4367,24 @@ msgstr ""
 "Chưa chỉ ra kho chứa máy chủ.  Xin hãy chỉ định hoặc là URL hoặc\n"
 "tên máy chủ từ cái mà những điểm xét duyệt mới có thể được fetch (lấy về)."
 
-#: builtin/fetch.c:933
+#: builtin/fetch.c:932
 msgid "You need to specify a tag name."
 msgstr "Bạn phải định rõ tên thẻ."
 
-#: builtin/fetch.c:985
+#: builtin/fetch.c:984
 msgid "fetch --all does not take a repository argument"
 msgstr "lệnh lấy về \"fetch --all\" không lấy đối số kho chứa"
 
-#: builtin/fetch.c:987
+#: builtin/fetch.c:986
 msgid "fetch --all does not make sense with refspecs"
 msgstr "lệnh lấy về \"fetch --all\" không hợp lý với refspecs"
 
-#: builtin/fetch.c:998
+#: builtin/fetch.c:997
 #, c-format
 msgid "No such remote or remote group: %s"
 msgstr "không có nhóm máy chủ hay máy chủ như thế: %s"
 
-#: builtin/fetch.c:1006
+#: builtin/fetch.c:1005
 msgid "Fetching a group and specifying refspecs does not make sense"
 msgstr "Việc lấy về cả một nhóm và chỉ định refspecs không hợp lý"
 
@@ -4417,7 +4393,7 @@ msgid "git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]"
 msgstr ""
 "git fmt-merge-msg [-m <thông điệp>] [--log[=<n>]|--no-log] [--file <tập-tin>]"
 
-#: builtin/fmt-merge-msg.c:653 builtin/fmt-merge-msg.c:656 builtin/grep.c:786
+#: builtin/fmt-merge-msg.c:653 builtin/fmt-merge-msg.c:656 builtin/grep.c:787
 #: builtin/merge.c:188 builtin/show-branch.c:656 builtin/show-ref.c:192
 #: builtin/tag.c:448 parse-options.h:133 parse-options.h:235
 msgid "n"
@@ -4553,12 +4529,7 @@ msgstr "cẩn thận hơn nữa (tăng thời gian chạy)"
 msgid "enable auto-gc mode"
 msgstr "bật chế độ auto-gc"
 
-#: builtin/gc.c:221
-#, c-format
-msgid "Auto packing the repository for optimum performance.\n"
-msgstr "Tự động đóng gói kho chứa để tối ưu hóa hiệu suất làm việc.\n"
-
-#: builtin/gc.c:224
+#: builtin/gc.c:222
 #, c-format
 msgid ""
 "Auto packing the repository for optimum performance. You may also\n"
@@ -4568,240 +4539,244 @@ msgstr ""
 "chạy lệnh \"git gc\" một cách thủ công. Hãy xem \"git help gc\" để biết thêm "
 "chi tiết.\n"
 
-#: builtin/gc.c:251
+#: builtin/gc.c:249
 msgid ""
 "There are too many unreachable loose objects; run 'git prune' to remove them."
 msgstr ""
-"Có quá nhiều đối tượng tự do không được dùng đến; hãy chạy lệnh 'git prune' "
+"Có quá nhiều đối tượng tự do không được dùng đến; hãy chạy lệnh `git prune' "
 "để xóa bỏ chúng đi."
 
 #: builtin/grep.c:22
 msgid "git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]"
 msgstr "git grep [các-tùy-chọn] [-e] <mẫu> [<rev>...] [[--] <đường-dẫn>...]"
 
-#: builtin/grep.c:216
+#: builtin/grep.c:217
 #, c-format
 msgid "grep: failed to create thread: %s"
 msgstr "grep: gặp lỗi tạo tuyến (thread): %s"
 
-#: builtin/grep.c:454
+#: builtin/grep.c:455
 #, c-format
 msgid "Failed to chdir: %s"
 msgstr "Gặp lỗi với lệnh chdir: %s"
 
-#: builtin/grep.c:530 builtin/grep.c:564
+#: builtin/grep.c:531 builtin/grep.c:565
 #, c-format
 msgid "unable to read tree (%s)"
 msgstr "không thể đọc cây (%s)"
 
-#: builtin/grep.c:578
+#: builtin/grep.c:579
 #, c-format
 msgid "unable to grep from object of type %s"
 msgstr "không thể thực hiện lệnh grep (lọc tìm) từ đối tượng thuộc kiểu %s"
 
-#: builtin/grep.c:636
+#: builtin/grep.c:637
 #, c-format
 msgid "switch `%c' expects a numerical value"
 msgstr "chuyển đến `%c' mong chờ một giá trị bằng số"
 
-#: builtin/grep.c:653
+#: builtin/grep.c:654
 #, c-format
 msgid "cannot open '%s'"
 msgstr "không mở được `%s'"
 
-#: builtin/grep.c:728
+#: builtin/grep.c:729
 msgid "search in index instead of in the work tree"
 msgstr "tìm trong bảng mục lục thay vì trong cây làm việc"
 
-#: builtin/grep.c:730
+#: builtin/grep.c:731
 msgid "find in contents not managed by git"
 msgstr "tìm trong nội dung không được quản lý bởi git"
 
-#: builtin/grep.c:732
+#: builtin/grep.c:733
 msgid "search in both tracked and untracked files"
 msgstr "tìm kiếm các tập tin được và chưa được theo dõi dấu vết"
 
-#: builtin/grep.c:734
+#: builtin/grep.c:735
 msgid "search also in ignored files"
 msgstr "tìm cả trong các tập tin đã bị lờ đi"
 
-#: builtin/grep.c:737
+#: builtin/grep.c:738
 msgid "show non-matching lines"
 msgstr "hiển thị  những dòng không khớp với mẫu"
 
-#: builtin/grep.c:739
+#: builtin/grep.c:740
 msgid "case insensitive matching"
 msgstr "phân biệt chữ hoa/thường"
 
-#: builtin/grep.c:741
+#: builtin/grep.c:742
 msgid "match patterns only at word boundaries"
 msgstr "chỉ khớp mẫu tại đường ranh giới từ"
 
-#: builtin/grep.c:743
+#: builtin/grep.c:744
 msgid "process binary files as text"
 msgstr "xử lý tập tin nhị phân như là dạng văn bản thường"
 
-#: builtin/grep.c:745
+#: builtin/grep.c:746
 msgid "don't match patterns in binary files"
 msgstr "không khớp mẫu trong các tập tin nhị phân"
 
-#: builtin/grep.c:748
+#: builtin/grep.c:749
 msgid "descend at most <depth> levels"
 msgstr "giảm xuống ít nhất mức <sâu>"
 
-#: builtin/grep.c:752
+#: builtin/grep.c:753
 msgid "use extended POSIX regular expressions"
 msgstr "dùng biểu thức chính qui POSIX có mở rộng"
 
-#: builtin/grep.c:755
+#: builtin/grep.c:756
 msgid "use basic POSIX regular expressions (default)"
 msgstr "sử dụng biểu thức chính quy kiểu POSIX (mặc định)"
 
-#: builtin/grep.c:758
+#: builtin/grep.c:759
 msgid "interpret patterns as fixed strings"
 msgstr "diễn dịch các mẫu như là chuỗi cố định"
 
-#: builtin/grep.c:761
+#: builtin/grep.c:762
 msgid "use Perl-compatible regular expressions"
 msgstr "sử dụng biểu thức chính quy tương thích Perl"
 
-#: builtin/grep.c:764
+#: builtin/grep.c:765
 msgid "show line numbers"
 msgstr "hiển thị số của dòng"
 
-#: builtin/grep.c:765
+#: builtin/grep.c:766
 msgid "don't show filenames"
 msgstr "không hiển thị tên tập tin"
 
-#: builtin/grep.c:766
+#: builtin/grep.c:767
 msgid "show filenames"
 msgstr "hiển thị các tên tập tin"
 
-#: builtin/grep.c:768
+#: builtin/grep.c:769
 msgid "show filenames relative to top directory"
 msgstr "hiển thị tên tập tin tương đối với thư mục đỉnh (top)"
 
-#: builtin/grep.c:770
+#: builtin/grep.c:771
 msgid "show only filenames instead of matching lines"
 msgstr "chỉ hiển thị tên tập tin thay vì những dòng khớp với mẫu"
 
-#: builtin/grep.c:772
+#: builtin/grep.c:773
 msgid "synonym for --files-with-matches"
 msgstr "đồng nghĩa với --files-with-matches"
 
-#: builtin/grep.c:775
+#: builtin/grep.c:776
 msgid "show only the names of files without match"
 msgstr "chỉ hiển thị tên cho những tập tin không khớp với mẫu"
 
-#: builtin/grep.c:777
+#: builtin/grep.c:778
 msgid "print NUL after filenames"
 msgstr "thêm NUL vào sau tên tập tin"
 
-#: builtin/grep.c:779
+#: builtin/grep.c:780
 msgid "show the number of matches instead of matching lines"
 msgstr "hiển thị số lượng khớp thay vì những dòng khớp với mẫu"
 
-#: builtin/grep.c:780
+#: builtin/grep.c:781
 msgid "highlight matches"
 msgstr "tô sáng cái khớp"
 
-#: builtin/grep.c:782
+#: builtin/grep.c:783
 msgid "print empty line between matches from different files"
 msgstr "hiển thị dòng trống giữa các lần khớp từ các tập tin khác biệt"
 
-#: builtin/grep.c:784
+#: builtin/grep.c:785
 msgid "show filename only once above matches from same file"
 msgstr ""
 "hiển thị tên tập tin một lần phía trên các lần khớp từ cùng một tập tin"
 
-#: builtin/grep.c:787
+#: builtin/grep.c:788
 msgid "show <n> context lines before and after matches"
 msgstr "hiển thị <n> dòng nội dung phía trước và sau các lần khớp"
 
-#: builtin/grep.c:790
+#: builtin/grep.c:791
 msgid "show <n> context lines before matches"
 msgstr "hiển thị <n> dòng nội dung trước khớp"
 
-#: builtin/grep.c:792
+#: builtin/grep.c:793
 msgid "show <n> context lines after matches"
 msgstr "hiển thị <n> dòng nội dung sau khớp"
 
-#: builtin/grep.c:793
+#: builtin/grep.c:794
 msgid "shortcut for -C NUM"
 msgstr "Dạng tắt cho -C SỐ"
 
-#: builtin/grep.c:796
+#: builtin/grep.c:797
 msgid "show a line with the function name before matches"
 msgstr "hiển thị dòng vói tên hàm trước các lần khớp"
 
-#: builtin/grep.c:798
+#: builtin/grep.c:799
 msgid "show the surrounding function"
 msgstr "hiển thị hàm bao quanh"
 
-#: builtin/grep.c:801
+#: builtin/grep.c:802
 msgid "read patterns from file"
 msgstr "đọc mẫu từ tập-tin"
 
-#: builtin/grep.c:803
+#: builtin/grep.c:804
 msgid "match <pattern>"
 msgstr "match <mẫu>"
 
-#: builtin/grep.c:805
+#: builtin/grep.c:806
 msgid "combine patterns specified with -e"
 msgstr "tổ hợp mẫu được chỉ ra với tùy chọn -e"
 
-#: builtin/grep.c:817
+#: builtin/grep.c:818
 msgid "indicate hit with exit status without output"
 msgstr "đưa ra gợi ý với trạng thái thoát mà không có kết xuất"
 
-#: builtin/grep.c:819
+#: builtin/grep.c:820
 msgid "show only matches from files that match all patterns"
 msgstr "chỉ hiển thị những cái khớp từ tập tin mà nó khớp toàn bộ các mẫu"
 
 #: builtin/grep.c:822
+msgid "show parse tree for grep expression"
+msgstr "hiển thị cây phân tích cú pháp cho biểu thức `grep' (tìm kiếm)"
+
+#: builtin/grep.c:826
 msgid "pager"
 msgstr "trang giấy"
 
-#: builtin/grep.c:822
+#: builtin/grep.c:826
 msgid "show matching files in the pager"
 msgstr "hiển thị các tập tin khớp trong trang giấy"
 
-#: builtin/grep.c:825
+#: builtin/grep.c:829
 msgid "allow calling of grep(1) (ignored by this build)"
 msgstr "cho phép gọi grep(1) (bị bỏ qua bởi lần dịch này)"
 
-#: builtin/grep.c:826 builtin/show-ref.c:201
+#: builtin/grep.c:830 builtin/show-ref.c:201
 msgid "show usage"
 msgstr "hiển thị cách dùng"
 
-#: builtin/grep.c:917
+#: builtin/grep.c:921
 msgid "no pattern given."
 msgstr "chưa chỉ ra mẫu."
 
-#: builtin/grep.c:931
+#: builtin/grep.c:935
 #, c-format
 msgid "bad object %s"
 msgstr "đối tượng sai %s"
 
-#: builtin/grep.c:972
+#: builtin/grep.c:976
 msgid "--open-files-in-pager only works on the worktree"
 msgstr "--open-files-in-pager chỉ làm việc trên cây-làm-việc"
 
-#: builtin/grep.c:995
+#: builtin/grep.c:999
 msgid "--cached or --untracked cannot be used with --no-index."
 msgstr "--cached hay --untracked không được sử dụng với --no-index."
 
-#: builtin/grep.c:1000
+#: builtin/grep.c:1004
 msgid "--no-index or --untracked cannot be used with revs."
 msgstr ""
 "--no-index hay --untracked không được sử dụng cùng với các tùy chọn liên "
 "quan đến revs."
 
-#: builtin/grep.c:1003
+#: builtin/grep.c:1007
 msgid "--[no-]exclude-standard cannot be used for tracked contents."
 msgstr "--[no-]exclude-standard không thể sử dụng cho nội dung lưu dấu vết."
 
-#: builtin/grep.c:1011
+#: builtin/grep.c:1015
 msgid "both --cached and trees are given."
 msgstr "cả hai --cached và các cây phải được chỉ ra."
 
@@ -5812,7 +5787,7 @@ msgstr "cho phép fast-forward (mặc định)"
 msgid "abort if fast-forward is not possible"
 msgstr "bỏ qua nếu fast-forward không thể được"
 
-#: builtin/merge.c:202 builtin/notes.c:867 builtin/revert.c:112
+#: builtin/merge.c:202 builtin/notes.c:870 builtin/revert.c:112
 msgid "strategy"
 msgstr "chiến lược"
 
@@ -5917,7 +5892,7 @@ msgstr "Không thể đọc từ `%s'"
 #, c-format
 msgid "Not committing merge; use 'git commit' to complete the merge.\n"
 msgstr ""
-"Vẫn chưa hòa trộn các lần chuyển giao (commit); sử dụng lệnh 'git commit' để "
+"Vẫn chưa hòa trộn các lần chuyển giao (commit); sử dụng lệnh `git commit' để "
 "hoàn tất việc hòa trộn.\n"
 
 #: builtin/merge.c:891
@@ -6289,11 +6264,11 @@ msgstr "đọc từ đầu vào tiêu chuẩn"
 msgid "allow to print `undefined` names"
 msgstr "cho phép hiển thị các tên `chưa định nghĩa'"
 
-#: builtin/notes.c:23
+#: builtin/notes.c:26
 msgid "git notes [--ref <notes_ref>] [list [<object>]]"
 msgstr "git notes [--ref <notes_ref>] [list [<đối-tượng>]]"
 
-#: builtin/notes.c:24
+#: builtin/notes.c:27
 msgid ""
 "git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) "
 "<object>] [<object>]"
@@ -6301,11 +6276,11 @@ msgstr ""
 "git notes [--ref <notes_ref>] add [-f] [-m <lời-nhắn> | -F <tập-tin> | (-c | "
 "-C) <đối-tượng>] [<đối-tượng>]"
 
-#: builtin/notes.c:25
+#: builtin/notes.c:28
 msgid "git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>"
 msgstr "git notes [--ref <notes_ref>] copy [-f] <từ-đối-tượng> <đến-đối-tượng>"
 
-#: builtin/notes.c:26
+#: builtin/notes.c:29
 msgid ""
 "git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) "
 "<object>] [<object>]"
@@ -6313,228 +6288,228 @@ msgstr ""
 "git notes [--ref <notes_ref>] append [-m <lời-nhắn> | -F <tập-tin> | (-c | -"
 "C) <đối-tượng>] [<đối-tượng>]"
 
-#: builtin/notes.c:27
+#: builtin/notes.c:30
 msgid "git notes [--ref <notes_ref>] edit [<object>]"
 msgstr "git notes [--ref <notes_ref>] edit [<đối-tượng>]"
 
-#: builtin/notes.c:28
+#: builtin/notes.c:31
 msgid "git notes [--ref <notes_ref>] show [<object>]"
 msgstr "git notes [--ref <notes_ref>] show [<đối-tượng>]"
 
-#: builtin/notes.c:29
+#: builtin/notes.c:32
 msgid ""
 "git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>"
 msgstr ""
 "git notes [--ref <notes_ref>] merge [-v | -q] [-s <chiến-lược> ] <notes_ref>"
 
-#: builtin/notes.c:30
+#: builtin/notes.c:33
 msgid "git notes merge --commit [-v | -q]"
 msgstr "git notes merge --commit [-v | -q]"
 
-#: builtin/notes.c:31
+#: builtin/notes.c:34
 msgid "git notes merge --abort [-v | -q]"
 msgstr "git notes merge --abort [-v | -q]"
 
-#: builtin/notes.c:32
+#: builtin/notes.c:35
 msgid "git notes [--ref <notes_ref>] remove [<object>...]"
 msgstr "git notes [--ref <notes_ref>] remove [<đối-tượng>...]"
 
-#: builtin/notes.c:33
+#: builtin/notes.c:36
 msgid "git notes [--ref <notes_ref>] prune [-n | -v]"
 msgstr "git notes [--ref <notes_ref>] prune [-n | -v]"
 
-#: builtin/notes.c:34
+#: builtin/notes.c:37
 msgid "git notes [--ref <notes_ref>] get-ref"
 msgstr "git notes [--ref <notes_ref>] get-ref"
 
-#: builtin/notes.c:39
+#: builtin/notes.c:42
 msgid "git notes [list [<object>]]"
 msgstr "git notes [list [<đối tượng>]]"
 
-#: builtin/notes.c:44
+#: builtin/notes.c:47
 msgid "git notes add [<options>] [<object>]"
 msgstr "git notes add [<các-tùy-chọn>] [<đối-tượng>]"
 
-#: builtin/notes.c:49
+#: builtin/notes.c:52
 msgid "git notes copy [<options>] <from-object> <to-object>"
 msgstr "git notes copy [<các-tùy-chọn>] <từ-đối-tượng> <đến-đối-tượng>"
 
-#: builtin/notes.c:50
+#: builtin/notes.c:53
 msgid "git notes copy --stdin [<from-object> <to-object>]..."
 msgstr "git notes copy --stdin [<từ-đối-tượng> <đến-đối-tượng>]..."
 
-#: builtin/notes.c:55
+#: builtin/notes.c:58
 msgid "git notes append [<options>] [<object>]"
 msgstr "git notes append [<các-tùy-chọn>] [<đối-tượng>]"
 
-#: builtin/notes.c:60
+#: builtin/notes.c:63
 msgid "git notes edit [<object>]"
 msgstr "git notes edit [<đối tượng>]"
 
-#: builtin/notes.c:65
+#: builtin/notes.c:68
 msgid "git notes show [<object>]"
 msgstr "git notes show [<đối tượng>]"
 
-#: builtin/notes.c:70
+#: builtin/notes.c:73
 msgid "git notes merge [<options>] <notes_ref>"
 msgstr "git notes merge [<các-tùy-chọn>] <notes_ref>"
 
-#: builtin/notes.c:71
+#: builtin/notes.c:74
 msgid "git notes merge --commit [<options>]"
 msgstr "git notes merge --commit [<các-tùy-chọn>]"
 
-#: builtin/notes.c:72
+#: builtin/notes.c:75
 msgid "git notes merge --abort [<options>]"
 msgstr "git notes merge --abort [<các-tùy-chọn>]"
 
-#: builtin/notes.c:77
+#: builtin/notes.c:80
 msgid "git notes remove [<object>]"
 msgstr "git notes remove [<đối tượng>]"
 
-#: builtin/notes.c:82
+#: builtin/notes.c:85
 msgid "git notes prune [<options>]"
 msgstr "git notes prune [<các-tùy-chọn>]"
 
-#: builtin/notes.c:87
+#: builtin/notes.c:90
 msgid "git notes get-ref"
 msgstr "git notes get-ref"
 
-#: builtin/notes.c:139
+#: builtin/notes.c:142
 #, c-format
 msgid "unable to start 'show' for object '%s'"
 msgstr "không thể khởi chạy 'show' cho đối tượng `%s'"
 
-#: builtin/notes.c:145
+#: builtin/notes.c:148
 msgid "can't fdopen 'show' output fd"
 msgstr "không thể fdopen 'show' (lệnh hiển thị) mô tả tập tin (fd) kết xuất"
 
-#: builtin/notes.c:155
+#: builtin/notes.c:158
 #, c-format
 msgid "failed to close pipe to 'show' for object '%s'"
 msgstr "gặp lỗi khi đóng đường ống cho lệnh 'show' cho đối tượng `%s'"
 
-#: builtin/notes.c:158
+#: builtin/notes.c:161
 #, c-format
 msgid "failed to finish 'show' for object '%s'"
 msgstr "gặp lỗi khi hoàn thành `show' cho đối tượng `%s'"
 
-#: builtin/notes.c:175 builtin/tag.c:347
+#: builtin/notes.c:178 builtin/tag.c:347
 #, c-format
 msgid "could not create file '%s'"
 msgstr "không thể tạo tập tin `%s'"
 
-#: builtin/notes.c:189
+#: builtin/notes.c:192
 msgid "Please supply the note contents using either -m or -F option"
 msgstr ""
 "Xin hãy áp dụng nội dung của ghi chú sử dụng hoặc là tùy chọn -m hoặc là -F"
 
-#: builtin/notes.c:210 builtin/notes.c:973
+#: builtin/notes.c:213 builtin/notes.c:976
 #, c-format
 msgid "Removing note for object %s\n"
 msgstr "Đang gỡ bỏ ghi chú (note) cho đối tượng %s\n"
 
-#: builtin/notes.c:215
+#: builtin/notes.c:218
 msgid "unable to write note object"
 msgstr "không thể ghi đối tượng ghi chú (note)"
 
-#: builtin/notes.c:217
+#: builtin/notes.c:220
 #, c-format
 msgid "The note contents has been left in %s"
 msgstr "Nội dung ghi chú còn lại %s"
 
-#: builtin/notes.c:251 builtin/tag.c:542
+#: builtin/notes.c:254 builtin/tag.c:542
 #, c-format
 msgid "cannot read '%s'"
 msgstr "không thể đọc `%s'"
 
-#: builtin/notes.c:253 builtin/tag.c:545
+#: builtin/notes.c:256 builtin/tag.c:545
 #, c-format
 msgid "could not open or read '%s'"
 msgstr "không thể mở để đọc hay ghi `%s'"
 
-#: builtin/notes.c:272 builtin/notes.c:445 builtin/notes.c:447
-#: builtin/notes.c:507 builtin/notes.c:561 builtin/notes.c:644
-#: builtin/notes.c:649 builtin/notes.c:724 builtin/notes.c:766
-#: builtin/notes.c:968 builtin/reset.c:293 builtin/tag.c:558
+#: builtin/notes.c:275 builtin/notes.c:448 builtin/notes.c:450
+#: builtin/notes.c:510 builtin/notes.c:564 builtin/notes.c:647
+#: builtin/notes.c:652 builtin/notes.c:727 builtin/notes.c:769
+#: builtin/notes.c:971 builtin/reset.c:293 builtin/tag.c:558
 #, c-format
 msgid "Failed to resolve '%s' as a valid ref."
 msgstr "Gặp lỗi khi giải quyết `%s' như là một tham chiếu (ref) hợp lệ."
 
-#: builtin/notes.c:275
+#: builtin/notes.c:278
 #, c-format
 msgid "Failed to read object '%s'."
 msgstr "Gặp lỗi khi đọc đối tượng `%s'."
 
-#: builtin/notes.c:299
+#: builtin/notes.c:302
 msgid "Cannot commit uninitialized/unreferenced notes tree"
 msgstr ""
 "Không thể chuyển giao (commit) chưa được khởi tạo hoặc không được tham chiếu "
 "cây ghi chú"
 
-#: builtin/notes.c:340
+#: builtin/notes.c:343
 #, c-format
 msgid "Bad notes.rewriteMode value: '%s'"
 msgstr "Giá trị notes.rewriteMode sai: `%s'"
 
-#: builtin/notes.c:350
+#: builtin/notes.c:353
 #, c-format
 msgid "Refusing to rewrite notes in %s (outside of refs/notes/)"
 msgstr "Từ chối ghi đè ghi chú trong %s (nằm ngoài của refs/notes/)"
 
 #. TRANSLATORS: The first %s is the name of the
 #. environment variable, the second %s is its value
-#: builtin/notes.c:377
+#: builtin/notes.c:380
 #, c-format
 msgid "Bad %s value: '%s'"
 msgstr "Giá trị %s sai: `%s'"
 
-#: builtin/notes.c:441
+#: builtin/notes.c:444
 #, c-format
 msgid "Malformed input line: '%s'."
 msgstr "Dòng nhập vào dị hình: `%s'."
 
-#: builtin/notes.c:456
+#: builtin/notes.c:459
 #, c-format
 msgid "Failed to copy notes from '%s' to '%s'"
 msgstr "Gặp lỗi khi sao chép ghi chú (note) từ `%s' tới `%s'"
 
-#: builtin/notes.c:500 builtin/notes.c:554 builtin/notes.c:627
-#: builtin/notes.c:639 builtin/notes.c:712 builtin/notes.c:759
-#: builtin/notes.c:1033
+#: builtin/notes.c:503 builtin/notes.c:557 builtin/notes.c:630
+#: builtin/notes.c:642 builtin/notes.c:715 builtin/notes.c:762
+#: builtin/notes.c:1036
 msgid "too many parameters"
 msgstr "quá nhiều đối số"
 
-#: builtin/notes.c:513 builtin/notes.c:772
+#: builtin/notes.c:516 builtin/notes.c:775
 #, c-format
 msgid "No note found for object %s."
 msgstr "không tìm thấy ghi chú cho đối tượng %s."
 
-#: builtin/notes.c:535 builtin/notes.c:692
+#: builtin/notes.c:538 builtin/notes.c:695
 msgid "note contents as a string"
 msgstr "nội dung ghi chú (note) nằm trong một chuỗi"
 
-#: builtin/notes.c:538 builtin/notes.c:695
+#: builtin/notes.c:541 builtin/notes.c:698
 msgid "note contents in a file"
 msgstr "nội dung ghi chú (note) nằm trong một tập tin"
 
-#: builtin/notes.c:540 builtin/notes.c:543 builtin/notes.c:697
-#: builtin/notes.c:700 builtin/tag.c:476
+#: builtin/notes.c:543 builtin/notes.c:546 builtin/notes.c:700
+#: builtin/notes.c:703 builtin/tag.c:476
 msgid "object"
 msgstr "đối tượng"
 
-#: builtin/notes.c:541 builtin/notes.c:698
+#: builtin/notes.c:544 builtin/notes.c:701
 msgid "reuse and edit specified note object"
 msgstr "dùng lại nhưng có sửa chữa đối tượng note đã chỉ ra"
 
-#: builtin/notes.c:544 builtin/notes.c:701
+#: builtin/notes.c:547 builtin/notes.c:704
 msgid "reuse specified note object"
 msgstr "dùng lại đối tượng ghi chú (note) đã chỉ ra"
 
-#: builtin/notes.c:546 builtin/notes.c:614
+#: builtin/notes.c:549 builtin/notes.c:617
 msgid "replace existing notes"
 msgstr "thay thế ghi chú trước"
 
-#: builtin/notes.c:580
+#: builtin/notes.c:583
 #, c-format
 msgid ""
 "Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite "
@@ -6543,24 +6518,24 @@ msgstr ""
 "Không thể thêm các ghi chú. Đã tìm thấy các ghi chú đã có sẵn cho đối tượng "
 "%s. Sử dụng tùy chọn '-f' để ghi đè lên các ghi chú cũ"
 
-#: builtin/notes.c:585 builtin/notes.c:662
+#: builtin/notes.c:588 builtin/notes.c:665
 #, c-format
 msgid "Overwriting existing notes for object %s\n"
 msgstr "Đang ghi đè lên ghi chú cũ cho đối tượng %s\n"
 
-#: builtin/notes.c:615
+#: builtin/notes.c:618
 msgid "read objects from stdin"
 msgstr "đọc các đối tượng từ đầu vào tiêu chuẩn"
 
-#: builtin/notes.c:617
+#: builtin/notes.c:620
 msgid "load rewriting config for <command> (implies --stdin)"
 msgstr "tải cấu hình chép lại cho <lệnh> (ngầm định là --stdin)"
 
-#: builtin/notes.c:635
+#: builtin/notes.c:638
 msgid "too few parameters"
 msgstr "quá ít đối số"
 
-#: builtin/notes.c:656
+#: builtin/notes.c:659
 #, c-format
 msgid ""
 "Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite "
@@ -6569,29 +6544,29 @@ msgstr ""
 "Không thể sao chép các ghi chú. Đã tìm thấy các ghi chú đã có sẵn cho đối "
 "tượng %s. Sử dụng tùy chọn '-f' để ghi đè lên các ghi chú cũ"
 
-#: builtin/notes.c:668
+#: builtin/notes.c:671
 #, c-format
 msgid "Missing notes on source object %s. Cannot copy."
 msgstr "Thiếu ghi chú trên đối tượng nguốn %s. Không thể sao chép."
 
-#: builtin/notes.c:717
+#: builtin/notes.c:720
 #, c-format
 msgid ""
 "The -m/-F/-c/-C options have been deprecated for the 'edit' subcommand.\n"
 "Please use 'git notes add -f -m/-F/-c/-C' instead.\n"
 msgstr ""
-"Các tùy chọn -m/-F/-c/-C đã cổ không còn dùng nữa cho lệnh con 'edit'.\n"
-"Xin hãy sử dụng lệnh sau để thay thế: 'git notes add -f -m/-F/-c/-C'.\n"
+"Các tùy chọn -m/-F/-c/-C đã cổ không còn dùng nữa cho lệnh con `edit'.\n"
+"Xin hãy sử dụng lệnh sau để thay thế: `git notes add -f -m/-F/-c/-C'.\n"
 
-#: builtin/notes.c:864
+#: builtin/notes.c:867
 msgid "General options"
 msgstr "Tùy chọn chung"
 
-#: builtin/notes.c:866
+#: builtin/notes.c:869
 msgid "Merge options"
 msgstr "Tùy chọn về hòa trộn"
 
-#: builtin/notes.c:868
+#: builtin/notes.c:871
 msgid ""
 "resolve notes conflicts using the given strategy (manual/ours/theirs/union/"
 "cat_sort_uniq)"
@@ -6599,46 +6574,46 @@ msgstr ""
 "phân giải các xung đột `notes' sử dụng chiến lược đã đưa ra (manual/ours/"
 "theirs/union/cat_sort_uniq)"
 
-#: builtin/notes.c:870
+#: builtin/notes.c:873
 msgid "Committing unmerged notes"
 msgstr "Chuyển giao các note chưa được hòa trộn"
 
-#: builtin/notes.c:872
+#: builtin/notes.c:875
 msgid "finalize notes merge by committing unmerged notes"
 msgstr ""
 "các note cuối cùng được hòa trộn bởi các note chưa hòa trộn của lần chuyển "
 "giao"
 
-#: builtin/notes.c:874
+#: builtin/notes.c:877
 msgid "Aborting notes merge resolution"
 msgstr "Hủy bỏ phân giải ghi chú (note) hòa trộn"
 
-#: builtin/notes.c:876
+#: builtin/notes.c:879
 msgid "abort notes merge"
 msgstr "bỏ qua hòa trộn các ghi chú (note)"
 
-#: builtin/notes.c:971
+#: builtin/notes.c:974
 #, c-format
 msgid "Object %s has no note\n"
 msgstr "Đối tượng %s không có ghi chú (note)\n"
 
-#: builtin/notes.c:983
+#: builtin/notes.c:986
 msgid "attempt to remove non-existent note is not an error"
 msgstr "cố gắng gỡ bỏ một note chưa từng tồn tại không phải là một lỗi"
 
-#: builtin/notes.c:986
+#: builtin/notes.c:989
 msgid "read object names from the standard input"
 msgstr "đọc tên đối tượng từ thiết bị nhập chuẩn"
 
-#: builtin/notes.c:1067
+#: builtin/notes.c:1070
 msgid "notes_ref"
 msgstr "notes_ref"
 
-#: builtin/notes.c:1068
+#: builtin/notes.c:1071
 msgid "use notes from <notes_ref>"
 msgstr "dùng `notes' từ <notes_ref>"
 
-#: builtin/notes.c:1103 builtin/remote.c:1598
+#: builtin/notes.c:1106 builtin/remote.c:1598
 #, c-format
 msgid "Unknown subcommand: %s"
 msgstr "Không hiểu câu lệnh con: %s"
@@ -6851,7 +6826,7 @@ msgid ""
 "To choose either option permanently, see push.default in 'git help config'."
 msgstr ""
 "\n"
-"Để chọn mỗi tùy chọn một cách cố định, xem push.default trong 'git help "
+"Để chọn mỗi tùy chọn một cách cố định, xem push.default trong `git help "
 "config'."
 
 #: builtin/push.c:102
@@ -6953,10 +6928,10 @@ msgstr ""
 "\n"
 "  git config --global push.default simple\n"
 "\n"
-"Xem 'git help config' và tìm đến 'push.default' để có thêm thông tin.\n"
+"Xem `git help config' và tìm đến `push.default' để có thêm thông tin.\n"
 "(chế độ 'simple' được bắt đầu sử dụng từ Git 1.7.11. Sử dụng chế độ tương "
 "tự\n"
-"'current' thay vì 'simple' nếu bạn thỉnh thoảng phải sử dụng bản Git cũ)"
+"`current' thay vì `simple' nếu bạn thỉnh thoảng phải sử dụng bản Git cũ)"
 
 #: builtin/push.c:199
 msgid ""
@@ -6973,10 +6948,10 @@ msgid ""
 "See the 'Note about fast-forwards' in 'git push --help' for details."
 msgstr ""
 "Việc cập nhật bị từ chối bởi vì đầu mút của nhánh được push nằm đằng sau bộ\n"
-"phận tương ứng của máy chủ. Hòa trộn với các thay đổi từ máy chủ (v.d. 'git "
+"phận tương ứng của máy chủ. Hòa trộn với các thay đổi từ máy chủ (v.d. `git "
 "pull')\n"
 "trước khi lại push lần nữa.\n"
-"Xem trong phần 'Note about fast-forwards' từ lệnh 'git push --help' để có "
+"Xem trong phần 'Note about fast-forwards' từ lệnh `git push --help' để có "
 "thông tin chi tiết."
 
 #: builtin/push.c:212
@@ -7004,8 +6979,8 @@ msgstr ""
 "Việc cập nhật bị từ chối bởi vì đầu mút của nhánh được push nằm đằng sau bộ\n"
 "phận tương ứng của máy chủ. Checkou nhánh này và hòa trộn với các thay đổi "
 "từ máy chủ\n"
-"(v.d. 'git pull') trước khi lại push lần nữa.\n"
-"Xem trong phần 'Note about fast-forwards' từ lệnh 'git push --help' để có "
+"(v.d. `git pull') trước khi lại push lần nữa.\n"
+"Xem trong phần 'Note about fast-forwards' từ lệnh `git push --help' để có "
 "thông tin chi tiết."
 
 #: builtin/push.c:258
@@ -7449,7 +7424,7 @@ msgstr " được theo vết"
 
 #: builtin/remote.c:948
 msgid " stale (use 'git remote prune' to remove)"
-msgstr " cũ (dùng 'git remote prune' để gỡ bỏ)"
+msgstr " cũ (dùng `git remote prune' để gỡ bỏ)"
 
 #: builtin/remote.c:950
 msgid " ???"
@@ -7571,12 +7546,12 @@ msgstr " (trạng thái không được yêu cầu)"
 #: builtin/remote.c:1163
 msgid "  Local branch configured for 'git pull':"
 msgid_plural "  Local branches configured for 'git pull':"
-msgstr[0] "  Nhánh nội bộ đã được cấu hình cho lệnh 'git pull':"
-msgstr[1] "  Những nhánh nội bộ đã được cấu hình cho lệnh 'git pull':"
+msgstr[0] "  Nhánh nội bộ đã được cấu hình cho lệnh `git pull':"
+msgstr[1] "  Những nhánh nội bộ đã được cấu hình cho lệnh `git pull':"
 
 #: builtin/remote.c:1171
 msgid "  Local refs will be mirrored by 'git push'"
-msgstr "  refs nội bộ sẽ được phản chiếu bởi lệnh 'git push'"
+msgstr "  refs nội bộ sẽ được phản chiếu bởi lệnh `git push'"
 
 #: builtin/remote.c:1178
 #, c-format
@@ -7830,7 +7805,7 @@ msgstr "--patch xung khắc với --{hard,mixed,soft}"
 #: builtin/reset.c:317
 msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead."
 msgstr ""
-"--mixed với các đường dẫn không còn dùng nữa; hãy thay thế bằng lệnh 'git "
+"--mixed với các đường dẫn không còn dùng nữa; hãy thay thế bằng lệnh `git "
 "reset -- <đường_dẫn>'."
 
 #: builtin/reset.c:319
@@ -8598,7 +8573,7 @@ msgstr "chỉ hữu ích khi cần gỡ lỗi"
 #: git.c:16
 msgid "See 'git help <command>' for more information on a specific command."
 msgstr ""
-"Chạy lệnh 'git help <tên-lệnh>' để có thêm thông tin về lệnh được chỉ ra."
+"Chạy lệnh `git help <tên-lệnh>' để có thêm thông tin về lệnh được chỉ ra."
 
 #: parse-options.h:156
 msgid "no-op (backward compatibility)"
@@ -8849,7 +8824,7 @@ msgid ""
 "If there is nothing left to stage, chances are that something else\n"
 "already introduced the same changes; you might want to skip this patch."
 msgstr ""
-"Không có thay đổi nào - bạn đã quên sử dụng lệnh 'git add' à?\n"
+"Không có thay đổi nào - bạn đã quên sử dụng lệnh `git add' à?\n"
 "Nếu ở đây không có gì còn lại stage, tình cờ là có một số thứ khác\n"
 "đã sẵn được đưa vào với cùng nội dung thay đổi; bạn có lẽ muốn bỏ qua miếng "
 "vá này."
@@ -8860,7 +8835,7 @@ msgid ""
 "did you forget to use 'git add'?"
 msgstr ""
 "Bạn vẫn có những đường dẫn chưa được hòa trộn trong bảng mục lục của mình\n"
-"bạn đã quên sử dụng lệnh 'git add' à?"
+"bạn đã quên sử dụng lệnh `git add' à?"
 
 #: git-am.sh:845
 msgid "No changes -- Patch already applied."
@@ -8914,7 +8889,7 @@ msgstr "HEAD sai - Tôi cần một HEAD"
 msgid ""
 "Checking out '$start_head' failed. Try 'git bisect reset <validbranch>'."
 msgstr ""
-"Việc checkout '$start_head' gặp lỗi. Hãy thử 'git bisect reset "
+"Việc checkout '$start_head' gặp lỗi. Hãy thử `git bisect reset "
 "<nhánh_hợp_lệ>'."
 
 #: git-bisect.sh:140
@@ -8946,7 +8921,7 @@ msgstr "Đầu vào rev sai: $rev"
 
 #: git-bisect.sh:250
 msgid "'git bisect bad' can take only one argument."
-msgstr "'git bisect bad' có thể lấy chỉ một đối số."
+msgstr "`git bisect bad' có thể lấy chỉ một đối số."
 
 #. have bad but not good.  we could bisect although
 #. this is less optimum.
@@ -8997,7 +8972,7 @@ msgid ""
 "Try 'git bisect reset <commit>'."
 msgstr ""
 "Không thể check-out HEAD nguyên thủy của '$branch'.\n"
-"Hãy thử 'git bisect reset <lần-chuyển-giao>'."
+"Hãy thử `git bisect reset <lần-chuyển-giao>'."
 
 #: git-bisect.sh:390
 msgid "No logfile given"
@@ -9050,8 +9025,8 @@ msgid ""
 "as appropriate to mark resolution, or use 'git commit -a'."
 msgstr ""
 "Pull là không thể được bởi vì bạn có những tập tin chưa được hòa trộn.\n"
-"Xin hãy sửa chữa chúng trước, và sau đó sử dụng lệnh 'git add/rm <tập-tin>'\n"
-"để phê chuẩn việc đánh dấu đây cần được giải quyết, hoặc là sử dụng 'git "
+"Xin hãy sửa chữa chúng trước, và sau đó sử dụng lệnh `git add/rm <tập-tin>'\n"
+"để phê chuẩn việc đánh dấu đây cần được giải quyết, hoặc là sử dụng `git "
 "commit -a'."
 
 #: git-pull.sh:25
@@ -9088,7 +9063,7 @@ msgstr "Không thể hòa trộn nhiều nhánh và trong một head trống r
 msgid "Cannot rebase onto multiple branches"
 msgstr "Không thể thực hiện lệnh rebase (cơ cấu lại) trên nhiều nhánh"
 
-#: git-rebase.sh:52
+#: git-rebase.sh:53
 msgid ""
 "When you have resolved this problem, run \"git rebase --continue\".\n"
 "If you prefer to skip this patch, run \"git rebase --skip\" instead.\n"
@@ -9101,29 +9076,35 @@ msgstr ""
 "Để phục hồi lại thành nhánh nguyên thủy và dừng việc vá lại thì chạy \"git "
 "rebase --abort\"."
 
-#: git-rebase.sh:159
+#: git-rebase.sh:160
 msgid "The pre-rebase hook refused to rebase."
 msgstr "hook (chương trình móc vào git) pre-rebase từ chối rebase."
 
-#: git-rebase.sh:164
+#: git-rebase.sh:165
 msgid "It looks like git-am is in progress. Cannot rebase."
 msgstr ""
 "Hình như đang trong quá trình thực hiện lệnh git-am. Không thể chạy lệnh "
 "rebase."
 
-#: git-rebase.sh:295
+#: git-rebase.sh:296
 msgid "The --exec option must be used with the --interactive option"
 msgstr "Tùy chọn --exec phải được sử dụng cùng với tùy chọn --interactive"
 
-#: git-rebase.sh:300
+#: git-rebase.sh:301
 msgid "No rebase in progress?"
 msgstr "Không có tiến trình rebase nào phải không?"
 
-#: git-rebase.sh:313
+#: git-rebase.sh:312
+msgid "The --edit-todo action can only be used during interactive rebase."
+msgstr ""
+"Hành động `--edit-todo' chỉ có thể dùng trong quá trình `rebase' (sửa lịch "
+"sử) tương tác."
+
+#: git-rebase.sh:319
 msgid "Cannot read HEAD"
 msgstr "Không thể đọc HEAD"
 
-#: git-rebase.sh:316
+#: git-rebase.sh:322
 msgid ""
 "You must edit all merge conflicts and then\n"
 "mark them as resolved using git add"
@@ -9131,12 +9112,12 @@ msgstr ""
 "Bạn phải sửa tất cả các lần hòa trộn xung đột và sau\n"
 "đó đánh dấu chúng là cần xử lý sử dụng lệnh git add"
 
-#: git-rebase.sh:334
+#: git-rebase.sh:340
 #, sh-format
 msgid "Could not move back to $head_name"
 msgstr "Không thể quay trở lại $head_name"
 
-#: git-rebase.sh:350
+#: git-rebase.sh:359
 #, sh-format
 msgid ""
 "It seems that there is already a $state_dir_base directory, and\n"
@@ -9159,57 +9140,57 @@ msgstr ""
 "\n"
 "TÔI: là lệnh bạn vừa gọi!"
 
-#: git-rebase.sh:395
+#: git-rebase.sh:404
 #, sh-format
 msgid "invalid upstream $upstream_name"
 msgstr "thượng nguồn không hợp lệ $upstream_name"
 
-#: git-rebase.sh:419
+#: git-rebase.sh:428
 #, sh-format
 msgid "$onto_name: there are more than one merge bases"
 msgstr "$onto_name: ở đây có nhiều hơn một"
 
-#: git-rebase.sh:422 git-rebase.sh:426
+#: git-rebase.sh:431 git-rebase.sh:435
 #, sh-format
 msgid "$onto_name: there is no merge base"
 msgstr "$onto_name: ở đây không có gì để hòa trộn"
 
-#: git-rebase.sh:431
+#: git-rebase.sh:440
 #, sh-format
 msgid "Does not point to a valid commit: $onto_name"
 msgstr "Không chỉ đến một lần chuyển giao (commit) không hợp lệ: $onto_name"
 
-#: git-rebase.sh:454
+#: git-rebase.sh:463
 #, sh-format
 msgid "fatal: no such branch: $branch_name"
 msgstr "nghiêm trọng: không có nhánh như thế: $branch_name"
 
-#: git-rebase.sh:474
+#: git-rebase.sh:483
 msgid "Please commit or stash them."
 msgstr "Xin hãy commit hoặc stash chúng."
 
-#: git-rebase.sh:492
+#: git-rebase.sh:501
 #, sh-format
 msgid "Current branch $branch_name is up to date."
 msgstr "Nhánh hiện tại $branch_name đã được cập nhật rồi."
 
-#: git-rebase.sh:495
+#: git-rebase.sh:504
 #, sh-format
 msgid "Current branch $branch_name is up to date, rebase forced."
 msgstr "Nhánh hiện tại $branch_name đã được cập nhật rồi, lệnh rebase ép buộc."
 
-#: git-rebase.sh:506
+#: git-rebase.sh:515
 #, sh-format
 msgid "Changes from $mb to $onto:"
 msgstr "Thay đổi từ $mb thành $onto:"
 
 #. Detach HEAD and reset the tree
-#: git-rebase.sh:515
+#: git-rebase.sh:524
 msgid "First, rewinding head to replay your work on top of it..."
 msgstr ""
 "Trước tiên, di chuyển head để xem lại các công việc trên đỉnh của nó..."
 
-#: git-rebase.sh:523
+#: git-rebase.sh:532
 #, sh-format
 msgid "Fast-forwarded $branch_name to $onto_name."
 msgstr "Fast-forward $branch_name thành $onto_name."
@@ -9547,6 +9528,27 @@ msgstr "# Những thay đổi mô-đun-con được chuyển giao (commit):"
 msgid "Synchronizing submodule url for '$name'"
 msgstr "Đang đồng bộ hóa url mô-đun-con cho '$name'"
 
+#~ msgid " 0 files changed"
+#~ msgstr " 0 có tập tin nào thay đổi cả"
+
+#~ msgid " %d file changed"
+#~ msgid_plural " %d files changed"
+#~ msgstr[0] " %d tập tin thay đổi"
+#~ msgstr[1] " %d tập tin thay đổi"
+
+#~ msgid ", %d insertion(+)"
+#~ msgid_plural ", %d insertions(+)"
+#~ msgstr[0] ", %d thêm(+)"
+#~ msgstr[1] ", %d thêm(+)"
+
+#~ msgid ", %d deletion(-)"
+#~ msgid_plural ", %d deletions(-)"
+#~ msgstr[0] ", %d xóa(-)"
+#~ msgstr[1] ", %d xóa(-)"
+
+#~ msgid "Auto packing the repository for optimum performance.\n"
+#~ msgstr "Tự động đóng gói kho chứa để tối ưu hóa hiệu suất làm việc.\n"
+
 #~ msgid " (use \"git add\" to track)"
 #~ msgstr " (dùng \"git add\" để theo dõi dấu vết)"
 
index 8b1ea9ffad2a0b5c5cb5c15cc5057a8a7132da07..413e7587b6f67326a68a7679ca5496cd1249fbcd 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -231,7 +231,7 @@ static int is_rfc822_special(char ch)
        }
 }
 
-static int has_rfc822_specials(const char *s, int len)
+static int needs_rfc822_quoting(const char *s, int len)
 {
        int i;
        for (i = 0; i < len; i++)
@@ -240,6 +240,17 @@ static int has_rfc822_specials(const char *s, int len)
        return 0;
 }
 
+static int last_line_length(struct strbuf *sb)
+{
+       int i;
+
+       /* How many bytes are already used on the last line? */
+       for (i = sb->len - 1; i >= 0; i--)
+               if (sb->buf[i] == '\n')
+                       break;
+       return sb->len - (i + 1);
+}
+
 static void add_rfc822_quoted(struct strbuf *out, const char *s, int len)
 {
        int i;
@@ -261,57 +272,110 @@ static void add_rfc822_quoted(struct strbuf *out, const char *s, int len)
        strbuf_addch(out, '"');
 }
 
-static int is_rfc2047_special(char ch)
+enum rfc2047_type {
+       RFC2047_SUBJECT,
+       RFC2047_ADDRESS,
+};
+
+static int is_rfc2047_special(char ch, enum rfc2047_type type)
 {
-       return (non_ascii(ch) || (ch == '=') || (ch == '?') || (ch == '_'));
+       /*
+        * rfc2047, section 4.2:
+        *
+        *    8-bit values which correspond to printable ASCII characters other
+        *    than "=", "?", and "_" (underscore), MAY be represented as those
+        *    characters.  (But see section 5 for restrictions.)  In
+        *    particular, SPACE and TAB MUST NOT be represented as themselves
+        *    within encoded words.
+        */
+
+       /*
+        * rule out non-ASCII characters and non-printable characters (the
+        * non-ASCII check should be redundant as isprint() is not localized
+        * and only knows about ASCII, but be defensive about that)
+        */
+       if (non_ascii(ch) || !isprint(ch))
+               return 1;
+
+       /*
+        * rule out special printable characters (' ' should be the only
+        * whitespace character considered printable, but be defensive and use
+        * isspace())
+        */
+       if (isspace(ch) || ch == '=' || ch == '?' || ch == '_')
+               return 1;
+
+       /*
+        * rfc2047, section 5.3:
+        *
+        *    As a replacement for a 'word' entity within a 'phrase', for example,
+        *    one that precedes an address in a From, To, or Cc header.  The ABNF
+        *    definition for 'phrase' from RFC 822 thus becomes:
+        *
+        *    phrase = 1*( encoded-word / word )
+        *
+        *    In this case the set of characters that may be used in a "Q"-encoded
+        *    'encoded-word' is restricted to: <upper and lower case ASCII
+        *    letters, decimal digits, "!", "*", "+", "-", "/", "=", and "_"
+        *    (underscore, ASCII 95.)>.  An 'encoded-word' that appears within a
+        *    'phrase' MUST be separated from any adjacent 'word', 'text' or
+        *    'special' by 'linear-white-space'.
+        */
+
+       if (type != RFC2047_ADDRESS)
+               return 0;
+
+       /* '=' and '_' are special cases and have been checked above */
+       return !(isalnum(ch) || ch == '!' || ch == '*' || ch == '+' || ch == '-' || ch == '/');
 }
 
-static void add_rfc2047(struct strbuf *sb, const char *line, int len,
-                      const char *encoding)
+static int needs_rfc2047_encoding(const char *line, int len,
+                                 enum rfc2047_type type)
 {
-       static const int max_length = 78; /* per rfc2822 */
        int i;
-       int line_len;
-
-       /* How many bytes are already used on the current line? */
-       for (i = sb->len - 1; i >= 0; i--)
-               if (sb->buf[i] == '\n')
-                       break;
-       line_len = sb->len - (i+1);
 
        for (i = 0; i < len; i++) {
                int ch = line[i];
                if (non_ascii(ch) || ch == '\n')
-                       goto needquote;
+                       return 1;
                if ((i + 1 < len) && (ch == '=' && line[i+1] == '?'))
-                       goto needquote;
+                       return 1;
        }
-       strbuf_add_wrapped_bytes(sb, line, len, 0, 1, max_length - line_len);
-       return;
 
-needquote:
+       return 0;
+}
+
+static void add_rfc2047(struct strbuf *sb, const char *line, int len,
+                      const char *encoding, enum rfc2047_type type)
+{
+       static const int max_encoded_length = 76; /* per rfc2047 */
+       int i;
+       int line_len = last_line_length(sb);
+
        strbuf_grow(sb, len * 3 + strlen(encoding) + 100);
        strbuf_addf(sb, "=?%s?q?", encoding);
        line_len += strlen(encoding) + 5; /* 5 for =??q? */
        for (i = 0; i < len; i++) {
                unsigned ch = line[i] & 0xFF;
+               int is_special = is_rfc2047_special(ch, type);
+
+               /*
+                * According to RFC 2047, we could encode the special character
+                * ' ' (space) with '_' (underscore) for readability. But many
+                * programs do not understand this and just leave the
+                * underscore in place. Thus, we do nothing special here, which
+                * causes ' ' to be encoded as '=20', avoiding this problem.
+                */
 
-               if (line_len >= max_length - 2) {
+               if (line_len + 2 + (is_special ? 3 : 1) > max_encoded_length) {
                        strbuf_addf(sb, "?=\n =?%s?q?", encoding);
                        line_len = strlen(encoding) + 5 + 1; /* =??q? plus SP */
                }
 
-               /*
-                * We encode ' ' using '=20' even though rfc2047
-                * allows using '_' for readability.  Unfortunately,
-                * many programs do not understand this and just
-                * leave the underscore in place.
-                */
-               if (is_rfc2047_special(ch) || ch == ' ' || ch == '\n') {
+               if (is_special) {
                        strbuf_addf(sb, "=%02X", ch);
                        line_len += 3;
-               }
-               else {
+               } else {
                        strbuf_addch(sb, ch);
                        line_len++;
                }
@@ -323,6 +387,7 @@ void pp_user_info(const struct pretty_print_context *pp,
                  const char *what, struct strbuf *sb,
                  const char *line, const char *encoding)
 {
+       int max_length = 78; /* per rfc2822 */
        char *date;
        int namelen;
        unsigned long time;
@@ -340,25 +405,27 @@ void pp_user_info(const struct pretty_print_context *pp,
        if (pp->fmt == CMIT_FMT_EMAIL) {
                char *name_tail = strchr(line, '<');
                int display_name_length;
-               int final_line;
                if (!name_tail)
                        return;
                while (line < name_tail && isspace(name_tail[-1]))
                        name_tail--;
                display_name_length = name_tail - line;
                strbuf_addstr(sb, "From: ");
-               if (!has_rfc822_specials(line, display_name_length)) {
-                       add_rfc2047(sb, line, display_name_length, encoding);
-               } else {
+               if (needs_rfc2047_encoding(line, display_name_length, RFC2047_ADDRESS)) {
+                       add_rfc2047(sb, line, display_name_length,
+                                               encoding, RFC2047_ADDRESS);
+                       max_length = 76; /* per rfc2047 */
+               } else if (needs_rfc822_quoting(line, display_name_length)) {
                        struct strbuf quoted = STRBUF_INIT;
                        add_rfc822_quoted(&quoted, line, display_name_length);
-                       add_rfc2047(sb, quoted.buf, quoted.len, encoding);
+                       strbuf_add_wrapped_bytes(sb, quoted.buf, quoted.len,
+                                                       -6, 1, max_length);
                        strbuf_release(&quoted);
+               } else {
+                       strbuf_add_wrapped_bytes(sb, line, display_name_length,
+                                                       -6, 1, max_length);
                }
-               for (final_line = 0; final_line < sb->len; final_line++)
-                       if (sb->buf[sb->len - final_line - 1] == '\n')
-                               break;
-               if (namelen - display_name_length + final_line > 78) {
+               if (namelen - display_name_length + last_line_length(sb) > max_length) {
                        strbuf_addch(sb, '\n');
                        if (!isspace(name_tail[0]))
                                strbuf_addch(sb, ' ');
@@ -1278,6 +1345,7 @@ void pp_title_line(const struct pretty_print_context *pp,
                   const char *encoding,
                   int need_8bit_cte)
 {
+       static const int max_length = 78; /* per rfc2047 */
        struct strbuf title;
 
        strbuf_init(&title, 80);
@@ -1287,7 +1355,12 @@ void pp_title_line(const struct pretty_print_context *pp,
        strbuf_grow(sb, title.len + 1024);
        if (pp->subject) {
                strbuf_addstr(sb, pp->subject);
-               add_rfc2047(sb, title.buf, title.len, encoding);
+               if (needs_rfc2047_encoding(title.buf, title.len, RFC2047_SUBJECT))
+                       add_rfc2047(sb, title.buf, title.len,
+                                               encoding, RFC2047_SUBJECT);
+               else
+                       strbuf_add_wrapped_bytes(sb, title.buf, title.len,
+                                        -last_line_length(sb), 1, max_length);
        } else {
                strbuf_addbuf(sb, &title);
        }
diff --git a/refs.c b/refs.c
index da74a2b29a20a2c94fef61641e35980007c1ab95..726c53c540a94c6ac994aa768c1ffb355ca4538e 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -1202,6 +1202,8 @@ int peel_ref(const char *refname, unsigned char *sha1)
        if (current_ref && (current_ref->name == refname
                || !strcmp(current_ref->name, refname))) {
                if (current_ref->flag & REF_KNOWS_PEELED) {
+                       if (is_null_sha1(current_ref->u.value.peeled))
+                           return -1;
                        hashcpy(sha1, current_ref->u.value.peeled);
                        return 0;
                }
@@ -1223,9 +1225,16 @@ int peel_ref(const char *refname, unsigned char *sha1)
        }
 
 fallback:
-       o = parse_object(base);
-       if (o && o->type == OBJ_TAG) {
-               o = deref_tag(o, refname, 0);
+       o = lookup_unknown_object(base);
+       if (o->type == OBJ_NONE) {
+               int type = sha1_object_info(base, NULL);
+               if (type < 0)
+                       return -1;
+               o->type = type;
+       }
+
+       if (o->type == OBJ_TAG) {
+               o = deref_tag_noverify(o);
                if (o) {
                        hashcpy(sha1, o->sha1);
                        return 0;
@@ -1753,26 +1762,18 @@ int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
        struct ref_lock *lock;
        int err, i = 0, ret = 0, flag = 0;
 
-       lock = lock_ref_sha1_basic(refname, sha1, 0, &flag);
+       lock = lock_ref_sha1_basic(refname, sha1, delopt, &flag);
        if (!lock)
                return 1;
        if (!(flag & REF_ISPACKED) || flag & REF_ISSYMREF) {
                /* loose */
-               const char *path;
-
-               if (!(delopt & REF_NODEREF)) {
-                       i = strlen(lock->lk->filename) - 5; /* .lock */
-                       lock->lk->filename[i] = 0;
-                       path = lock->lk->filename;
-               } else {
-                       path = git_path("%s", refname);
-               }
-               err = unlink_or_warn(path);
+               i = strlen(lock->lk->filename) - 5; /* .lock */
+               lock->lk->filename[i] = 0;
+               err = unlink_or_warn(lock->lk->filename);
                if (err && errno != ENOENT)
                        ret = 1;
 
-               if (!(delopt & REF_NODEREF))
-                       lock->lk->filename[i] = '.';
+               lock->lk->filename[i] = '.';
        }
        /* removing the loose one could have resurrected an earlier
         * packed one.  Also, if it was not loose we need to repack
index 42716c59cfe419571d98a7f3b3674e94e2fe3618..278fecdd9bd00bf0df0a3d1f35777546794bc92f 100644 (file)
@@ -356,7 +356,7 @@ static int run_slot(struct active_request_slot *slot)
        slot->curl_result = curl_easy_perform(slot->curl);
        finish_active_slot(slot);
 
-       err = handle_curl_result(slot, &results);
+       err = handle_curl_result(&results);
        if (err != HTTP_OK && err != HTTP_REAUTH) {
                error("RPC failed; result=%d, HTTP code = %ld",
                      results.curl_result, results.http_code);
@@ -431,6 +431,11 @@ static int post_rpc(struct rpc_state *rpc)
                        return -1;
        }
 
+       headers = curl_slist_append(headers, rpc->hdr_content_type);
+       headers = curl_slist_append(headers, rpc->hdr_accept);
+       headers = curl_slist_append(headers, "Expect:");
+
+retry:
        slot = get_active_slot();
 
        curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0);
@@ -438,10 +443,6 @@ static int post_rpc(struct rpc_state *rpc)
        curl_easy_setopt(slot->curl, CURLOPT_URL, rpc->service_url);
        curl_easy_setopt(slot->curl, CURLOPT_ENCODING, "gzip");
 
-       headers = curl_slist_append(headers, rpc->hdr_content_type);
-       headers = curl_slist_append(headers, rpc->hdr_accept);
-       headers = curl_slist_append(headers, "Expect:");
-
        if (large_request) {
                /* The request body is large and the size cannot be predicted.
                 * We must use chunked encoding to send it.
@@ -515,9 +516,9 @@ static int post_rpc(struct rpc_state *rpc)
        curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, rpc_in);
        curl_easy_setopt(slot->curl, CURLOPT_FILE, rpc);
 
-       do {
-               err = run_slot(slot);
-       } while (err == HTTP_REAUTH && !large_request && !use_gzip);
+       err = run_slot(slot);
+       if (err == HTTP_REAUTH && !large_request && !use_gzip)
+               goto retry;
        if (err != HTTP_OK)
                err = -1;
 
diff --git a/remote-testsvn.c b/remote-testsvn.c
new file mode 100644 (file)
index 0000000..51fba05
--- /dev/null
@@ -0,0 +1,342 @@
+#include "cache.h"
+#include "remote.h"
+#include "strbuf.h"
+#include "url.h"
+#include "exec_cmd.h"
+#include "run-command.h"
+#include "vcs-svn/svndump.h"
+#include "notes.h"
+#include "argv-array.h"
+
+static const char *url;
+static int dump_from_file;
+static const char *private_ref;
+static const char *remote_ref = "refs/heads/master";
+static const char *marksfilename, *notes_ref;
+struct rev_note { unsigned int rev_nr; };
+
+static int cmd_capabilities(const char *line);
+static int cmd_import(const char *line);
+static int cmd_list(const char *line);
+
+typedef int (*input_command_handler)(const char *);
+struct input_command_entry {
+       const char *name;
+       input_command_handler fn;
+       unsigned char batchable;        /* whether the command starts or is part of a batch */
+};
+
+static const struct input_command_entry input_command_list[] = {
+       { "capabilities", cmd_capabilities, 0 },
+       { "import", cmd_import, 1 },
+       { "list", cmd_list, 0 },
+       { NULL, NULL }
+};
+
+static int cmd_capabilities(const char *line)
+{
+       printf("import\n");
+       printf("bidi-import\n");
+       printf("refspec %s:%s\n\n", remote_ref, private_ref);
+       fflush(stdout);
+       return 0;
+}
+
+static void terminate_batch(void)
+{
+       /* terminate a current batch's fast-import stream */
+       printf("done\n");
+       fflush(stdout);
+}
+
+/* NOTE: 'ref' refers to a git reference, while 'rev' refers to a svn revision. */
+static char *read_ref_note(const unsigned char sha1[20])
+{
+       const unsigned char *note_sha1;
+       char *msg = NULL;
+       unsigned long msglen;
+       enum object_type type;
+
+       init_notes(NULL, notes_ref, NULL, 0);
+       if (!(note_sha1 = get_note(NULL, sha1)))
+               return NULL;    /* note tree not found */
+       if (!(msg = read_sha1_file(note_sha1, &type, &msglen)))
+               error("Empty notes tree. %s", notes_ref);
+       else if (!msglen || type != OBJ_BLOB) {
+               error("Note contains unusable content. "
+                       "Is something else using this notes tree? %s", notes_ref);
+               free(msg);
+               msg = NULL;
+       }
+       free_notes(NULL);
+       return msg;
+}
+
+static int parse_rev_note(const char *msg, struct rev_note *res)
+{
+       const char *key, *value, *end;
+       size_t len;
+
+       while (*msg) {
+               end = strchr(msg, '\n');
+               len = end ? end - msg : strlen(msg);
+
+               key = "Revision-number: ";
+               if (!prefixcmp(msg, key)) {
+                       long i;
+                       char *end;
+                       value = msg + strlen(key);
+                       i = strtol(value, &end, 0);
+                       if (end == value || i < 0 || i > UINT32_MAX)
+                               return -1;
+                       res->rev_nr = i;
+               }
+               msg += len + 1;
+       }
+       return 0;
+}
+
+static int note2mark_cb(const unsigned char *object_sha1,
+               const unsigned char *note_sha1, char *note_path,
+               void *cb_data)
+{
+       FILE *file = (FILE *)cb_data;
+       char *msg;
+       unsigned long msglen;
+       enum object_type type;
+       struct rev_note note;
+
+       if (!(msg = read_sha1_file(note_sha1, &type, &msglen)) ||
+                       !msglen || type != OBJ_BLOB) {
+               free(msg);
+               return 1;
+       }
+       if (parse_rev_note(msg, &note))
+               return 2;
+       if (fprintf(file, ":%d %s\n", note.rev_nr, sha1_to_hex(object_sha1)) < 1)
+               return 3;
+       return 0;
+}
+
+static void regenerate_marks(void)
+{
+       int ret;
+       FILE *marksfile = fopen(marksfilename, "w+");
+
+       if (!marksfile)
+               die_errno("Couldn't create mark file %s.", marksfilename);
+       ret = for_each_note(NULL, 0, note2mark_cb, marksfile);
+       if (ret)
+               die("Regeneration of marks failed, returned %d.", ret);
+       fclose(marksfile);
+}
+
+static void check_or_regenerate_marks(int latestrev)
+{
+       FILE *marksfile;
+       struct strbuf sb = STRBUF_INIT;
+       struct strbuf line = STRBUF_INIT;
+       int found = 0;
+
+       if (latestrev < 1)
+               return;
+
+       init_notes(NULL, notes_ref, NULL, 0);
+       marksfile = fopen(marksfilename, "r");
+       if (!marksfile) {
+               regenerate_marks();
+               marksfile = fopen(marksfilename, "r");
+               if (!marksfile)
+                       die_errno("cannot read marks file %s!", marksfilename);
+               fclose(marksfile);
+       } else {
+               strbuf_addf(&sb, ":%d ", latestrev);
+               while (strbuf_getline(&line, marksfile, '\n') != EOF) {
+                       if (!prefixcmp(line.buf, sb.buf)) {
+                               found++;
+                               break;
+                       }
+               }
+               fclose(marksfile);
+               if (!found)
+                       regenerate_marks();
+       }
+       free_notes(NULL);
+       strbuf_release(&sb);
+       strbuf_release(&line);
+}
+
+static int cmd_import(const char *line)
+{
+       int code;
+       int dumpin_fd;
+       char *note_msg;
+       unsigned char head_sha1[20];
+       unsigned int startrev;
+       struct argv_array svndump_argv = ARGV_ARRAY_INIT;
+       struct child_process svndump_proc;
+
+       if (read_ref(private_ref, head_sha1))
+               startrev = 0;
+       else {
+               note_msg = read_ref_note(head_sha1);
+               if(note_msg == NULL) {
+                       warning("No note found for %s.", private_ref);
+                       startrev = 0;
+               } else {
+                       struct rev_note note = { 0 };
+                       if (parse_rev_note(note_msg, &note))
+                               die("Revision number couldn't be parsed from note.");
+                       startrev = note.rev_nr + 1;
+                       free(note_msg);
+               }
+       }
+       check_or_regenerate_marks(startrev - 1);
+
+       if (dump_from_file) {
+               dumpin_fd = open(url, O_RDONLY);
+               if(dumpin_fd < 0)
+                       die_errno("Couldn't open svn dump file %s.", url);
+       } else {
+               memset(&svndump_proc, 0, sizeof(struct child_process));
+               svndump_proc.out = -1;
+               argv_array_push(&svndump_argv, "svnrdump");
+               argv_array_push(&svndump_argv, "dump");
+               argv_array_push(&svndump_argv, url);
+               argv_array_pushf(&svndump_argv, "-r%u:HEAD", startrev);
+               svndump_proc.argv = svndump_argv.argv;
+
+               code = start_command(&svndump_proc);
+               if (code)
+                       die("Unable to start %s, code %d", svndump_proc.argv[0], code);
+               dumpin_fd = svndump_proc.out;
+       }
+       /* setup marks file import/export */
+       printf("feature import-marks-if-exists=%s\n"
+                       "feature export-marks=%s\n", marksfilename, marksfilename);
+
+       svndump_init_fd(dumpin_fd, STDIN_FILENO);
+       svndump_read(url, private_ref, notes_ref);
+       svndump_deinit();
+       svndump_reset();
+
+       close(dumpin_fd);
+       if (!dump_from_file) {
+               code = finish_command(&svndump_proc);
+               if (code)
+                       warning("%s, returned %d", svndump_proc.argv[0], code);
+               argv_array_clear(&svndump_argv);
+       }
+
+       return 0;
+}
+
+static int cmd_list(const char *line)
+{
+       printf("? %s\n\n", remote_ref);
+       fflush(stdout);
+       return 0;
+}
+
+static int do_command(struct strbuf *line)
+{
+       const struct input_command_entry *p = input_command_list;
+       static struct string_list batchlines = STRING_LIST_INIT_DUP;
+       static const struct input_command_entry *batch_cmd;
+       /*
+        * commands can be grouped together in a batch.
+        * Batches are ended by \n. If no batch is active the program ends.
+        * During a batch all lines are buffered and passed to the handler function
+        * when the batch is terminated.
+        */
+       if (line->len == 0) {
+               if (batch_cmd) {
+                       struct string_list_item *item;
+                       for_each_string_list_item(item, &batchlines)
+                               batch_cmd->fn(item->string);
+                       terminate_batch();
+                       batch_cmd = NULL;
+                       string_list_clear(&batchlines, 0);
+                       return 0;       /* end of the batch, continue reading other commands. */
+               }
+               return 1;       /* end of command stream, quit */
+       }
+       if (batch_cmd) {
+               if (prefixcmp(batch_cmd->name, line->buf))
+                       die("Active %s batch interrupted by %s", batch_cmd->name, line->buf);
+               /* buffer batch lines */
+               string_list_append(&batchlines, line->buf);
+               return 0;
+       }
+
+       for (p = input_command_list; p->name; p++) {
+               if (!prefixcmp(line->buf, p->name) && (strlen(p->name) == line->len ||
+                               line->buf[strlen(p->name)] == ' ')) {
+                       if (p->batchable) {
+                               batch_cmd = p;
+                               string_list_append(&batchlines, line->buf);
+                               return 0;
+                       }
+                       return p->fn(line->buf);
+               }
+       }
+       die("Unknown command '%s'\n", line->buf);
+       return 0;
+}
+
+int main(int argc, const char **argv)
+{
+       struct strbuf buf = STRBUF_INIT, url_sb = STRBUF_INIT,
+                       private_ref_sb = STRBUF_INIT, marksfilename_sb = STRBUF_INIT,
+                       notes_ref_sb = STRBUF_INIT;
+       static struct remote *remote;
+       const char *url_in;
+
+       git_extract_argv0_path(argv[0]);
+       setup_git_directory();
+       if (argc < 2 || argc > 3) {
+               usage("git-remote-svn <remote-name> [<url>]");
+               return 1;
+       }
+
+       remote = remote_get(argv[1]);
+       url_in = (argc == 3) ? argv[2] : remote->url[0];
+
+       if (!prefixcmp(url_in, "file://")) {
+               dump_from_file = 1;
+               url = url_decode(url_in + sizeof("file://")-1);
+       } else {
+               dump_from_file = 0;
+               end_url_with_slash(&url_sb, url_in);
+               url = url_sb.buf;
+       }
+
+       strbuf_addf(&private_ref_sb, "refs/svn/%s/master", remote->name);
+       private_ref = private_ref_sb.buf;
+
+       strbuf_addf(&notes_ref_sb, "refs/notes/%s/revs", remote->name);
+       notes_ref = notes_ref_sb.buf;
+
+       strbuf_addf(&marksfilename_sb, "%s/info/fast-import/remote-svn/%s.marks",
+               get_git_dir(), remote->name);
+       marksfilename = marksfilename_sb.buf;
+
+       while (1) {
+               if (strbuf_getline(&buf, stdin, '\n') == EOF) {
+                       if (ferror(stdin))
+                               die("Error reading command stream");
+                       else
+                               die("Unexpected end of command stream");
+               }
+               if (do_command(&buf))
+                       break;
+               strbuf_reset(&buf);
+       }
+
+       strbuf_release(&buf);
+       strbuf_release(&url_sb);
+       strbuf_release(&private_ref_sb);
+       strbuf_release(&notes_ref_sb);
+       strbuf_release(&marksfilename_sb);
+       return 0;
+}
index a09e60bedbbbf2c6bdeeacc3d1032bcc1be9cb55..d7d621cdbf224f5a2bc1780e9602dcd3d08c1d57 100644 (file)
@@ -1048,9 +1048,9 @@ void init_revisions(struct rev_info *revs, const char *prefix)
 
        revs->commit_format = CMIT_FMT_DEFAULT;
 
+       init_grep_defaults();
+       grep_init(&revs->grep_filter, prefix);
        revs->grep_filter.status_only = 1;
-       revs->grep_filter.pattern_tail = &(revs->grep_filter.pattern_list);
-       revs->grep_filter.header_tail = &(revs->grep_filter.header_list);
        revs->grep_filter.regflags = REG_NEWLINE;
 
        diff_setup(&revs->diffopt);
@@ -1603,13 +1603,17 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
                return argcount;
        } else if (!strcmp(arg, "--grep-debug")) {
                revs->grep_filter.debug = 1;
+       } else if (!strcmp(arg, "--basic-regexp")) {
+               grep_set_pattern_type_option(GREP_PATTERN_TYPE_BRE, &revs->grep_filter);
        } else if (!strcmp(arg, "--extended-regexp") || !strcmp(arg, "-E")) {
-               revs->grep_filter.regflags |= REG_EXTENDED;
+               grep_set_pattern_type_option(GREP_PATTERN_TYPE_ERE, &revs->grep_filter);
        } else if (!strcmp(arg, "--regexp-ignore-case") || !strcmp(arg, "-i")) {
                revs->grep_filter.regflags |= REG_ICASE;
                DIFF_OPT_SET(&revs->diffopt, PICKAXE_IGNORE_CASE);
        } else if (!strcmp(arg, "--fixed-strings") || !strcmp(arg, "-F")) {
-               revs->grep_filter.fixed = 1;
+               grep_set_pattern_type_option(GREP_PATTERN_TYPE_FIXED, &revs->grep_filter);
+       } else if (!strcmp(arg, "--perl-regexp")) {
+               grep_set_pattern_type_option(GREP_PATTERN_TYPE_PCRE, &revs->grep_filter);
        } else if (!strcmp(arg, "--all-match")) {
                revs->grep_filter.all_match = 1;
        } else if ((argcount = parse_long_opt("encoding", argv, &optarg))) {
@@ -1893,6 +1897,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
        revs->diffopt.abbrev = revs->abbrev;
        diff_setup_done(&revs->diffopt);
 
+       grep_commit_pattern_type(GREP_PATTERN_TYPE_UNSPECIFIED,
+                                &revs->grep_filter);
        compile_grep_patterns(&revs->grep_filter);
 
        if (revs->reverse && revs->reflog_info)
index 1101ef72378a502b1681a8e1bc306f38027974ae..3b982e4d55274ebe87c5751fa198bee53e371d9b 100644 (file)
@@ -397,16 +397,6 @@ int start_command(struct child_process *cmd)
                                        unsetenv(*cmd->env);
                        }
                }
-               if (cmd->preexec_cb) {
-                       /*
-                        * We cannot predict what the pre-exec callback does.
-                        * Forgo parent notification.
-                        */
-                       close(child_notifier);
-                       child_notifier = -1;
-
-                       cmd->preexec_cb();
-               }
                if (cmd->git_cmd) {
                        execv_git_cmd(cmd->argv);
                } else if (cmd->use_shell) {
index 44f7d2bd42ddcf2d65722b7e54bea69645d167a2..850c638f19a2b6776c0311db28371b18438f207a 100644 (file)
@@ -39,7 +39,6 @@ struct child_process {
        unsigned stdout_to_stderr:1;
        unsigned use_shell:1;
        unsigned clean_on_exit:1;
-       void (*preexec_cb)(void);
 };
 
 int start_command(struct child_process *);
index 0510f76c24b3b3ce66baa0f05054d3f01b960b6e..4b9e30cadcd1ff45e7d4f23b210b22006445da91 100644 (file)
--- a/strbuf.c
+++ b/strbuf.c
@@ -44,7 +44,9 @@ void strbuf_release(struct strbuf *sb)
 
 char *strbuf_detach(struct strbuf *sb, size_t *sz)
 {
-       char *res = sb->alloc ? sb->buf : NULL;
+       char *res;
+       strbuf_grow(sb, 0);
+       res = sb->buf;
        if (sz)
                *sz = sb->len;
        strbuf_init(sb, 0);
index 50f213e926374e86c23cdbfc730f6d81af4816b8..e3e0b455eae925996aa8ecf8bf931edd0638d1cc 100644 (file)
@@ -759,6 +759,86 @@ unsigned is_submodule_modified(const char *path, int ignore_untracked)
        return dirty_submodule;
 }
 
+int submodule_uses_gitfile(const char *path)
+{
+       struct child_process cp;
+       const char *argv[] = {
+               "submodule",
+               "foreach",
+               "--quiet",
+               "--recursive",
+               "test -f .git",
+               NULL,
+       };
+       struct strbuf buf = STRBUF_INIT;
+       const char *git_dir;
+
+       strbuf_addf(&buf, "%s/.git", path);
+       git_dir = read_gitfile(buf.buf);
+       if (!git_dir) {
+               strbuf_release(&buf);
+               return 0;
+       }
+       strbuf_release(&buf);
+
+       /* Now test that all nested submodules use a gitfile too */
+       memset(&cp, 0, sizeof(cp));
+       cp.argv = argv;
+       cp.env = local_repo_env;
+       cp.git_cmd = 1;
+       cp.no_stdin = 1;
+       cp.no_stderr = 1;
+       cp.no_stdout = 1;
+       cp.dir = path;
+       if (run_command(&cp))
+               return 0;
+
+       return 1;
+}
+
+int ok_to_remove_submodule(const char *path)
+{
+       struct stat st;
+       ssize_t len;
+       struct child_process cp;
+       const char *argv[] = {
+               "status",
+               "--porcelain",
+               "-u",
+               "--ignore-submodules=none",
+               NULL,
+       };
+       struct strbuf buf = STRBUF_INIT;
+       int ok_to_remove = 1;
+
+       if ((lstat(path, &st) < 0) || is_empty_dir(path))
+               return 1;
+
+       if (!submodule_uses_gitfile(path))
+               return 0;
+
+       memset(&cp, 0, sizeof(cp));
+       cp.argv = argv;
+       cp.env = local_repo_env;
+       cp.git_cmd = 1;
+       cp.no_stdin = 1;
+       cp.out = -1;
+       cp.dir = path;
+       if (start_command(&cp))
+               die("Could not run 'git status --porcelain -uall --ignore-submodules=none' in submodule %s", path);
+
+       len = strbuf_read(&buf, cp.out, 1024);
+       if (len > 2)
+               ok_to_remove = 0;
+       close(cp.out);
+
+       if (finish_command(&cp))
+               die("'git status --porcelain -uall --ignore-submodules=none' failed in submodule %s", path);
+
+       strbuf_release(&buf);
+       return ok_to_remove;
+}
+
 static int find_first_merges(struct object_array *result, const char *path,
                struct commit *a, struct commit *b)
 {
index 594b50d51066be35d2f9dc9aa795f3ecdf131573..f2e8271fc68c3b1e78d200e2af374a77f253f1ee 100644 (file)
@@ -28,6 +28,8 @@ int fetch_populated_submodules(const struct argv_array *options,
                               const char *prefix, int command_line_option,
                               int quiet);
 unsigned is_submodule_modified(const char *path, int ignore_untracked);
+int submodule_uses_gitfile(const char *path);
+int ok_to_remove_submodule(const char *path);
 int merge_submodule(unsigned char result[20], const char *path, const unsigned char base[20],
                    const unsigned char a[20], const unsigned char b[20], int search);
 int find_unpushed_submodules(unsigned char new_sha1[20], const char *remotes_name,
index febc45c9cc6f34a606ebac8470e582efad798148..807b8b88e215df5ce39504b1858be8694499727d 100755 (executable)
@@ -196,6 +196,16 @@ test_expect_success 'root subdir attribute test' '
        attr_check subdir/a/i unspecified
 '
 
+test_expect_success 'negative patterns' '
+       echo "!f test=bar" >.gitattributes &&
+       test_must_fail git check-attr test -- f
+'
+
+test_expect_success 'patterns starting with exclamation' '
+       echo "\!f test=foo" >.gitattributes &&
+       attr_check "!f" foo
+'
+
 test_expect_success 'setup bare' '
        git clone --bare . bare.git &&
        cd bare.git
index c8fe9782672c0e6ba2f0fd0c1b708fc980263182..dc2f0458fd0e74a3dcb4769517f5cde2606eb6f2 100755 (executable)
@@ -214,4 +214,10 @@ test_expect_success 'subdirectory ignore (l1)' '
        test_cmp expect actual
 '
 
+test_expect_success 'pattern matches prefix completely' '
+       : >expect &&
+       git ls-files -i -o --exclude "/three/a.3[abc]" >actual &&
+       test_cmp expect actual
+'
+
 test_done
index 79c8d0142ea72d25a2c403738312a01d0ace50cb..80e6be39d7b76d8e5daa6cad24a22a80a42e8eff 100755 (executable)
@@ -262,6 +262,25 @@ test_expect_success 'config information was renamed, too' \
        "test $(git config branch.s.dummy) = Hello &&
         test_must_fail git config branch.s/s/dummy"
 
+test_expect_success 'deleting a symref' '
+       git branch target &&
+       git symbolic-ref refs/heads/symref refs/heads/target &&
+       echo "Deleted branch symref (was refs/heads/target)." >expect &&
+       git branch -d symref >actual &&
+       test_path_is_file .git/refs/heads/target &&
+       test_path_is_missing .git/refs/heads/symref &&
+       test_i18ncmp expect actual
+'
+
+test_expect_success 'deleting a dangling symref' '
+       git symbolic-ref refs/heads/dangling-symref nowhere &&
+       test_path_is_file .git/refs/heads/dangling-symref &&
+       echo "Deleted branch dangling-symref (was nowhere)." >expect &&
+       git branch -d dangling-symref >actual &&
+       test_path_is_missing .git/refs/heads/dangling-symref &&
+       test_i18ncmp expect actual
+'
+
 test_expect_success 'renaming a symref is not allowed' \
 '
        git symbolic-ref refs/heads/master2 refs/heads/master &&
index 9fd28bcf3435f831fa24285dd703c82b8396d635..97254e8d337ff066f633ece5d1a7c8a59108e703 100755 (executable)
@@ -262,4 +262,347 @@ test_expect_success 'rm removes subdirectories recursively' '
        ! test -d dir
 '
 
+cat >expect <<EOF
+D  submod
+EOF
+
+cat >expect.modified <<EOF
+ M submod
+EOF
+
+test_expect_success 'rm removes empty submodules from work tree' '
+       mkdir submod &&
+       git update-index --add --cacheinfo 160000 $(git rev-parse HEAD) submod &&
+       git config -f .gitmodules submodule.sub.url ./. &&
+       git config -f .gitmodules submodule.sub.path submod &&
+       git submodule init &&
+       git add .gitmodules &&
+       git commit -m "add submodule" &&
+       git rm submod &&
+       test ! -e submod &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'rm removes removed submodule from index' '
+       git reset --hard &&
+       git submodule update &&
+       rm -rf submod &&
+       git rm submod &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'rm removes work tree of unmodified submodules' '
+       git reset --hard &&
+       git submodule update &&
+       git rm submod &&
+       test ! -d submod &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'rm of a populated submodule with different HEAD fails unless forced' '
+       git reset --hard &&
+       git submodule update &&
+       (cd submod &&
+               git checkout HEAD^
+       ) &&
+       test_must_fail git rm submod &&
+       test -d submod &&
+       test -f submod/.git &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect.modified actual &&
+       git rm -f submod &&
+       test ! -d submod &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'rm of a populated submodule with modifications fails unless forced' '
+       git reset --hard &&
+       git submodule update &&
+       (cd submod &&
+               echo X >empty
+       ) &&
+       test_must_fail git rm submod &&
+       test -d submod &&
+       test -f submod/.git &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect.modified actual &&
+       git rm -f submod &&
+       test ! -d submod &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'rm of a populated submodule with untracked files fails unless forced' '
+       git reset --hard &&
+       git submodule update &&
+       (cd submod &&
+               echo X >untracked
+       ) &&
+       test_must_fail git rm submod &&
+       test -d submod &&
+       test -f submod/.git &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect.modified actual &&
+       git rm -f submod &&
+       test ! -d submod &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'setup submodule conflict' '
+       git reset --hard &&
+       git submodule update &&
+       git checkout -b branch1 &&
+       echo 1 >nitfol &&
+       git add nitfol &&
+       git commit -m "added nitfol 1" &&
+       git checkout -b branch2 master &&
+       echo 2 >nitfol &&
+       git add nitfol &&
+       git commit -m "added nitfol 2" &&
+       git checkout -b conflict1 master &&
+       (cd submod &&
+               git fetch &&
+               git checkout branch1
+       ) &&
+       git add submod &&
+       git commit -m "submod 1" &&
+       git checkout -b conflict2 master &&
+       (cd submod &&
+               git checkout branch2
+       ) &&
+       git add submod &&
+       git commit -m "submod 2"
+'
+
+cat >expect.conflict <<EOF
+UU submod
+EOF
+
+test_expect_success 'rm removes work tree of unmodified conflicted submodule' '
+       git checkout conflict1 &&
+       git reset --hard &&
+       git submodule update &&
+       test_must_fail git merge conflict2 &&
+       git rm submod &&
+       test ! -d submod &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'rm of a conflicted populated submodule with different HEAD fails unless forced' '
+       git checkout conflict1 &&
+       git reset --hard &&
+       git submodule update &&
+       (cd submod &&
+               git checkout HEAD^
+       ) &&
+       test_must_fail git merge conflict2 &&
+       test_must_fail git rm submod &&
+       test -d submod &&
+       test -f submod/.git &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect.conflict actual &&
+       git rm -f submod &&
+       test ! -d submod &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'rm of a conflicted populated submodule with modifications fails unless forced' '
+       git checkout conflict1 &&
+       git reset --hard &&
+       git submodule update &&
+       (cd submod &&
+               echo X >empty
+       ) &&
+       test_must_fail git merge conflict2 &&
+       test_must_fail git rm submod &&
+       test -d submod &&
+       test -f submod/.git &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect.conflict actual &&
+       git rm -f submod &&
+       test ! -d submod &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'rm of a conflicted populated submodule with untracked files fails unless forced' '
+       git checkout conflict1 &&
+       git reset --hard &&
+       git submodule update &&
+       (cd submod &&
+               echo X >untracked
+       ) &&
+       test_must_fail git merge conflict2 &&
+       test_must_fail git rm submod &&
+       test -d submod &&
+       test -f submod/.git &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect.conflict actual &&
+       git rm -f submod &&
+       test ! -d submod &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'rm of a conflicted populated submodule with a .git directory fails even when forced' '
+       git checkout conflict1 &&
+       git reset --hard &&
+       git submodule update &&
+       (cd submod &&
+               rm .git &&
+               cp -a ../.git/modules/sub .git &&
+               GIT_WORK_TREE=. git config --unset core.worktree
+       ) &&
+       test_must_fail git merge conflict2 &&
+       test_must_fail git rm submod &&
+       test -d submod &&
+       test -d submod/.git &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect.conflict actual &&
+       test_must_fail git rm -f submod &&
+       test -d submod &&
+       test -d submod/.git &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect.conflict actual &&
+       git merge --abort &&
+       rm -rf submod
+'
+
+test_expect_success 'rm of a conflicted unpopulated submodule succeeds' '
+       git checkout conflict1 &&
+       git reset --hard &&
+       test_must_fail git merge conflict2 &&
+       git rm submod &&
+       test ! -d submod &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'rm of a populated submodule with a .git directory fails even when forced' '
+       git checkout -f master &&
+       git reset --hard &&
+       git submodule update &&
+       (cd submod &&
+               rm .git &&
+               cp -a ../.git/modules/sub .git &&
+               GIT_WORK_TREE=. git config --unset core.worktree
+       ) &&
+       test_must_fail git rm submod &&
+       test -d submod &&
+       test -d submod/.git &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       ! test -s actual &&
+       test_must_fail git rm -f submod &&
+       test -d submod &&
+       test -d submod/.git &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       ! test -s actual &&
+       rm -rf submod
+'
+
+cat >expect.deepmodified <<EOF
+ M submod/subsubmod
+EOF
+
+test_expect_success 'setup subsubmodule' '
+       git reset --hard &&
+       git submodule update &&
+       (cd submod &&
+               git update-index --add --cacheinfo 160000 $(git rev-parse HEAD) subsubmod &&
+               git config -f .gitmodules submodule.sub.url ../. &&
+               git config -f .gitmodules submodule.sub.path subsubmod &&
+               git submodule init &&
+               git add .gitmodules &&
+               git commit -m "add subsubmodule" &&
+               git submodule update subsubmod
+       ) &&
+       git commit -a -m "added deep submodule"
+'
+
+test_expect_success 'rm recursively removes work tree of unmodified submodules' '
+       git rm submod &&
+       test ! -d submod &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'rm of a populated nested submodule with different nested HEAD fails unless forced' '
+       git reset --hard &&
+       git submodule update --recursive &&
+       (cd submod/subsubmod &&
+               git checkout HEAD^
+       ) &&
+       test_must_fail git rm submod &&
+       test -d submod &&
+       test -f submod/.git &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect.modified actual &&
+       git rm -f submod &&
+       test ! -d submod &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'rm of a populated nested submodule with nested modifications fails unless forced' '
+       git reset --hard &&
+       git submodule update --recursive &&
+       (cd submod/subsubmod &&
+               echo X >empty
+       ) &&
+       test_must_fail git rm submod &&
+       test -d submod &&
+       test -f submod/.git &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect.modified actual &&
+       git rm -f submod &&
+       test ! -d submod &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'rm of a populated nested submodule with nested untracked files fails unless forced' '
+       git reset --hard &&
+       git submodule update --recursive &&
+       (cd submod/subsubmod &&
+               echo X >untracked
+       ) &&
+       test_must_fail git rm submod &&
+       test -d submod &&
+       test -f submod/.git &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect.modified actual &&
+       git rm -f submod &&
+       test ! -d submod &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'rm of a populated nested submodule with a nested .git directory fails even when forced' '
+       git reset --hard &&
+       git submodule update --recursive &&
+       (cd submod/subsubmod &&
+               rm .git &&
+               cp -a ../../.git/modules/sub/modules/sub .git &&
+               GIT_WORK_TREE=. git config --unset core.worktree
+       ) &&
+       test_must_fail git rm submod &&
+       test -d submod &&
+       test -d submod/subsubmod/.git &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       ! test -s actual &&
+       test_must_fail git rm -f submod &&
+       test -d submod &&
+       test -d submod/subsubmod/.git &&
+       git status -s -uno --ignore-submodules=none > actual &&
+       ! test -s actual &&
+       rm -rf submod
+'
+
 test_done
index 959aa26ef5d96f4be79e6051fb6ae159e03b556e..ad9f69e6074311cc3828896bd8409822344d6f62 100755 (executable)
@@ -110,73 +110,107 @@ test_expect_success 'replay did not screw up the log message' '
 
 test_expect_success 'extra headers' '
 
-       git config format.headers "To: R. E. Cipient <rcipient@example.com>
+       git config format.headers "To: R E Cipient <rcipient@example.com>
 " &&
-       git config --add format.headers "Cc: S. E. Cipient <scipient@example.com>
+       git config --add format.headers "Cc: S E Cipient <scipient@example.com>
 " &&
        git format-patch --stdout master..side > patch2 &&
        sed -e "/^\$/q" patch2 > hdrs2 &&
-       grep "^To: R. E. Cipient <rcipient@example.com>\$" hdrs2 &&
-       grep "^Cc: S. E. Cipient <scipient@example.com>\$" hdrs2
+       grep "^To: R E Cipient <rcipient@example.com>\$" hdrs2 &&
+       grep "^Cc: S E Cipient <scipient@example.com>\$" hdrs2
 
 '
 
 test_expect_success 'extra headers without newlines' '
 
-       git config --replace-all format.headers "To: R. E. Cipient <rcipient@example.com>" &&
-       git config --add format.headers "Cc: S. E. Cipient <scipient@example.com>" &&
+       git config --replace-all format.headers "To: R E Cipient <rcipient@example.com>" &&
+       git config --add format.headers "Cc: S E Cipient <scipient@example.com>" &&
        git format-patch --stdout master..side >patch3 &&
        sed -e "/^\$/q" patch3 > hdrs3 &&
-       grep "^To: R. E. Cipient <rcipient@example.com>\$" hdrs3 &&
-       grep "^Cc: S. E. Cipient <scipient@example.com>\$" hdrs3
+       grep "^To: R E Cipient <rcipient@example.com>\$" hdrs3 &&
+       grep "^Cc: S E Cipient <scipient@example.com>\$" hdrs3
 
 '
 
 test_expect_success 'extra headers with multiple To:s' '
 
-       git config --replace-all format.headers "To: R. E. Cipient <rcipient@example.com>" &&
-       git config --add format.headers "To: S. E. Cipient <scipient@example.com>" &&
+       git config --replace-all format.headers "To: R E Cipient <rcipient@example.com>" &&
+       git config --add format.headers "To: S E Cipient <scipient@example.com>" &&
        git format-patch --stdout master..side > patch4 &&
        sed -e "/^\$/q" patch4 > hdrs4 &&
-       grep "^To: R. E. Cipient <rcipient@example.com>,\$" hdrs4 &&
-       grep "^ *S. E. Cipient <scipient@example.com>\$" hdrs4
+       grep "^To: R E Cipient <rcipient@example.com>,\$" hdrs4 &&
+       grep "^ *S E Cipient <scipient@example.com>\$" hdrs4
 '
 
-test_expect_success 'additional command line cc' '
+test_expect_success 'additional command line cc (ascii)' '
 
-       git config --replace-all format.headers "Cc: R. E. Cipient <rcipient@example.com>" &&
+       git config --replace-all format.headers "Cc: R E Cipient <rcipient@example.com>" &&
+       git format-patch --cc="S E Cipient <scipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch5 &&
+       grep "^Cc: R E Cipient <rcipient@example.com>,\$" patch5 &&
+       grep "^ *S E Cipient <scipient@example.com>\$" patch5
+'
+
+test_expect_failure 'additional command line cc (rfc822)' '
+
+       git config --replace-all format.headers "Cc: R E Cipient <rcipient@example.com>" &&
        git format-patch --cc="S. E. Cipient <scipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch5 &&
-       grep "^Cc: R. E. Cipient <rcipient@example.com>,\$" patch5 &&
-       grep "^ *S. E. Cipient <scipient@example.com>\$" patch5
+       grep "^Cc: R E Cipient <rcipient@example.com>,\$" patch5 &&
+       grep "^ *"S. E. Cipient" <scipient@example.com>\$" patch5
 '
 
 test_expect_success 'command line headers' '
 
        git config --unset-all format.headers &&
-       git format-patch --add-header="Cc: R. E. Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch6 &&
-       grep "^Cc: R. E. Cipient <rcipient@example.com>\$" patch6
+       git format-patch --add-header="Cc: R E Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch6 &&
+       grep "^Cc: R E Cipient <rcipient@example.com>\$" patch6
 '
 
 test_expect_success 'configuration headers and command line headers' '
 
-       git config --replace-all format.headers "Cc: R. E. Cipient <rcipient@example.com>" &&
-       git format-patch --add-header="Cc: S. E. Cipient <scipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch7 &&
-       grep "^Cc: R. E. Cipient <rcipient@example.com>,\$" patch7 &&
-       grep "^ *S. E. Cipient <scipient@example.com>\$" patch7
+       git config --replace-all format.headers "Cc: R E Cipient <rcipient@example.com>" &&
+       git format-patch --add-header="Cc: S E Cipient <scipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch7 &&
+       grep "^Cc: R E Cipient <rcipient@example.com>,\$" patch7 &&
+       grep "^ *S E Cipient <scipient@example.com>\$" patch7
 '
 
-test_expect_success 'command line To: header' '
+test_expect_success 'command line To: header (ascii)' '
 
        git config --unset-all format.headers &&
+       git format-patch --to="R E Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch8 &&
+       grep "^To: R E Cipient <rcipient@example.com>\$" patch8
+'
+
+test_expect_failure 'command line To: header (rfc822)' '
+
        git format-patch --to="R. E. Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch8 &&
-       grep "^To: R. E. Cipient <rcipient@example.com>\$" patch8
+       grep "^To: "R. E. Cipient" <rcipient@example.com>\$" patch8
 '
 
-test_expect_success 'configuration To: header' '
+test_expect_failure 'command line To: header (rfc2047)' '
+
+       git format-patch --to="R Ä Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch8 &&
+       grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= <rcipient@example.com>\$" patch8
+'
+
+test_expect_success 'configuration To: header (ascii)' '
+
+       git config format.to "R E Cipient <rcipient@example.com>" &&
+       git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 &&
+       grep "^To: R E Cipient <rcipient@example.com>\$" patch9
+'
+
+test_expect_failure 'configuration To: header (rfc822)' '
 
        git config format.to "R. E. Cipient <rcipient@example.com>" &&
        git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 &&
-       grep "^To: R. E. Cipient <rcipient@example.com>\$" patch9
+       grep "^To: "R. E. Cipient" <rcipient@example.com>\$" patch9
+'
+
+test_expect_failure 'configuration To: header (rfc2047)' '
+
+       git config format.to "R Ä Cipient <rcipient@example.com>" &&
+       git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 &&
+       grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= <rcipient@example.com>\$" patch9
 '
 
 # check_patch <patch>: Verify that <patch> looks like a half-sane
@@ -190,11 +224,11 @@ check_patch () {
 test_expect_success '--no-to overrides config.to' '
 
        git config --replace-all format.to \
-               "R. E. Cipient <rcipient@example.com>" &&
+               "R E Cipient <rcipient@example.com>" &&
        git format-patch --no-to --stdout master..side |
        sed -e "/^\$/q" >patch10 &&
        check_patch patch10 &&
-       ! grep "^To: R. E. Cipient <rcipient@example.com>\$" patch10
+       ! grep "^To: R E Cipient <rcipient@example.com>\$" patch10
 '
 
 test_expect_success '--no-to and --to replaces config.to' '
@@ -212,21 +246,21 @@ test_expect_success '--no-to and --to replaces config.to' '
 test_expect_success '--no-cc overrides config.cc' '
 
        git config --replace-all format.cc \
-               "C. E. Cipient <rcipient@example.com>" &&
+               "C E Cipient <rcipient@example.com>" &&
        git format-patch --no-cc --stdout master..side |
        sed -e "/^\$/q" >patch12 &&
        check_patch patch12 &&
-       ! grep "^Cc: C. E. Cipient <rcipient@example.com>\$" patch12
+       ! grep "^Cc: C E Cipient <rcipient@example.com>\$" patch12
 '
 
 test_expect_success '--no-add-header overrides config.headers' '
 
        git config --replace-all format.headers \
-               "Header1: B. E. Cipient <rcipient@example.com>" &&
+               "Header1: B E Cipient <rcipient@example.com>" &&
        git format-patch --no-add-header --stdout master..side |
        sed -e "/^\$/q" >patch13 &&
        check_patch patch13 &&
-       ! grep "^Header1: B. E. Cipient <rcipient@example.com>\$" patch13
+       ! grep "^Header1: B E Cipient <rcipient@example.com>\$" patch13
 '
 
 test_expect_success 'multiple files' '
@@ -752,16 +786,14 @@ M64=$M8$M8$M8$M8$M8$M8$M8$M8
 M512=$M64$M64$M64$M64$M64$M64$M64$M64
 cat >expect <<'EOF'
 Subject: [PATCH] foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
- bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
- foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
- bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
- foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
- bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
- foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
- bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
- foo bar foo bar foo bar foo bar
+ bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
+ foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
+ bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
+ foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
+ bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
+ foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
 EOF
-test_expect_success 'format-patch wraps extremely long headers (ascii)' '
+test_expect_success 'format-patch wraps extremely long subject (ascii)' '
        echo content >>file &&
        git add file &&
        git commit -m "$M512" &&
@@ -774,30 +806,31 @@ M8="föö bar "
 M64=$M8$M8$M8$M8$M8$M8$M8$M8
 M512=$M64$M64$M64$M64$M64$M64$M64$M64
 cat >expect <<'EOF'
-Subject: [PATCH] =?UTF-8?q?f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
- =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
+Subject: [PATCH] =?UTF-8?q?f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
+ =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
+ =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
+ =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?=
+ =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3?=
+ =?UTF-8?q?=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3?=
+ =?UTF-8?q?=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
+ =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
+ =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
+ =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?=
+ =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3?=
+ =?UTF-8?q?=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3?=
+ =?UTF-8?q?=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
+ =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
+ =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
+ =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?=
+ =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3?=
+ =?UTF-8?q?=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3?=
+ =?UTF-8?q?=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
+ =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
 EOF
-test_expect_success 'format-patch wraps extremely long headers (rfc2047)' '
+test_expect_success 'format-patch wraps extremely long subject (rfc2047)' '
        rm -rf patches/ &&
        echo content >>file &&
        git add file &&
@@ -807,52 +840,80 @@ test_expect_success 'format-patch wraps extremely long headers (rfc2047)' '
        test_cmp expect subject
 '
 
-M8="foo_bar_"
-M64=$M8$M8$M8$M8$M8$M8$M8$M8
-cat >expect <<EOF
-From: $M64
- <foobar@foo.bar>
-EOF
-test_expect_success 'format-patch wraps non-quotable headers' '
-       rm -rf patches/ &&
-       echo content >>file &&
-       git add file &&
-       git commit -mfoo --author "$M64 <foobar@foo.bar>" &&
-       git format-patch --stdout -1 >patch &&
-       sed -n "/^From: /p; /^ /p; /^$/q" <patch >from &&
-       test_cmp expect from
-'
-
 check_author() {
        echo content >>file &&
        git add file &&
        GIT_AUTHOR_NAME=$1 git commit -m author-check &&
        git format-patch --stdout -1 >patch &&
-       grep ^From: patch >actual &&
+       sed -n "/^From: /p; /^ /p; /^$/q" <patch >actual &&
        test_cmp expect actual
 }
 
 cat >expect <<'EOF'
 From: "Foo B. Bar" <author@example.com>
 EOF
-test_expect_success 'format-patch quotes dot in headers' '
+test_expect_success 'format-patch quotes dot in from-headers' '
        check_author "Foo B. Bar"
 '
 
 cat >expect <<'EOF'
 From: "Foo \"The Baz\" Bar" <author@example.com>
 EOF
-test_expect_success 'format-patch quotes double-quote in headers' '
+test_expect_success 'format-patch quotes double-quote in from-headers' '
        check_author "Foo \"The Baz\" Bar"
 '
 
 cat >expect <<'EOF'
-From: =?UTF-8?q?"F=C3=B6o=20B.=20Bar"?= <author@example.com>
+From: =?UTF-8?q?F=C3=B6o=20Bar?= <author@example.com>
+EOF
+test_expect_success 'format-patch uses rfc2047-encoded from-headers when necessary' '
+       check_author "Föo Bar"
+'
+
+cat >expect <<'EOF'
+From: =?UTF-8?q?F=C3=B6o=20B=2E=20Bar?= <author@example.com>
 EOF
-test_expect_success 'rfc2047-encoded headers also double-quote 822 specials' '
+test_expect_success 'rfc2047-encoded from-headers leave no rfc822 specials' '
        check_author "Föo B. Bar"
 '
 
+cat >expect <<EOF
+From: foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_
+ <author@example.com>
+EOF
+test_expect_success 'format-patch wraps moderately long from-header (ascii)' '
+       check_author "foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_"
+'
+
+cat >expect <<'EOF'
+From: Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar
+ Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo
+ Bar Foo Bar Foo Bar Foo Bar <author@example.com>
+EOF
+test_expect_success 'format-patch wraps extremely long from-header (ascii)' '
+       check_author "Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar"
+'
+
+cat >expect <<'EOF'
+From: "Foo.Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar
+ Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo
+ Bar Foo Bar Foo Bar Foo Bar" <author@example.com>
+EOF
+test_expect_success 'format-patch wraps extremely long from-header (rfc822)' '
+       check_author "Foo.Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar"
+'
+
+cat >expect <<'EOF'
+From: =?UTF-8?q?Fo=C3=B6=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo?=
+ =?UTF-8?q?=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20?=
+ =?UTF-8?q?Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar?=
+ =?UTF-8?q?=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20?=
+ =?UTF-8?q?Foo=20Bar=20Foo=20Bar?= <author@example.com>
+EOF
+test_expect_success 'format-patch wraps extremely long from-header (rfc2047)' '
+       check_author "Foö Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar"
+'
+
 cat >expect <<'EOF'
 Subject: header with . in it
 EOF
diff --git a/t/t4055-diff-context.sh b/t/t4055-diff-context.sh
new file mode 100755 (executable)
index 0000000..97172b4
--- /dev/null
@@ -0,0 +1,92 @@
+#!/bin/sh
+#
+# Copyright (c) 2012 Mozilla Foundation
+#
+
+test_description='diff.context configuration'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+       cat >template <<-\EOF &&
+       firstline
+       b
+       c
+       d
+       e
+       f
+       preline
+       TARGET
+       postline
+       i
+       j
+       k
+       l
+       m
+       n
+       EOF
+       sed "/TARGET/d" >x <template &&
+       git update-index --add x &&
+       git commit -m initial &&
+
+       sed "s/TARGET/ADDED/" >x <template &&
+       git update-index --add x &&
+       git commit -m next &&
+
+       sed "s/TARGET/MODIFIED/" >x <template
+'
+
+test_expect_success 'the default number of context lines is 3' '
+       git diff >output &&
+       ! grep "^ d" output &&
+       grep "^ e" output &&
+       grep "^ j" output &&
+       ! grep "^ k" output
+'
+
+test_expect_success 'diff.context honored by "log"' '
+       git log -1 -p >output &&
+       ! grep firstline output &&
+       git config diff.context 8 &&
+       git log -1 -p >output &&
+       grep "^ firstline" output
+'
+
+test_expect_success 'The -U option overrides diff.context' '
+       git config diff.context 8 &&
+       git log -U4 -1 >output &&
+       ! grep "^ firstline" output
+'
+
+test_expect_success 'diff.context honored by "diff"' '
+       git config diff.context 8 &&
+       git diff >output &&
+       grep "^ firstline" output
+'
+
+test_expect_success 'plumbing not affected' '
+       git config diff.context 8 &&
+       git diff-files -p >output &&
+       ! grep "^ firstline" output
+'
+
+test_expect_success 'non-integer config parsing' '
+       git config diff.context no &&
+       test_must_fail git diff 2>output &&
+       test_i18ngrep "bad config value" output
+'
+
+test_expect_success 'negative integer config parsing' '
+       git config diff.context -1 &&
+       test_must_fail git diff 2>output &&
+       test_i18ngrep "bad config file" output
+'
+
+test_expect_success '-U0 is valid, so is diff.context=0' '
+       git config diff.context 0 &&
+       git diff >output &&
+       grep "^-ADDED" output &&
+       grep "^+MODIFIED" output
+'
+
+test_done
index 924ba536ca9718da0f4126d53c316a5f7a1926a5..a343bf6c629f8e6acaf7559d3168a97fcce9d286 100755 (executable)
@@ -72,9 +72,9 @@ cat > expect << EOF
   commit.
 EOF
 
-test_expect_success 'format %w(12,1,2)' '
+test_expect_success 'format %w(11,1,2)' '
 
-       git log -2 --format="%w(12,1,2)This is the %s commit." > actual &&
+       git log -2 --format="%w(11,1,2)This is the %s commit." > actual &&
        test_cmp expect actual
 '
 
@@ -230,6 +230,12 @@ test_expect_success 'log --grep -i' '
        test_cmp expect actual
 '
 
+test_expect_success 'log -F -E --grep=<ere> uses ere' '
+       echo second >expect &&
+       git log -1 --pretty="tformat:%s" -F -E --grep=s.c.nd >actual &&
+       test_cmp expect actual
+'
+
 cat > expect <<EOF
 * Second
 * sixth
index 4d13e10de1f2594ab304b3a2b7b5905d75d6ff84..1e7a209efa715bc52d14d7f653ecfc13ffb5301f 100755 (executable)
@@ -167,10 +167,11 @@ test_expect_success 'author information is preserved' '
        test_tick &&
        GIT_AUTHOR_NAME="B V Uips" git commit -m bvuips &&
        git branch preserved-author &&
-       git filter-branch -f --msg-filter "cat; \
+       (sane_unset GIT_AUTHOR_NAME &&
+        git filter-branch -f --msg-filter "cat; \
                        test \$GIT_COMMIT != $(git rev-parse master) || \
                        echo Hallo" \
-               preserved-author &&
+               preserved-author) &&
        test 1 = $(git rev-list --author="B V Uips" preserved-author | wc -l)
 '
 
index fd6410fc7149ed381d4d09120089859281e40696..26f831984d603a959e2141641269268a2f0d78c8 100755 (executable)
@@ -111,6 +111,28 @@ test_expect_success 'grep respects binary diff attribute' '
        test_cmp expect actual
 '
 
+test_expect_success 'grep --cached respects binary diff attribute' '
+       git grep --cached text t >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'grep --cached respects binary diff attribute (2)' '
+       git add .gitattributes &&
+       rm .gitattributes &&
+       git grep --cached text t >actual &&
+       test_when_finished "git rm --cached .gitattributes" &&
+       test_when_finished "git checkout .gitattributes" &&
+       test_cmp expect actual
+'
+
+test_expect_success 'grep revision respects binary diff attribute' '
+       git commit -m new &&
+       echo "Binary file HEAD:t matches" >expect &&
+       git grep text HEAD -- t >actual &&
+       test_when_finished "git reset HEAD^" &&
+       test_cmp expect actual
+'
+
 test_expect_success 'grep respects not-binary diff attribute' '
        echo binQary | q_to_nul >b &&
        git add b &&
index 53970374913eaa6f1b5921b14b5f25043974e3a4..de7d45352e001d3c1b2c7f24361dc38dd9e0ea0a 100755 (executable)
@@ -681,4 +681,79 @@ test_expect_success 'moving the superproject does not break submodules' '
        )
 '
 
+test_expect_success 'submodule add --name allows to replace a submodule with another at the same path' '
+       (
+               cd addtest2 &&
+               (
+                       cd repo &&
+                       echo "$submodurl/repo" >expect &&
+                       git config remote.origin.url >actual &&
+                       test_cmp expect actual &&
+                       echo "gitdir: ../.git/modules/repo" >expect &&
+                       test_cmp expect .git
+               ) &&
+               rm -rf repo &&
+               git rm repo &&
+               git submodule add -q --name repo_new "$submodurl/bare.git" repo >actual &&
+               test ! -s actual &&
+               echo "gitdir: ../.git/modules/submod" >expect &&
+               test_cmp expect submod/.git &&
+               (
+                       cd repo &&
+                       echo "$submodurl/bare.git" >expect &&
+                       git config remote.origin.url >actual &&
+                       test_cmp expect actual &&
+                       echo "gitdir: ../.git/modules/repo_new" >expect &&
+                       test_cmp expect .git
+               ) &&
+               echo "repo" >expect &&
+               git config -f .gitmodules submodule.repo.path >actual &&
+               test_cmp expect actual &&
+               git config -f .gitmodules submodule.repo_new.path >actual &&
+               test_cmp expect actual&&
+               echo "$submodurl/repo" >expect &&
+               git config -f .gitmodules submodule.repo.url >actual &&
+               test_cmp expect actual &&
+               echo "$submodurl/bare.git" >expect &&
+               git config -f .gitmodules submodule.repo_new.url >actual &&
+               test_cmp expect actual &&
+               echo "$submodurl/repo" >expect &&
+               git config submodule.repo.url >actual &&
+               test_cmp expect actual &&
+               echo "$submodurl/bare.git" >expect &&
+               git config submodule.repo_new.url >actual &&
+               test_cmp expect actual
+       )
+'
+
+test_expect_success 'submodule add with an existing name fails unless forced' '
+       (
+               cd addtest2 &&
+               rm -rf repo &&
+               git rm repo &&
+               test_must_fail git submodule add -q --name repo_new "$submodurl/repo.git" repo &&
+               test ! -d repo &&
+               echo "repo" >expect &&
+               git config -f .gitmodules submodule.repo_new.path >actual &&
+               test_cmp expect actual&&
+               echo "$submodurl/bare.git" >expect &&
+               git config -f .gitmodules submodule.repo_new.url >actual &&
+               test_cmp expect actual &&
+               echo "$submodurl/bare.git" >expect &&
+               git config submodule.repo_new.url >actual &&
+               test_cmp expect actual &&
+               git submodule add -f -q --name repo_new "$submodurl/repo.git" repo &&
+               test -d repo &&
+               echo "repo" >expect &&
+               git config -f .gitmodules submodule.repo_new.path >actual &&
+               test_cmp expect actual&&
+               echo "$submodurl/repo.git" >expect &&
+               git config -f .gitmodules submodule.repo_new.url >actual &&
+               test_cmp expect actual &&
+               echo "$submodurl/repo.git" >expect &&
+               git config submodule.repo_new.url >actual &&
+               test_cmp expect actual
+       )
+'
+
 test_done
index 15426530e49ef2e42cda2528f4a72a784eb40cd9..feaec6cdf4b8c7eac348ea1de61887c93c69244d 100755 (executable)
@@ -627,7 +627,7 @@ test_expect_success 'submodule add properly re-creates deeper level submodules'
        (cd super &&
         git reset --hard master &&
         rm -rf deeper/ &&
-        git submodule add ../submodule deeper/submodule
+        git submodule add --force ../submodule deeper/submodule
        )
 '
 
index 035122808b6e859810ee70daf381c2c895527894..6c6af7d13f80bdc582e1d45558c24174a5800a38 100755 (executable)
@@ -854,6 +854,75 @@ test_expect_success $PREREQ 'utf8 author is correctly passed on' '
        grep "^From: Füñný Nâmé <odd_?=mail@example.com>" msgtxt1
 '
 
+test_expect_success $PREREQ 'sendemail.composeencoding works' '
+       clean_fake_sendmail &&
+       git config sendemail.composeencoding iso-8859-1 &&
+       (echo "#!$SHELL_PATH" &&
+        echo "echo utf8 body: àéìöú >>\"\$1\""
+       ) >fake-editor-utf8 &&
+       chmod +x fake-editor-utf8 &&
+         GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \
+         git send-email \
+         --compose --subject foo \
+         --from="Example <nobody@example.com>" \
+         --to=nobody@example.com \
+         --smtp-server="$(pwd)/fake.sendmail" \
+         $patches &&
+       grep "^utf8 body" msgtxt1 &&
+       grep "^Content-Type: text/plain; charset=iso-8859-1" msgtxt1
+'
+
+test_expect_success $PREREQ '--compose-encoding works' '
+       clean_fake_sendmail &&
+       (echo "#!$SHELL_PATH" &&
+        echo "echo utf8 body: àéìöú >>\"\$1\""
+       ) >fake-editor-utf8 &&
+       chmod +x fake-editor-utf8 &&
+         GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \
+         git send-email \
+         --compose-encoding iso-8859-1 \
+         --compose --subject foo \
+         --from="Example <nobody@example.com>" \
+         --to=nobody@example.com \
+         --smtp-server="$(pwd)/fake.sendmail" \
+         $patches &&
+       grep "^utf8 body" msgtxt1 &&
+       grep "^Content-Type: text/plain; charset=iso-8859-1" msgtxt1
+'
+
+test_expect_success $PREREQ '--compose-encoding overrides sendemail.composeencoding' '
+       clean_fake_sendmail &&
+       git config sendemail.composeencoding iso-8859-1 &&
+       (echo "#!$SHELL_PATH" &&
+        echo "echo utf8 body: àéìöú >>\"\$1\""
+       ) >fake-editor-utf8 &&
+       chmod +x fake-editor-utf8 &&
+         GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \
+         git send-email \
+         --compose-encoding iso-8859-2 \
+         --compose --subject foo \
+         --from="Example <nobody@example.com>" \
+         --to=nobody@example.com \
+         --smtp-server="$(pwd)/fake.sendmail" \
+         $patches &&
+       grep "^utf8 body" msgtxt1 &&
+       grep "^Content-Type: text/plain; charset=iso-8859-2" msgtxt1
+'
+
+test_expect_success $PREREQ '--compose-encoding adds correct MIME for subject' '
+       clean_fake_sendmail &&
+         GIT_EDITOR="\"$(pwd)/fake-editor\"" \
+         git send-email \
+         --compose-encoding iso-8859-2 \
+         --compose --subject utf8-sübjëct \
+         --from="Example <nobody@example.com>" \
+         --to=nobody@example.com \
+         --smtp-server="$(pwd)/fake.sendmail" \
+         $patches &&
+       grep "^fake edit" msgtxt1 &&
+       grep "^Subject: =?iso-8859-2?q?utf8-s=C3=BCbj=C3=ABct?=" msgtxt1
+'
+
 test_expect_success $PREREQ 'detects ambiguous reference/file conflict' '
        echo master > master &&
        git add master &&
@@ -1073,6 +1142,23 @@ Dieser deutsche Text enthält einen Umlaut!
 EOF
 '
 
+test_expect_success $PREREQ 'setup expect' '
+cat >expected <<EOF
+Subject: subject goes here
+EOF
+'
+
+test_expect_success $PREREQ 'ASCII subject is not RFC2047 quoted' '
+       clean_fake_sendmail &&
+       echo bogus |
+       git send-email --from=author@example.com --to=nobody@example.com \
+                       --smtp-server="$(pwd)/fake.sendmail" \
+                       --8bit-encoding=UTF-8 \
+                       email-using-8bit >stdout &&
+       grep "Subject" msgtxt1 >actual &&
+       test_cmp expected actual
+'
+
 test_expect_success $PREREQ 'setup expect' '
 cat >content-type-decl <<EOF
 MIME-Version: 1.0
diff --git a/t/t9020-remote-svn.sh b/t/t9020-remote-svn.sh
new file mode 100755 (executable)
index 0000000..4f2dfe0
--- /dev/null
@@ -0,0 +1,84 @@
+#!/bin/sh
+
+test_description='tests remote-svn'
+
+. ./test-lib.sh
+
+MARKSPATH=.git/info/fast-import/remote-svn
+
+if ! test_have_prereq PYTHON
+then
+       skip_all='skipping remote-svn tests, python not available'
+       test_done
+fi
+
+# We override svnrdump by placing a symlink to the svnrdump-emulator in .
+export PATH="$HOME:$PATH"
+ln -sf $GIT_BUILD_DIR/contrib/svn-fe/svnrdump_sim.py "$HOME/svnrdump"
+
+init_git () {
+       rm -fr .git &&
+       git init &&
+       #git remote add svnsim testsvn::sim:///$TEST_DIRECTORY/t9020/example.svnrdump
+       # let's reuse an exisiting dump file!?
+       git remote add svnsim testsvn::sim://$TEST_DIRECTORY/t9154/svn.dump
+       git remote add svnfile testsvn::file://$TEST_DIRECTORY/t9154/svn.dump
+}
+
+if test -e "$GIT_BUILD_DIR/git-remote-testsvn"
+then
+       test_set_prereq REMOTE_SVN
+fi
+
+test_debug '
+       git --version
+       which git
+       which svnrdump
+'
+
+test_expect_success REMOTE_SVN 'simple fetch' '
+       init_git &&
+       git fetch svnsim &&
+       test_cmp .git/refs/svn/svnsim/master .git/refs/remotes/svnsim/master  &&
+       cp .git/refs/remotes/svnsim/master master.good
+'
+
+test_debug '
+       cat .git/refs/svn/svnsim/master
+       cat .git/refs/remotes/svnsim/master
+'
+
+test_expect_success REMOTE_SVN 'repeated fetch, nothing shall change' '
+       git fetch svnsim &&
+       test_cmp master.good .git/refs/remotes/svnsim/master
+'
+
+test_expect_success REMOTE_SVN 'fetch from a file:// url gives the same result' '
+       git fetch svnfile
+'
+
+test_expect_failure REMOTE_SVN 'the sha1 differ because the git-svn-id line in the commit msg contains the url' '
+       test_cmp .git/refs/remotes/svnfile/master .git/refs/remotes/svnsim/master
+'
+
+test_expect_success REMOTE_SVN 'mark-file regeneration' '
+       # filter out any other marks, that can not be regenerated. Only up to 3 digit revisions are allowed here
+       grep ":[0-9]\{1,3\} " $MARKSPATH/svnsim.marks > $MARKSPATH/svnsim.marks.old &&
+       rm $MARKSPATH/svnsim.marks &&
+       git fetch svnsim &&
+       test_cmp $MARKSPATH/svnsim.marks.old $MARKSPATH/svnsim.marks
+'
+
+test_expect_success REMOTE_SVN 'incremental imports must lead to the same head' '
+       export SVNRMAX=3 &&
+       init_git &&
+       git fetch svnsim &&
+       test_cmp .git/refs/svn/svnsim/master .git/refs/remotes/svnsim/master  &&
+       unset SVNRMAX &&
+       git fetch svnsim &&
+       test_cmp master.good .git/refs/remotes/svnsim/master
+'
+
+test_debug 'git branch -a'
+
+test_done
index b59be9a894b2481ece7dc5ea9038bc6c88d29f15..69934b2e775c8591ca209c9275abc40b921ecab6 100755 (executable)
@@ -19,7 +19,7 @@ then
     test_done
 fi
 
-CVSROOT=$PWD/cvsroot
+CVSROOT=$PWD/tmpcvsroot
 CVSWORK=$PWD/cvswork
 GIT_DIR=$PWD/.git
 export CVSROOT CVSWORK GIT_DIR
index 514282cbdfde7e661dcf17c0e1388c3c03a8d287..489bc80fc1b1ba4066a1fd5ad6d2024d67160ba7 100644 (file)
@@ -230,7 +230,7 @@ else
        say_color() {
                test -z "$1" && test -n "$quiet" && return
                shift
-               echo "$*"
+               printf "%s\n" "$*"
        }
 fi
 
index 83633a21e586fd94015bd983b683ffc10b2c1963..0f2d9a4a3d8ea732c7c61e3818bd0bbe417c76b0 100644 (file)
@@ -40,7 +40,7 @@ int main(int argc, char *argv[])
        if (argc == 2) {
                if (svndump_init(argv[1]))
                        return 1;
-               svndump_read(NULL);
+               svndump_read(NULL, "refs/heads/master", "refs/notes/svn/revs");
                svndump_deinit();
                svndump_reset();
                return 0;
index cfe098849022fcc56bcb1a57d00e4c89e753492b..4713b6930248d961824c9f867b10340e6278132f 100644 (file)
@@ -10,6 +10,7 @@
 #include "string-list.h"
 #include "thread-utils.h"
 #include "sigchain.h"
+#include "argv-array.h"
 
 static int debug;
 
@@ -19,6 +20,7 @@ struct helper_data {
        FILE *out;
        unsigned fetch : 1,
                import : 1,
+               bidi_import : 1,
                export : 1,
                option : 1,
                push : 1,
@@ -101,6 +103,7 @@ static void do_take_over(struct transport *transport)
 static struct child_process *get_helper(struct transport *transport)
 {
        struct helper_data *data = transport->data;
+       struct argv_array argv = ARGV_ARRAY_INIT;
        struct strbuf buf = STRBUF_INIT;
        struct child_process *helper;
        const char **refspecs = NULL;
@@ -122,11 +125,10 @@ static struct child_process *get_helper(struct transport *transport)
        helper->in = -1;
        helper->out = -1;
        helper->err = 0;
-       helper->argv = xcalloc(4, sizeof(*helper->argv));
-       strbuf_addf(&buf, "git-remote-%s", data->name);
-       helper->argv[0] = strbuf_detach(&buf, NULL);
-       helper->argv[1] = transport->remote->name;
-       helper->argv[2] = remove_ext_force(transport->url);
+       argv_array_pushf(&argv, "git-remote-%s", data->name);
+       argv_array_push(&argv, transport->remote->name);
+       argv_array_push(&argv, remove_ext_force(transport->url));
+       helper->argv = argv_array_detach(&argv, NULL);
        helper->git_cmd = 0;
        helper->silent_exec_failure = 1;
 
@@ -178,6 +180,8 @@ static struct child_process *get_helper(struct transport *transport)
                        data->push = 1;
                else if (!strcmp(capname, "import"))
                        data->import = 1;
+               else if (!strcmp(capname, "bidi-import"))
+                       data->bidi_import = 1;
                else if (!strcmp(capname, "export"))
                        data->export = 1;
                else if (!data->refspecs && !prefixcmp(capname, "refspec ")) {
@@ -241,8 +245,7 @@ static int disconnect_helper(struct transport *transport)
                close(data->helper->out);
                fclose(data->out);
                res = finish_command(data->helper);
-               free((char *)data->helper->argv[0]);
-               free(data->helper->argv);
+               argv_array_free_detached(data->helper->argv);
                free(data->helper);
                data->helper = NULL;
        }
@@ -376,14 +379,23 @@ static int fetch_with_fetch(struct transport *transport,
 static int get_importer(struct transport *transport, struct child_process *fastimport)
 {
        struct child_process *helper = get_helper(transport);
+       struct helper_data *data = transport->data;
+       struct argv_array argv = ARGV_ARRAY_INIT;
+       int cat_blob_fd, code;
        memset(fastimport, 0, sizeof(*fastimport));
        fastimport->in = helper->out;
-       fastimport->argv = xcalloc(5, sizeof(*fastimport->argv));
-       fastimport->argv[0] = "fast-import";
-       fastimport->argv[1] = "--quiet";
+       argv_array_push(&argv, "fast-import");
+       argv_array_push(&argv, debug ? "--stats" : "--quiet");
 
+       if (data->bidi_import) {
+               cat_blob_fd = xdup(helper->in);
+               argv_array_pushf(&argv, "--cat-blob-fd=%d", cat_blob_fd);
+       }
+       fastimport->argv = argv.argv;
        fastimport->git_cmd = 1;
-       return start_command(fastimport);
+
+       code = start_command(fastimport);
+       return code;
 }
 
 static int get_exporter(struct transport *transport,
@@ -438,11 +450,17 @@ static int fetch_with_import(struct transport *transport,
        }
 
        write_constant(data->helper->in, "\n");
+       /*
+        * remote-helpers that advertise the bidi-import capability are required to
+        * buffer the complete batch of import commands until this newline before
+        * sending data to fast-import.
+        * These helpers read back data from fast-import on their stdin, which could
+        * be mixed with import commands, otherwise.
+        */
 
        if (finish_command(&fastimport))
                die("Error while running fast-import");
-       free(fastimport.argv);
-       fastimport.argv = NULL;
+       argv_array_free_detached(fastimport.argv);
 
        /*
         * The fast-import stream of a remote helper that advertises
index 2e90ccb74fe45e6335ee6a76451da40d7d3f5a09..6142421ea1172f7fe6b57486a4f41b81d92bab85 100644 (file)
@@ -727,12 +727,7 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo
                " include-tag multi_ack_detailed";
        struct object *o = lookup_unknown_object(sha1);
        const char *refname_nons = strip_namespace(refname);
-
-       if (o->type == OBJ_NONE) {
-               o->type = sha1_object_info(sha1, NULL);
-               if (o->type < 0)
-                   die("git upload-pack: cannot find object %s:", sha1_to_hex(sha1));
-       }
+       unsigned char peeled[20];
 
        if (capabilities)
                packet_write(1, "%s %s%c%s%s agent=%s\n",
@@ -747,11 +742,8 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo
                o->flags |= OUR_REF;
                nr_our_refs++;
        }
-       if (o->type == OBJ_TAG) {
-               o = deref_tag_noverify(o);
-               if (o)
-                       packet_write(1, "%s %s^{}\n", sha1_to_hex(o->sha1), refname_nons);
-       }
+       if (!peel_ref(refname, peeled))
+               packet_write(1, "%s %s^{}\n", sha1_to_hex(peeled), refname_nons);
        return 0;
 }
 
diff --git a/utf8.c b/utf8.c
index a544f15456656df642253533eaa28885ce3496a6..28791a7c3174924967182d54c8b4a7f9600c87bf 100644 (file)
--- a/utf8.c
+++ b/utf8.c
@@ -353,7 +353,7 @@ int strbuf_add_wrapped_text(struct strbuf *buf,
 
                c = *text;
                if (!c || isspace(c)) {
-                       if (w < width || !space) {
+                       if (w <= width || !space) {
                                const char *start = bol;
                                if (!c && text == start)
                                        return w;
index 1f04697866bd481e24f17e0833c1c2d29c8e12e2..f2b23c81de11a63c2c1c2ac925be9081ad5bea5c 100644 (file)
@@ -3,8 +3,7 @@
  * See LICENSE for details.
  */
 
-#include "git-compat-util.h"
-#include "strbuf.h"
+#include "cache.h"
 #include "quote.h"
 #include "fast_export.h"
 #include "repo_tree.h"
@@ -68,11 +67,33 @@ void fast_export_modify(const char *path, uint32_t mode, const char *dataref)
        putchar('\n');
 }
 
+void fast_export_begin_note(uint32_t revision, const char *author,
+               const char *log, unsigned long timestamp, const char *note_ref)
+{
+       static int firstnote = 1;
+       size_t loglen = strlen(log);
+       printf("commit %s\n", note_ref);
+       printf("committer %s <%s@%s> %ld +0000\n", author, author, "local", timestamp);
+       printf("data %"PRIuMAX"\n", (uintmax_t)loglen);
+       fwrite(log, loglen, 1, stdout);
+       if (firstnote) {
+               if (revision > 1)
+                       printf("from %s^0", note_ref);
+               firstnote = 0;
+       }
+       fputc('\n', stdout);
+}
+
+void fast_export_note(const char *committish, const char *dataref)
+{
+       printf("N %s %s\n", dataref, committish);
+}
+
 static char gitsvnline[MAX_GITSVN_LINE_LEN];
 void fast_export_begin_commit(uint32_t revision, const char *author,
                        const struct strbuf *log,
                        const char *uuid, const char *url,
-                       unsigned long timestamp)
+                       unsigned long timestamp, const char *local_ref)
 {
        static const struct strbuf empty = STRBUF_INIT;
        if (!log)
@@ -84,7 +105,7 @@ void fast_export_begin_commit(uint32_t revision, const char *author,
        } else {
                *gitsvnline = '\0';
        }
-       printf("commit refs/heads/master\n");
+       printf("commit %s\n", local_ref);
        printf("mark :%"PRIu32"\n", revision);
        printf("committer %s <%s@%s> %ld +0000\n",
                   *author ? author : "nobody",
@@ -222,6 +243,13 @@ static long apply_delta(off_t len, struct line_buffer *input,
        return ret;
 }
 
+void fast_export_buf_to_data(const struct strbuf *data)
+{
+       printf("data %"PRIuMAX"\n", (uintmax_t)data->len);
+       fwrite(data->buf, data->len, 1, stdout);
+       fputc('\n', stdout);
+}
+
 void fast_export_data(uint32_t mode, off_t len, struct line_buffer *input)
 {
        assert(len >= 0);
index 8823aca15c9592ce732e741e879aa182f2273202..c8b5adb811c7ba5652b94a6cf6f9ea54d6d9335f 100644 (file)
@@ -9,11 +9,15 @@ void fast_export_deinit(void);
 
 void fast_export_delete(const char *path);
 void fast_export_modify(const char *path, uint32_t mode, const char *dataref);
+void fast_export_note(const char *committish, const char *dataref);
+void fast_export_begin_note(uint32_t revision, const char *author,
+               const char *log, unsigned long timestamp, const char *note_ref);
 void fast_export_begin_commit(uint32_t revision, const char *author,
-                       const struct strbuf *log, const char *uuid,
-                       const char *url, unsigned long timestamp);
+                       const struct strbuf *log, const char *uuid,const char *url,
+                       unsigned long timestamp, const char *local_ref);
 void fast_export_end_commit(uint32_t revision);
 void fast_export_data(uint32_t mode, off_t len, struct line_buffer *input);
+void fast_export_buf_to_data(const struct strbuf *data);
 void fast_export_blob_delta(uint32_t mode,
                        uint32_t old_mode, const char *old_data,
                        off_t len, struct line_buffer *input);
index 2b168aee75ddc299f22c738b26f07e12c285f9ae..31d1d83d451e0e78f19067799d14e555a62e2cc8 100644 (file)
@@ -48,7 +48,7 @@ static struct {
 static struct {
        uint32_t revision;
        unsigned long timestamp;
-       struct strbuf log, author;
+       struct strbuf log, author, note;
 } rev_ctx;
 
 static struct {
@@ -77,6 +77,7 @@ static void reset_rev_ctx(uint32_t revision)
        rev_ctx.timestamp = 0;
        strbuf_reset(&rev_ctx.log);
        strbuf_reset(&rev_ctx.author);
+       strbuf_reset(&rev_ctx.note);
 }
 
 static void reset_dump_ctx(const char *url)
@@ -299,22 +300,29 @@ static void handle_node(void)
                                node_ctx.text_length, &input);
 }
 
-static void begin_revision(void)
+static void begin_revision(const char *remote_ref)
 {
        if (!rev_ctx.revision)  /* revision 0 gets no git commit. */
                return;
        fast_export_begin_commit(rev_ctx.revision, rev_ctx.author.buf,
                &rev_ctx.log, dump_ctx.uuid.buf, dump_ctx.url.buf,
-               rev_ctx.timestamp);
+               rev_ctx.timestamp, remote_ref);
 }
 
-static void end_revision(void)
+static void end_revision(const char *note_ref)
 {
-       if (rev_ctx.revision)
+       struct strbuf mark = STRBUF_INIT;
+       if (rev_ctx.revision) {
                fast_export_end_commit(rev_ctx.revision);
+               fast_export_begin_note(rev_ctx.revision, "remote-svn",
+                               "Note created by remote-svn.", rev_ctx.timestamp, note_ref);
+               strbuf_addf(&mark, ":%"PRIu32, rev_ctx.revision);
+               fast_export_note(mark.buf, "inline");
+               fast_export_buf_to_data(&rev_ctx.note);
+       }
 }
 
-void svndump_read(const char *url)
+void svndump_read(const char *url, const char *local_ref, const char *notes_ref)
 {
        char *val;
        char *t;
@@ -353,11 +361,12 @@ void svndump_read(const char *url)
                        if (active_ctx == NODE_CTX)
                                handle_node();
                        if (active_ctx == REV_CTX)
-                               begin_revision();
+                               begin_revision(local_ref);
                        if (active_ctx != DUMP_CTX)
-                               end_revision();
+                               end_revision(notes_ref);
                        active_ctx = REV_CTX;
                        reset_rev_ctx(atoi(val));
+                       strbuf_addf(&rev_ctx.note, "%s\n", t);
                        break;
                case sizeof("Node-path"):
                        if (constcmp(t, "Node-"))
@@ -366,13 +375,15 @@ void svndump_read(const char *url)
                                if (active_ctx == NODE_CTX)
                                        handle_node();
                                if (active_ctx == REV_CTX)
-                                       begin_revision();
+                                       begin_revision(local_ref);
                                active_ctx = NODE_CTX;
                                reset_node_ctx(val);
+                               strbuf_addf(&rev_ctx.note, "%s\n", t);
                                break;
                        }
                        if (constcmp(t + strlen("Node-"), "kind"))
                                continue;
+                       strbuf_addf(&rev_ctx.note, "%s\n", t);
                        if (!strcmp(val, "dir"))
                                node_ctx.type = REPO_MODE_DIR;
                        else if (!strcmp(val, "file"))
@@ -383,6 +394,7 @@ void svndump_read(const char *url)
                case sizeof("Node-action"):
                        if (constcmp(t, "Node-action"))
                                continue;
+                       strbuf_addf(&rev_ctx.note, "%s\n", t);
                        if (!strcmp(val, "delete")) {
                                node_ctx.action = NODEACT_DELETE;
                        } else if (!strcmp(val, "add")) {
@@ -401,11 +413,13 @@ void svndump_read(const char *url)
                                continue;
                        strbuf_reset(&node_ctx.src);
                        strbuf_addstr(&node_ctx.src, val);
+                       strbuf_addf(&rev_ctx.note, "%s\n", t);
                        break;
                case sizeof("Node-copyfrom-rev"):
                        if (constcmp(t, "Node-copyfrom-rev"))
                                continue;
                        node_ctx.srcRev = atoi(val);
+                       strbuf_addf(&rev_ctx.note, "%s\n", t);
                        break;
                case sizeof("Text-content-length"):
                        if (constcmp(t, "Text") && constcmp(t, "Prop"))
@@ -463,25 +477,40 @@ void svndump_read(const char *url)
        if (active_ctx == NODE_CTX)
                handle_node();
        if (active_ctx == REV_CTX)
-               begin_revision();
+               begin_revision(local_ref);
        if (active_ctx != DUMP_CTX)
-               end_revision();
+               end_revision(notes_ref);
 }
 
-int svndump_init(const char *filename)
+static void init(int report_fd)
 {
-       if (buffer_init(&input, filename))
-               return error("cannot open %s: %s", filename, strerror(errno));
-       fast_export_init(REPORT_FILENO);
+       fast_export_init(report_fd);
        strbuf_init(&dump_ctx.uuid, 4096);
        strbuf_init(&dump_ctx.url, 4096);
        strbuf_init(&rev_ctx.log, 4096);
        strbuf_init(&rev_ctx.author, 4096);
+       strbuf_init(&rev_ctx.note, 4096);
        strbuf_init(&node_ctx.src, 4096);
        strbuf_init(&node_ctx.dst, 4096);
        reset_dump_ctx(NULL);
        reset_rev_ctx(0);
        reset_node_ctx(NULL);
+       return;
+}
+
+int svndump_init(const char *filename)
+{
+       if (buffer_init(&input, filename))
+               return error("cannot open %s: %s", filename ? filename : "NULL", strerror(errno));
+       init(REPORT_FILENO);
+       return 0;
+}
+
+int svndump_init_fd(int in_fd, int back_fd)
+{
+       if(buffer_fdinit(&input, xdup(in_fd)))
+               return error("cannot open fd %d: %s", in_fd, strerror(errno));
+       init(xdup(back_fd));
        return 0;
 }
 
@@ -492,6 +521,8 @@ void svndump_deinit(void)
        reset_rev_ctx(0);
        reset_node_ctx(NULL);
        strbuf_release(&rev_ctx.log);
+       strbuf_release(&rev_ctx.author);
+       strbuf_release(&rev_ctx.note);
        strbuf_release(&node_ctx.src);
        strbuf_release(&node_ctx.dst);
        if (buffer_deinit(&input))
index df9ceb0e8d473b65fc22ac142d3856dc4f9980e0..b8eb12954e816e0e1490f6ef7eefe64901c38ae1 100644 (file)
@@ -2,7 +2,8 @@
 #define SVNDUMP_H_
 
 int svndump_init(const char *filename);
-void svndump_read(const char *url);
+int svndump_init_fd(int in_fd, int back_fd);
+void svndump_read(const char *url, const char *local_ref, const char *notes_ref);
 void svndump_deinit(void);
 void svndump_reset(void);
 
index d45b536021e15c5a674f7969be39f238194bef99..960f448cffd9ffd4e53763dfed3669bc374b8620 100644 (file)
@@ -34,12 +34,7 @@ void maybe_flush_or_die(FILE *f, const char *desc)
                        return;
        }
        if (fflush(f)) {
-               /*
-                * On Windows, EPIPE is returned only by the first write()
-                * after the reading end has closed its handle; subsequent
-                * write()s return EINVAL.
-                */
-               if (errno == EPIPE || errno == EINVAL)
+               if (errno == EPIPE)
                        exit(0);
                die_errno("write failure on '%s'", desc);
        }