David S. Miller <davem@davemloft.net>
Deskin Miller <deskinm@umich.edu>
Dirk Süsserott <newsletter@dirk.my1.cc>
+Erik Faye-Lund <kusmabite@gmail.com> <kusmabite@googlemail.com>
Fredrik Kuivinen <freku045@student.liu.se>
H. Peter Anvin <hpa@bonde.sc.orionmulti.com>
H. Peter Anvin <hpa@tazenda.sc.orionmulti.com>
İsmail Dönmez <ismail@pardus.org.tr>
Jay Soffian <jaysoffian+git@gmail.com>
Joachim Berdal Haga <cjhaga@fys.uio.no>
+Johannes Sixt <j6t@kdbg.org> <johannes.sixt@telecom.at>
+Johannes Sixt <j6t@kdbg.org> <j.sixt@viscovery.net>
+Johannes Sixt <j6t@kdbg.org> <J.Sixt@eudaptics.com>
Jon Loeliger <jdl@freescale.com>
Jon Seymour <jon@blackcubes.dyndns.org>
Jonathan Nieder <jrnieder@uchicago.edu>
Li Hong <leehong@pku.edu.cn>
Lukas Sandström <lukass@etek.chalmers.se>
Martin Langhoff <martin@laptop.org>
+Martin von Zweigbergk <martinvonz@gmail.com> <martin.von.zweigbergk@gmail.com>
Michael Coleman <tutufan@gmail.com>
Michael J Gruber <git@drmicha.warpmail.net> <michaeljgruber+gmane@fastmail.fm>
Michael W. Olson <mwolson@gnu.org>
Nanako Shiraishi <nanako3@lavabit.com>
Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
<nico@fluxnic.net> <nico@cam.org>
+Peter Krefting <peter@softwolves.pp.se> <peter@svarten.intern.softwolves.pp.se>
+Peter Krefting <peter@softwolves.pp.se> <peter@softwolves.pp.se>
Philippe Bruhat <book@cpan.org>
+Ralf Thielow <ralf.thielow@gmail.com> <ralf.thielow@googlemail.com>
Ramsay Allan Jones <ramsay@ramsay1.demon.co.uk>
René Scharfe <rene.scharfe@lsrfire.ath.cx>
Robert Fitzsimons <robfitz@273k.net>
Shawn O. Pearce <spearce@spearce.org>
Steven Grimm <koreth@midwinter.com>
Theodore Ts'o <tytso@mit.edu>
+Thomas Rast <trast@inf.ethz.ch> <trast@student.ethz.ch>
Tony Luck <tony.luck@intel.com>
Uwe Kleine-König <Uwe_Zeisberger@digi.com>
Uwe Kleine-König <Uwe.Kleine-Koenig@digi.com>
--- /dev/null
+Git v1.8.0 Release Notes
+========================
+
+Backward compatibility notes
+----------------------------
+
+In the next major release, we will change the behaviour of the "git
+push" command. When "git push [$there]" does not say what to push, we
+have used the traditional "matching" semantics (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.
+
+"git branch --set-upstream" is deprecated and may be removed in a
+relatively distant future. "git branch [-u|--set-upstream-to]" has
+been introduced with a saner order of arguments.
+
+
+Updates since v1.7.12
+---------------------
+
+UI, Workflows & Features
+
+ * A credential helper for Win32 to allow access to the keychain of
+ the logged-in user has been added.
+
+ * A credential helper to allow access to the Gnome keyring has been
+ added.
+
+ * It was tempting to say "git branch --set-upstream origin/master",
+ but that tells Git to arrange the local branch "origin/master" to
+ integrate with the currently checked out branch, which is highly
+ unlikely what the user meant. The option is deprecated; use the
+ new "--set-upstream-to" (with a short-and-sweet "-u") option
+ instead.
+
+ * "git cherry-pick" learned the "--allow-empty-message" option to
+ allow it to replay a commit without any log message.
+
+ * "git daemon" learned the "--access-hook" option to allow an
+ external command to decline service based on the client address,
+ repository path, etc.
+
+ * "git difftool --dir-diff" learned to use symbolic links to prepare
+ temporary copy of the working tree when available.
+
+ * "git grep" learned to use a non-standard pattern type by default if
+ a configuration variable tells it to.
+
+Foreign Interface
+
+ * "git svn" has been updated to work with SVN 1.7.
+
+Performance, Internal Implementation, etc. (please report possible regressions)
+
+ * The "check-docs" build target has been updated and greatly
+ simplified.
+
+ * The documentation in the TeXinfo format was using indented output
+ for materials meant to be examples that are better typeset in
+ monospace.
+
+ * Compatibility wrapper to learn the maximum number of file
+ descriptors we can open around sysconf(_SC_OPEN_MAX) and
+ getrlimit(RLIMIT_NO_FILE) has been introduced for portability.
+
+ * Compatibility wrapper around some mkdir(2) implementations that
+ reject parameter with trailing slash has been introduced.
+
+ * The heuristics to detect and silently convert latin1 to utf8 when
+ we were told to use utf-8 in the log message has been transplanted
+ from "mailinfo" to "commit" and "commit-tree".
+
+ * Messages given by "git <subcommand> -h" from many subcommands have
+ been marked for translation.
+
+Also contains minor documentation updates and code clean-ups.
+
+
+Fixes since v1.7.12
+-------------------
+
+Unless otherwise noted, all the fixes since v1.7.12 in the
+maintenance track are contained in this release (see release notes
+to them for details).
+
+ * "git cherry-pick A C B" used to replay changes in A and then B and
+ then C if these three commits had committer timestamps in that
+ order, which is not what the user who said "A C B" naturally
+ expects.
+ (merge a73e22e mz/cherry-pick-cmdline-order later to maint).
+
+ * "git show --quiet" ought to be a synonym for "git show -s", but
+ wasn't.
+ (merge f9c75d8 jk/maint-quiet-is-synonym-to-s-in-log later to maint).
+
+ * "git p4", when "--use-client-spec" and "--detect-branches" are used
+ together, misdetected branches.
+ (merge 21ef5df pw/p4-use-client-spec-branch-detection later to maint).
+
+ * Output from "git branch -v" contains "(no branch)" that could be
+ localized, but the code to align it along with the names of
+ branches were counting in bytes, not in display columns.
+ (merge 1452bd6 nd/branch-v-alignment later to maint).
+
+ * "git for-each-ref" did not currectly support more than one --sort
+ option.
+ (merge 3b51222 kk/maint-for-each-ref-multi-sort later to maint).
+
+ * Pushing to smart HTTP server with recent Git fails without having
+ the username in the URL to force authentication, if the server is
+ configured to allow GET anonymously, while requiring authentication
+ for POST.
+ (merge b81401c jk/maint-http-half-auth-push later to maint).
+
+ * When looking for $HOME/.gitconfig etc., it is OK if we cannot read
+ them because they do not exist, but we did not diagnose existing
+ files that we cannot read.
+
+ * The synopsis said "checkout [-B branch]" to make it clear the
+ branch name is a parameter to the option, but the heading for the
+ option description was "-B::", not "-B branch::", making the
+ documentation misleading. There may be room in documentation pages
+ of other commands for similar improvements (hint, hint).
+ (merge 45aaf03 jc/maint-doc-checkout-b-always-takes-branch-name later to maint).
+
+ * "git log .." errored out saying it is both rev range and a path
+ when there is no disambiguating "--" is on the command line.
+ Update the command line parser to interpret ".." as a path in such
+ a case.
+ (merge 003c84f jc/dotdot-is-parent-directory later to maint).
+
+ * "git apply -p0" did not parse pathnames on "diff --git" line
+ correctly. This caused patches that had pathnames in no other
+ places to be mistakenly rejected (most notably, binary patch that
+ does not rename nor change mode). Textual patches, renames or mode
+ changes have preimage and postimage pathnames in different places
+ in a form that can be parsed unambiguously and did not suffer from
+ this problem.
+ (merge 6a2abdc jc/apply-binary-p0 later to maint).
+
+ * The exit status code from "git config" was way overspecified while
+ being incorrect. The implementation has been updated to give the
+ documented status for a case that was documented, and introduce a
+ new code for "all other errors".
+ (merge 9409c7a jc/maint-config-exit-status later to maint).
+
+ * "git foo" errored out with "Not a directory" when the user had a
+ non-directory on $PATH, and worse yet it masked an alias "foo" from
+ running. (merge a785508 jc/maint-sane-execvp-notdir later to
+ maint).
+
+ * The interactive prompt "git send-email" gives was error prone. It
+ asked "What e-mail address do you want to use?" with the address it
+ guessed (correctly) the user would want to use in its prompt,
+ tempting the user to say "y". But the response was taken as "No,
+ please use 'y' as the e-mail address instead", which is most
+ certainly not what the user meant.
+ (merge 51bbccf jc/send-email-reconfirm later to maint).
+
+ * "git stash apply/pop" did not trigger "rerere" upon conflicts
+ unlike other mergy operations.
+ (merge 743bf6d ph/stash-rerere later to maint).
+
+ * "git submodule update -f" did not update paths in the working tree
+ that has local changes.
+ (merge 01d4721 sz/submodule-force-update later to maint).
+
+ * We used curl_easy_strerror() without checking version of cURL,
+ breaking the build for versions before curl 7.12.0.
+ (merge 4246b0b js/no-curl-easy-strerror-on-old-curl later to maint).
+
+ * Code to work around MacOS X UTF-8 gotcha has been cleaned up.
+ (merge 9a27f96 rr/precompose-utf8-cleanup later to maint).
+
+ * Documentation for the configuration file format had a confusing
+ example.
+ (merge d1e1fe7 mh/maint-config-doc-proxy-command later to maint).
+
+ * "git submodule <cmd> path" did not error out when the path to the
+ submodule was misspelt.
+ (merge be9d0a3 hv/submodule-path-unmatch later to maint).
+
+ * Some capabilities were asked by fetch-pack even when upload-pack
+ did not advertise that they are available. fetch-pack has been
+ fixed not to do so.
+
+ * The output from "git diff -B" for a file that ends with an
+ incomplete line did not put "\ No newline..." on a line of its own.
grep.lineNumber::
If set to true, enable '-n' option by default.
+grep.patternType::
+ Set the default matching behavior. Using a value of 'basic', 'extended',
+ 'fixed', or 'perl' will enable the '--basic-regexp', '--extended-regexp',
+ '--fixed-strings', or '--perl-regexp' option accordingly, while the
+ value 'default' will return to the default matching behavior.
+
grep.extendedRegexp::
- If set to true, enable '--extended-regexp' option by default.
+ If set to true, enable '--extended-regexp' option by default. This
+ option is ignored when the 'grep.patternType' option is set to a value
+ other than 'default'.
gpg.program::
Use this custom program instead of "gpg" found on $PATH when
[--column[=<options>] | --no-column]
[(--merged | --no-merged | --contains) [<commit>]] [<pattern>...]
'git branch' [--set-upstream | --track | --no-track] [-l] [-f] <branchname> [<start-point>]
+'git branch' (--set-upstream-to=<upstream> | -u <upstream>) [<branchname>]
+'git branch' --unset-upstream [<branchname>]
'git branch' (-m | -M) [<oldbranch>] <newbranch>
'git branch' (-d | -D) [-r] <branchname>...
'git branch' --edit-description [<branchname>]
the remote-tracking branch. This behavior may be changed via the global
`branch.autosetupmerge` configuration flag. That setting can be
overridden by using the `--track` and `--no-track` options, and
-changed later using `git branch --set-upstream`.
+changed later using `git branch --set-upstream-to`.
With a `-m` or `-M` option, <oldbranch> will be renamed to <newbranch>.
If <oldbranch> had a corresponding reflog, it is renamed to match
like `--track` would when creating the branch, except that where
branch points to is not changed.
+-u <upstream>::
+--set-upstream-to=<upstream>::
+ Set up <branchname>'s tracking information so <upstream> is
+ considered <branchname>'s upstream branch. If no <branchname>
+ is specified, then it defaults to the current branch.
+
+--unset-upstream::
+ Remove the upstream information for <branchname>. If no branch
+ is specified it defaults to the current branch.
+
--edit-description::
Open an editor and edit the text to explain what the branch is
for, to be used by various other commands (e.g. `request-pull`).
When checking out paths from the index, check out stage #2
('ours') or #3 ('theirs') for unmerged paths.
--b::
+-b <new_branch>::
Create a new branch named <new_branch> and start it at
<start_point>; see linkgit:git-branch[1] for details.
--B::
+-B <new_branch>::
Creates the branch <new_branch> and start it at <start_point>;
if it already exists, then reset it to <start_point>. This is
equivalent to running "git branch" with "-f"; see
<commit> is not a branch name. See the "DETACHED HEAD" section
below for details.
---orphan::
+--orphan <new_branch>::
Create a new 'orphan' branch, named <new_branch>, started from
<start_point> and switch to it. The first commit made on this
new branch will have no parents and it will be the root of a new
previous commit are dropped. To force the inclusion of those commits
use `--keep-redundant-commits`.
+--allow-empty-message::
+ By default, cherry-picking a commit with an empty message will fail.
+ This option overrides that behaviour, allowing commits with empty
+ messages to be cherry picked.
+
--keep-redundant-commits::
If a commit being cherry picked duplicates a commit already in the
current history, it will become empty. By default these
[--reuseaddr] [--detach] [--pid-file=<file>]
[--enable=<service>] [--disable=<service>]
[--allow-override=<service>] [--forbid-override=<service>]
+ [--access-hook=<path>]
[--inetd | [--listen=<host_or_ipaddr>] [--port=<n>] [--user=<user> [--group=<group>]]
[<directory>...]
errors are not enabled, all errors report "access denied" to the
client. The default is --no-informative-errors.
+--access-hook=<path>::
+ Every time a client connects, first run an external command
+ specified by the <path> with service name (e.g. "upload-pack"),
+ path to the repository, hostname (%H), canonical hostname
+ (%CH), ip address (%IP), and tcp port (%P) as its command line
+ arguments. The external command can decide to decline the
+ service by exiting with a non-zero status (or to allow it by
+ exiting with a zero status). It can also look at the $REMOTE_ADDR
+ and $REMOTE_PORT environment variables to learn about the
+ requestor when making this decision.
++
+The external command can optionally write a single line to its
+standard output to be sent to the requestor as an error message when
+it declines the service.
+
<directory>::
A directory to add to the whitelist of allowed directories. Unless
--strict-paths is specified this will also include subdirectories
--tool-help::
Print a list of diff tools that may be used with `--tool`.
+--symlinks::
+--no-symlinks::
+ 'git difftool''s default behavior is create symlinks to the
+ working tree when run in `--dir-diff` mode.
++
+ Specifying `--no-symlinks` instructs 'git difftool' to create
+ copies instead. `--no-symlinks` is the default on Windows.
+
-x <command>::
--extcmd=<command>::
Specify a custom command for viewing diffs.
grep.lineNumber::
If set to true, enable '-n' option by default.
+grep.patternType::
+ Set the default matching behavior. Using a value of 'basic', 'extended',
+ 'fixed', or 'perl' will enable the '--basic-regexp', '--extended-regexp',
+ '--fixed-strings', or '--perl-regexp' option accordingly, while the
+ value 'default' will return to the default matching behavior.
+
grep.extendedRegexp::
- If set to true, enable '--extended-regexp' option by default.
+ If set to true, enable '--extended-regexp' option by default. This
+ option is ignored when the 'grep.patternType' option is set to a value
+ other than 'default'.
OPTIONS
Otherwise, 'git mergetool' will prompt the user to indicate the
success of the resolution after the custom tool has exited.
+--tool-help::
+ Print a list of merge tools that may be used with `--tool`.
+
-y::
--no-prompt::
Don't prompt before each invocation of the merge resolution
Only useful with '--objects'; print the object IDs that are not
in packs.
---no-walk::
-
- Only show the given revs, but do not traverse their ancestors.
- This has no effect if a range is specified.
+--no-walk[=(sorted|unsorted)]::
+
+ Only show the given commits, but do not traverse their ancestors.
+ This has no effect if a range is specified. If the argument
+ "unsorted" is given, the commits are show in the order they were
+ given on the command line. Otherwise (if "sorted" or no argument
+ was given), the commits are show in reverse chronological order
+ by commit time.
--do-walk::
+
Note that any of the 'refs/*' cases above may come either from
the '$GIT_DIR/refs' directory or from the '$GIT_DIR/packed-refs' file.
+While the ref name encoding is unspecified, UTF-8 is prefered as
+some output processing may assume ref names in UTF-8.
'<refname>@\{<date>\}', e.g. 'master@\{yesterday\}', 'HEAD@\{5 minutes ago\}'::
A ref followed by the suffix '@' with a date specification
It is the set of commits that are reachable from either one of
'r1' or 'r2' but not from both.
+In these two shorthands, you can omit one end and let it default to HEAD.
+For example, 'origin..' is a shorthand for 'origin..HEAD' and asks "What
+did I do since I forked from the origin branch?" Similarly, '..origin'
+is a shorthand for 'HEAD..origin' and asks "What did the origin do since
+I forked from them?" Note that '..' would mean 'HEAD..HEAD' which is an
+empty range that is both reachable and unreachable from HEAD.
+
Two other shorthands for naming a set that is formed by a commit
and its parent commits exist. The 'r1{caret}@' notation means all
parents of 'r1'. 'r1{caret}!' includes commit 'r1' but excludes
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v1.7.12
+DEF_VER=v1.7.12.GIT
LF='
'
-Documentation/RelNotes/1.7.12.1.txt
\ No newline at end of file
+Documentation/RelNotes/1.8.0.txt
\ No newline at end of file
#include "unpack-trees.h"
static char const * const archive_usage[] = {
- "git archive [options] <tree-ish> [<path>...]",
- "git archive --list",
- "git archive --remote <repo> [--exec <cmd>] [options] <tree-ish> [<path>...]",
- "git archive --remote <repo> [--exec <cmd>] --list",
+ N_("git archive [options] <tree-ish> [<path>...]"),
+ N_("git archive --list"),
+ N_("git archive --remote <repo> [--exec <cmd>] [options] <tree-ish> [<path>...]"),
+ N_("git archive --remote <repo> [--exec <cmd>] --list"),
NULL
};
int worktree_attributes = 0;
struct option opts[] = {
OPT_GROUP(""),
- OPT_STRING(0, "format", &format, "fmt", "archive format"),
- OPT_STRING(0, "prefix", &base, "prefix",
- "prepend prefix to each pathname in the archive"),
- OPT_STRING('o', "output", &output, "file",
- "write the archive to this file"),
+ OPT_STRING(0, "format", &format, N_("fmt"), N_("archive format")),
+ OPT_STRING(0, "prefix", &base, N_("prefix"),
+ N_("prepend prefix to each pathname in the archive")),
+ OPT_STRING('o', "output", &output, N_("file"),
+ N_("write the archive to this file")),
OPT_BOOL(0, "worktree-attributes", &worktree_attributes,
- "read .gitattributes in working directory"),
- OPT__VERBOSE(&verbose, "report archived files on stderr"),
- OPT__COMPR('0', &compression_level, "store only", 0),
- OPT__COMPR('1', &compression_level, "compress faster", 1),
+ N_("read .gitattributes in working directory")),
+ OPT__VERBOSE(&verbose, N_("report archived files on stderr")),
+ OPT__COMPR('0', &compression_level, N_("store only"), 0),
+ OPT__COMPR('1', &compression_level, N_("compress faster"), 1),
OPT__COMPR_HIDDEN('2', &compression_level, 2),
OPT__COMPR_HIDDEN('3', &compression_level, 3),
OPT__COMPR_HIDDEN('4', &compression_level, 4),
OPT__COMPR_HIDDEN('6', &compression_level, 6),
OPT__COMPR_HIDDEN('7', &compression_level, 7),
OPT__COMPR_HIDDEN('8', &compression_level, 8),
- OPT__COMPR('9', &compression_level, "compress better", 9),
+ OPT__COMPR('9', &compression_level, N_("compress better"), 9),
OPT_GROUP(""),
OPT_BOOL('l', "list", &list,
- "list supported archive formats"),
+ N_("list supported archive formats")),
OPT_GROUP(""),
- OPT_STRING(0, "remote", &remote, "repo",
- "retrieve the archive from remote repository <repo>"),
- OPT_STRING(0, "exec", &exec, "cmd",
- "path to the remote git-upload-archive command"),
+ OPT_STRING(0, "remote", &remote, N_("repo"),
+ N_("retrieve the archive from remote repository <repo>")),
+ OPT_STRING(0, "exec", &exec, N_("command"),
+ N_("path to the remote git-upload-archive command")),
OPT_END()
};
char buf[2048];
int lineno = 0;
- if (!fp)
+ if (!fp) {
+ if (errno != ENOENT)
+ warn_on_inaccessible(path);
return NULL;
+ }
res = xcalloc(1, sizeof(*res));
while (fgets(buf, sizeof(buf), fp))
handle_attr_line(res, buf, path, ++lineno, macro_ok);
#include "bulk-checkin.h"
static const char * const builtin_add_usage[] = {
- "git add [options] [--] <filepattern>...",
+ N_("git add [options] [--] <filepattern>..."),
NULL
};
static int patch_interactive, add_interactive, edit_interactive;
static int ignore_add_errors, addremove, intent_to_add, ignore_missing = 0;
static struct option builtin_add_options[] = {
- OPT__DRY_RUN(&show_only, "dry run"),
- OPT__VERBOSE(&verbose, "be verbose"),
+ OPT__DRY_RUN(&show_only, N_("dry run")),
+ OPT__VERBOSE(&verbose, N_("be verbose")),
OPT_GROUP(""),
- OPT_BOOLEAN('i', "interactive", &add_interactive, "interactive picking"),
- OPT_BOOLEAN('p', "patch", &patch_interactive, "select hunks interactively"),
- OPT_BOOLEAN('e', "edit", &edit_interactive, "edit current diff and apply"),
- OPT__FORCE(&ignored_too, "allow adding otherwise ignored files"),
- OPT_BOOLEAN('u', "update", &take_worktree_changes, "update tracked files"),
- OPT_BOOLEAN('N', "intent-to-add", &intent_to_add, "record only the fact that the path will be added later"),
- OPT_BOOLEAN('A', "all", &addremove, "add changes from all tracked and untracked files"),
- OPT_BOOLEAN( 0 , "refresh", &refresh_only, "don't add, only refresh the index"),
- OPT_BOOLEAN( 0 , "ignore-errors", &ignore_add_errors, "just skip files which cannot be added because of errors"),
- OPT_BOOLEAN( 0 , "ignore-missing", &ignore_missing, "check if - even missing - files are ignored in dry run"),
+ OPT_BOOLEAN('i', "interactive", &add_interactive, N_("interactive picking")),
+ OPT_BOOLEAN('p', "patch", &patch_interactive, N_("select hunks interactively")),
+ OPT_BOOLEAN('e', "edit", &edit_interactive, N_("edit current diff and apply")),
+ OPT__FORCE(&ignored_too, N_("allow adding otherwise ignored files")),
+ OPT_BOOLEAN('u', "update", &take_worktree_changes, N_("update tracked files")),
+ OPT_BOOLEAN('N', "intent-to-add", &intent_to_add, N_("record only the fact that the path will be added later")),
+ OPT_BOOLEAN('A', "all", &addremove, N_("add changes from all tracked and untracked files")),
+ OPT_BOOLEAN( 0 , "refresh", &refresh_only, N_("don't add, only refresh the index")),
+ OPT_BOOLEAN( 0 , "ignore-errors", &ignore_add_errors, N_("just skip files which cannot be added because of errors")),
+ OPT_BOOLEAN( 0 , "ignore-missing", &ignore_missing, N_("check if - even missing - files are ignored in dry run")),
OPT_END(),
};
return -1;
}
-static const char *stop_at_slash(const char *line, int llen)
+/*
+ * Skip p_value leading components from "line"; as we do not accept
+ * absolute paths, return NULL in that case.
+ */
+static const char *skip_tree_prefix(const char *line, int llen)
{
- int nslash = p_value;
+ int nslash;
int i;
+ if (!p_value)
+ return (llen && line[0] == '/') ? NULL : line;
+
+ nslash = p_value;
for (i = 0; i < llen; i++) {
int ch = line[i];
if (ch == '/' && --nslash <= 0)
- return &line[i];
+ return (i == 0) ? NULL : &line[i + 1];
}
return NULL;
}
if (unquote_c_style(&first, line, &second))
goto free_and_fail1;
- /* advance to the first slash */
- cp = stop_at_slash(first.buf, first.len);
- /* we do not accept absolute paths */
- if (!cp || cp == first.buf)
+ /* strip the a/b prefix including trailing slash */
+ cp = skip_tree_prefix(first.buf, first.len);
+ if (!cp)
goto free_and_fail1;
- strbuf_remove(&first, 0, cp + 1 - first.buf);
+ strbuf_remove(&first, 0, cp - first.buf);
/*
* second points at one past closing dq of name.
if (*second == '"') {
if (unquote_c_style(&sp, second, NULL))
goto free_and_fail1;
- cp = stop_at_slash(sp.buf, sp.len);
- if (!cp || cp == sp.buf)
+ cp = skip_tree_prefix(sp.buf, sp.len);
+ if (!cp)
goto free_and_fail1;
/* They must match, otherwise ignore */
- if (strcmp(cp + 1, first.buf))
+ if (strcmp(cp, first.buf))
goto free_and_fail1;
strbuf_release(&sp);
return strbuf_detach(&first, NULL);
}
/* unquoted second */
- cp = stop_at_slash(second, line + llen - second);
- if (!cp || cp == second)
+ cp = skip_tree_prefix(second, line + llen - second);
+ if (!cp)
goto free_and_fail1;
- cp++;
- if (line + llen - cp != first.len + 1 ||
+ if (line + llen - cp != first.len ||
memcmp(first.buf, cp, first.len))
goto free_and_fail1;
return strbuf_detach(&first, NULL);
}
/* unquoted first name */
- name = stop_at_slash(line, llen);
- if (!name || name == line)
+ name = skip_tree_prefix(line, llen);
+ if (!name)
return NULL;
- name++;
/*
* since the first name is unquoted, a dq if exists must be
if (unquote_c_style(&sp, second, NULL))
goto free_and_fail2;
- np = stop_at_slash(sp.buf, sp.len);
- if (!np || np == sp.buf)
+ np = skip_tree_prefix(sp.buf, sp.len);
+ if (!np)
goto free_and_fail2;
- np++;
len = sp.buf + sp.len - np;
if (len < second - name &&
case '\n':
return NULL;
case '\t': case ' ':
- second = stop_at_slash(name + len, line_len - len);
+ /*
+ * Is this the separator between the preimage
+ * and the postimage pathname? Again, we are
+ * only interested in the case where there is
+ * no rename, as this is only to set def_name
+ * and a rename patch has the names elsewhere
+ * in an unambiguous form.
+ */
+ if (!name[len + 1])
+ return NULL; /* no postimage name */
+ second = skip_tree_prefix(name + len + 1,
+ line_len - (len + 1));
if (!second)
return NULL;
- second++;
- if (second[len] == '\n' && !strncmp(name, second, len)) {
+ /*
+ * Does len bytes starting at "name" and "second"
+ * (that are separated by one HT or SP we just
+ * found) exactly match?
+ */
+ if (second[len] == '\n' && !strncmp(name, second, len))
return xmemdupz(name, len);
- }
}
}
}
OPT_NOOP_NOARG(0, "allow-binary-replacement"),
OPT_NOOP_NOARG(0, "binary"),
OPT_BOOLEAN(0, "numstat", &numstat,
- N_("shows number of added and deleted lines in decimal notation")),
+ N_("show number of added and deleted lines in decimal notation")),
OPT_BOOLEAN(0, "summary", &summary,
N_("instead of applying the patch, output a summary for the input")),
OPT_BOOLEAN(0, "check", &check,
const char *output = NULL;
const char *remote = NULL;
struct option local_opts[] = {
- OPT_STRING('o', "output", &output, "file",
- "write the archive to this file"),
- OPT_STRING(0, "remote", &remote, "repo",
- "retrieve the archive from remote repository <repo>"),
- OPT_STRING(0, "exec", &exec, "cmd",
- "path to the remote git-upload-archive command"),
+ OPT_STRING('o', "output", &output, N_("file"),
+ N_("write the archive to this file")),
+ OPT_STRING(0, "remote", &remote, N_("repo"),
+ N_("retrieve the archive from remote repository <repo>")),
+ OPT_STRING(0, "exec", &exec, N_("command"),
+ N_("path to the remote git-upload-archive command")),
OPT_END()
};
#include "bisect.h"
static const char * const git_bisect_helper_usage[] = {
- "git bisect--helper --next-all [--no-checkout]",
+ N_("git bisect--helper --next-all [--no-checkout]"),
NULL
};
int no_checkout = 0;
struct option options[] = {
OPT_BOOLEAN(0, "next-all", &next_all,
- "perform 'git bisect next'"),
+ N_("perform 'git bisect next'")),
OPT_BOOLEAN(0, "no-checkout", &no_checkout,
- "update BISECT_HEAD instead of checking out the current commit"),
+ N_("update BISECT_HEAD instead of checking out the current commit")),
OPT_END()
};
#include "utf8.h"
#include "userdiff.h"
-static char blame_usage[] = "git blame [options] [rev-opts] [rev] [--] file";
+static char blame_usage[] = N_("git blame [options] [rev-opts] [rev] [--] file");
static const char *blame_opt_usage[] = {
blame_usage,
"",
- "[rev-opts] are documented in git-rev-list(1)",
+ N_("[rev-opts] are documented in git-rev-list(1)"),
NULL
};
static const char *revs_file = NULL;
static const char *contents_from = NULL;
static const struct option options[] = {
- OPT_BOOLEAN(0, "incremental", &incremental, "Show blame entries as we find them, incrementally"),
- OPT_BOOLEAN('b', NULL, &blank_boundary, "Show blank SHA-1 for boundary commits (Default: off)"),
- OPT_BOOLEAN(0, "root", &show_root, "Do not treat root commits as boundaries (Default: off)"),
- OPT_BOOLEAN(0, "show-stats", &show_stats, "Show work cost statistics"),
- OPT_BIT(0, "score-debug", &output_option, "Show output score for blame entries", OUTPUT_SHOW_SCORE),
- OPT_BIT('f', "show-name", &output_option, "Show original filename (Default: auto)", OUTPUT_SHOW_NAME),
- OPT_BIT('n', "show-number", &output_option, "Show original linenumber (Default: off)", OUTPUT_SHOW_NUMBER),
- OPT_BIT('p', "porcelain", &output_option, "Show in a format designed for machine consumption", OUTPUT_PORCELAIN),
- OPT_BIT(0, "line-porcelain", &output_option, "Show porcelain format with per-line commit information", OUTPUT_PORCELAIN|OUTPUT_LINE_PORCELAIN),
- OPT_BIT('c', NULL, &output_option, "Use the same output mode as git-annotate (Default: off)", OUTPUT_ANNOTATE_COMPAT),
- OPT_BIT('t', NULL, &output_option, "Show raw timestamp (Default: off)", OUTPUT_RAW_TIMESTAMP),
- OPT_BIT('l', NULL, &output_option, "Show long commit SHA1 (Default: off)", OUTPUT_LONG_OBJECT_NAME),
- OPT_BIT('s', NULL, &output_option, "Suppress author name and timestamp (Default: off)", OUTPUT_NO_AUTHOR),
- OPT_BIT('e', "show-email", &output_option, "Show author email instead of name (Default: off)", OUTPUT_SHOW_EMAIL),
- OPT_BIT('w', NULL, &xdl_opts, "Ignore whitespace differences", XDF_IGNORE_WHITESPACE),
- OPT_BIT(0, "minimal", &xdl_opts, "Spend extra cycles to find better match", XDF_NEED_MINIMAL),
- OPT_STRING('S', NULL, &revs_file, "file", "Use revisions from <file> instead of calling git-rev-list"),
- OPT_STRING(0, "contents", &contents_from, "file", "Use <file>'s contents as the final image"),
- { OPTION_CALLBACK, 'C', NULL, &opt, "score", "Find line copies within and across files", PARSE_OPT_OPTARG, blame_copy_callback },
- { OPTION_CALLBACK, 'M', NULL, &opt, "score", "Find line movements within and across files", PARSE_OPT_OPTARG, blame_move_callback },
- OPT_CALLBACK('L', NULL, &bottomtop, "n,m", "Process only line range n,m, counting from 1", blame_bottomtop_callback),
+ OPT_BOOLEAN(0, "incremental", &incremental, N_("Show blame entries as we find them, incrementally")),
+ OPT_BOOLEAN('b', NULL, &blank_boundary, N_("Show blank SHA-1 for boundary commits (Default: off)")),
+ OPT_BOOLEAN(0, "root", &show_root, N_("Do not treat root commits as boundaries (Default: off)")),
+ OPT_BOOLEAN(0, "show-stats", &show_stats, N_("Show work cost statistics")),
+ OPT_BIT(0, "score-debug", &output_option, N_("Show output score for blame entries"), OUTPUT_SHOW_SCORE),
+ OPT_BIT('f', "show-name", &output_option, N_("Show original filename (Default: auto)"), OUTPUT_SHOW_NAME),
+ OPT_BIT('n', "show-number", &output_option, N_("Show original linenumber (Default: off)"), OUTPUT_SHOW_NUMBER),
+ OPT_BIT('p', "porcelain", &output_option, N_("Show in a format designed for machine consumption"), OUTPUT_PORCELAIN),
+ OPT_BIT(0, "line-porcelain", &output_option, N_("Show porcelain format with per-line commit information"), OUTPUT_PORCELAIN|OUTPUT_LINE_PORCELAIN),
+ OPT_BIT('c', NULL, &output_option, N_("Use the same output mode as git-annotate (Default: off)"), OUTPUT_ANNOTATE_COMPAT),
+ OPT_BIT('t', NULL, &output_option, N_("Show raw timestamp (Default: off)"), OUTPUT_RAW_TIMESTAMP),
+ OPT_BIT('l', NULL, &output_option, N_("Show long commit SHA1 (Default: off)"), OUTPUT_LONG_OBJECT_NAME),
+ OPT_BIT('s', NULL, &output_option, N_("Suppress author name and timestamp (Default: off)"), OUTPUT_NO_AUTHOR),
+ OPT_BIT('e', "show-email", &output_option, N_("Show author email instead of name (Default: off)"), OUTPUT_SHOW_EMAIL),
+ OPT_BIT('w', NULL, &xdl_opts, N_("Ignore whitespace differences"), XDF_IGNORE_WHITESPACE),
+ OPT_BIT(0, "minimal", &xdl_opts, N_("Spend extra cycles to find better match"), XDF_NEED_MINIMAL),
+ OPT_STRING('S', NULL, &revs_file, N_("file"), N_("Use revisions from <file> instead of calling git-rev-list")),
+ OPT_STRING(0, "contents", &contents_from, N_("file"), N_("Use <file>'s contents as the final image")),
+ { OPTION_CALLBACK, 'C', NULL, &opt, N_("score"), N_("Find line copies within and across files"), PARSE_OPT_OPTARG, blame_copy_callback },
+ { OPTION_CALLBACK, 'M', NULL, &opt, N_("score"), N_("Find line movements within and across files"), PARSE_OPT_OPTARG, blame_move_callback },
+ OPT_CALLBACK('L', NULL, &bottomtop, N_("n,m"), N_("Process only line range n,m, counting from 1"), blame_bottomtop_callback),
OPT__ABBREV(&abbrev),
OPT_END()
};
#include "revision.h"
#include "string-list.h"
#include "column.h"
+#include "utf8.h"
static const char * const builtin_branch_usage[] = {
- "git branch [options] [-r | -a] [--merged | --no-merged]",
- "git branch [options] [-l] [-f] <branchname> [<start-point>]",
- "git branch [options] [-r] (-d | -D) <branchname>...",
- "git branch [options] (-m | -M) [<oldbranch>] <newbranch>",
+ N_("git branch [options] [-r | -a] [--merged | --no-merged]"),
+ N_("git branch [options] [-l] [-f] <branchname> [<start-point>]"),
+ N_("git branch [options] [-r] (-d | -D) <branchname>..."),
+ N_("git branch [options] (-m | -M) [<oldbranch>] <newbranch>"),
NULL
};
struct ref_item {
char *name;
char *dest;
- unsigned int kind, len;
+ unsigned int kind, width;
struct commit *commit;
};
newitem->name = xstrdup(refname);
newitem->kind = kind;
newitem->commit = commit;
- newitem->len = strlen(refname);
+ newitem->width = utf8_strwidth(refname);
newitem->dest = resolve_symref(orig_refname, prefix);
/* adjust for "remotes/" */
if (newitem->kind == REF_REMOTE_BRANCH &&
ref_list->kinds != REF_REMOTE_BRANCH)
- newitem->len += 8;
- if (newitem->len > ref_list->maxwidth)
- ref_list->maxwidth = newitem->len;
+ newitem->width += 8;
+ if (newitem->width > ref_list->maxwidth)
+ ref_list->maxwidth = newitem->width;
return 0;
}
}
strbuf_addf(&name, "%s%s", prefix, item->name);
- if (verbose)
+ if (verbose) {
+ int utf8_compensation = strlen(name.buf) - utf8_strwidth(name.buf);
strbuf_addf(&out, "%c %s%-*s%s", c, branch_get_color(color),
- maxwidth, name.buf,
+ maxwidth + utf8_compensation, name.buf,
branch_get_color(BRANCH_COLOR_RESET));
- else
+ } else
strbuf_addf(&out, "%c %s%s%s", c, branch_get_color(color),
name.buf, branch_get_color(BRANCH_COLOR_RESET));
for (i = 0; i < refs->index; i++) {
if (!matches_merge_filter(refs->list[i].commit))
continue;
- if (refs->list[i].len > w)
- w = refs->list[i].len;
+ if (refs->list[i].width > w)
+ w = refs->list[i].width;
}
return w;
}
if (head_commit && is_descendant_of(head_commit, ref_list->with_commit)) {
struct ref_item item;
item.name = xstrdup(_("(no branch)"));
- item.len = strlen(item.name);
+ item.width = utf8_strwidth(item.name);
item.kind = REF_LOCAL_BRANCH;
item.dest = NULL;
item.commit = head_commit;
- if (item.len > ref_list->maxwidth)
- ref_list->maxwidth = item.len;
+ if (item.width > ref_list->maxwidth)
+ ref_list->maxwidth = item.width;
print_ref_item(&item, ref_list->maxwidth, ref_list->verbose, ref_list->abbrev, 1, "");
free(item.name);
}
int delete = 0, rename = 0, force_create = 0, list = 0;
int verbose = 0, abbrev = -1, detached = 0;
int reflog = 0, edit_description = 0;
- int quiet = 0;
+ int quiet = 0, unset_upstream = 0;
+ const char *new_upstream = NULL;
enum branch_track track;
int kinds = REF_LOCAL_BRANCH;
struct commit_list *with_commit = NULL;
struct option options[] = {
- OPT_GROUP("Generic options"),
+ OPT_GROUP(N_("Generic options")),
OPT__VERBOSE(&verbose,
- "show hash and subject, give twice for upstream branch"),
- OPT__QUIET(&quiet, "suppress informational messages"),
- OPT_SET_INT('t', "track", &track, "set up tracking mode (see git-pull(1))",
+ N_("show hash and subject, give twice for upstream branch")),
+ OPT__QUIET(&quiet, N_("suppress informational messages")),
+ OPT_SET_INT('t', "track", &track, N_("set up tracking mode (see git-pull(1))"),
BRANCH_TRACK_EXPLICIT),
- OPT_SET_INT( 0, "set-upstream", &track, "change upstream info",
+ OPT_SET_INT( 0, "set-upstream", &track, N_("change upstream info"),
BRANCH_TRACK_OVERRIDE),
- OPT__COLOR(&branch_use_color, "use colored output"),
- OPT_SET_INT('r', "remotes", &kinds, "act on remote-tracking branches",
+ OPT_STRING('u', "set-upstream-to", &new_upstream, "upstream", "change the upstream info"),
+ OPT_BOOLEAN(0, "unset-upstream", &unset_upstream, "Unset the upstream info"),
+ OPT__COLOR(&branch_use_color, N_("use colored output")),
+ OPT_SET_INT('r', "remotes", &kinds, N_("act on remote-tracking branches"),
REF_REMOTE_BRANCH),
{
- OPTION_CALLBACK, 0, "contains", &with_commit, "commit",
- "print only branches that contain the commit",
+ OPTION_CALLBACK, 0, "contains", &with_commit, N_("commit"),
+ N_("print only branches that contain the commit"),
PARSE_OPT_LASTARG_DEFAULT,
parse_opt_with_commit, (intptr_t)"HEAD",
},
{
- OPTION_CALLBACK, 0, "with", &with_commit, "commit",
- "print only branches that contain the commit",
+ OPTION_CALLBACK, 0, "with", &with_commit, N_("commit"),
+ N_("print only branches that contain the commit"),
PARSE_OPT_HIDDEN | PARSE_OPT_LASTARG_DEFAULT,
parse_opt_with_commit, (intptr_t) "HEAD",
},
OPT__ABBREV(&abbrev),
- OPT_GROUP("Specific git-branch actions:"),
- OPT_SET_INT('a', "all", &kinds, "list both remote-tracking and local branches",
+ OPT_GROUP(N_("Specific git-branch actions:")),
+ OPT_SET_INT('a', "all", &kinds, N_("list both remote-tracking and local branches"),
REF_REMOTE_BRANCH | REF_LOCAL_BRANCH),
- OPT_BIT('d', "delete", &delete, "delete fully merged branch", 1),
- OPT_BIT('D', NULL, &delete, "delete branch (even if not merged)", 2),
- OPT_BIT('m', "move", &rename, "move/rename a branch and its reflog", 1),
- OPT_BIT('M', NULL, &rename, "move/rename a branch, even if target exists", 2),
- OPT_BOOLEAN(0, "list", &list, "list branch names"),
- OPT_BOOLEAN('l', "create-reflog", &reflog, "create the branch's reflog"),
+ OPT_BIT('d', "delete", &delete, N_("delete fully merged branch"), 1),
+ OPT_BIT('D', NULL, &delete, N_("delete branch (even if not merged)"), 2),
+ OPT_BIT('m', "move", &rename, N_("move/rename a branch and its reflog"), 1),
+ OPT_BIT('M', NULL, &rename, N_("move/rename a branch, even if target exists"), 2),
+ OPT_BOOLEAN(0, "list", &list, N_("list branch names")),
+ OPT_BOOLEAN('l', "create-reflog", &reflog, N_("create the branch's reflog")),
OPT_BOOLEAN(0, "edit-description", &edit_description,
- "edit the description for the branch"),
- OPT__FORCE(&force_create, "force creation (when already exists)"),
+ N_("edit the description for the branch")),
+ OPT__FORCE(&force_create, N_("force creation (when already exists)")),
{
OPTION_CALLBACK, 0, "no-merged", &merge_filter_ref,
- "commit", "print only not merged branches",
+ N_("commit"), N_("print only not merged branches"),
PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NONEG,
opt_parse_merge_filter, (intptr_t) "HEAD",
},
{
OPTION_CALLBACK, 0, "merged", &merge_filter_ref,
- "commit", "print only merged branches",
+ N_("commit"), N_("print only merged branches"),
PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NONEG,
opt_parse_merge_filter, (intptr_t) "HEAD",
},
- OPT_COLUMN(0, "column", &colopts, "list branches in columns"),
+ OPT_COLUMN(0, "column", &colopts, N_("list branches in columns")),
OPT_END(),
};
argc = parse_options(argc, argv, prefix, options, builtin_branch_usage,
0);
- if (!delete && !rename && !edit_description && argc == 0)
+ if (!delete && !rename && !edit_description && !new_upstream && !unset_upstream && argc == 0)
list = 1;
- if (!!delete + !!rename + !!force_create + !!list > 1)
+ if (!!delete + !!rename + !!force_create + !!list + !!new_upstream + !!unset_upstream > 1)
usage_with_options(builtin_branch_usage, options);
if (abbrev == -1)
rename_branch(argv[0], argv[1], rename > 1);
else
usage_with_options(builtin_branch_usage, options);
+ } else if (new_upstream) {
+ struct branch *branch = branch_get(argv[0]);
+
+ if (!ref_exists(branch->refname))
+ die(_("branch '%s' does not exist"), branch->name);
+
+ /*
+ * create_branch takes care of setting up the tracking
+ * info and making sure new_upstream is correct
+ */
+ create_branch(head, branch->name, new_upstream, 0, 0, 0, quiet, BRANCH_TRACK_OVERRIDE);
+ } else if (unset_upstream) {
+ struct branch *branch = branch_get(argv[0]);
+ struct strbuf buf = STRBUF_INIT;
+
+ if (!branch_has_merge_config(branch)) {
+ die(_("Branch '%s' has no upstream information"), branch->name);
+ }
+
+ strbuf_addf(&buf, "branch.%s.remote", branch->name);
+ git_config_set_multivar(buf.buf, NULL, NULL, 1);
+ strbuf_reset(&buf);
+ strbuf_addf(&buf, "branch.%s.merge", branch->name);
+ git_config_set_multivar(buf.buf, NULL, NULL, 1);
+ strbuf_release(&buf);
} else if (argc > 0 && argc <= 2) {
+ struct branch *branch = branch_get(argv[0]);
+ int branch_existed = 0, remote_tracking = 0;
+ struct strbuf buf = STRBUF_INIT;
+
if (kinds != REF_LOCAL_BRANCH)
die(_("-a and -r options to 'git branch' do not make sense with a branch name"));
+
+ if (track == BRANCH_TRACK_OVERRIDE)
+ fprintf(stderr, _("The --set-upstream flag is deprecated and will be removed. Consider using --track or --set-upstream-to\n"));
+
+ strbuf_addf(&buf, "refs/remotes/%s", branch->name);
+ remote_tracking = ref_exists(buf.buf);
+ strbuf_release(&buf);
+
+ branch_existed = ref_exists(branch->refname);
create_branch(head, argv[0], (argc == 2) ? argv[1] : head,
force_create, reflog, 0, quiet, track);
+
+ /*
+ * We only show the instructions if the user gave us
+ * one branch which doesn't exist locally, but is the
+ * name of a remote-tracking branch.
+ */
+ if (argc == 1 && track == BRANCH_TRACK_OVERRIDE &&
+ !branch_existed && remote_tracking) {
+ fprintf(stderr, _("\nIf you wanted to make '%s' track '%s', do this:\n\n"), head, branch->name);
+ fprintf(stderr, _(" git branch -d %s\n"), branch->name);
+ fprintf(stderr, _(" git branch --set-upstream-to %s\n"), branch->name);
+ }
+
} else
usage_with_options(builtin_branch_usage, options);
}
static const char * const cat_file_usage[] = {
- "git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>",
- "git cat-file (--batch|--batch-check) < <list_of_objects>",
+ N_("git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>"),
+ N_("git cat-file (--batch|--batch-check) < <list_of_objects>"),
NULL
};
const char *exp_type = NULL, *obj_name = NULL;
const struct option options[] = {
- OPT_GROUP("<type> can be one of: blob, tree, commit, tag"),
- OPT_SET_INT('t', NULL, &opt, "show object type", 't'),
- OPT_SET_INT('s', NULL, &opt, "show object size", 's'),
+ OPT_GROUP(N_("<type> can be one of: blob, tree, commit, tag")),
+ OPT_SET_INT('t', NULL, &opt, N_("show object type"), 't'),
+ OPT_SET_INT('s', NULL, &opt, N_("show object size"), 's'),
OPT_SET_INT('e', NULL, &opt,
- "exit with zero when there's no error", 'e'),
- OPT_SET_INT('p', NULL, &opt, "pretty-print object's content", 'p'),
+ N_("exit with zero when there's no error"), 'e'),
+ OPT_SET_INT('p', NULL, &opt, N_("pretty-print object's content"), 'p'),
OPT_SET_INT(0, "textconv", &opt,
- "for blob objects, run textconv on object's content", 'c'),
+ N_("for blob objects, run textconv on object's content"), 'c'),
OPT_SET_INT(0, "batch", &batch,
- "show info and content of objects fed from the standard input",
+ N_("show info and content of objects fed from the standard input"),
BATCH),
OPT_SET_INT(0, "batch-check", &batch,
- "show info about objects fed from the standard input",
+ N_("show info about objects fed from the standard input"),
BATCH_CHECK),
OPT_END()
};
static int cached_attrs;
static int stdin_paths;
static const char * const check_attr_usage[] = {
-"git check-attr [-a | --all | attr...] [--] pathname...",
-"git check-attr --stdin [-a | --all | attr...] < <list-of-paths>",
+N_("git check-attr [-a | --all | attr...] [--] pathname..."),
+N_("git check-attr --stdin [-a | --all | attr...] < <list-of-paths>"),
NULL
};
static int null_term_line;
static const struct option check_attr_options[] = {
- OPT_BOOLEAN('a', "all", &all_attrs, "report all attributes set on file"),
- OPT_BOOLEAN(0, "cached", &cached_attrs, "use .gitattributes only from the index"),
- OPT_BOOLEAN(0 , "stdin", &stdin_paths, "read file names from stdin"),
+ OPT_BOOLEAN('a', "all", &all_attrs, N_("report all attributes set on file")),
+ OPT_BOOLEAN(0, "cached", &cached_attrs, N_("use .gitattributes only from the index")),
+ OPT_BOOLEAN(0 , "stdin", &stdin_paths, N_("read file names from stdin")),
OPT_BOOLEAN('z', NULL, &null_term_line,
- "input paths are terminated by a null character"),
+ N_("input paths are terminated by a null character")),
OPT_END()
};
}
static const char * const builtin_checkout_index_usage[] = {
- "git checkout-index [options] [--] [<file>...]",
+ N_("git checkout-index [options] [--] [<file>...]"),
NULL
};
int force = 0, quiet = 0, not_new = 0;
struct option builtin_checkout_index_options[] = {
OPT_BOOLEAN('a', "all", &all,
- "checks out all files in the index"),
- OPT__FORCE(&force, "forces overwrite of existing files"),
+ N_("check out all files in the index")),
+ OPT__FORCE(&force, N_("force overwrite of existing files")),
OPT__QUIET(&quiet,
- "no warning for existing files and files not in index"),
+ N_("no warning for existing files and files not in index")),
OPT_BOOLEAN('n', "no-create", ¬_new,
- "don't checkout new files"),
+ N_("don't checkout new files")),
{ OPTION_CALLBACK, 'u', "index", &newfd, NULL,
- "update stat information in the index file",
+ N_("update stat information in the index file"),
PARSE_OPT_NOARG, option_parse_u },
{ OPTION_CALLBACK, 'z', NULL, NULL, NULL,
- "paths are separated with NUL character",
+ N_("paths are separated with NUL character"),
PARSE_OPT_NOARG, option_parse_z },
OPT_BOOLEAN(0, "stdin", &read_from_stdin,
- "read list of paths from the standard input"),
+ N_("read list of paths from the standard input")),
OPT_BOOLEAN(0, "temp", &to_tempfile,
- "write the content to temporary files"),
- OPT_CALLBACK(0, "prefix", NULL, "string",
- "when creating files, prepend <string>",
+ N_("write the content to temporary files")),
+ OPT_CALLBACK(0, "prefix", NULL, N_("string"),
+ N_("when creating files, prepend <string>"),
option_parse_prefix),
OPT_CALLBACK(0, "stage", NULL, NULL,
- "copy out the files from named stage",
+ N_("copy out the files from named stage"),
option_parse_stage),
OPT_END()
};
#include "argv-array.h"
static const char * const checkout_usage[] = {
- "git checkout [options] <branch>",
- "git checkout [options] [<branch>] -- <file>...",
+ N_("git checkout [options] <branch>"),
+ N_("git checkout [options] [<branch>] -- <file>..."),
NULL,
};
int patch_mode = 0;
int dwim_new_local_branch = 1;
struct option options[] = {
- OPT__QUIET(&opts.quiet, "suppress progress reporting"),
- OPT_STRING('b', NULL, &opts.new_branch, "branch",
- "create and checkout a new branch"),
- OPT_STRING('B', NULL, &opts.new_branch_force, "branch",
- "create/reset and checkout a branch"),
- OPT_BOOLEAN('l', NULL, &opts.new_branch_log, "create reflog for new branch"),
- OPT_BOOLEAN(0, "detach", &opts.force_detach, "detach the HEAD at named commit"),
- OPT_SET_INT('t', "track", &opts.track, "set upstream info for new branch",
+ OPT__QUIET(&opts.quiet, N_("suppress progress reporting")),
+ OPT_STRING('b', NULL, &opts.new_branch, N_("branch"),
+ N_("create and checkout a new branch")),
+ OPT_STRING('B', NULL, &opts.new_branch_force, N_("branch"),
+ N_("create/reset and checkout a branch")),
+ OPT_BOOLEAN('l', NULL, &opts.new_branch_log, N_("create reflog for new branch")),
+ OPT_BOOLEAN(0, "detach", &opts.force_detach, N_("detach the HEAD at named commit")),
+ OPT_SET_INT('t', "track", &opts.track, N_("set upstream info for new branch"),
BRANCH_TRACK_EXPLICIT),
- OPT_STRING(0, "orphan", &opts.new_orphan_branch, "new branch", "new unparented branch"),
- OPT_SET_INT('2', "ours", &opts.writeout_stage, "checkout our version for unmerged files",
+ OPT_STRING(0, "orphan", &opts.new_orphan_branch, N_("new branch"), N_("new unparented branch")),
+ OPT_SET_INT('2', "ours", &opts.writeout_stage, N_("checkout our version for unmerged files"),
2),
- OPT_SET_INT('3', "theirs", &opts.writeout_stage, "checkout their version for unmerged files",
+ OPT_SET_INT('3', "theirs", &opts.writeout_stage, N_("checkout their version for unmerged files"),
3),
- OPT__FORCE(&opts.force, "force checkout (throw away local modifications)"),
- OPT_BOOLEAN('m', "merge", &opts.merge, "perform a 3-way merge with the new branch"),
- OPT_BOOLEAN(0, "overwrite-ignore", &opts.overwrite_ignore, "update ignored files (default)"),
- OPT_STRING(0, "conflict", &conflict_style, "style",
- "conflict style (merge or diff3)"),
- OPT_BOOLEAN('p', "patch", &patch_mode, "select hunks interactively"),
+ OPT__FORCE(&opts.force, N_("force checkout (throw away local modifications)")),
+ OPT_BOOLEAN('m', "merge", &opts.merge, N_("perform a 3-way merge with the new branch")),
+ OPT_BOOLEAN(0, "overwrite-ignore", &opts.overwrite_ignore, N_("update ignored files (default)")),
+ OPT_STRING(0, "conflict", &conflict_style, N_("style"),
+ N_("conflict style (merge or diff3)")),
+ OPT_BOOLEAN('p', "patch", &patch_mode, N_("select hunks interactively")),
{ OPTION_BOOLEAN, 0, "guess", &dwim_new_local_branch, NULL,
- "second guess 'git checkout no-such-branch'",
+ N_("second guess 'git checkout no-such-branch'"),
PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
OPT_END(),
};
static int force = -1; /* unset */
static const char *const builtin_clean_usage[] = {
- "git clean [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>...",
+ N_("git clean [-d] [-f] [-n] [-q] [-e <pattern>] [-x | -X] [--] <paths>..."),
NULL
};
const char *qname;
char *seen = NULL;
struct option options[] = {
- OPT__QUIET(&quiet, "do not print names of files removed"),
- OPT__DRY_RUN(&show_only, "dry run"),
- OPT__FORCE(&force, "force"),
+ OPT__QUIET(&quiet, N_("do not print names of files removed")),
+ OPT__DRY_RUN(&show_only, N_("dry run")),
+ OPT__FORCE(&force, N_("force")),
OPT_BOOLEAN('d', NULL, &remove_directories,
- "remove whole directories"),
- { OPTION_CALLBACK, 'e', "exclude", &exclude_list, "pattern",
- "add <pattern> to ignore rules", PARSE_OPT_NONEG, exclude_cb },
- OPT_BOOLEAN('x', NULL, &ignored, "remove ignored files, too"),
+ N_("remove whole directories")),
+ { OPTION_CALLBACK, 'e', "exclude", &exclude_list, N_("pattern"),
+ N_("add <pattern> to ignore rules"), PARSE_OPT_NONEG, exclude_cb },
+ OPT_BOOLEAN('x', NULL, &ignored, N_("remove ignored files, too")),
OPT_BOOLEAN('X', NULL, &ignored_only,
- "remove only ignored files"),
+ N_("remove only ignored files")),
OPT_END()
};
*
*/
static const char * const builtin_clone_usage[] = {
- "git clone [options] [--] <repo> [<dir>]",
+ N_("git clone [options] [--] <repo> [<dir>]"),
NULL
};
static struct option builtin_clone_options[] = {
OPT__VERBOSITY(&option_verbosity),
OPT_BOOL(0, "progress", &option_progress,
- "force progress reporting"),
+ N_("force progress reporting")),
OPT_BOOLEAN('n', "no-checkout", &option_no_checkout,
- "don't create a checkout"),
- OPT_BOOLEAN(0, "bare", &option_bare, "create a bare repository"),
+ N_("don't create a checkout")),
+ OPT_BOOLEAN(0, "bare", &option_bare, N_("create a bare repository")),
{ OPTION_BOOLEAN, 0, "naked", &option_bare, NULL,
- "create a bare repository",
+ N_("create a bare repository"),
PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
OPT_BOOLEAN(0, "mirror", &option_mirror,
- "create a mirror repository (implies bare)"),
+ N_("create a mirror repository (implies bare)")),
OPT_BOOL('l', "local", &option_local,
- "to clone from a local repository"),
+ N_("to clone from a local repository")),
OPT_BOOLEAN(0, "no-hardlinks", &option_no_hardlinks,
- "don't use local hardlinks, always copy"),
+ N_("don't use local hardlinks, always copy")),
OPT_BOOLEAN('s', "shared", &option_shared,
- "setup as shared repository"),
+ N_("setup as shared repository")),
OPT_BOOLEAN(0, "recursive", &option_recursive,
- "initialize submodules in the clone"),
+ N_("initialize submodules in the clone")),
OPT_BOOLEAN(0, "recurse-submodules", &option_recursive,
- "initialize submodules in the clone"),
- OPT_STRING(0, "template", &option_template, "template-directory",
- "directory from which templates will be used"),
- OPT_CALLBACK(0 , "reference", &option_reference, "repo",
- "reference repository", &opt_parse_reference),
- OPT_STRING('o', "origin", &option_origin, "name",
- "use <name> instead of 'origin' to track upstream"),
- OPT_STRING('b', "branch", &option_branch, "branch",
- "checkout <branch> instead of the remote's HEAD"),
- OPT_STRING('u', "upload-pack", &option_upload_pack, "path",
- "path to git-upload-pack on the remote"),
- OPT_STRING(0, "depth", &option_depth, "depth",
- "create a shallow clone of that depth"),
+ N_("initialize submodules in the clone")),
+ OPT_STRING(0, "template", &option_template, N_("template-directory"),
+ N_("directory from which templates will be used")),
+ OPT_CALLBACK(0 , "reference", &option_reference, N_("repo"),
+ N_("reference repository"), &opt_parse_reference),
+ OPT_STRING('o', "origin", &option_origin, N_("name"),
+ N_("use <name> instead of 'origin' to track upstream")),
+ OPT_STRING('b', "branch", &option_branch, N_("branch"),
+ N_("checkout <branch> instead of the remote's HEAD")),
+ OPT_STRING('u', "upload-pack", &option_upload_pack, N_("path"),
+ N_("path to git-upload-pack on the remote")),
+ OPT_STRING(0, "depth", &option_depth, N_("depth"),
+ N_("create a shallow clone of that depth")),
OPT_BOOL(0, "single-branch", &option_single_branch,
- "clone only one branch, HEAD or --branch"),
- OPT_STRING(0, "separate-git-dir", &real_git_dir, "gitdir",
- "separate git dir from working tree"),
- OPT_STRING_LIST('c', "config", &option_config, "key=value",
- "set config inside the new repository"),
+ N_("clone only one branch, HEAD or --branch")),
+ OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"),
+ N_("separate git dir from working tree")),
+ OPT_STRING_LIST('c', "config", &option_config, N_("key=value"),
+ N_("set config inside the new repository")),
OPT_END()
};
#include "column.h"
static const char * const builtin_column_usage[] = {
- "git column [options]",
+ N_("git column [options]"),
NULL
};
static unsigned int colopts;
struct column_options copts;
const char *command = NULL, *real_command = NULL;
struct option options[] = {
- OPT_STRING(0, "command", &real_command, "name", "lookup config vars"),
- OPT_COLUMN(0, "mode", &colopts, "layout to use"),
- OPT_INTEGER(0, "raw-mode", &colopts, "layout to use"),
- OPT_INTEGER(0, "width", &copts.width, "Maximum width"),
- OPT_STRING(0, "indent", &copts.indent, "string", "Padding space on left border"),
- OPT_INTEGER(0, "nl", &copts.nl, "Padding space on right border"),
- OPT_INTEGER(0, "padding", &copts.padding, "Padding space between columns"),
+ OPT_STRING(0, "command", &real_command, N_("name"), N_("lookup config vars")),
+ OPT_COLUMN(0, "mode", &colopts, N_("layout to use")),
+ OPT_INTEGER(0, "raw-mode", &colopts, N_("layout to use")),
+ OPT_INTEGER(0, "width", &copts.width, N_("Maximum width")),
+ OPT_STRING(0, "indent", &copts.indent, N_("string"), N_("Padding space on left border")),
+ OPT_INTEGER(0, "nl", &copts.nl, N_("Padding space on right border")),
+ OPT_INTEGER(0, "padding", &copts.padding, N_("Padding space between columns")),
OPT_END()
};
#include "column.h"
static const char * const builtin_commit_usage[] = {
- "git commit [options] [--] <filepattern>...",
+ N_("git commit [options] [--] <filepattern>..."),
NULL
};
static const char * const builtin_status_usage[] = {
- "git status [options] [--] <filepattern>...",
+ N_("git status [options] [--] <filepattern>..."),
NULL
};
int fd;
unsigned char sha1[20];
static struct option builtin_status_options[] = {
- OPT__VERBOSE(&verbose, "be verbose"),
+ OPT__VERBOSE(&verbose, N_("be verbose")),
OPT_SET_INT('s', "short", &status_format,
- "show status concisely", STATUS_FORMAT_SHORT),
+ N_("show status concisely"), STATUS_FORMAT_SHORT),
OPT_BOOLEAN('b', "branch", &s.show_branch,
- "show branch information"),
+ N_("show branch information")),
OPT_SET_INT(0, "porcelain", &status_format,
- "machine-readable output",
+ N_("machine-readable output"),
STATUS_FORMAT_PORCELAIN),
OPT_BOOLEAN('z', "null", &s.null_termination,
- "terminate entries with NUL"),
+ N_("terminate entries with NUL")),
{ OPTION_STRING, 'u', "untracked-files", &untracked_files_arg,
- "mode",
- "show untracked files, optional modes: all, normal, no. (Default: all)",
+ N_("mode"),
+ N_("show untracked files, optional modes: all, normal, no. (Default: all)"),
PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
OPT_BOOLEAN(0, "ignored", &show_ignored_in_status,
- "show ignored files"),
- { OPTION_STRING, 0, "ignore-submodules", &ignore_submodule_arg, "when",
- "ignore changes to submodules, optional when: all, dirty, untracked. (Default: all)",
+ N_("show ignored files")),
+ { OPTION_STRING, 0, "ignore-submodules", &ignore_submodule_arg, N_("when"),
+ N_("ignore changes to submodules, optional when: all, dirty, untracked. (Default: all)"),
PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
- OPT_COLUMN(0, "column", &s.colopts, "list untracked files in columns"),
+ OPT_COLUMN(0, "column", &s.colopts, N_("list untracked files in columns")),
OPT_END(),
};
{
static struct wt_status s;
static struct option builtin_commit_options[] = {
- OPT__QUIET(&quiet, "suppress summary after successful commit"),
- OPT__VERBOSE(&verbose, "show diff in commit message template"),
-
- OPT_GROUP("Commit message options"),
- OPT_FILENAME('F', "file", &logfile, "read message from file"),
- OPT_STRING(0, "author", &force_author, "author", "override author for commit"),
- OPT_STRING(0, "date", &force_date, "date", "override date for commit"),
- OPT_CALLBACK('m', "message", &message, "message", "commit message", opt_parse_m),
- OPT_STRING('c', "reedit-message", &edit_message, "commit", "reuse and edit message from specified commit"),
- OPT_STRING('C', "reuse-message", &use_message, "commit", "reuse message from specified commit"),
- OPT_STRING(0, "fixup", &fixup_message, "commit", "use autosquash formatted message to fixup specified commit"),
- OPT_STRING(0, "squash", &squash_message, "commit", "use autosquash formatted message to squash specified commit"),
- OPT_BOOLEAN(0, "reset-author", &renew_authorship, "the commit is authored by me now (used with -C/-c/--amend)"),
- OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by:"),
- OPT_FILENAME('t', "template", &template_file, "use specified template file"),
- OPT_BOOL('e', "edit", &edit_flag, "force edit of commit"),
- OPT_STRING(0, "cleanup", &cleanup_arg, "default", "how to strip spaces and #comments from message"),
- OPT_BOOLEAN(0, "status", &include_status, "include status in commit message template"),
- { OPTION_STRING, 'S', "gpg-sign", &sign_commit, "key id",
- "GPG sign commit", PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
+ OPT__QUIET(&quiet, N_("suppress summary after successful commit")),
+ OPT__VERBOSE(&verbose, N_("show diff in commit message template")),
+
+ OPT_GROUP(N_("Commit message options")),
+ OPT_FILENAME('F', "file", &logfile, N_("read message from file")),
+ OPT_STRING(0, "author", &force_author, N_("author"), N_("override author for commit")),
+ OPT_STRING(0, "date", &force_date, N_("date"), N_("override date for commit")),
+ OPT_CALLBACK('m', "message", &message, N_("message"), N_("commit message"), opt_parse_m),
+ OPT_STRING('c', "reedit-message", &edit_message, N_("commit"), N_("reuse and edit message from specified commit")),
+ OPT_STRING('C', "reuse-message", &use_message, N_("commit"), N_("reuse message from specified commit")),
+ OPT_STRING(0, "fixup", &fixup_message, N_("commit"), N_("use autosquash formatted message to fixup specified commit")),
+ OPT_STRING(0, "squash", &squash_message, N_("commit"), N_("use autosquash formatted message to squash specified commit")),
+ OPT_BOOLEAN(0, "reset-author", &renew_authorship, N_("the commit is authored by me now (used with -C/-c/--amend)")),
+ OPT_BOOLEAN('s', "signoff", &signoff, N_("add Signed-off-by:")),
+ OPT_FILENAME('t', "template", &template_file, N_("use specified template file")),
+ OPT_BOOL('e', "edit", &edit_flag, N_("force edit of commit")),
+ OPT_STRING(0, "cleanup", &cleanup_arg, N_("default"), N_("how to strip spaces and #comments from message")),
+ OPT_BOOLEAN(0, "status", &include_status, N_("include status in commit message template")),
+ { OPTION_STRING, 'S', "gpg-sign", &sign_commit, N_("key id"),
+ N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
/* end commit message options */
- OPT_GROUP("Commit contents options"),
- OPT_BOOLEAN('a', "all", &all, "commit all changed files"),
- OPT_BOOLEAN('i', "include", &also, "add specified files to index for commit"),
- OPT_BOOLEAN(0, "interactive", &interactive, "interactively add files"),
- OPT_BOOLEAN('p', "patch", &patch_interactive, "interactively add changes"),
- OPT_BOOLEAN('o', "only", &only, "commit only specified files"),
- OPT_BOOLEAN('n', "no-verify", &no_verify, "bypass pre-commit hook"),
- OPT_BOOLEAN(0, "dry-run", &dry_run, "show what would be committed"),
- OPT_SET_INT(0, "short", &status_format, "show status concisely",
+ OPT_GROUP(N_("Commit contents options")),
+ OPT_BOOLEAN('a', "all", &all, N_("commit all changed files")),
+ OPT_BOOLEAN('i', "include", &also, N_("add specified files to index for commit")),
+ OPT_BOOLEAN(0, "interactive", &interactive, N_("interactively add files")),
+ OPT_BOOLEAN('p', "patch", &patch_interactive, N_("interactively add changes")),
+ OPT_BOOLEAN('o', "only", &only, N_("commit only specified files")),
+ OPT_BOOLEAN('n', "no-verify", &no_verify, N_("bypass pre-commit hook")),
+ OPT_BOOLEAN(0, "dry-run", &dry_run, N_("show what would be committed")),
+ OPT_SET_INT(0, "short", &status_format, N_("show status concisely"),
STATUS_FORMAT_SHORT),
- OPT_BOOLEAN(0, "branch", &s.show_branch, "show branch information"),
+ OPT_BOOLEAN(0, "branch", &s.show_branch, N_("show branch information")),
OPT_SET_INT(0, "porcelain", &status_format,
- "machine-readable output", STATUS_FORMAT_PORCELAIN),
+ N_("machine-readable output"), STATUS_FORMAT_PORCELAIN),
OPT_BOOLEAN('z', "null", &s.null_termination,
- "terminate entries with NUL"),
- OPT_BOOLEAN(0, "amend", &amend, "amend previous commit"),
- OPT_BOOLEAN(0, "no-post-rewrite", &no_post_rewrite, "bypass post-rewrite hook"),
- { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, "mode", "show untracked files, optional modes: all, normal, no. (Default: all)", PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
+ N_("terminate entries with NUL")),
+ OPT_BOOLEAN(0, "amend", &amend, N_("amend previous commit")),
+ OPT_BOOLEAN(0, "no-post-rewrite", &no_post_rewrite, N_("bypass post-rewrite hook")),
+ { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, N_("mode"), N_("show untracked files, optional modes: all, normal, no. (Default: all)"), PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
/* end commit contents options */
{ OPTION_BOOLEAN, 0, "allow-empty", &allow_empty, NULL,
- "ok to record an empty change",
+ N_("ok to record an empty change"),
PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
{ OPTION_BOOLEAN, 0, "allow-empty-message", &allow_empty_message, NULL,
- "ok to record a change with an empty message",
+ N_("ok to record a change with an empty message"),
PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
OPT_END()
#include "parse-options.h"
static const char *const builtin_config_usage[] = {
- "git config [options]",
+ N_("git config [options]"),
NULL
};
#define TYPE_PATH (1<<3)
static struct option builtin_config_options[] = {
- OPT_GROUP("Config file location"),
- OPT_BOOLEAN(0, "global", &use_global_config, "use global config file"),
- OPT_BOOLEAN(0, "system", &use_system_config, "use system config file"),
- OPT_BOOLEAN(0, "local", &use_local_config, "use repository config file"),
- OPT_STRING('f', "file", &given_config_file, "file", "use given config file"),
- OPT_GROUP("Action"),
- OPT_BIT(0, "get", &actions, "get value: name [value-regex]", ACTION_GET),
- OPT_BIT(0, "get-all", &actions, "get all values: key [value-regex]", ACTION_GET_ALL),
- OPT_BIT(0, "get-regexp", &actions, "get values for regexp: name-regex [value-regex]", ACTION_GET_REGEXP),
- OPT_BIT(0, "replace-all", &actions, "replace all matching variables: name value [value_regex]", ACTION_REPLACE_ALL),
- OPT_BIT(0, "add", &actions, "adds a new variable: name value", ACTION_ADD),
- OPT_BIT(0, "unset", &actions, "removes a variable: name [value-regex]", ACTION_UNSET),
- OPT_BIT(0, "unset-all", &actions, "removes all matches: name [value-regex]", ACTION_UNSET_ALL),
- OPT_BIT(0, "rename-section", &actions, "rename section: old-name new-name", ACTION_RENAME_SECTION),
- OPT_BIT(0, "remove-section", &actions, "remove a section: name", ACTION_REMOVE_SECTION),
- OPT_BIT('l', "list", &actions, "list all", ACTION_LIST),
- OPT_BIT('e', "edit", &actions, "opens an editor", ACTION_EDIT),
- OPT_STRING(0, "get-color", &get_color_slot, "slot", "find the color configured: [default]"),
- OPT_STRING(0, "get-colorbool", &get_colorbool_slot, "slot", "find the color setting: [stdout-is-tty]"),
- OPT_GROUP("Type"),
- OPT_BIT(0, "bool", &types, "value is \"true\" or \"false\"", TYPE_BOOL),
- OPT_BIT(0, "int", &types, "value is decimal number", TYPE_INT),
- OPT_BIT(0, "bool-or-int", &types, "value is --bool or --int", TYPE_BOOL_OR_INT),
- OPT_BIT(0, "path", &types, "value is a path (file or directory name)", TYPE_PATH),
- OPT_GROUP("Other"),
- OPT_BOOLEAN('z', "null", &end_null, "terminate values with NUL byte"),
- OPT_BOOL(0, "includes", &respect_includes, "respect include directives on lookup"),
+ OPT_GROUP(N_("Config file location")),
+ OPT_BOOLEAN(0, "global", &use_global_config, N_("use global config file")),
+ OPT_BOOLEAN(0, "system", &use_system_config, N_("use system config file")),
+ OPT_BOOLEAN(0, "local", &use_local_config, N_("use repository config file")),
+ OPT_STRING('f', "file", &given_config_file, N_("file"), N_("use given config file")),
+ OPT_GROUP(N_("Action")),
+ OPT_BIT(0, "get", &actions, N_("get value: name [value-regex]"), ACTION_GET),
+ OPT_BIT(0, "get-all", &actions, N_("get all values: key [value-regex]"), ACTION_GET_ALL),
+ OPT_BIT(0, "get-regexp", &actions, N_("get values for regexp: name-regex [value-regex]"), ACTION_GET_REGEXP),
+ OPT_BIT(0, "replace-all", &actions, N_("replace all matching variables: name value [value_regex]"), ACTION_REPLACE_ALL),
+ OPT_BIT(0, "add", &actions, N_("add a new variable: name value"), ACTION_ADD),
+ OPT_BIT(0, "unset", &actions, N_("remove a variable: name [value-regex]"), ACTION_UNSET),
+ OPT_BIT(0, "unset-all", &actions, N_("remove all matches: name [value-regex]"), ACTION_UNSET_ALL),
+ OPT_BIT(0, "rename-section", &actions, N_("rename section: old-name new-name"), ACTION_RENAME_SECTION),
+ OPT_BIT(0, "remove-section", &actions, N_("remove a section: name"), ACTION_REMOVE_SECTION),
+ OPT_BIT('l', "list", &actions, N_("list all"), ACTION_LIST),
+ OPT_BIT('e', "edit", &actions, N_("open an editor"), ACTION_EDIT),
+ OPT_STRING(0, "get-color", &get_color_slot, N_("slot"), N_("find the color configured: [default]")),
+ OPT_STRING(0, "get-colorbool", &get_colorbool_slot, N_("slot"), N_("find the color setting: [stdout-is-tty]")),
+ OPT_GROUP(N_("Type")),
+ OPT_BIT(0, "bool", &types, N_("value is \"true\" or \"false\""), TYPE_BOOL),
+ OPT_BIT(0, "int", &types, N_("value is decimal number"), TYPE_INT),
+ OPT_BIT(0, "bool-or-int", &types, N_("value is --bool or --int"), TYPE_BOOL_OR_INT),
+ OPT_BIT(0, "path", &types, N_("value is a path (file or directory name)"), TYPE_PATH),
+ OPT_GROUP(N_("Other")),
+ OPT_BOOLEAN('z', "null", &end_null, N_("terminate values with NUL byte")),
+ OPT_BOOL(0, "includes", &respect_includes, N_("respect include directives on lookup")),
OPT_END(),
};
*/
die("$HOME not set");
- if (access(user_config, R_OK) &&
- xdg_config && !access(xdg_config, R_OK))
+ if (access_or_warn(user_config, R_OK) &&
+ xdg_config && !access_or_warn(xdg_config, R_OK))
given_config_file = xdg_config;
else
given_config_file = user_config;
}
static char const * const count_objects_usage[] = {
- "git count-objects [-v]",
+ N_("git count-objects [-v]"),
NULL
};
unsigned long loose = 0, packed = 0, packed_loose = 0, garbage = 0;
off_t loose_size = 0;
struct option opts[] = {
- OPT__VERBOSE(&verbose, "be verbose"),
+ OPT__VERBOSE(&verbose, N_("be verbose")),
OPT_END(),
};
#define MAX_TAGS (FLAG_BITS - 1)
static const char * const describe_usage[] = {
- "git describe [options] <committish>*",
- "git describe [options] --dirty",
+ N_("git describe [options] <committish>*"),
+ N_("git describe [options] --dirty"),
NULL
};
{
int contains = 0;
struct option options[] = {
- OPT_BOOLEAN(0, "contains", &contains, "find the tag that comes after the commit"),
- OPT_BOOLEAN(0, "debug", &debug, "debug search strategy on stderr"),
- OPT_BOOLEAN(0, "all", &all, "use any ref in .git/refs"),
- OPT_BOOLEAN(0, "tags", &tags, "use any tag in .git/refs/tags"),
- OPT_BOOLEAN(0, "long", &longformat, "always use long format"),
+ OPT_BOOLEAN(0, "contains", &contains, N_("find the tag that comes after the commit")),
+ OPT_BOOLEAN(0, "debug", &debug, N_("debug search strategy on stderr")),
+ OPT_BOOLEAN(0, "all", &all, N_("use any ref in .git/refs")),
+ OPT_BOOLEAN(0, "tags", &tags, N_("use any tag in .git/refs/tags")),
+ OPT_BOOLEAN(0, "long", &longformat, N_("always use long format")),
OPT__ABBREV(&abbrev),
OPT_SET_INT(0, "exact-match", &max_candidates,
- "only output exact matches", 0),
+ N_("only output exact matches"), 0),
OPT_INTEGER(0, "candidates", &max_candidates,
- "consider <n> most recent tags (default: 10)"),
- OPT_STRING(0, "match", &pattern, "pattern",
- "only consider tags matching <pattern>"),
+ N_("consider <n> most recent tags (default: 10)")),
+ OPT_STRING(0, "match", &pattern, N_("pattern"),
+ N_("only consider tags matching <pattern>")),
OPT_BOOLEAN(0, "always", &always,
- "show abbreviated commit object as fallback"),
- {OPTION_STRING, 0, "dirty", &dirty, "mark",
- "append <mark> on dirty working tree (default: \"-dirty\")",
+ N_("show abbreviated commit object as fallback")),
+ {OPTION_STRING, 0, "dirty", &dirty, N_("mark"),
+ N_("append <mark> on dirty working tree (default: \"-dirty\")"),
PARSE_OPT_OPTARG, NULL, (intptr_t) "-dirty"},
OPT_END(),
};
#include "quote.h"
static const char *fast_export_usage[] = {
- "git fast-export [rev-list-opts]",
+ N_("git fast-export [rev-list-opts]"),
NULL
};
char *export_filename = NULL, *import_filename = NULL;
struct option options[] = {
OPT_INTEGER(0, "progress", &progress,
- "show progress after <n> objects"),
- OPT_CALLBACK(0, "signed-tags", &signed_tag_mode, "mode",
- "select handling of signed tags",
+ N_("show progress after <n> objects")),
+ OPT_CALLBACK(0, "signed-tags", &signed_tag_mode, N_("mode"),
+ N_("select handling of signed tags"),
parse_opt_signed_tag_mode),
- OPT_CALLBACK(0, "tag-of-filtered-object", &tag_of_filtered_mode, "mode",
- "select handling of tags that tag filtered objects",
+ OPT_CALLBACK(0, "tag-of-filtered-object", &tag_of_filtered_mode, N_("mode"),
+ N_("select handling of tags that tag filtered objects"),
parse_opt_tag_of_filtered_mode),
- OPT_STRING(0, "export-marks", &export_filename, "file",
- "Dump marks to this file"),
- OPT_STRING(0, "import-marks", &import_filename, "file",
- "Import marks from this file"),
+ OPT_STRING(0, "export-marks", &export_filename, N_("file"),
+ N_("Dump marks to this file")),
+ OPT_STRING(0, "import-marks", &import_filename, N_("file"),
+ N_("Import marks from this file")),
OPT_BOOLEAN(0, "fake-missing-tagger", &fake_missing_tagger,
- "Fake a tagger when tags lack one"),
+ N_("Fake a tagger when tags lack one")),
OPT_BOOLEAN(0, "full-tree", &full_tree,
- "Output full tree for each commit"),
+ N_("Output full tree for each commit")),
OPT_BOOLEAN(0, "use-done-feature", &use_done_feature,
- "Use the done feature to terminate the stream"),
- OPT_BOOL(0, "no-data", &no_data, "Skip output of blob data"),
+ N_("Use the done feature to terminate the stream")),
+ OPT_BOOL(0, "no-data", &no_data, N_("Skip output of blob data")),
OPT_END()
};
#include "connected.h"
static const char * const builtin_fetch_usage[] = {
- "git fetch [<options>] [<repository> [<refspec>...]]",
- "git fetch [<options>] <group>",
- "git fetch --multiple [<options>] [(<repository> | <group>)...]",
- "git fetch --all [<options>]",
+ N_("git fetch [<options>] [<repository> [<refspec>...]]"),
+ N_("git fetch [<options>] <group>"),
+ N_("git fetch --multiple [<options>] [(<repository> | <group>)...]"),
+ N_("git fetch --all [<options>]"),
NULL
};
static struct option builtin_fetch_options[] = {
OPT__VERBOSITY(&verbosity),
OPT_BOOLEAN(0, "all", &all,
- "fetch from all remotes"),
+ N_("fetch from all remotes")),
OPT_BOOLEAN('a', "append", &append,
- "append to .git/FETCH_HEAD instead of overwriting"),
- OPT_STRING(0, "upload-pack", &upload_pack, "path",
- "path to upload pack on remote end"),
- OPT__FORCE(&force, "force overwrite of local branch"),
+ N_("append to .git/FETCH_HEAD instead of overwriting")),
+ OPT_STRING(0, "upload-pack", &upload_pack, N_("path"),
+ N_("path to upload pack on remote end")),
+ OPT__FORCE(&force, N_("force overwrite of local branch")),
OPT_BOOLEAN('m', "multiple", &multiple,
- "fetch from multiple remotes"),
+ N_("fetch from multiple remotes")),
OPT_SET_INT('t', "tags", &tags,
- "fetch all tags and associated objects", TAGS_SET),
+ N_("fetch all tags and associated objects"), TAGS_SET),
OPT_SET_INT('n', NULL, &tags,
- "do not fetch all tags (--no-tags)", TAGS_UNSET),
+ N_("do not fetch all tags (--no-tags)"), TAGS_UNSET),
OPT_BOOLEAN('p', "prune", &prune,
- "prune remote-tracking branches no longer on remote"),
- { OPTION_CALLBACK, 0, "recurse-submodules", NULL, "on-demand",
- "control recursive fetching of submodules",
+ N_("prune remote-tracking branches no longer on remote")),
+ { OPTION_CALLBACK, 0, "recurse-submodules", NULL, N_("on-demand"),
+ N_("control recursive fetching of submodules"),
PARSE_OPT_OPTARG, option_parse_recurse_submodules },
OPT_BOOLEAN(0, "dry-run", &dry_run,
- "dry run"),
- OPT_BOOLEAN('k', "keep", &keep, "keep downloaded pack"),
+ N_("dry run")),
+ OPT_BOOLEAN('k', "keep", &keep, N_("keep downloaded pack")),
OPT_BOOLEAN('u', "update-head-ok", &update_head_ok,
- "allow updating of HEAD ref"),
- OPT_BOOL(0, "progress", &progress, "force progress reporting"),
- OPT_STRING(0, "depth", &depth, "depth",
- "deepen history of shallow clone"),
- { OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, "dir",
- "prepend this to submodule path output", PARSE_OPT_HIDDEN },
+ N_("allow updating of HEAD ref")),
+ OPT_BOOL(0, "progress", &progress, N_("force progress reporting")),
+ OPT_STRING(0, "depth", &depth, N_("depth"),
+ N_("deepen history of shallow clone")),
+ { OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, N_("dir"),
+ N_("prepend this to submodule path output"), PARSE_OPT_HIDDEN },
{ OPTION_STRING, 0, "recurse-submodules-default",
&recurse_submodules_default, NULL,
- "default mode for recursion", PARSE_OPT_HIDDEN },
+ N_("default mode for recursion"), PARSE_OPT_HIDDEN },
OPT_END()
};
#include "gpg-interface.h"
static const char * const fmt_merge_msg_usage[] = {
- "git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]",
+ N_("git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]"),
NULL
};
const char *message = NULL;
int shortlog_len = -1;
struct option options[] = {
- { OPTION_INTEGER, 0, "log", &shortlog_len, "n",
- "populate log with at most <n> entries from shortlog",
+ { OPTION_INTEGER, 0, "log", &shortlog_len, N_("n"),
+ N_("populate log with at most <n> entries from shortlog"),
PARSE_OPT_OPTARG, NULL, DEFAULT_MERGE_LOG_LEN },
- { OPTION_INTEGER, 0, "summary", &shortlog_len, "n",
- "alias for --log (deprecated)",
+ { OPTION_INTEGER, 0, "summary", &shortlog_len, N_("n"),
+ N_("alias for --log (deprecated)"),
PARSE_OPT_OPTARG | PARSE_OPT_HIDDEN, NULL,
DEFAULT_MERGE_LOG_LEN },
- OPT_STRING('m', "message", &message, "text",
- "use <text> as start of message"),
- OPT_FILENAME('F', "file", &inpath, "file to read from"),
+ OPT_STRING('m', "message", &message, N_("text"),
+ N_("use <text> as start of message")),
+ OPT_FILENAME('F', "file", &inpath, N_("file to read from")),
OPT_END()
};
if (!arg) /* should --no-sort void the list ? */
return -1;
- *sort_tail = s = xcalloc(1, sizeof(*s));
+ s = xcalloc(1, sizeof(*s));
+ s->next = *sort_tail;
+ *sort_tail = s;
if (*arg == '-') {
s->reverse = 1;
}
static char const * const for_each_ref_usage[] = {
- "git for-each-ref [options] [<pattern>]",
+ N_("git for-each-ref [options] [<pattern>]"),
NULL
};
struct option opts[] = {
OPT_BIT('s', "shell", "e_style,
- "quote placeholders suitably for shells", QUOTE_SHELL),
+ N_("quote placeholders suitably for shells"), QUOTE_SHELL),
OPT_BIT('p', "perl", "e_style,
- "quote placeholders suitably for perl", QUOTE_PERL),
+ N_("quote placeholders suitably for perl"), QUOTE_PERL),
OPT_BIT(0 , "python", "e_style,
- "quote placeholders suitably for python", QUOTE_PYTHON),
+ N_("quote placeholders suitably for python"), QUOTE_PYTHON),
OPT_BIT(0 , "tcl", "e_style,
- "quote placeholders suitably for tcl", QUOTE_TCL),
+ N_("quote placeholders suitably for tcl"), QUOTE_TCL),
OPT_GROUP(""),
- OPT_INTEGER( 0 , "count", &maxcount, "show only <n> matched refs"),
- OPT_STRING( 0 , "format", &format, "format", "format to use for the output"),
- OPT_CALLBACK(0 , "sort", sort_tail, "key",
- "field name to sort on", &opt_parse_sort),
+ OPT_INTEGER( 0 , "count", &maxcount, N_("show only <n> matched refs")),
+ OPT_STRING( 0 , "format", &format, N_("format"), N_("format to use for the output")),
+ OPT_CALLBACK(0 , "sort", sort_tail, N_("key"),
+ N_("field name to sort on"), &opt_parse_sort),
OPT_END(),
};
}
static char const * const fsck_usage[] = {
- "git fsck [options] [<object>...]",
+ N_("git fsck [options] [<object>...]"),
NULL
};
static struct option fsck_opts[] = {
- OPT__VERBOSE(&verbose, "be verbose"),
- OPT_BOOLEAN(0, "unreachable", &show_unreachable, "show unreachable objects"),
- OPT_BOOL(0, "dangling", &show_dangling, "show dangling objects"),
- OPT_BOOLEAN(0, "tags", &show_tags, "report tags"),
- OPT_BOOLEAN(0, "root", &show_root, "report root nodes"),
- OPT_BOOLEAN(0, "cache", &keep_cache_objects, "make index objects head nodes"),
- OPT_BOOLEAN(0, "reflogs", &include_reflogs, "make reflogs head nodes (default)"),
- OPT_BOOLEAN(0, "full", &check_full, "also consider packs and alternate objects"),
- OPT_BOOLEAN(0, "strict", &check_strict, "enable more strict checking"),
+ OPT__VERBOSE(&verbose, N_("be verbose")),
+ OPT_BOOLEAN(0, "unreachable", &show_unreachable, N_("show unreachable objects")),
+ OPT_BOOL(0, "dangling", &show_dangling, N_("show dangling objects")),
+ OPT_BOOLEAN(0, "tags", &show_tags, N_("report tags")),
+ OPT_BOOLEAN(0, "root", &show_root, N_("report root nodes")),
+ OPT_BOOLEAN(0, "cache", &keep_cache_objects, N_("make index objects head nodes")),
+ OPT_BOOLEAN(0, "reflogs", &include_reflogs, N_("make reflogs head nodes (default)")),
+ OPT_BOOLEAN(0, "full", &check_full, N_("also consider packs and alternate objects")),
+ OPT_BOOLEAN(0, "strict", &check_strict, N_("enable more strict checking")),
OPT_BOOLEAN(0, "lost-found", &write_lost_and_found,
- "write dangling objects in .git/lost-found"),
- OPT_BOOL(0, "progress", &show_progress, "show progress"),
+ N_("write dangling objects in .git/lost-found")),
+ OPT_BOOL(0, "progress", &show_progress, N_("show progress")),
OPT_END(),
};
#define FAILED_RUN "failed to run %s"
static const char * const builtin_gc_usage[] = {
- "git gc [options]",
+ N_("git gc [options]"),
NULL
};
int quiet = 0;
struct option builtin_gc_options[] = {
- OPT__QUIET(&quiet, "suppress progress reporting"),
- { OPTION_STRING, 0, "prune", &prune_expire, "date",
- "prune unreferenced objects",
+ OPT__QUIET(&quiet, N_("suppress progress reporting")),
+ { OPTION_STRING, 0, "prune", &prune_expire, N_("date"),
+ N_("prune unreferenced objects"),
PARSE_OPT_OPTARG, NULL, (intptr_t)prune_expire },
- OPT_BOOLEAN(0, "aggressive", &aggressive, "be more thorough (increased runtime)"),
- OPT_BOOLEAN(0, "auto", &auto_gc, "enable auto-gc mode"),
+ OPT_BOOLEAN(0, "aggressive", &aggressive, N_("be more thorough (increased runtime)")),
+ OPT_BOOLEAN(0, "auto", &auto_gc, N_("enable auto-gc mode")),
OPT_END()
};
#include "dir.h"
static char const * const grep_usage[] = {
- "git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]",
+ N_("git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]"),
NULL
};
}
#endif
+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);
+}
+
+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;
if (!strcmp(var, "grep.extendedregexp")) {
if (git_config_bool(var, value))
- opt->regflags |= REG_EXTENDED;
+ opt->extended_regexp_option = 1;
else
- opt->regflags &= ~REG_EXTENDED;
+ 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;
int i;
int dummy;
int use_index = 1;
- enum {
- pattern_type_unspecified = 0,
- pattern_type_bre,
- pattern_type_ere,
- pattern_type_fixed,
- pattern_type_pcre,
- };
- int pattern_type = pattern_type_unspecified;
+ int pattern_type_arg = GREP_PATTERN_TYPE_UNSPECIFIED;
struct option options[] = {
OPT_BOOLEAN(0, "cached", &cached,
- "search in index instead of in the work tree"),
+ N_("search in index instead of in the work tree")),
OPT_NEGBIT(0, "no-index", &use_index,
- "finds in contents not managed by git", 1),
+ N_("find in contents not managed by git"), 1),
OPT_BOOLEAN(0, "untracked", &untracked,
- "search in both tracked and untracked files"),
+ N_("search in both tracked and untracked files")),
OPT_SET_INT(0, "exclude-standard", &opt_exclude,
- "search also in ignored files", 1),
+ N_("search also in ignored files"), 1),
OPT_GROUP(""),
OPT_BOOLEAN('v', "invert-match", &opt.invert,
- "show non-matching lines"),
+ N_("show non-matching lines")),
OPT_BOOLEAN('i', "ignore-case", &opt.ignore_case,
- "case insensitive matching"),
+ N_("case insensitive matching")),
OPT_BOOLEAN('w', "word-regexp", &opt.word_regexp,
- "match patterns only at word boundaries"),
+ N_("match patterns only at word boundaries")),
OPT_SET_INT('a', "text", &opt.binary,
- "process binary files as text", GREP_BINARY_TEXT),
+ N_("process binary files as text"), GREP_BINARY_TEXT),
OPT_SET_INT('I', NULL, &opt.binary,
- "don't match patterns in binary files",
+ N_("don't match patterns in binary files"),
GREP_BINARY_NOMATCH),
- { OPTION_INTEGER, 0, "max-depth", &opt.max_depth, "depth",
- "descend at most <depth> levels", PARSE_OPT_NONEG,
+ { OPTION_INTEGER, 0, "max-depth", &opt.max_depth, N_("depth"),
+ N_("descend at most <depth> levels"), PARSE_OPT_NONEG,
NULL, 1 },
OPT_GROUP(""),
- OPT_SET_INT('E', "extended-regexp", &pattern_type,
- "use extended POSIX regular expressions",
- pattern_type_ere),
- OPT_SET_INT('G', "basic-regexp", &pattern_type,
- "use basic POSIX regular expressions (default)",
- pattern_type_bre),
- OPT_SET_INT('F', "fixed-strings", &pattern_type,
- "interpret patterns as fixed strings",
- pattern_type_fixed),
- OPT_SET_INT('P', "perl-regexp", &pattern_type,
- "use Perl-compatible regular expressions",
- pattern_type_pcre),
+ OPT_SET_INT('E', "extended-regexp", &pattern_type_arg,
+ N_("use extended POSIX regular expressions"),
+ GREP_PATTERN_TYPE_ERE),
+ OPT_SET_INT('G', "basic-regexp", &pattern_type_arg,
+ N_("use basic POSIX regular expressions (default)"),
+ GREP_PATTERN_TYPE_BRE),
+ OPT_SET_INT('F', "fixed-strings", &pattern_type_arg,
+ N_("interpret patterns as fixed strings"),
+ GREP_PATTERN_TYPE_FIXED),
+ OPT_SET_INT('P', "perl-regexp", &pattern_type_arg,
+ N_("use Perl-compatible regular expressions"),
+ GREP_PATTERN_TYPE_PCRE),
OPT_GROUP(""),
- OPT_BOOLEAN('n', "line-number", &opt.linenum, "show line numbers"),
- OPT_NEGBIT('h', NULL, &opt.pathname, "don't show filenames", 1),
- OPT_BIT('H', NULL, &opt.pathname, "show filenames", 1),
+ OPT_BOOLEAN('n', "line-number", &opt.linenum, N_("show line numbers")),
+ OPT_NEGBIT('h', NULL, &opt.pathname, N_("don't show filenames"), 1),
+ OPT_BIT('H', NULL, &opt.pathname, N_("show filenames"), 1),
OPT_NEGBIT(0, "full-name", &opt.relative,
- "show filenames relative to top directory", 1),
+ N_("show filenames relative to top directory"), 1),
OPT_BOOLEAN('l', "files-with-matches", &opt.name_only,
- "show only filenames instead of matching lines"),
+ N_("show only filenames instead of matching lines")),
OPT_BOOLEAN(0, "name-only", &opt.name_only,
- "synonym for --files-with-matches"),
+ N_("synonym for --files-with-matches")),
OPT_BOOLEAN('L', "files-without-match",
&opt.unmatch_name_only,
- "show only the names of files without match"),
+ N_("show only the names of files without match")),
OPT_BOOLEAN('z', "null", &opt.null_following_name,
- "print NUL after filenames"),
+ N_("print NUL after filenames")),
OPT_BOOLEAN('c', "count", &opt.count,
- "show the number of matches instead of matching lines"),
- OPT__COLOR(&opt.color, "highlight matches"),
+ N_("show the number of matches instead of matching lines")),
+ OPT__COLOR(&opt.color, N_("highlight matches")),
OPT_BOOLEAN(0, "break", &opt.file_break,
- "print empty line between matches from different files"),
+ N_("print empty line between matches from different files")),
OPT_BOOLEAN(0, "heading", &opt.heading,
- "show filename only once above matches from same file"),
+ N_("show filename only once above matches from same file")),
OPT_GROUP(""),
- OPT_CALLBACK('C', "context", &opt, "n",
- "show <n> context lines before and after matches",
+ OPT_CALLBACK('C', "context", &opt, N_("n"),
+ N_("show <n> context lines before and after matches"),
context_callback),
OPT_INTEGER('B', "before-context", &opt.pre_context,
- "show <n> context lines before matches"),
+ N_("show <n> context lines before matches")),
OPT_INTEGER('A', "after-context", &opt.post_context,
- "show <n> context lines after matches"),
- OPT_NUMBER_CALLBACK(&opt, "shortcut for -C NUM",
+ N_("show <n> context lines after matches")),
+ OPT_NUMBER_CALLBACK(&opt, N_("shortcut for -C NUM"),
context_callback),
OPT_BOOLEAN('p', "show-function", &opt.funcname,
- "show a line with the function name before matches"),
+ N_("show a line with the function name before matches")),
OPT_BOOLEAN('W', "function-context", &opt.funcbody,
- "show the surrounding function"),
+ N_("show the surrounding function")),
OPT_GROUP(""),
- OPT_CALLBACK('f', NULL, &opt, "file",
- "read patterns from file", file_callback),
- { OPTION_CALLBACK, 'e', NULL, &opt, "pattern",
- "match <pattern>", PARSE_OPT_NONEG, pattern_callback },
+ OPT_CALLBACK('f', NULL, &opt, N_("file"),
+ N_("read patterns from file"), file_callback),
+ { OPTION_CALLBACK, 'e', NULL, &opt, N_("pattern"),
+ N_("match <pattern>"), PARSE_OPT_NONEG, pattern_callback },
{ OPTION_CALLBACK, 0, "and", &opt, NULL,
- "combine patterns specified with -e",
+ N_("combine patterns specified with -e"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, and_callback },
OPT_BOOLEAN(0, "or", &dummy, ""),
{ OPTION_CALLBACK, 0, "not", &opt, NULL, "",
PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH,
close_callback },
OPT__QUIET(&opt.status_only,
- "indicate hit with exit status without output"),
+ N_("indicate hit with exit status without output")),
OPT_BOOLEAN(0, "all-match", &opt.all_match,
- "show only matches from files that match all patterns"),
+ N_("show only matches from files that match all patterns")),
OPT_GROUP(""),
{ OPTION_STRING, 'O', "open-files-in-pager", &show_in_pager,
- "pager", "show matching files in the pager",
+ N_("pager"), N_("show matching files in the pager"),
PARSE_OPT_OPTARG, NULL, (intptr_t)default_pager },
OPT_BOOLEAN(0, "ext-grep", &external_grep_allowed__ignored,
- "allow calling of grep(1) (ignored by this build)"),
- { OPTION_CALLBACK, 0, "help-all", &options, NULL, "show usage",
+ N_("allow calling of grep(1) (ignored by this build)")),
+ { OPTION_CALLBACK, 0, "help-all", &options, NULL, N_("show usage"),
PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, help_callback },
OPT_END()
};
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, "");
PARSE_OPT_KEEP_DASHDASH |
PARSE_OPT_STOP_AT_NON_OPTION |
PARSE_OPT_NO_INTERNAL_HELP);
- switch (pattern_type) {
- case pattern_type_fixed:
- opt.fixed = 1;
- opt.pcre = 0;
- break;
- case pattern_type_bre:
- opt.fixed = 0;
- opt.pcre = 0;
- opt.regflags &= ~REG_EXTENDED;
- break;
- case pattern_type_ere:
- opt.fixed = 0;
- opt.pcre = 0;
- opt.regflags |= REG_EXTENDED;
- break;
- case pattern_type_pcre:
- opt.fixed = 0;
- opt.pcre = 1;
- break;
- default:
- break; /* nothing */
- }
+
+ 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);
if (use_index && !startup_info->have_repository)
/* die the same way as if we did it at the beginning */
}
static const char * const hash_object_usage[] = {
- "git hash-object [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin] [--] <file>...",
- "git hash-object --stdin-paths < <list-of-paths>",
+ N_("git hash-object [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin] [--] <file>..."),
+ N_("git hash-object --stdin-paths < <list-of-paths>"),
NULL
};
static const char *vpath;
static const struct option hash_object_options[] = {
- OPT_STRING('t', NULL, &type, "type", "object type"),
- OPT_BOOLEAN('w', NULL, &write_object, "write the object into the object database"),
- OPT_BOOLEAN( 0 , "stdin", &hashstdin, "read the object from stdin"),
- OPT_BOOLEAN( 0 , "stdin-paths", &stdin_paths, "read file names from stdin"),
- OPT_BOOLEAN( 0 , "no-filters", &no_filters, "store file as is without filters"),
- OPT_STRING( 0 , "path", &vpath, "file", "process file as it were from this path"),
+ OPT_STRING('t', NULL, &type, N_("type"), N_("object type")),
+ OPT_BOOLEAN('w', NULL, &write_object, N_("write the object into the object database")),
+ OPT_BOOLEAN( 0 , "stdin", &hashstdin, N_("read the object from stdin")),
+ OPT_BOOLEAN( 0 , "stdin-paths", &stdin_paths, N_("read file names from stdin")),
+ OPT_BOOLEAN( 0 , "no-filters", &no_filters, N_("store file as is without filters")),
+ OPT_STRING( 0 , "path", &vpath, N_("file"), N_("process file as it were from this path")),
OPT_END()
};
static unsigned int colopts;
static enum help_format help_format = HELP_FORMAT_NONE;
static struct option builtin_help_options[] = {
- OPT_BOOLEAN('a', "all", &show_all, "print all available commands"),
- OPT_SET_INT('m', "man", &help_format, "show man page", HELP_FORMAT_MAN),
- OPT_SET_INT('w', "web", &help_format, "show manual in web browser",
+ OPT_BOOLEAN('a', "all", &show_all, N_("print all available commands")),
+ OPT_SET_INT('m', "man", &help_format, N_("show man page"), HELP_FORMAT_MAN),
+ OPT_SET_INT('w', "web", &help_format, N_("show manual in web browser"),
HELP_FORMAT_WEB),
- OPT_SET_INT('i', "info", &help_format, "show info page",
+ OPT_SET_INT('i', "info", &help_format, N_("show info page"),
HELP_FORMAT_INFO),
OPT_END(),
};
static const char * const builtin_help_usage[] = {
- "git help [--all] [--man|--web|--info] [command]",
+ N_("git help [--all] [--man|--web|--info] [command]"),
NULL
};
}
static const char *const init_db_usage[] = {
- "git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared[=<permissions>]] [directory]",
+ N_("git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared[=<permissions>]] [directory]"),
NULL
};
const char *template_dir = NULL;
unsigned int flags = 0;
const struct option init_db_options[] = {
- OPT_STRING(0, "template", &template_dir, "template-directory",
- "directory from which templates will be used"),
+ OPT_STRING(0, "template", &template_dir, N_("template-directory"),
+ N_("directory from which templates will be used")),
OPT_SET_INT(0, "bare", &is_bare_repository_cfg,
- "create a bare repository", 1),
+ N_("create a bare repository"), 1),
{ OPTION_CALLBACK, 0, "shared", &init_shared_repository,
- "permissions",
- "specify that the git repository is to be shared amongst several users",
+ N_("permissions"),
+ N_("specify that the git repository is to be shared amongst several users"),
PARSE_OPT_OPTARG | PARSE_OPT_NONEG, shared_callback, 0},
- OPT_BIT('q', "quiet", &flags, "be quiet", INIT_DB_QUIET),
- OPT_STRING(0, "separate-git-dir", &real_git_dir, "gitdir",
- "separate git dir from working tree"),
+ OPT_BIT('q', "quiet", &flags, N_("be quiet"), INIT_DB_QUIET),
+ OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"),
+ N_("separate git dir from working tree")),
OPT_END()
};
static const char *fmt_pretty;
static const char * const builtin_log_usage[] = {
- "git log [<options>] [<since>..<until>] [[--] <path>...]\n"
- " or: git show [options] <object>...",
+ N_("git log [<options>] [<since>..<until>] [[--] <path>...]\n")
+ N_(" or: git show [options] <object>..."),
NULL
};
int quiet = 0, source = 0;
const struct option builtin_log_options[] = {
- OPT_BOOLEAN(0, "quiet", &quiet, "suppress diff output"),
- OPT_BOOLEAN(0, "source", &source, "show source"),
- { OPTION_CALLBACK, 0, "decorate", NULL, NULL, "decorate options",
+ OPT_BOOLEAN(0, "quiet", &quiet, N_("suppress diff output")),
+ OPT_BOOLEAN(0, "source", &source, N_("show source")),
+ { OPTION_CALLBACK, 0, "decorate", NULL, NULL, N_("decorate options"),
PARSE_OPT_OPTARG, decorate_callback},
OPT_END()
};
PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN |
PARSE_OPT_KEEP_DASHDASH);
- argc = setup_revisions(argc, argv, rev, opt);
if (quiet)
rev->diffopt.output_format |= DIFF_FORMAT_NO_OUTPUT;
+ argc = setup_revisions(argc, argv, rev, opt);
/* Any arguments at this point are not recognized */
if (argc > 1)
init_revisions(&rev, prefix);
rev.diff = 1;
rev.always_show_header = 1;
- rev.no_walk = 1;
+ rev.no_walk = REVISION_WALK_NO_WALK_SORTED;
rev.diffopt.stat_width = -1; /* Scale to real terminal size */
memset(&opt, 0, sizeof(opt));
return 0;
}
-static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids, const char *prefix)
+static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids)
{
struct rev_info check_rev;
struct commit *commit;
init_patch_ids(ids);
/* given a range a..b get all patch ids for b..a */
- init_revisions(&check_rev, prefix);
+ init_revisions(&check_rev, rev->prefix);
+ check_rev.max_parents = 1;
o1->flags ^= UNINTERESTING;
o2->flags ^= UNINTERESTING;
add_pending_object(&check_rev, o1, "o1");
die(_("revision walk setup failed"));
while ((commit = get_revision(&check_rev)) != NULL) {
- /* ignore merges */
- if (commit->parents && commit->parents->next)
- continue;
-
add_commit_patch_id(commit, ids);
}
}
static const char * const builtin_format_patch_usage[] = {
- "git format-patch [options] [<since> | <revision range>]",
+ N_("git format-patch [options] [<since> | <revision range>]"),
NULL
};
char *branch_name = NULL;
const struct option builtin_format_patch_options[] = {
{ OPTION_CALLBACK, 'n', "numbered", &numbered, NULL,
- "use [PATCH n/m] even with a single patch",
+ N_("use [PATCH n/m] even with a single patch"),
PARSE_OPT_NOARG, numbered_callback },
{ OPTION_CALLBACK, 'N', "no-numbered", &numbered, NULL,
- "use [PATCH] even with multiple patches",
+ N_("use [PATCH] even with multiple patches"),
PARSE_OPT_NOARG, no_numbered_callback },
- OPT_BOOLEAN('s', "signoff", &do_signoff, "add Signed-off-by:"),
+ OPT_BOOLEAN('s', "signoff", &do_signoff, N_("add Signed-off-by:")),
OPT_BOOLEAN(0, "stdout", &use_stdout,
- "print patches to standard out"),
+ N_("print patches to standard out")),
OPT_BOOLEAN(0, "cover-letter", &cover_letter,
- "generate a cover letter"),
+ N_("generate a cover letter")),
OPT_BOOLEAN(0, "numbered-files", &numbered_files,
- "use simple number sequence for output file names"),
- OPT_STRING(0, "suffix", &fmt_patch_suffix, "sfx",
- "use <sfx> instead of '.patch'"),
+ N_("use simple number sequence for output file names")),
+ OPT_STRING(0, "suffix", &fmt_patch_suffix, N_("sfx"),
+ N_("use <sfx> instead of '.patch'")),
OPT_INTEGER(0, "start-number", &start_number,
- "start numbering patches at <n> instead of 1"),
- { OPTION_CALLBACK, 0, "subject-prefix", &rev, "prefix",
- "Use [<prefix>] instead of [PATCH]",
+ N_("start numbering patches at <n> instead of 1")),
+ { OPTION_CALLBACK, 0, "subject-prefix", &rev, N_("prefix"),
+ N_("Use [<prefix>] instead of [PATCH]"),
PARSE_OPT_NONEG, subject_prefix_callback },
{ OPTION_CALLBACK, 'o', "output-directory", &output_directory,
- "dir", "store resulting files in <dir>",
+ N_("dir"), N_("store resulting files in <dir>"),
PARSE_OPT_NONEG, output_directory_callback },
{ OPTION_CALLBACK, 'k', "keep-subject", &rev, NULL,
- "don't strip/add [PATCH]",
+ N_("don't strip/add [PATCH]"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, keep_callback },
OPT_BOOLEAN(0, "no-binary", &no_binary_diff,
- "don't output binary diffs"),
+ N_("don't output binary diffs")),
OPT_BOOLEAN(0, "ignore-if-in-upstream", &ignore_if_in_upstream,
- "don't include a patch matching a commit upstream"),
+ N_("don't include a patch matching a commit upstream")),
{ OPTION_BOOLEAN, 'p', "no-stat", &use_patch_format, NULL,
- "show patch format instead of default (patch + stat)",
+ N_("show patch format instead of default (patch + stat)"),
PARSE_OPT_NONEG | PARSE_OPT_NOARG },
- OPT_GROUP("Messaging"),
- { OPTION_CALLBACK, 0, "add-header", NULL, "header",
- "add email header", 0, header_callback },
- { OPTION_CALLBACK, 0, "to", NULL, "email", "add To: header",
+ OPT_GROUP(N_("Messaging")),
+ { OPTION_CALLBACK, 0, "add-header", NULL, N_("header"),
+ N_("add email header"), 0, header_callback },
+ { OPTION_CALLBACK, 0, "to", NULL, N_("email"), N_("add To: header"),
0, to_callback },
- { OPTION_CALLBACK, 0, "cc", NULL, "email", "add Cc: header",
+ { OPTION_CALLBACK, 0, "cc", NULL, N_("email"), N_("add Cc: header"),
0, cc_callback },
- OPT_STRING(0, "in-reply-to", &in_reply_to, "message-id",
- "make first mail a reply to <message-id>"),
- { OPTION_CALLBACK, 0, "attach", &rev, "boundary",
- "attach the patch", PARSE_OPT_OPTARG,
+ OPT_STRING(0, "in-reply-to", &in_reply_to, N_("message-id"),
+ N_("make first mail a reply to <message-id>")),
+ { OPTION_CALLBACK, 0, "attach", &rev, N_("boundary"),
+ N_("attach the patch"), PARSE_OPT_OPTARG,
attach_callback },
- { OPTION_CALLBACK, 0, "inline", &rev, "boundary",
- "inline the patch",
+ { OPTION_CALLBACK, 0, "inline", &rev, N_("boundary"),
+ N_("inline the patch"),
PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
inline_callback },
- { OPTION_CALLBACK, 0, "thread", &thread, "style",
- "enable message threading, styles: shallow, deep",
+ { OPTION_CALLBACK, 0, "thread", &thread, N_("style"),
+ N_("enable message threading, styles: shallow, deep"),
PARSE_OPT_OPTARG, thread_callback },
- OPT_STRING(0, "signature", &signature, "signature",
- "add a signature"),
+ OPT_STRING(0, "signature", &signature, N_("signature"),
+ N_("add a signature")),
OPT_BOOLEAN(0, "quiet", &quiet,
- "don't print the patch filenames"),
+ N_("don't print the patch filenames")),
OPT_END()
};
if (hashcmp(o[0].item->sha1, o[1].item->sha1) == 0)
return 0;
}
- get_patch_ids(&rev, &ids, prefix);
+ get_patch_ids(&rev, &ids);
}
if (!use_stdout)
}
static const char * const cherry_usage[] = {
- "git cherry [-v] [<upstream> [<head> [<limit>]]]",
+ N_("git cherry [-v] [<upstream> [<head> [<limit>]]]"),
NULL
};
struct option options[] = {
OPT__ABBREV(&abbrev),
- OPT__VERBOSE(&verbose, "be verbose"),
+ OPT__VERBOSE(&verbose, N_("be verbose")),
OPT_END()
};
}
init_revisions(&revs, prefix);
- revs.diff = 1;
- revs.combine_merges = 0;
- revs.ignore_merges = 1;
- DIFF_OPT_SET(&revs.diffopt, RECURSIVE);
+ revs.max_parents = 1;
if (add_pending_commit(head, &revs, 0))
die(_("Unknown commit %s"), head);
return 0;
}
- get_patch_ids(&revs, &ids, prefix);
+ get_patch_ids(&revs, &ids);
if (limit && add_pending_commit(limit, &revs, UNINTERESTING))
die(_("Unknown commit %s"), limit);
if (prepare_revision_walk(&revs))
die(_("revision walk setup failed"));
while ((commit = get_revision(&revs)) != NULL) {
- /* ignore merges */
- if (commit->parents && commit->parents->next)
- continue;
-
commit_list_insert(commit, &list);
}
}
static const char * const ls_files_usage[] = {
- "git ls-files [options] [<file>...]",
+ N_("git ls-files [options] [<file>...]"),
NULL
};
struct dir_struct dir;
struct option builtin_ls_files_options[] = {
{ OPTION_CALLBACK, 'z', NULL, NULL, NULL,
- "paths are separated with NUL character",
+ N_("paths are separated with NUL character"),
PARSE_OPT_NOARG, option_parse_z },
OPT_BOOLEAN('t', NULL, &show_tag,
- "identify the file status with tags"),
+ N_("identify the file status with tags")),
OPT_BOOLEAN('v', NULL, &show_valid_bit,
- "use lowercase letters for 'assume unchanged' files"),
+ N_("use lowercase letters for 'assume unchanged' files")),
OPT_BOOLEAN('c', "cached", &show_cached,
- "show cached files in the output (default)"),
+ N_("show cached files in the output (default)")),
OPT_BOOLEAN('d', "deleted", &show_deleted,
- "show deleted files in the output"),
+ N_("show deleted files in the output")),
OPT_BOOLEAN('m', "modified", &show_modified,
- "show modified files in the output"),
+ N_("show modified files in the output")),
OPT_BOOLEAN('o', "others", &show_others,
- "show other files in the output"),
+ N_("show other files in the output")),
OPT_BIT('i', "ignored", &dir.flags,
- "show ignored files in the output",
+ N_("show ignored files in the output"),
DIR_SHOW_IGNORED),
OPT_BOOLEAN('s', "stage", &show_stage,
- "show staged contents' object name in the output"),
+ N_("show staged contents' object name in the output")),
OPT_BOOLEAN('k', "killed", &show_killed,
- "show files on the filesystem that need to be removed"),
+ N_("show files on the filesystem that need to be removed")),
OPT_BIT(0, "directory", &dir.flags,
- "show 'other' directories' name only",
+ N_("show 'other' directories' name only"),
DIR_SHOW_OTHER_DIRECTORIES),
OPT_NEGBIT(0, "empty-directory", &dir.flags,
- "don't show empty directories",
+ N_("don't show empty directories"),
DIR_HIDE_EMPTY_DIRECTORIES),
OPT_BOOLEAN('u', "unmerged", &show_unmerged,
- "show unmerged files in the output"),
+ N_("show unmerged files in the output")),
OPT_BOOLEAN(0, "resolve-undo", &show_resolve_undo,
- "show resolve-undo information"),
- { OPTION_CALLBACK, 'x', "exclude", &dir.exclude_list[EXC_CMDL], "pattern",
- "skip files matching pattern",
+ N_("show resolve-undo information")),
+ { OPTION_CALLBACK, 'x', "exclude", &dir.exclude_list[EXC_CMDL], N_("pattern"),
+ N_("skip files matching pattern"),
0, option_parse_exclude },
- { OPTION_CALLBACK, 'X', "exclude-from", &dir, "file",
- "exclude patterns are read from <file>",
+ { OPTION_CALLBACK, 'X', "exclude-from", &dir, N_("file"),
+ N_("exclude patterns are read from <file>"),
0, option_parse_exclude_from },
- OPT_STRING(0, "exclude-per-directory", &dir.exclude_per_dir, "file",
- "read additional per-directory exclude patterns in <file>"),
+ OPT_STRING(0, "exclude-per-directory", &dir.exclude_per_dir, N_("file"),
+ N_("read additional per-directory exclude patterns in <file>")),
{ OPTION_CALLBACK, 0, "exclude-standard", &dir, NULL,
- "add the standard git exclusions",
+ N_("add the standard git exclusions"),
PARSE_OPT_NOARG, option_parse_exclude_standard },
{ OPTION_SET_INT, 0, "full-name", &prefix_len, NULL,
- "make the output relative to the project top directory",
+ N_("make the output relative to the project top directory"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL },
OPT_BOOLEAN(0, "error-unmatch", &error_unmatch,
- "if any <file> is not in the index, treat this as an error"),
- OPT_STRING(0, "with-tree", &with_tree, "tree-ish",
- "pretend that paths removed since <tree-ish> are still present"),
+ N_("if any <file> is not in the index, treat this as an error")),
+ OPT_STRING(0, "with-tree", &with_tree, N_("tree-ish"),
+ N_("pretend that paths removed since <tree-ish> are still present")),
OPT__ABBREV(&abbrev),
- OPT_BOOLEAN(0, "debug", &debug_mode, "show debugging data"),
+ OPT_BOOLEAN(0, "debug", &debug_mode, N_("show debugging data")),
OPT_END()
};
static const char *ls_tree_prefix;
static const char * const ls_tree_usage[] = {
- "git ls-tree [<options>] <tree-ish> [<path>...]",
+ N_("git ls-tree [<options>] <tree-ish> [<path>...]"),
NULL
};
struct tree *tree;
int i, full_tree = 0;
const struct option ls_tree_options[] = {
- OPT_BIT('d', NULL, &ls_options, "only show trees",
+ OPT_BIT('d', NULL, &ls_options, N_("only show trees"),
LS_TREE_ONLY),
- OPT_BIT('r', NULL, &ls_options, "recurse into subtrees",
+ OPT_BIT('r', NULL, &ls_options, N_("recurse into subtrees"),
LS_RECURSIVE),
- OPT_BIT('t', NULL, &ls_options, "show trees when recursing",
+ OPT_BIT('t', NULL, &ls_options, N_("show trees when recursing"),
LS_SHOW_TREES),
OPT_SET_INT('z', NULL, &line_termination,
- "terminate entries with NUL byte", 0),
- OPT_BIT('l', "long", &ls_options, "include object size",
+ N_("terminate entries with NUL byte"), 0),
+ OPT_BIT('l', "long", &ls_options, N_("include object size"),
LS_SHOW_SIZE),
- OPT_BIT(0, "name-only", &ls_options, "list only filenames",
+ OPT_BIT(0, "name-only", &ls_options, N_("list only filenames"),
LS_NAME_ONLY),
- OPT_BIT(0, "name-status", &ls_options, "list only filenames",
+ OPT_BIT(0, "name-status", &ls_options, N_("list only filenames"),
LS_NAME_ONLY),
OPT_SET_INT(0, "full-name", &chomp_prefix,
- "use full path names", 0),
+ N_("use full path names"), 0),
OPT_BOOLEAN(0, "full-tree", &full_tree,
- "list entire tree; not just current directory "
- "(implies --full-name)"),
+ N_("list entire tree; not just current directory "
+ "(implies --full-name)")),
OPT__ABBREV(&abbrev),
OPT_END()
};
return out;
}
-/*
- * When there is no known charset, guess.
- *
- * Right now we assume that if the target is UTF-8 (the default),
- * and it already looks like UTF-8 (which includes US-ASCII as its
- * subset, of course) then that is what it is and there is nothing
- * to do.
- *
- * Otherwise, we default to assuming it is Latin1 for historical
- * reasons.
- */
-static const char *guess_charset(const struct strbuf *line, const char *target_charset)
-{
- if (is_encoding_utf8(target_charset)) {
- if (is_utf8(line->buf))
- return NULL;
- }
- return "ISO8859-1";
-}
-
static void convert_to_utf8(struct strbuf *line, const char *charset)
{
char *out;
- if (!charset || !*charset) {
- charset = guess_charset(line, metainfo_charset);
- if (!charset)
- return;
- }
-
+ if (!charset || !*charset)
+ return;
if (!strcasecmp(metainfo_charset, charset))
return;
out = reencode_string(line->buf, metainfo_charset, charset);
}
static const char * const merge_base_usage[] = {
- "git merge-base [-a|--all] <commit> <commit>...",
- "git merge-base [-a|--all] --octopus <commit>...",
- "git merge-base --independent <commit>...",
+ N_("git merge-base [-a|--all] <commit> <commit>..."),
+ N_("git merge-base [-a|--all] --octopus <commit>..."),
+ N_("git merge-base --independent <commit>..."),
NULL
};
int reduce = 0;
struct option options[] = {
- OPT_BOOLEAN('a', "all", &show_all, "output all common ancestors"),
- OPT_BOOLEAN(0, "octopus", &octopus, "find ancestors for a single n-way merge"),
- OPT_BOOLEAN(0, "independent", &reduce, "list revs not reachable from others"),
+ OPT_BOOLEAN('a', "all", &show_all, N_("output all common ancestors")),
+ OPT_BOOLEAN(0, "octopus", &octopus, N_("find ancestors for a single n-way merge")),
+ OPT_BOOLEAN(0, "independent", &reduce, N_("list revs not reachable from others")),
OPT_END()
};
#include "parse-options.h"
static const char *const merge_file_usage[] = {
- "git merge-file [options] [-L name1 [-L orig [-L name2]]] file1 orig_file file2",
+ N_("git merge-file [options] [-L name1 [-L orig [-L name2]]] file1 orig_file file2"),
NULL
};
int quiet = 0;
int prefixlen = 0;
struct option options[] = {
- OPT_BOOLEAN('p', "stdout", &to_stdout, "send results to standard output"),
- OPT_SET_INT(0, "diff3", &xmp.style, "use a diff3 based merge", XDL_MERGE_DIFF3),
- OPT_SET_INT(0, "ours", &xmp.favor, "for conflicts, use our version",
+ OPT_BOOLEAN('p', "stdout", &to_stdout, N_("send results to standard output")),
+ OPT_SET_INT(0, "diff3", &xmp.style, N_("use a diff3 based merge"), XDL_MERGE_DIFF3),
+ OPT_SET_INT(0, "ours", &xmp.favor, N_("for conflicts, use our version"),
XDL_MERGE_FAVOR_OURS),
- OPT_SET_INT(0, "theirs", &xmp.favor, "for conflicts, use their version",
+ OPT_SET_INT(0, "theirs", &xmp.favor, N_("for conflicts, use their version"),
XDL_MERGE_FAVOR_THEIRS),
- OPT_SET_INT(0, "union", &xmp.favor, "for conflicts, use a union version",
+ OPT_SET_INT(0, "union", &xmp.favor, N_("for conflicts, use a union version"),
XDL_MERGE_FAVOR_UNION),
OPT_INTEGER(0, "marker-size", &xmp.marker_size,
- "for conflicts, use this marker size"),
- OPT__QUIET(&quiet, "do not warn about conflicts"),
- OPT_CALLBACK('L', NULL, names, "name",
- "set labels for file1/orig_file/file2", &label_cb),
+ N_("for conflicts, use this marker size")),
+ OPT__QUIET(&quiet, N_("do not warn about conflicts")),
+ OPT_CALLBACK('L', NULL, names, N_("name"),
+ N_("set labels for file1/orig_file/file2"), &label_cb),
OPT_END(),
};
};
static const char * const builtin_merge_usage[] = {
- "git merge [options] [<commit>...]",
- "git merge [options] <msg> HEAD <commit>",
- "git merge --abort",
+ N_("git merge [options] [<commit>...]"),
+ N_("git merge [options] <msg> HEAD <commit>"),
+ N_("git merge --abort"),
NULL
};
static struct option builtin_merge_options[] = {
{ OPTION_CALLBACK, 'n', NULL, NULL, NULL,
- "do not show a diffstat at the end of the merge",
+ N_("do not show a diffstat at the end of the merge"),
PARSE_OPT_NOARG, option_parse_n },
OPT_BOOLEAN(0, "stat", &show_diffstat,
- "show a diffstat at the end of the merge"),
- OPT_BOOLEAN(0, "summary", &show_diffstat, "(synonym to --stat)"),
- { OPTION_INTEGER, 0, "log", &shortlog_len, "n",
- "add (at most <n>) entries from shortlog to merge commit message",
+ N_("show a diffstat at the end of the merge")),
+ OPT_BOOLEAN(0, "summary", &show_diffstat, N_("(synonym to --stat)")),
+ { OPTION_INTEGER, 0, "log", &shortlog_len, N_("n"),
+ N_("add (at most <n>) entries from shortlog to merge commit message"),
PARSE_OPT_OPTARG, NULL, DEFAULT_MERGE_LOG_LEN },
OPT_BOOLEAN(0, "squash", &squash,
- "create a single commit instead of doing a merge"),
+ N_("create a single commit instead of doing a merge")),
OPT_BOOLEAN(0, "commit", &option_commit,
- "perform a commit if the merge succeeds (default)"),
+ N_("perform a commit if the merge succeeds (default)")),
OPT_BOOL('e', "edit", &option_edit,
- "edit message before committing"),
+ N_("edit message before committing")),
OPT_BOOLEAN(0, "ff", &allow_fast_forward,
- "allow fast-forward (default)"),
+ N_("allow fast-forward (default)")),
OPT_BOOLEAN(0, "ff-only", &fast_forward_only,
- "abort if fast-forward is not possible"),
+ N_("abort if fast-forward is not possible")),
OPT_RERERE_AUTOUPDATE(&allow_rerere_auto),
- OPT_CALLBACK('s', "strategy", &use_strategies, "strategy",
- "merge strategy to use", option_parse_strategy),
- OPT_CALLBACK('X', "strategy-option", &xopts, "option=value",
- "option for selected merge strategy", option_parse_x),
- OPT_CALLBACK('m', "message", &merge_msg, "message",
- "merge commit message (for a non-fast-forward merge)",
+ OPT_CALLBACK('s', "strategy", &use_strategies, N_("strategy"),
+ N_("merge strategy to use"), option_parse_strategy),
+ OPT_CALLBACK('X', "strategy-option", &xopts, N_("option=value"),
+ N_("option for selected merge strategy"), option_parse_x),
+ OPT_CALLBACK('m', "message", &merge_msg, N_("message"),
+ N_("merge commit message (for a non-fast-forward merge)"),
option_parse_message),
OPT__VERBOSITY(&verbosity),
OPT_BOOLEAN(0, "abort", &abort_current_merge,
- "abort the current in-progress merge"),
- OPT_SET_INT(0, "progress", &show_progress, "force progress reporting", 1),
- { OPTION_STRING, 'S', "gpg-sign", &sign_commit, "key id",
- "GPG sign commit", PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
- OPT_BOOLEAN(0, "overwrite-ignore", &overwrite_ignore, "update ignored files (default)"),
+ N_("abort the current in-progress merge")),
+ OPT_SET_INT(0, "progress", &show_progress, N_("force progress reporting"), 1),
+ { OPTION_STRING, 'S', "gpg-sign", &sign_commit, N_("key id"),
+ N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
+ OPT_BOOLEAN(0, "overwrite-ignore", &overwrite_ignore, N_("update ignored files (default)")),
OPT_END()
};
}
static const char *mktree_usage[] = {
- "git mktree [-z] [--missing] [--batch]",
+ N_("git mktree [-z] [--missing] [--batch]"),
NULL
};
int got_eof = 0;
const struct option option[] = {
- OPT_SET_INT('z', NULL, &line_termination, "input is NUL terminated", '\0'),
- OPT_SET_INT( 0 , "missing", &allow_missing, "allow missing objects", 1),
- OPT_SET_INT( 0 , "batch", &is_batch_mode, "allow creation of more than one tree", 1),
+ OPT_SET_INT('z', NULL, &line_termination, N_("input is NUL terminated"), '\0'),
+ OPT_SET_INT( 0 , "missing", &allow_missing, N_("allow missing objects"), 1),
+ OPT_SET_INT( 0 , "batch", &is_batch_mode, N_("allow creation of more than one tree"), 1),
OPT_END()
};
#include "parse-options.h"
static const char * const builtin_mv_usage[] = {
- "git mv [options] <source>... <destination>",
+ N_("git mv [options] <source>... <destination>"),
NULL
};
int i, newfd;
int verbose = 0, show_only = 0, force = 0, ignore_errors = 0;
struct option builtin_mv_options[] = {
- OPT__VERBOSE(&verbose, "be verbose"),
- OPT__DRY_RUN(&show_only, "dry run"),
- OPT__FORCE(&force, "force move/rename even if target exists"),
- OPT_BOOLEAN('k', NULL, &ignore_errors, "skip move/rename errors"),
+ OPT__VERBOSE(&verbose, N_("be verbose")),
+ OPT__DRY_RUN(&show_only, N_("dry run")),
+ OPT__FORCE(&force, N_("force move/rename even if target exists")),
+ OPT_BOOLEAN('k', NULL, &ignore_errors, N_("skip move/rename errors")),
OPT_END(),
};
const char **source, **destination, **dest_path;
}
static char const * const name_rev_usage[] = {
- "git name-rev [options] <commit>...",
- "git name-rev [options] --all",
- "git name-rev [options] --stdin",
+ N_("git name-rev [options] <commit>..."),
+ N_("git name-rev [options] --all"),
+ N_("git name-rev [options] --stdin"),
NULL
};
int all = 0, transform_stdin = 0, allow_undefined = 1, always = 0;
struct name_ref_data data = { 0, 0, NULL };
struct option opts[] = {
- OPT_BOOLEAN(0, "name-only", &data.name_only, "print only names (no SHA-1)"),
- OPT_BOOLEAN(0, "tags", &data.tags_only, "only use tags to name the commits"),
- OPT_STRING(0, "refs", &data.ref_filter, "pattern",
- "only use refs matching <pattern>"),
+ OPT_BOOLEAN(0, "name-only", &data.name_only, N_("print only names (no SHA-1)")),
+ OPT_BOOLEAN(0, "tags", &data.tags_only, N_("only use tags to name the commits")),
+ OPT_STRING(0, "refs", &data.ref_filter, N_("pattern"),
+ N_("only use refs matching <pattern>")),
OPT_GROUP(""),
- OPT_BOOLEAN(0, "all", &all, "list all commits reachable from all refs"),
- OPT_BOOLEAN(0, "stdin", &transform_stdin, "read from stdin"),
- OPT_BOOLEAN(0, "undefined", &allow_undefined, "allow to print `undefined` names"),
+ OPT_BOOLEAN(0, "all", &all, N_("list all commits reachable from all refs")),
+ OPT_BOOLEAN(0, "stdin", &transform_stdin, N_("read from stdin")),
+ OPT_BOOLEAN(0, "undefined", &allow_undefined, N_("allow to print `undefined` names")),
OPT_BOOLEAN(0, "always", &always,
- "show abbreviated commit object as fallback"),
+ N_("show abbreviated commit object as fallback")),
OPT_END(),
};
#include "notes-merge.h"
static const char * const git_notes_usage[] = {
- "git notes [--ref <notes_ref>] [list [<object>]]",
- "git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]",
- "git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>",
- "git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]",
- "git notes [--ref <notes_ref>] edit [<object>]",
- "git notes [--ref <notes_ref>] show [<object>]",
- "git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>",
- "git notes merge --commit [-v | -q]",
- "git notes merge --abort [-v | -q]",
- "git notes [--ref <notes_ref>] remove [<object>...]",
- "git notes [--ref <notes_ref>] prune [-n | -v]",
- "git notes [--ref <notes_ref>] get-ref",
+ N_("git notes [--ref <notes_ref>] [list [<object>]]"),
+ N_("git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
+ N_("git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>"),
+ N_("git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
+ N_("git notes [--ref <notes_ref>] edit [<object>]"),
+ N_("git notes [--ref <notes_ref>] show [<object>]"),
+ N_("git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>"),
+ N_("git notes merge --commit [-v | -q]"),
+ N_("git notes merge --abort [-v | -q]"),
+ N_("git notes [--ref <notes_ref>] remove [<object>...]"),
+ N_("git notes [--ref <notes_ref>] prune [-n | -v]"),
+ N_("git notes [--ref <notes_ref>] get-ref"),
NULL
};
static const char * const git_notes_list_usage[] = {
- "git notes [list [<object>]]",
+ N_("git notes [list [<object>]]"),
NULL
};
static const char * const git_notes_add_usage[] = {
- "git notes add [<options>] [<object>]",
+ N_("git notes add [<options>] [<object>]"),
NULL
};
static const char * const git_notes_copy_usage[] = {
- "git notes copy [<options>] <from-object> <to-object>",
- "git notes copy --stdin [<from-object> <to-object>]...",
+ N_("git notes copy [<options>] <from-object> <to-object>"),
+ N_("git notes copy --stdin [<from-object> <to-object>]..."),
NULL
};
static const char * const git_notes_append_usage[] = {
- "git notes append [<options>] [<object>]",
+ N_("git notes append [<options>] [<object>]"),
NULL
};
static const char * const git_notes_edit_usage[] = {
- "git notes edit [<object>]",
+ N_("git notes edit [<object>]"),
NULL
};
static const char * const git_notes_show_usage[] = {
- "git notes show [<object>]",
+ N_("git notes show [<object>]"),
NULL
};
static const char * const git_notes_merge_usage[] = {
- "git notes merge [<options>] <notes_ref>",
- "git notes merge --commit [<options>]",
- "git notes merge --abort [<options>]",
+ N_("git notes merge [<options>] <notes_ref>"),
+ N_("git notes merge --commit [<options>]"),
+ N_("git notes merge --abort [<options>]"),
NULL
};
static const char * const git_notes_remove_usage[] = {
- "git notes remove [<object>]",
+ N_("git notes remove [<object>]"),
NULL
};
static const char * const git_notes_prune_usage[] = {
- "git notes prune [<options>]",
+ N_("git notes prune [<options>]"),
NULL
};
static const char * const git_notes_get_ref_usage[] = {
- "git notes get-ref",
+ N_("git notes get-ref"),
NULL
};
const unsigned char *note;
struct msg_arg msg = { 0, 0, STRBUF_INIT };
struct option options[] = {
- { OPTION_CALLBACK, 'm', "message", &msg, "msg",
- "note contents as a string", PARSE_OPT_NONEG,
+ { OPTION_CALLBACK, 'm', "message", &msg, N_("message"),
+ N_("note contents as a string"), PARSE_OPT_NONEG,
parse_msg_arg},
- { OPTION_CALLBACK, 'F', "file", &msg, "file",
- "note contents in a file", PARSE_OPT_NONEG,
+ { OPTION_CALLBACK, 'F', "file", &msg, N_("file"),
+ N_("note contents in a file"), PARSE_OPT_NONEG,
parse_file_arg},
- { OPTION_CALLBACK, 'c', "reedit-message", &msg, "object",
- "reuse and edit specified note object", PARSE_OPT_NONEG,
+ { OPTION_CALLBACK, 'c', "reedit-message", &msg, N_("object"),
+ N_("reuse and edit specified note object"), PARSE_OPT_NONEG,
parse_reedit_arg},
- { OPTION_CALLBACK, 'C', "reuse-message", &msg, "object",
- "reuse specified note object", PARSE_OPT_NONEG,
+ { OPTION_CALLBACK, 'C', "reuse-message", &msg, N_("object"),
+ N_("reuse specified note object"), PARSE_OPT_NONEG,
parse_reuse_arg},
- OPT__FORCE(&force, "replace existing notes"),
+ OPT__FORCE(&force, N_("replace existing notes")),
OPT_END()
};
struct notes_tree *t;
const char *rewrite_cmd = NULL;
struct option options[] = {
- OPT__FORCE(&force, "replace existing notes"),
- OPT_BOOLEAN(0, "stdin", &from_stdin, "read objects from stdin"),
- OPT_STRING(0, "for-rewrite", &rewrite_cmd, "command",
- "load rewriting config for <command> (implies "
- "--stdin)"),
+ OPT__FORCE(&force, N_("replace existing notes")),
+ OPT_BOOLEAN(0, "stdin", &from_stdin, N_("read objects from stdin")),
+ OPT_STRING(0, "for-rewrite", &rewrite_cmd, N_("command"),
+ N_("load rewriting config for <command> (implies "
+ "--stdin)")),
OPT_END()
};
const char * const *usage;
struct msg_arg msg = { 0, 0, STRBUF_INIT };
struct option options[] = {
- { OPTION_CALLBACK, 'm', "message", &msg, "msg",
- "note contents as a string", PARSE_OPT_NONEG,
+ { OPTION_CALLBACK, 'm', "message", &msg, N_("message"),
+ N_("note contents as a string"), PARSE_OPT_NONEG,
parse_msg_arg},
- { OPTION_CALLBACK, 'F', "file", &msg, "file",
- "note contents in a file", PARSE_OPT_NONEG,
+ { OPTION_CALLBACK, 'F', "file", &msg, N_("file"),
+ N_("note contents in a file"), PARSE_OPT_NONEG,
parse_file_arg},
- { OPTION_CALLBACK, 'c', "reedit-message", &msg, "object",
- "reuse and edit specified note object", PARSE_OPT_NONEG,
+ { OPTION_CALLBACK, 'c', "reedit-message", &msg, N_("object"),
+ N_("reuse and edit specified note object"), PARSE_OPT_NONEG,
parse_reedit_arg},
- { OPTION_CALLBACK, 'C', "reuse-message", &msg, "object",
- "reuse specified note object", PARSE_OPT_NONEG,
+ { OPTION_CALLBACK, 'C', "reuse-message", &msg, N_("object"),
+ N_("reuse specified note object"), PARSE_OPT_NONEG,
parse_reuse_arg},
OPT_END()
};
int verbosity = 0, result;
const char *strategy = NULL;
struct option options[] = {
- OPT_GROUP("General options"),
+ OPT_GROUP(N_("General options")),
OPT__VERBOSITY(&verbosity),
- OPT_GROUP("Merge options"),
- OPT_STRING('s', "strategy", &strategy, "strategy",
- "resolve notes conflicts using the given strategy "
- "(manual/ours/theirs/union/cat_sort_uniq)"),
- OPT_GROUP("Committing unmerged notes"),
+ OPT_GROUP(N_("Merge options")),
+ OPT_STRING('s', "strategy", &strategy, N_("strategy"),
+ N_("resolve notes conflicts using the given strategy "
+ "(manual/ours/theirs/union/cat_sort_uniq)")),
+ OPT_GROUP(N_("Committing unmerged notes")),
{ OPTION_BOOLEAN, 0, "commit", &do_commit, NULL,
- "finalize notes merge by committing unmerged notes",
+ N_("finalize notes merge by committing unmerged notes"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG },
- OPT_GROUP("Aborting notes merge resolution"),
+ OPT_GROUP(N_("Aborting notes merge resolution")),
{ OPTION_BOOLEAN, 0, "abort", &do_abort, NULL,
- "abort notes merge",
+ N_("abort notes merge"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG },
OPT_END()
};
int from_stdin = 0;
struct option options[] = {
OPT_BIT(0, "ignore-missing", &flag,
- "attempt to remove non-existent note is not an error",
+ N_("attempt to remove non-existent note is not an error"),
IGNORE_MISSING),
OPT_BOOLEAN(0, "stdin", &from_stdin,
- "read object names from the standard input"),
+ N_("read object names from the standard input")),
OPT_END()
};
struct notes_tree *t;
int result;
const char *override_notes_ref = NULL;
struct option options[] = {
- OPT_STRING(0, "ref", &override_notes_ref, "notes_ref",
- "use notes from <notes_ref>"),
+ OPT_STRING(0, "ref", &override_notes_ref, N_("notes_ref"),
+ N_("use notes from <notes_ref>")),
OPT_END()
};
#include "thread-utils.h"
static const char *pack_usage[] = {
- "git pack-objects --stdout [options...] [< ref-list | < object-list]",
- "git pack-objects [options...] base-name [< ref-list | < object-list]",
+ N_("git pack-objects --stdout [options...] [< ref-list | < object-list]"),
+ N_("git pack-objects [options...] base-name [< ref-list | < object-list]"),
NULL
};
int rev_list_unpacked = 0, rev_list_all = 0, rev_list_reflog = 0;
struct option pack_objects_options[] = {
OPT_SET_INT('q', "quiet", &progress,
- "do not show progress meter", 0),
+ N_("do not show progress meter"), 0),
OPT_SET_INT(0, "progress", &progress,
- "show progress meter", 1),
+ N_("show progress meter"), 1),
OPT_SET_INT(0, "all-progress", &progress,
- "show progress meter during object writing phase", 2),
+ N_("show progress meter during object writing phase"), 2),
OPT_BOOL(0, "all-progress-implied",
&all_progress_implied,
- "similar to --all-progress when progress meter is shown"),
- { OPTION_CALLBACK, 0, "index-version", NULL, "version[,offset]",
- "write the pack index file in the specified idx format version",
+ N_("similar to --all-progress when progress meter is shown")),
+ { OPTION_CALLBACK, 0, "index-version", NULL, N_("version[,offset]"),
+ N_("write the pack index file in the specified idx format version"),
0, option_parse_index_version },
OPT_ULONG(0, "max-pack-size", &pack_size_limit,
- "maximum size of each output pack file"),
+ N_("maximum size of each output pack file")),
OPT_BOOL(0, "local", &local,
- "ignore borrowed objects from alternate object store"),
+ N_("ignore borrowed objects from alternate object store")),
OPT_BOOL(0, "incremental", &incremental,
- "ignore packed objects"),
+ N_("ignore packed objects")),
OPT_INTEGER(0, "window", &window,
- "limit pack window by objects"),
+ N_("limit pack window by objects")),
OPT_ULONG(0, "window-memory", &window_memory_limit,
- "limit pack window by memory in addition to object limit"),
+ N_("limit pack window by memory in addition to object limit")),
OPT_INTEGER(0, "depth", &depth,
- "maximum length of delta chain allowed in the resulting pack"),
+ N_("maximum length of delta chain allowed in the resulting pack")),
OPT_BOOL(0, "reuse-delta", &reuse_delta,
- "reuse existing deltas"),
+ N_("reuse existing deltas")),
OPT_BOOL(0, "reuse-object", &reuse_object,
- "reuse existing objects"),
+ N_("reuse existing objects")),
OPT_BOOL(0, "delta-base-offset", &allow_ofs_delta,
- "use OFS_DELTA objects"),
+ N_("use OFS_DELTA objects")),
OPT_INTEGER(0, "threads", &delta_search_threads,
- "use threads when searching for best delta matches"),
+ N_("use threads when searching for best delta matches")),
OPT_BOOL(0, "non-empty", &non_empty,
- "do not create an empty pack output"),
+ N_("do not create an empty pack output")),
OPT_BOOL(0, "revs", &use_internal_rev_list,
- "read revision arguments from standard input"),
+ N_("read revision arguments from standard input")),
{ OPTION_SET_INT, 0, "unpacked", &rev_list_unpacked, NULL,
- "limit the objects to those that are not yet packed",
+ N_("limit the objects to those that are not yet packed"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },
{ OPTION_SET_INT, 0, "all", &rev_list_all, NULL,
- "include objects reachable from any reference",
+ N_("include objects reachable from any reference"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },
{ OPTION_SET_INT, 0, "reflog", &rev_list_reflog, NULL,
- "include objects referred by reflog entries",
+ N_("include objects referred by reflog entries"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 },
OPT_BOOL(0, "stdout", &pack_to_stdout,
- "output pack to stdout"),
+ N_("output pack to stdout")),
OPT_BOOL(0, "include-tag", &include_tag,
- "include tag objects that refer to objects to be packed"),
+ N_("include tag objects that refer to objects to be packed")),
OPT_BOOL(0, "keep-unreachable", &keep_unreachable,
- "keep unreachable objects"),
- { OPTION_CALLBACK, 0, "unpack-unreachable", NULL, "time",
- "unpack unreachable objects newer than <time>",
+ N_("keep unreachable objects")),
+ { OPTION_CALLBACK, 0, "unpack-unreachable", NULL, N_("time"),
+ N_("unpack unreachable objects newer than <time>"),
PARSE_OPT_OPTARG, option_parse_unpack_unreachable },
OPT_BOOL(0, "thin", &thin,
- "create thin packs"),
+ N_("create thin packs")),
OPT_BOOL(0, "honor-pack-keep", &ignore_packed_keep,
- "ignore packs that have companion .keep file"),
+ N_("ignore packs that have companion .keep file")),
OPT_INTEGER(0, "compression", &pack_compression_level,
- "pack compression level"),
+ N_("pack compression level")),
OPT_SET_INT(0, "keep-true-parents", &grafts_replace_parents,
- "do not hide commits by grafts", 0),
+ N_("do not hide commits by grafts"), 0),
OPT_END(),
};
#include "pack-refs.h"
static char const * const pack_refs_usage[] = {
- "git pack-refs [options]",
+ N_("git pack-refs [options]"),
NULL
};
{
unsigned int flags = PACK_REFS_PRUNE;
struct option opts[] = {
- OPT_BIT(0, "all", &flags, "pack everything", PACK_REFS_ALL),
- OPT_BIT(0, "prune", &flags, "prune loose refs (default)", PACK_REFS_PRUNE),
+ OPT_BIT(0, "all", &flags, N_("pack everything"), PACK_REFS_ALL),
+ OPT_BIT(0, "prune", &flags, N_("prune loose refs (default)"), PACK_REFS_PRUNE),
OPT_END(),
};
if (parse_options(argc, argv, prefix, opts, pack_refs_usage, 0))
#include "parse-options.h"
static const char * const prune_packed_usage[] = {
- "git prune-packed [-n|--dry-run] [-q|--quiet]",
+ N_("git prune-packed [-n|--dry-run] [-q|--quiet]"),
NULL
};
{
int opts = isatty(2) ? VERBOSE : 0;
const struct option prune_packed_options[] = {
- OPT_BIT('n', "dry-run", &opts, "dry run", DRY_RUN),
- OPT_NEGBIT('q', "quiet", &opts, "be quiet", VERBOSE),
+ OPT_BIT('n', "dry-run", &opts, N_("dry run"), DRY_RUN),
+ OPT_NEGBIT('q', "quiet", &opts, N_("be quiet"), VERBOSE),
OPT_END()
};
#include "dir.h"
static const char * const prune_usage[] = {
- "git prune [-n] [-v] [--expire <time>] [--] [<head>...]",
+ N_("git prune [-n] [-v] [--expire <time>] [--] [<head>...]"),
NULL
};
static int show_only;
struct rev_info revs;
struct progress *progress = NULL;
const struct option options[] = {
- OPT__DRY_RUN(&show_only, "do not remove, show only"),
- OPT__VERBOSE(&verbose, "report pruned objects"),
- OPT_BOOL(0, "progress", &show_progress, "show progress"),
+ OPT__DRY_RUN(&show_only, N_("do not remove, show only")),
+ OPT__VERBOSE(&verbose, N_("report pruned objects")),
+ OPT_BOOL(0, "progress", &show_progress, N_("show progress")),
OPT_DATE(0, "expire", &expire,
- "expire objects older than <time>"),
+ N_("expire objects older than <time>")),
OPT_END()
};
char *s;
#include "submodule.h"
static const char * const push_usage[] = {
- "git push [<options>] [<repository> [<refspec>...]]",
+ N_("git push [<options>] [<repository> [<refspec>...]]"),
NULL,
};
add_refspec(refspec.buf);
}
+static char warn_unspecified_push_default_msg[] =
+N_("push.default is unset; its implicit value is changing in\n"
+ "Git 2.0 from 'matching' to 'simple'. To squelch this message\n"
+ "and maintain the current behavior after the default changes, use:\n"
+ "\n"
+ " git config --global push.default matching\n"
+ "\n"
+ "To squelch this message and adopt the new behavior now, use:\n"
+ "\n"
+ " git config --global push.default simple\n"
+ "\n"
+ "See 'git help config' and search for 'push.default' for further information.\n"
+ "(the 'simple' mode was introduced in Git 1.7.11. Use the similar mode\n"
+ "'current' instead of 'simple' if you sometimes use older versions of Git)");
+
+static void warn_unspecified_push_default_configuration(void)
+{
+ static int warn_once;
+
+ if (warn_once++)
+ return;
+ warning("%s\n", _(warn_unspecified_push_default_msg));
+}
+
static void setup_default_push_refspecs(struct remote *remote)
{
switch (push_default) {
default:
case PUSH_DEFAULT_UNSPECIFIED:
default_matching_used = 1;
+ warn_unspecified_push_default_configuration();
/* fallthru */
case PUSH_DEFAULT_MATCHING:
add_refspec(":");
static const char message_advice_use_upstream[] =
N_("Updates were rejected because a pushed branch tip is behind its remote\n"
"counterpart. If you did not intend to push that branch, you may want to\n"
- "specify branches to push or set the 'push.default' configuration\n"
- "variable to 'current' or 'upstream' to push only the current branch.");
+ "specify branches to push or set the 'push.default' configuration variable\n"
+ "to 'simple', 'current' or 'upstream' to push only the current branch.");
static const char message_advice_checkout_pull_push[] =
N_("Updates were rejected because a pushed branch tip is behind its remote\n"
const char *repo = NULL; /* default repository */
struct option options[] = {
OPT__VERBOSITY(&verbosity),
- OPT_STRING( 0 , "repo", &repo, "repository", "repository"),
- OPT_BIT( 0 , "all", &flags, "push all refs", TRANSPORT_PUSH_ALL),
- OPT_BIT( 0 , "mirror", &flags, "mirror all refs",
+ OPT_STRING( 0 , "repo", &repo, N_("repository"), N_("repository")),
+ OPT_BIT( 0 , "all", &flags, N_("push all refs"), TRANSPORT_PUSH_ALL),
+ OPT_BIT( 0 , "mirror", &flags, N_("mirror all refs"),
(TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)),
- OPT_BOOLEAN( 0, "delete", &deleterefs, "delete refs"),
- OPT_BOOLEAN( 0 , "tags", &tags, "push tags (can't be used with --all or --mirror)"),
- OPT_BIT('n' , "dry-run", &flags, "dry run", TRANSPORT_PUSH_DRY_RUN),
- OPT_BIT( 0, "porcelain", &flags, "machine-readable output", TRANSPORT_PUSH_PORCELAIN),
- OPT_BIT('f', "force", &flags, "force updates", TRANSPORT_PUSH_FORCE),
- { OPTION_CALLBACK, 0, "recurse-submodules", &flags, "check",
- "controls recursive pushing of submodules",
+ OPT_BOOLEAN( 0, "delete", &deleterefs, N_("delete refs")),
+ OPT_BOOLEAN( 0 , "tags", &tags, N_("push tags (can't be used with --all or --mirror)")),
+ OPT_BIT('n' , "dry-run", &flags, N_("dry run"), TRANSPORT_PUSH_DRY_RUN),
+ OPT_BIT( 0, "porcelain", &flags, N_("machine-readable output"), TRANSPORT_PUSH_PORCELAIN),
+ OPT_BIT('f', "force", &flags, N_("force updates"), TRANSPORT_PUSH_FORCE),
+ { OPTION_CALLBACK, 0, "recurse-submodules", &flags, N_("check"),
+ N_("control recursive pushing of submodules"),
PARSE_OPT_OPTARG, option_parse_recurse_submodules },
- OPT_BOOLEAN( 0 , "thin", &thin, "use thin pack"),
- OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", "receive pack program"),
- OPT_STRING( 0 , "exec", &receivepack, "receive-pack", "receive pack program"),
- OPT_BIT('u', "set-upstream", &flags, "set upstream for git pull/status",
+ OPT_BOOLEAN( 0 , "thin", &thin, N_("use thin pack")),
+ OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", N_("receive pack program")),
+ OPT_STRING( 0 , "exec", &receivepack, "receive-pack", N_("receive pack program")),
+ OPT_BIT('u', "set-upstream", &flags, N_("set upstream for git pull/status"),
TRANSPORT_PUSH_SET_UPSTREAM),
- OPT_BOOL(0, "progress", &progress, "force progress reporting"),
- OPT_BIT(0, "prune", &flags, "prune locally removed refs",
+ OPT_BOOL(0, "progress", &progress, N_("force progress reporting")),
+ OPT_BIT(0, "prune", &flags, N_("prune locally removed refs"),
TRANSPORT_PUSH_PRUNE),
OPT_END()
};
}
static const char * const read_tree_usage[] = {
- "git read-tree [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] [-u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] [--index-output=<file>] (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])",
+ N_("git read-tree [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] [-u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] [--index-output=<file>] (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])"),
NULL
};
struct unpack_trees_options opts;
int prefix_set = 0;
const struct option read_tree_options[] = {
- { OPTION_CALLBACK, 0, "index-output", NULL, "file",
- "write resulting index to <file>",
+ { OPTION_CALLBACK, 0, "index-output", NULL, N_("file"),
+ N_("write resulting index to <file>"),
PARSE_OPT_NONEG, index_output_cb },
OPT_SET_INT(0, "empty", &read_empty,
- "only empty the index", 1),
- OPT__VERBOSE(&opts.verbose_update, "be verbose"),
- OPT_GROUP("Merging"),
+ N_("only empty the index"), 1),
+ OPT__VERBOSE(&opts.verbose_update, N_("be verbose")),
+ OPT_GROUP(N_("Merging")),
OPT_SET_INT('m', NULL, &opts.merge,
- "perform a merge in addition to a read", 1),
+ N_("perform a merge in addition to a read"), 1),
OPT_SET_INT(0, "trivial", &opts.trivial_merges_only,
- "3-way merge if no file level merging required", 1),
+ N_("3-way merge if no file level merging required"), 1),
OPT_SET_INT(0, "aggressive", &opts.aggressive,
- "3-way merge in presence of adds and removes", 1),
+ N_("3-way merge in presence of adds and removes"), 1),
OPT_SET_INT(0, "reset", &opts.reset,
- "same as -m, but discard unmerged entries", 1),
- { OPTION_STRING, 0, "prefix", &opts.prefix, "<subdirectory>/",
- "read the tree into the index under <subdirectory>/",
+ N_("same as -m, but discard unmerged entries"), 1),
+ { OPTION_STRING, 0, "prefix", &opts.prefix, N_("<subdirectory>/"),
+ N_("read the tree into the index under <subdirectory>/"),
PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP },
OPT_SET_INT('u', NULL, &opts.update,
- "update working tree with merge result", 1),
+ N_("update working tree with merge result"), 1),
{ OPTION_CALLBACK, 0, "exclude-per-directory", &opts,
- "gitignore",
- "allow explicitly ignored files to be overwritten",
+ N_("gitignore"),
+ N_("allow explicitly ignored files to be overwritten"),
PARSE_OPT_NONEG, exclude_per_directory_cb },
OPT_SET_INT('i', NULL, &opts.index_only,
- "don't check the working tree after merging", 1),
- OPT__DRY_RUN(&opts.dry_run, "don't update the index or the work tree"),
+ N_("don't check the working tree after merging"), 1),
+ OPT__DRY_RUN(&opts.dry_run, N_("don't update the index or the work tree")),
OPT_SET_INT(0, "no-sparse-checkout", &opts.skip_sparse_checkout,
- "skip applying sparse checkout filter", 1),
+ N_("skip applying sparse checkout filter"), 1),
OPT_SET_INT(0, "debug-unpack", &opts.debug_unpack,
- "debug unpack-trees", 1),
+ N_("debug unpack-trees"), 1),
OPT_END()
};
#include "refs.h"
static const char * const builtin_remote_usage[] = {
- "git remote [-v | --verbose]",
- "git remote add [-t <branch>] [-m <master>] [-f] [--tags|--no-tags] [--mirror=<fetch|push>] <name> <url>",
- "git remote rename <old> <new>",
- "git remote rm <name>",
- "git remote set-head <name> (-a | -d | <branch>)",
- "git remote [-v | --verbose] show [-n] <name>",
- "git remote prune [-n | --dry-run] <name>",
- "git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]",
- "git remote set-branches [--add] <name> <branch>...",
- "git remote set-url [--push] <name> <newurl> [<oldurl>]",
- "git remote set-url --add <name> <newurl>",
- "git remote set-url --delete <name> <url>",
+ N_("git remote [-v | --verbose]"),
+ N_("git remote add [-t <branch>] [-m <master>] [-f] [--tags|--no-tags] [--mirror=<fetch|push>] <name> <url>"),
+ N_("git remote rename <old> <new>"),
+ N_("git remote rm <name>"),
+ N_("git remote set-head <name> (-a | -d | <branch>)"),
+ N_("git remote [-v | --verbose] show [-n] <name>"),
+ N_("git remote prune [-n | --dry-run] <name>"),
+ N_("git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]"),
+ N_("git remote set-branches [--add] <name> <branch>..."),
+ N_("git remote set-url [--push] <name> <newurl> [<oldurl>]"),
+ N_("git remote set-url --add <name> <newurl>"),
+ N_("git remote set-url --delete <name> <url>"),
NULL
};
static const char * const builtin_remote_add_usage[] = {
- "git remote add [<options>] <name> <url>",
+ N_("git remote add [<options>] <name> <url>"),
NULL
};
static const char * const builtin_remote_rename_usage[] = {
- "git remote rename <old> <new>",
+ N_("git remote rename <old> <new>"),
NULL
};
static const char * const builtin_remote_rm_usage[] = {
- "git remote rm <name>",
+ N_("git remote rm <name>"),
NULL
};
static const char * const builtin_remote_sethead_usage[] = {
- "git remote set-head <name> (-a | -d | <branch>])",
+ N_("git remote set-head <name> (-a | -d | <branch>])"),
NULL
};
static const char * const builtin_remote_setbranches_usage[] = {
- "git remote set-branches <name> <branch>...",
- "git remote set-branches --add <name> <branch>...",
+ N_("git remote set-branches <name> <branch>..."),
+ N_("git remote set-branches --add <name> <branch>..."),
NULL
};
static const char * const builtin_remote_show_usage[] = {
- "git remote show [<options>] <name>",
+ N_("git remote show [<options>] <name>"),
NULL
};
static const char * const builtin_remote_prune_usage[] = {
- "git remote prune [<options>] <name>",
+ N_("git remote prune [<options>] <name>"),
NULL
};
static const char * const builtin_remote_update_usage[] = {
- "git remote update [<options>] [<group> | <remote>]...",
+ N_("git remote update [<options>] [<group> | <remote>]..."),
NULL
};
static const char * const builtin_remote_seturl_usage[] = {
- "git remote set-url [--push] <name> <newurl> [<oldurl>]",
- "git remote set-url --add <name> <newurl>",
- "git remote set-url --delete <name> <url>",
+ N_("git remote set-url [--push] <name> <newurl> [<oldurl>]"),
+ N_("git remote set-url --add <name> <newurl>"),
+ N_("git remote set-url --delete <name> <url>"),
NULL
};
int i;
struct option options[] = {
- OPT_BOOLEAN('f', "fetch", &fetch, "fetch the remote branches"),
+ OPT_BOOLEAN('f', "fetch", &fetch, N_("fetch the remote branches")),
OPT_SET_INT(0, "tags", &fetch_tags,
- "import all tags and associated objects when fetching",
+ N_("import all tags and associated objects when fetching"),
TAGS_SET),
OPT_SET_INT(0, NULL, &fetch_tags,
- "or do not fetch any tag at all (--no-tags)", TAGS_UNSET),
- OPT_STRING_LIST('t', "track", &track, "branch",
- "branch(es) to track"),
- OPT_STRING('m', "master", &master, "branch", "master branch"),
- { OPTION_CALLBACK, 0, "mirror", &mirror, "push|fetch",
- "set up remote as a mirror to push to or fetch from",
+ N_("or do not fetch any tag at all (--no-tags)"), TAGS_UNSET),
+ OPT_STRING_LIST('t', "track", &track, N_("branch"),
+ N_("branch(es) to track")),
+ OPT_STRING('m', "master", &master, N_("branch"), N_("master branch")),
+ { OPTION_CALLBACK, 0, "mirror", &mirror, N_("push|fetch"),
+ N_("set up remote as a mirror to push to or fetch from"),
PARSE_OPT_OPTARG, parse_mirror_opt },
OPT_END()
};
{
int no_query = 0, result = 0, query_flag = 0;
struct option options[] = {
- OPT_BOOLEAN('n', NULL, &no_query, "do not query remotes"),
+ OPT_BOOLEAN('n', NULL, &no_query, N_("do not query remotes")),
OPT_END()
};
struct ref_states states;
struct option options[] = {
OPT_BOOLEAN('a', "auto", &opt_a,
- "set refs/remotes/<name>/HEAD according to remote"),
+ N_("set refs/remotes/<name>/HEAD according to remote")),
OPT_BOOLEAN('d', "delete", &opt_d,
- "delete refs/remotes/<name>/HEAD"),
+ N_("delete refs/remotes/<name>/HEAD")),
OPT_END()
};
argc = parse_options(argc, argv, NULL, options, builtin_remote_sethead_usage,
{
int dry_run = 0, result = 0;
struct option options[] = {
- OPT__DRY_RUN(&dry_run, "dry run"),
+ OPT__DRY_RUN(&dry_run, N_("dry run")),
OPT_END()
};
int i, prune = 0;
struct option options[] = {
OPT_BOOLEAN('p', "prune", &prune,
- "prune remotes after fetching"),
+ N_("prune remotes after fetching")),
OPT_END()
};
const char **fetch_argv;
{
int add_mode = 0;
struct option options[] = {
- OPT_BOOLEAN('\0', "add", &add_mode, "add branch"),
+ OPT_BOOLEAN('\0', "add", &add_mode, N_("add branch")),
OPT_END()
};
struct strbuf name_buf = STRBUF_INIT;
struct option options[] = {
OPT_BOOLEAN('\0', "push", &push_mode,
- "manipulate push URLs"),
+ N_("manipulate push URLs")),
OPT_BOOLEAN('\0', "add", &add_mode,
- "add URL"),
+ N_("add URL")),
OPT_BOOLEAN('\0', "delete", &delete_mode,
- "delete URLs"),
+ N_("delete URLs")),
OPT_END()
};
argc = parse_options(argc, argv, NULL, options, builtin_remote_seturl_usage,
int cmd_remote(int argc, const char **argv, const char *prefix)
{
struct option options[] = {
- OPT__VERBOSE(&verbose, "be verbose; must be placed before a subcommand"),
+ OPT__VERBOSE(&verbose, N_("be verbose; must be placed before a subcommand")),
OPT_END()
};
int result;
#include "parse-options.h"
static const char * const git_replace_usage[] = {
- "git replace [-f] <object> <replacement>",
- "git replace -d <object>...",
- "git replace -l [<pattern>]",
+ N_("git replace [-f] <object> <replacement>"),
+ N_("git replace -d <object>..."),
+ N_("git replace -l [<pattern>]"),
NULL
};
{
int list = 0, delete = 0, force = 0;
struct option options[] = {
- OPT_BOOLEAN('l', NULL, &list, "list replace refs"),
- OPT_BOOLEAN('d', NULL, &delete, "delete replace refs"),
- OPT_BOOLEAN('f', NULL, &force, "replace the ref if it exists"),
+ OPT_BOOLEAN('l', NULL, &list, N_("list replace refs")),
+ OPT_BOOLEAN('d', NULL, &delete, N_("delete replace refs")),
+ OPT_BOOLEAN('f', NULL, &force, N_("replace the ref if it exists")),
OPT_END()
};
#include "xdiff-interface.h"
static const char * const rerere_usage[] = {
- "git rerere [clear | forget path... | status | remaining | diff | gc]",
+ N_("git rerere [clear | forget path... | status | remaining | diff | gc]"),
NULL,
};
struct option options[] = {
OPT_SET_INT(0, "rerere-autoupdate", &autoupdate,
- "register clean resolutions in index", 1),
+ N_("register clean resolutions in index"), 1),
OPT_END(),
};
#include "cache-tree.h"
static const char * const git_reset_usage[] = {
- "git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]",
- "git reset [-q] <commit> [--] <paths>...",
- "git reset --patch [<commit>] [--] [<paths>...]",
+ N_("git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"),
+ N_("git reset [-q] <commit> [--] <paths>..."),
+ N_("git reset --patch [<commit>] [--] [<paths>...]"),
NULL
};
struct commit *commit;
struct strbuf msg = STRBUF_INIT;
const struct option options[] = {
- OPT__QUIET(&quiet, "be quiet, only report errors"),
+ OPT__QUIET(&quiet, N_("be quiet, only report errors")),
OPT_SET_INT(0, "mixed", &reset_type,
- "reset HEAD and index", MIXED),
- OPT_SET_INT(0, "soft", &reset_type, "reset only HEAD", SOFT),
+ N_("reset HEAD and index"), MIXED),
+ OPT_SET_INT(0, "soft", &reset_type, N_("reset only HEAD"), SOFT),
OPT_SET_INT(0, "hard", &reset_type,
- "reset HEAD, index and working tree", HARD),
+ N_("reset HEAD, index and working tree"), HARD),
OPT_SET_INT(0, "merge", &reset_type,
- "reset HEAD, index and working tree", MERGE),
+ N_("reset HEAD, index and working tree"), MERGE),
OPT_SET_INT(0, "keep", &reset_type,
- "reset HEAD but keep local changes", KEEP),
- OPT_BOOLEAN('p', "patch", &patch_mode, "select hunks interactively"),
+ N_("reset HEAD but keep local changes"), KEEP),
+ OPT_BOOLEAN('p', "patch", &patch_mode, N_("select hunks interactively")),
OPT_END()
};
const char *next;
const char *this;
int symmetric;
+ static const char head_by_default[] = "HEAD";
if (!(dotdot = strstr(arg, "..")))
return 0;
next += symmetric;
if (!*next)
- next = "HEAD";
+ next = head_by_default;
if (dotdot == arg)
- this = "HEAD";
+ this = head_by_default;
+
+ if (this == head_by_default && next == head_by_default &&
+ !symmetric) {
+ /*
+ * Just ".."? That is not a range but the
+ * pathspec for the parent directory.
+ */
+ *dotdot = '.';
+ return 0;
+ }
+
if (!get_sha1_committish(this, sha1) && !get_sha1_committish(next, end)) {
show_rev(NORMAL, end, next);
show_rev(symmetric ? NORMAL : REVERSED, sha1, this);
{
static int keep_dashdash = 0, stop_at_non_option = 0;
static char const * const parseopt_usage[] = {
- "git rev-parse --parseopt [options] -- [<args>...]",
+ N_("git rev-parse --parseopt [options] -- [<args>...]"),
NULL
};
static struct option parseopt_opts[] = {
OPT_BOOLEAN(0, "keep-dashdash", &keep_dashdash,
- "keep the `--` passed as an arg"),
+ N_("keep the `--` passed as an arg")),
OPT_BOOLEAN(0, "stop-at-non-option", &stop_at_non_option,
- "stop parsing after the "
- "first non-option argument"),
+ N_("stop parsing after the "
+ "first non-option argument")),
OPT_END(),
};
}
static const char builtin_rev_parse_usage[] =
-"git rev-parse --parseopt [options] -- [<args>...]\n"
-" or: git rev-parse --sq-quote [<arg>...]\n"
-" or: git rev-parse [options] [<arg>...]\n"
-"\n"
-"Run \"git rev-parse --parseopt -h\" for more information on the first usage.";
+N_("git rev-parse --parseopt [options] -- [<args>...]\n"
+ " or: git rev-parse --sq-quote [<arg>...]\n"
+ " or: git rev-parse [options] [<arg>...]\n"
+ "\n"
+ "Run \"git rev-parse --parseopt -h\" for more information on the first usage.");
int cmd_rev_parse(int argc, const char **argv, const char *prefix)
{
*/
static const char * const revert_usage[] = {
- "git revert [options] <commit-ish>",
- "git revert <subcommand>",
+ N_("git revert [options] <commit-ish>"),
+ N_("git revert <subcommand>"),
NULL
};
static const char * const cherry_pick_usage[] = {
- "git cherry-pick [options] <commit-ish>",
- "git cherry-pick <subcommand>",
+ N_("git cherry-pick [options] <commit-ish>"),
+ N_("git cherry-pick <subcommand>"),
NULL
};
int contin = 0;
int rollback = 0;
struct option options[] = {
- OPT_BOOLEAN(0, "quit", &remove_state, "end revert or cherry-pick sequence"),
- OPT_BOOLEAN(0, "continue", &contin, "resume revert or cherry-pick sequence"),
- OPT_BOOLEAN(0, "abort", &rollback, "cancel revert or cherry-pick sequence"),
- OPT_BOOLEAN('n', "no-commit", &opts->no_commit, "don't automatically commit"),
- OPT_BOOLEAN('e', "edit", &opts->edit, "edit the commit message"),
+ OPT_BOOLEAN(0, "quit", &remove_state, N_("end revert or cherry-pick sequence")),
+ OPT_BOOLEAN(0, "continue", &contin, N_("resume revert or cherry-pick sequence")),
+ OPT_BOOLEAN(0, "abort", &rollback, N_("cancel revert or cherry-pick sequence")),
+ OPT_BOOLEAN('n', "no-commit", &opts->no_commit, N_("don't automatically commit")),
+ OPT_BOOLEAN('e', "edit", &opts->edit, N_("edit the commit message")),
OPT_NOOP_NOARG('r', NULL),
- OPT_BOOLEAN('s', "signoff", &opts->signoff, "add Signed-off-by:"),
- OPT_INTEGER('m', "mainline", &opts->mainline, "parent number"),
+ OPT_BOOLEAN('s', "signoff", &opts->signoff, N_("add Signed-off-by:")),
+ OPT_INTEGER('m', "mainline", &opts->mainline, N_("parent number")),
OPT_RERERE_AUTOUPDATE(&opts->allow_rerere_auto),
- OPT_STRING(0, "strategy", &opts->strategy, "strategy", "merge strategy"),
- OPT_CALLBACK('X', "strategy-option", &opts, "option",
- "option for merge strategy", option_parse_x),
+ OPT_STRING(0, "strategy", &opts->strategy, N_("strategy"), N_("merge strategy")),
+ OPT_CALLBACK('X', "strategy-option", &opts, N_("option"),
+ N_("option for merge strategy"), option_parse_x),
+ OPT_END(),
OPT_END(),
OPT_END(),
OPT_END(),
if (opts->action == REPLAY_PICK) {
struct option cp_extra[] = {
- OPT_BOOLEAN('x', NULL, &opts->record_origin, "append commit name"),
- OPT_BOOLEAN(0, "ff", &opts->allow_ff, "allow fast-forward"),
- OPT_BOOLEAN(0, "allow-empty", &opts->allow_empty, "preserve initially empty commits"),
- OPT_BOOLEAN(0, "keep-redundant-commits", &opts->keep_redundant_commits, "keep redundant, empty commits"),
+ OPT_BOOLEAN('x', NULL, &opts->record_origin, N_("append commit name")),
+ OPT_BOOLEAN(0, "ff", &opts->allow_ff, N_("allow fast-forward")),
+ OPT_BOOLEAN(0, "allow-empty", &opts->allow_empty, N_("preserve initially empty commits")),
+ OPT_BOOLEAN(0, "allow-empty-message", &opts->allow_empty_message, N_("allow commits with empty messages")),
+ OPT_BOOLEAN(0, "keep-redundant-commits", &opts->keep_redundant_commits, N_("keep redundant, empty commits")),
OPT_END(),
};
if (parse_options_concat(options, ARRAY_SIZE(options), cp_extra))
struct setup_revision_opt s_r_opt;
opts->revs = xmalloc(sizeof(*opts->revs));
init_revisions(opts->revs, NULL);
- opts->revs->no_walk = 1;
+ opts->revs->no_walk = REVISION_WALK_NO_WALK_UNSORTED;
if (argc < 2)
usage_with_options(usage_str, options);
memset(&s_r_opt, 0, sizeof(s_r_opt));
#include "parse-options.h"
static const char * const builtin_rm_usage[] = {
- "git rm [options] [--] <file>...",
+ N_("git rm [options] [--] <file>..."),
NULL
};
static int ignore_unmatch = 0;
static struct option builtin_rm_options[] = {
- OPT__DRY_RUN(&show_only, "dry run"),
- OPT__QUIET(&quiet, "do not list removed files"),
- OPT_BOOLEAN( 0 , "cached", &index_only, "only remove from the index"),
- OPT__FORCE(&force, "override the up-to-date check"),
- OPT_BOOLEAN('r', NULL, &recursive, "allow recursive removal"),
+ OPT__DRY_RUN(&show_only, N_("dry run")),
+ OPT__QUIET(&quiet, N_("do not list removed files")),
+ OPT_BOOLEAN( 0 , "cached", &index_only, N_("only remove from the index")),
+ OPT__FORCE(&force, N_("override the up-to-date check")),
+ OPT_BOOLEAN('r', NULL, &recursive, N_("allow recursive removal")),
OPT_BOOLEAN( 0 , "ignore-unmatch", &ignore_unmatch,
- "exit with a zero status even if nothing matched"),
+ N_("exit with a zero status even if nothing matched")),
OPT_END(),
};
#include "parse-options.h"
static char const * const shortlog_usage[] = {
- "git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [<commit-id>... ]",
+ N_("git shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [<commit-id>... ]"),
"",
- "[rev-opts] are documented in git-rev-list(1)",
+ N_("[rev-opts] are documented in git-rev-list(1)"),
NULL
};
static const struct option options[] = {
OPT_BOOLEAN('n', "numbered", &log.sort_by_number,
- "sort output according to the number of commits per author"),
+ N_("sort output according to the number of commits per author")),
OPT_BOOLEAN('s', "summary", &log.summary,
- "Suppress commit descriptions, only provides commit count"),
+ N_("Suppress commit descriptions, only provides commit count")),
OPT_BOOLEAN('e', "email", &log.email,
- "Show the email address of each author"),
- { OPTION_CALLBACK, 'w', NULL, &log, "w[,i1[,i2]]",
- "Linewrap output", PARSE_OPT_OPTARG, &parse_wrap_args },
+ N_("Show the email address of each author")),
+ { OPTION_CALLBACK, 'w', NULL, &log, N_("w[,i1[,i2]]"),
+ N_("Linewrap output"), PARSE_OPT_OPTARG, &parse_wrap_args },
OPT_END(),
};
#include "parse-options.h"
static const char* show_branch_usage[] = {
- "git show-branch [-a|--all] [-r|--remotes] [--topo-order | --date-order] [--current] [--color[=<when>] | --no-color] [--sparse] [--more=<n> | --list | --independent | --merge-base] [--no-name | --sha1-name] [--topics] [(<rev> | <glob>)...]",
- "git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]",
+ N_("git show-branch [-a|--all] [-r|--remotes] [--topo-order | --date-order] [--current] [--color[=<when>] | --no-color] [--sparse] [--more=<n> | --list | --independent | --merge-base] [--no-name | --sha1-name] [--topics] [(<rev> | <glob>)...]"),
+ N_("git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]"),
NULL
};
const char *reflog_base = NULL;
struct option builtin_show_branch_options[] = {
OPT_BOOLEAN('a', "all", &all_heads,
- "show remote-tracking and local branches"),
+ N_("show remote-tracking and local branches")),
OPT_BOOLEAN('r', "remotes", &all_remotes,
- "show remote-tracking branches"),
+ N_("show remote-tracking branches")),
OPT__COLOR(&showbranch_use_color,
- "color '*!+-' corresponding to the branch"),
- { OPTION_INTEGER, 0, "more", &extra, "n",
- "show <n> more commits after the common ancestor",
+ N_("color '*!+-' corresponding to the branch")),
+ { OPTION_INTEGER, 0, "more", &extra, N_("n"),
+ N_("show <n> more commits after the common ancestor"),
PARSE_OPT_OPTARG, NULL, (intptr_t)1 },
- OPT_SET_INT(0, "list", &extra, "synonym to more=-1", -1),
- OPT_BOOLEAN(0, "no-name", &no_name, "suppress naming strings"),
+ OPT_SET_INT(0, "list", &extra, N_("synonym to more=-1"), -1),
+ OPT_BOOLEAN(0, "no-name", &no_name, N_("suppress naming strings")),
OPT_BOOLEAN(0, "current", &with_current_branch,
- "include the current branch"),
+ N_("include the current branch")),
OPT_BOOLEAN(0, "sha1-name", &sha1_name,
- "name commits with their object names"),
+ N_("name commits with their object names")),
OPT_BOOLEAN(0, "merge-base", &merge_base,
- "show possible merge bases"),
+ N_("show possible merge bases")),
OPT_BOOLEAN(0, "independent", &independent,
- "show refs unreachable from any other ref"),
+ N_("show refs unreachable from any other ref")),
OPT_BOOLEAN(0, "topo-order", &lifo,
- "show commits in topological order"),
+ N_("show commits in topological order")),
OPT_BOOLEAN(0, "topics", &topics,
- "show only commits not on the first branch"),
+ N_("show only commits not on the first branch")),
OPT_SET_INT(0, "sparse", &dense,
- "show merges reachable from only one tip", 0),
+ N_("show merges reachable from only one tip"), 0),
OPT_SET_INT(0, "date-order", &lifo,
- "show commits where no parent comes before its "
- "children", 0),
- { OPTION_CALLBACK, 'g', "reflog", &reflog_base, "<n>[,<base>]",
- "show <n> most recent ref-log entries starting at "
- "base",
+ N_("show commits where no parent comes before its "
+ "children"), 0),
+ { OPTION_CALLBACK, 'g', "reflog", &reflog_base, N_("<n>[,<base>]"),
+ N_("show <n> most recent ref-log entries starting at "
+ "base"),
PARSE_OPT_OPTARG | PARSE_OPT_LITERAL_ARGHELP,
parse_reflog_param },
OPT_END()
#include "parse-options.h"
static const char * const show_ref_usage[] = {
- "git show-ref [-q|--quiet] [--verify] [--head] [-d|--dereference] [-s|--hash[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [pattern*] ",
- "git show-ref --exclude-existing[=pattern] < ref-list",
+ N_("git show-ref [-q|--quiet] [--verify] [--head] [-d|--dereference] [-s|--hash[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [pattern*] "),
+ N_("git show-ref --exclude-existing[=pattern] < ref-list"),
NULL
};
}
static const struct option show_ref_options[] = {
- OPT_BOOLEAN(0, "tags", &tags_only, "only show tags (can be combined with heads)"),
- OPT_BOOLEAN(0, "heads", &heads_only, "only show heads (can be combined with tags)"),
- OPT_BOOLEAN(0, "verify", &verify, "stricter reference checking, "
- "requires exact ref path"),
+ OPT_BOOLEAN(0, "tags", &tags_only, N_("only show tags (can be combined with heads)")),
+ OPT_BOOLEAN(0, "heads", &heads_only, N_("only show heads (can be combined with tags)")),
+ OPT_BOOLEAN(0, "verify", &verify, N_("stricter reference checking, "
+ "requires exact ref path")),
{ OPTION_BOOLEAN, 'h', NULL, &show_head, NULL,
- "show the HEAD reference",
+ N_("show the HEAD reference"),
PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
- OPT_BOOLEAN(0, "head", &show_head, "show the HEAD reference"),
+ OPT_BOOLEAN(0, "head", &show_head, N_("show the HEAD reference")),
OPT_BOOLEAN('d', "dereference", &deref_tags,
- "dereference tags into object IDs"),
- { OPTION_CALLBACK, 's', "hash", &abbrev, "n",
- "only show SHA1 hash using <n> digits",
+ N_("dereference tags into object IDs")),
+ { OPTION_CALLBACK, 's', "hash", &abbrev, N_("n"),
+ N_("only show SHA1 hash using <n> digits"),
PARSE_OPT_OPTARG, &hash_callback },
OPT__ABBREV(&abbrev),
OPT__QUIET(&quiet,
- "do not print results to stdout (useful with --verify)"),
+ N_("do not print results to stdout (useful with --verify)")),
{ OPTION_CALLBACK, 0, "exclude-existing", &exclude_existing_arg,
- "pattern", "show refs from stdin that aren't in local repository",
+ N_("pattern"), N_("show refs from stdin that aren't in local repository"),
PARSE_OPT_OPTARG | PARSE_OPT_NONEG, exclude_existing_callback },
- { OPTION_CALLBACK, 0, "help-all", NULL, NULL, "show usage",
+ { OPTION_CALLBACK, 0, "help-all", NULL, NULL, N_("show usage"),
PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, help_callback },
OPT_END()
};
#include "parse-options.h"
static const char * const git_symbolic_ref_usage[] = {
- "git symbolic-ref [options] name [ref]",
+ N_("git symbolic-ref [options] name [ref]"),
NULL
};
const char *msg = NULL;
struct option options[] = {
OPT__QUIET(&quiet,
- "suppress error message for non-symbolic (detached) refs"),
- OPT_BOOL(0, "short", &shorten, "shorten ref output"),
- OPT_STRING('m', NULL, &msg, "reason", "reason of the update"),
+ N_("suppress error message for non-symbolic (detached) refs")),
+ OPT_BOOL(0, "short", &shorten, N_("shorten ref output")),
+ OPT_STRING('m', NULL, &msg, N_("reason"), N_("reason of the update")),
OPT_END(),
};
#include "column.h"
static const char * const git_tag_usage[] = {
- "git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]",
- "git tag -d <tagname>...",
- "git tag -l [-n[<num>]] [--contains <commit>] [--points-at <object>] "
- "\n\t\t[<pattern>...]",
- "git tag -v <tagname>...",
+ N_("git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]"),
+ N_("git tag -d <tagname>..."),
+ N_("git tag -l [-n[<num>]] [--contains <commit>] [--points-at <object>] "
+ "\n\t\t[<pattern>...]"),
+ N_("git tag -v <tagname>..."),
NULL
};
struct msg_arg msg = { 0, STRBUF_INIT };
struct commit_list *with_commit = NULL;
struct option options[] = {
- OPT_BOOLEAN('l', "list", &list, "list tag names"),
- { OPTION_INTEGER, 'n', NULL, &lines, "n",
- "print <n> lines of each tag message",
+ OPT_BOOLEAN('l', "list", &list, N_("list tag names")),
+ { OPTION_INTEGER, 'n', NULL, &lines, N_("n"),
+ N_("print <n> lines of each tag message"),
PARSE_OPT_OPTARG, NULL, 1 },
- OPT_BOOLEAN('d', "delete", &delete, "delete tags"),
- OPT_BOOLEAN('v', "verify", &verify, "verify tags"),
+ OPT_BOOLEAN('d', "delete", &delete, N_("delete tags")),
+ OPT_BOOLEAN('v', "verify", &verify, N_("verify tags")),
- OPT_GROUP("Tag creation options"),
+ OPT_GROUP(N_("Tag creation options")),
OPT_BOOLEAN('a', "annotate", &annotate,
- "annotated tag, needs a message"),
- OPT_CALLBACK('m', "message", &msg, "message",
- "tag message", parse_msg_arg),
- OPT_FILENAME('F', "file", &msgfile, "read message from file"),
- OPT_BOOLEAN('s', "sign", &opt.sign, "annotated and GPG-signed tag"),
- OPT_STRING(0, "cleanup", &cleanup_arg, "mode",
- "how to strip spaces and #comments from message"),
- OPT_STRING('u', "local-user", &keyid, "key-id",
- "use another key to sign the tag"),
- OPT__FORCE(&force, "replace the tag if exists"),
- OPT_COLUMN(0, "column", &colopts, "show tag list in columns"),
-
- OPT_GROUP("Tag listing options"),
+ N_("annotated tag, needs a message")),
+ OPT_CALLBACK('m', "message", &msg, N_("message"),
+ N_("tag message"), parse_msg_arg),
+ OPT_FILENAME('F', "file", &msgfile, N_("read message from file")),
+ OPT_BOOLEAN('s', "sign", &opt.sign, N_("annotated and GPG-signed tag")),
+ OPT_STRING(0, "cleanup", &cleanup_arg, N_("mode"),
+ N_("how to strip spaces and #comments from message")),
+ OPT_STRING('u', "local-user", &keyid, N_("key id"),
+ N_("use another key to sign the tag")),
+ OPT__FORCE(&force, N_("replace the tag if exists")),
+ OPT_COLUMN(0, "column", &colopts, N_("show tag list in columns")),
+
+ OPT_GROUP(N_("Tag listing options")),
{
- OPTION_CALLBACK, 0, "contains", &with_commit, "commit",
- "print only tags that contain the commit",
+ OPTION_CALLBACK, 0, "contains", &with_commit, N_("commit"),
+ N_("print only tags that contain the commit"),
PARSE_OPT_LASTARG_DEFAULT,
parse_opt_with_commit, (intptr_t)"HEAD",
},
{
- OPTION_CALLBACK, 0, "points-at", NULL, "object",
- "print only tags of the object", 0, parse_opt_points_at
+ OPTION_CALLBACK, 0, "points-at", NULL, N_("object"),
+ N_("print only tags of the object"), 0, parse_opt_points_at
},
OPT_END()
};
}
static const char * const update_index_usage[] = {
- "git update-index [options] [--] [<file>...]",
+ N_("git update-index [options] [--] [<file>...]"),
NULL
};
int parseopt_state = PARSE_OPT_UNKNOWN;
struct option options[] = {
OPT_BIT('q', NULL, &refresh_args.flags,
- "continue refresh even when index needs update",
+ N_("continue refresh even when index needs update"),
REFRESH_QUIET),
OPT_BIT(0, "ignore-submodules", &refresh_args.flags,
- "refresh: ignore submodules",
+ N_("refresh: ignore submodules"),
REFRESH_IGNORE_SUBMODULES),
OPT_SET_INT(0, "add", &allow_add,
- "do not ignore new files", 1),
+ N_("do not ignore new files"), 1),
OPT_SET_INT(0, "replace", &allow_replace,
- "let files replace directories and vice-versa", 1),
+ N_("let files replace directories and vice-versa"), 1),
OPT_SET_INT(0, "remove", &allow_remove,
- "notice files missing from worktree", 1),
+ N_("notice files missing from worktree"), 1),
OPT_BIT(0, "unmerged", &refresh_args.flags,
- "refresh even if index contains unmerged entries",
+ N_("refresh even if index contains unmerged entries"),
REFRESH_UNMERGED),
{OPTION_CALLBACK, 0, "refresh", &refresh_args, NULL,
- "refresh stat information",
+ N_("refresh stat information"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG,
refresh_callback},
{OPTION_CALLBACK, 0, "really-refresh", &refresh_args, NULL,
- "like --refresh, but ignore assume-unchanged setting",
+ N_("like --refresh, but ignore assume-unchanged setting"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG,
really_refresh_callback},
{OPTION_LOWLEVEL_CALLBACK, 0, "cacheinfo", NULL,
- "<mode> <object> <path>",
- "add the specified entry to the index",
+ N_("<mode> <object> <path>"),
+ N_("add the specified entry to the index"),
PARSE_OPT_NOARG | /* disallow --cacheinfo=<mode> form */
PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP,
(parse_opt_cb *) cacheinfo_callback},
- {OPTION_CALLBACK, 0, "chmod", &set_executable_bit, "(+/-)x",
- "override the executable bit of the listed files",
+ {OPTION_CALLBACK, 0, "chmod", &set_executable_bit, N_("(+/-)x"),
+ N_("override the executable bit of the listed files"),
PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP,
chmod_callback},
{OPTION_SET_INT, 0, "assume-unchanged", &mark_valid_only, NULL,
- "mark files as \"not changing\"",
+ N_("mark files as \"not changing\""),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, MARK_FLAG},
{OPTION_SET_INT, 0, "no-assume-unchanged", &mark_valid_only, NULL,
- "clear assumed-unchanged bit",
+ N_("clear assumed-unchanged bit"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, UNMARK_FLAG},
{OPTION_SET_INT, 0, "skip-worktree", &mark_skip_worktree_only, NULL,
- "mark files as \"index-only\"",
+ N_("mark files as \"index-only\""),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, MARK_FLAG},
{OPTION_SET_INT, 0, "no-skip-worktree", &mark_skip_worktree_only, NULL,
- "clear skip-worktree bit",
+ N_("clear skip-worktree bit"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, UNMARK_FLAG},
OPT_SET_INT(0, "info-only", &info_only,
- "add to index only; do not add content to object database", 1),
+ N_("add to index only; do not add content to object database"), 1),
OPT_SET_INT(0, "force-remove", &force_remove,
- "remove named paths even if present in worktree", 1),
+ N_("remove named paths even if present in worktree"), 1),
OPT_SET_INT('z', NULL, &line_termination,
- "with --stdin: input lines are terminated by null bytes", '\0'),
+ N_("with --stdin: input lines are terminated by null bytes"), '\0'),
{OPTION_LOWLEVEL_CALLBACK, 0, "stdin", &read_from_stdin, NULL,
- "read list of paths to be updated from standard input",
+ N_("read list of paths to be updated from standard input"),
PARSE_OPT_NONEG | PARSE_OPT_NOARG,
(parse_opt_cb *) stdin_callback},
{OPTION_LOWLEVEL_CALLBACK, 0, "index-info", &line_termination, NULL,
- "add entries from standard input to the index",
+ N_("add entries from standard input to the index"),
PARSE_OPT_NONEG | PARSE_OPT_NOARG,
(parse_opt_cb *) stdin_cacheinfo_callback},
{OPTION_LOWLEVEL_CALLBACK, 0, "unresolve", &has_errors, NULL,
- "repopulate stages #2 and #3 for the listed paths",
+ N_("repopulate stages #2 and #3 for the listed paths"),
PARSE_OPT_NONEG | PARSE_OPT_NOARG,
(parse_opt_cb *) unresolve_callback},
{OPTION_LOWLEVEL_CALLBACK, 'g', "again", &has_errors, NULL,
- "only update entries that differ from HEAD",
+ N_("only update entries that differ from HEAD"),
PARSE_OPT_NONEG | PARSE_OPT_NOARG,
(parse_opt_cb *) reupdate_callback},
OPT_BIT(0, "ignore-missing", &refresh_args.flags,
- "ignore files missing from worktree",
+ N_("ignore files missing from worktree"),
REFRESH_IGNORE_MISSING),
OPT_SET_INT(0, "verbose", &verbose,
- "report actions to standard output", 1),
+ N_("report actions to standard output"), 1),
{OPTION_CALLBACK, 0, "clear-resolve-undo", NULL, NULL,
- "(for porcelains) forget saved unresolved conflicts",
+ N_("(for porcelains) forget saved unresolved conflicts"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG,
resolve_undo_clear_callback},
OPT_INTEGER(0, "index-version", &preferred_index_format,
- "write index in this format"),
+ N_("write index in this format")),
OPT_END()
};
#include "parse-options.h"
static const char * const git_update_ref_usage[] = {
- "git update-ref [options] -d <refname> [<oldval>]",
- "git update-ref [options] <refname> <newval> [<oldval>]",
+ N_("git update-ref [options] -d <refname> [<oldval>]"),
+ N_("git update-ref [options] <refname> <newval> [<oldval>]"),
NULL
};
unsigned char sha1[20], oldsha1[20];
int delete = 0, no_deref = 0, flags = 0;
struct option options[] = {
- OPT_STRING( 'm', NULL, &msg, "reason", "reason of the update"),
- OPT_BOOLEAN('d', NULL, &delete, "deletes the reference"),
+ OPT_STRING( 'm', NULL, &msg, N_("reason"), N_("reason of the update")),
+ OPT_BOOLEAN('d', NULL, &delete, N_("delete the reference")),
OPT_BOOLEAN( 0 , "no-deref", &no_deref,
- "update <refname> not the one it points to"),
+ N_("update <refname> not the one it points to")),
OPT_END(),
};
#include "parse-options.h"
static const char * const update_server_info_usage[] = {
- "git update-server-info [--force]",
+ N_("git update-server-info [--force]"),
NULL
};
{
int force = 0;
struct option options[] = {
- OPT__FORCE(&force, "update the info files from scratch"),
+ OPT__FORCE(&force, N_("update the info files from scratch")),
OPT_END()
};
}
static const char * const verify_pack_usage[] = {
- "git verify-pack [-v|--verbose] [-s|--stat-only] <pack>...",
+ N_("git verify-pack [-v|--verbose] [-s|--stat-only] <pack>..."),
NULL
};
unsigned int flags = 0;
int i;
const struct option verify_pack_options[] = {
- OPT_BIT('v', "verbose", &flags, "verbose",
+ OPT_BIT('v', "verbose", &flags, N_("verbose"),
VERIFY_PACK_VERBOSE),
- OPT_BIT('s', "stat-only", &flags, "show statistics only",
+ OPT_BIT('s', "stat-only", &flags, N_("show statistics only"),
VERIFY_PACK_STAT_ONLY),
OPT_END()
};
#include "gpg-interface.h"
static const char * const verify_tag_usage[] = {
- "git verify-tag [-v|--verbose] <tag>...",
+ N_("git verify-tag [-v|--verbose] <tag>..."),
NULL
};
{
int i = 1, verbose = 0, had_error = 0;
const struct option verify_tag_options[] = {
- OPT__VERBOSE(&verbose, "print tag contents"),
+ OPT__VERBOSE(&verbose, N_("print tag contents")),
OPT_END()
};
#include "parse-options.h"
static const char * const write_tree_usage[] = {
- "git write-tree [--missing-ok] [--prefix=<prefix>/]",
+ N_("git write-tree [--missing-ok] [--prefix=<prefix>/]"),
NULL
};
unsigned char sha1[20];
const char *me = "git-write-tree";
struct option write_tree_options[] = {
- OPT_BIT(0, "missing-ok", &flags, "allow missing objects",
+ OPT_BIT(0, "missing-ok", &flags, N_("allow missing objects"),
WRITE_TREE_MISSING_OK),
- { OPTION_STRING, 0, "prefix", &prefix, "<prefix>/",
- "write tree object for a subdirectory <prefix>" ,
+ { OPTION_STRING, 0, "prefix", &prefix, N_("<prefix>/"),
+ N_("write tree object for a subdirectory <prefix>") ,
PARSE_OPT_LITERAL_ARGHELP },
{ OPTION_BIT, 0, "ignore-cache-tree", &flags, NULL,
- "only useful for debugging",
+ N_("only useful for debugging"),
PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, NULL,
WRITE_TREE_IGNORE_CACHE_TREE },
OPT_END()
return result;
}
+static int find_invalid_utf8(const char *buf, int len)
+{
+ int offset = 0;
+
+ while (len) {
+ unsigned char c = *buf++;
+ int bytes, bad_offset;
+
+ len--;
+ offset++;
+
+ /* Simple US-ASCII? No worries. */
+ if (c < 0x80)
+ continue;
+
+ bad_offset = offset-1;
+
+ /*
+ * Count how many more high bits set: that's how
+ * many more bytes this sequence should have.
+ */
+ bytes = 0;
+ while (c & 0x40) {
+ c <<= 1;
+ bytes++;
+ }
+
+ /* Must be between 1 and 5 more bytes */
+ if (bytes < 1 || bytes > 5)
+ return bad_offset;
+
+ /* Do we *have* that many bytes? */
+ if (len < bytes)
+ return bad_offset;
+
+ offset += bytes;
+ len -= bytes;
+
+ /* And verify that they are good continuation bytes */
+ do {
+ if ((*buf++ & 0xc0) != 0x80)
+ return bad_offset;
+ } while (--bytes);
+
+ /* We could/should check the value and length here too */
+ }
+ return -1;
+}
+
+/*
+ * This verifies that the buffer is in proper utf8 format.
+ *
+ * If it isn't, it assumes any non-utf8 characters are Latin1,
+ * and does the conversion.
+ *
+ * Fixme: we should probably also disallow overlong forms and
+ * invalid characters. But we don't do that currently.
+ */
+static int verify_utf8(struct strbuf *buf)
+{
+ int ok = 1;
+ long pos = 0;
+
+ for (;;) {
+ int bad;
+ unsigned char c;
+ unsigned char replace[2];
+
+ bad = find_invalid_utf8(buf->buf + pos, buf->len - pos);
+ if (bad < 0)
+ return ok;
+ pos += bad;
+ ok = 0;
+ c = buf->buf[pos];
+ strbuf_remove(buf, pos, 1);
+
+ /* We know 'c' must be in the range 128-255 */
+ replace[0] = 0xc0 + (c >> 6);
+ replace[1] = 0x80 + (c & 0x3f);
+ strbuf_insert(buf, pos, replace, 2);
+ pos += 2;
+ }
+}
+
static const char commit_utf8_warn[] =
-"Warning: commit message does not conform to UTF-8.\n"
+"Warning: commit message did not conform to UTF-8.\n"
"You may want to amend it after fixing the message, or set the config\n"
"variable i18n.commitencoding to the encoding your project uses.\n";
strbuf_addbuf(&buffer, msg);
/* And check the encoding */
- if (encoding_is_utf8 && !is_utf8(buffer.buf))
+ if (encoding_is_utf8 && !verify_utf8(&buffer))
fprintf(stderr, commit_utf8_warn);
if (sign_commit && do_sign_commit(&buffer, sign_commit))
--- /dev/null
+#include "../git-compat-util.h"
+#undef mkdir
+
+/* for platforms that can't deal with a trailing '/' */
+int compat_mkdir_wo_trailing_slash(const char *dir, mode_t mode)
+{
+ int retval;
+ char *tmp_dir = NULL;
+ size_t len = strlen(dir);
+
+ if (len && dir[len-1] == '/') {
+ if ((tmp_dir = strdup(dir)) == NULL)
+ return -1;
+ tmp_dir[len-1] = '\0';
+ }
+ else
+ tmp_dir = (char *)dir;
+
+ retval = mkdir(tmp_dir, mode);
+ if (tmp_dir != dir)
+ free(tmp_dir);
+
+ return retval;
+}
path = buf.buf;
}
- if (!access(path, R_OK)) {
+ if (!access_or_warn(path, R_OK)) {
if (++inc->depth > MAX_INCLUDE_DEPTH)
die(include_depth_advice, MAX_INCLUDE_DEPTH, path,
cf && cf->name ? cf->name : "the command line");
home_config_paths(&user_config, &xdg_config, "config");
- if (git_config_system() && !access(git_etc_gitconfig(), R_OK)) {
+ if (git_config_system() && !access_or_warn(git_etc_gitconfig(), R_OK)) {
ret += git_config_from_file(fn, git_etc_gitconfig(),
data);
found += 1;
}
- if (xdg_config && !access(xdg_config, R_OK)) {
+ if (xdg_config && !access_or_warn(xdg_config, R_OK)) {
ret += git_config_from_file(fn, xdg_config, data);
found += 1;
}
- if (user_config && !access(user_config, R_OK)) {
+ if (user_config && !access_or_warn(user_config, R_OK)) {
ret += git_config_from_file(fn, user_config, data);
found += 1;
}
- if (repo_config && !access(repo_config, R_OK)) {
+ if (repo_config && !access_or_warn(repo_config, R_OK)) {
ret += git_config_from_file(fn, repo_config, data);
found += 1;
}
}
__git_mergetools_common="diffuse ecmerge emerge kdiff3 meld opendiff
- tkdiff vimdiff gvimdiff xxdiff araxis p4merge bc3
+ tkdiff vimdiff gvimdiff xxdiff araxis p4merge bc3 codecompare
"
_git_difftool ()
--- /dev/null
+git-credential-gnome-keyring
--- /dev/null
+MAIN:=git-credential-gnome-keyring
+all:: $(MAIN)
+
+CC = gcc
+RM = rm -f
+CFLAGS = -g -O2 -Wall
+
+-include ../../../config.mak.autogen
+-include ../../../config.mak
+
+INCS:=$(shell pkg-config --cflags gnome-keyring-1)
+LIBS:=$(shell pkg-config --libs gnome-keyring-1)
+
+SRCS:=$(MAIN).c
+OBJS:=$(SRCS:.c=.o)
+
+%.o: %.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) $(INCS) -o $@ -c $<
+
+$(MAIN): $(OBJS)
+ $(CC) -o $@ $(LDFLAGS) $^ $(LIBS)
+
+clean:
+ @$(RM) $(MAIN) $(OBJS)
--- /dev/null
+/*
+ * Copyright (C) 2011 John Szakmeister <john@szakmeister.net>
+ * 2012 Philipp A. Hartmann <pah@qo.cx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * Credits:
+ * - GNOME Keyring API handling originally written by John Szakmeister
+ * - ported to credential helper API by Philipp A. Hartmann
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <gnome-keyring.h>
+
+/*
+ * This credential struct and API is simplified from git's credential.{h,c}
+ */
+struct credential
+{
+ char *protocol;
+ char *host;
+ unsigned short port;
+ char *path;
+ char *username;
+ char *password;
+};
+
+#define CREDENTIAL_INIT \
+ { NULL,NULL,0,NULL,NULL,NULL }
+
+void credential_init(struct credential *c);
+void credential_clear(struct credential *c);
+int credential_read(struct credential *c);
+void credential_write(const struct credential *c);
+
+typedef int (*credential_op_cb)(struct credential*);
+
+struct credential_operation
+{
+ char *name;
+ credential_op_cb op;
+};
+
+#define CREDENTIAL_OP_END \
+ { NULL,NULL }
+
+/*
+ * Table with operation callbacks is defined in concrete
+ * credential helper implementation and contains entries
+ * like { "get", function_to_get_credential } terminated
+ * by CREDENTIAL_OP_END.
+ */
+struct credential_operation const credential_helper_ops[];
+
+/* ---------------- common helper functions ----------------- */
+
+static inline void free_password(char *password)
+{
+ char *c = password;
+ if (!password)
+ return;
+
+ while (*c) *c++ = '\0';
+ free(password);
+}
+
+static inline void warning(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ fprintf(stderr, "warning: ");
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n" );
+ va_end(ap);
+}
+
+static inline void error(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ fprintf(stderr, "error: ");
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n" );
+ va_end(ap);
+}
+
+static inline void die(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap,fmt);
+ error(fmt, ap);
+ va_end(ap);
+ exit(EXIT_FAILURE);
+}
+
+static inline void die_errno(int err)
+{
+ error("%s", strerror(err));
+ exit(EXIT_FAILURE);
+}
+
+static inline char *xstrdup(const char *str)
+{
+ char *ret = strdup(str);
+ if (!ret)
+ die_errno(errno);
+
+ return ret;
+}
+
+/* ----------------- GNOME Keyring functions ----------------- */
+
+/* create a special keyring option string, if path is given */
+static char* keyring_object(struct credential *c)
+{
+ char* object = NULL;
+
+ if (!c->path)
+ return object;
+
+ object = (char*) malloc(strlen(c->host)+strlen(c->path)+8);
+ if(!object)
+ die_errno(errno);
+
+ if(c->port)
+ sprintf(object,"%s:%hd/%s",c->host,c->port,c->path);
+ else
+ sprintf(object,"%s/%s",c->host,c->path);
+
+ return object;
+}
+
+int keyring_get(struct credential *c)
+{
+ char* object = NULL;
+ GList *entries;
+ GnomeKeyringNetworkPasswordData *password_data;
+ GnomeKeyringResult result;
+
+ if (!c->protocol || !(c->host || c->path))
+ return EXIT_FAILURE;
+
+ object = keyring_object(c);
+
+ result = gnome_keyring_find_network_password_sync(
+ c->username,
+ NULL /* domain */,
+ c->host,
+ object,
+ c->protocol,
+ NULL /* authtype */,
+ c->port,
+ &entries);
+
+ free(object);
+
+ if (result == GNOME_KEYRING_RESULT_NO_MATCH)
+ return EXIT_SUCCESS;
+
+ if (result == GNOME_KEYRING_RESULT_CANCELLED)
+ return EXIT_SUCCESS;
+
+ if (result != GNOME_KEYRING_RESULT_OK) {
+ error("%s",gnome_keyring_result_to_message(result));
+ return EXIT_FAILURE;
+ }
+
+ /* pick the first one from the list */
+ password_data = (GnomeKeyringNetworkPasswordData *) entries->data;
+
+ free_password(c->password);
+ c->password = xstrdup(password_data->password);
+
+ if (!c->username)
+ c->username = xstrdup(password_data->user);
+
+ gnome_keyring_network_password_list_free(entries);
+
+ return EXIT_SUCCESS;
+}
+
+
+int keyring_store(struct credential *c)
+{
+ guint32 item_id;
+ char *object = NULL;
+
+ /*
+ * Sanity check that what we are storing is actually sensible.
+ * In particular, we can't make a URL without a protocol field.
+ * Without either a host or pathname (depending on the scheme),
+ * we have no primary key. And without a username and password,
+ * we are not actually storing a credential.
+ */
+ if (!c->protocol || !(c->host || c->path) ||
+ !c->username || !c->password)
+ return EXIT_FAILURE;
+
+ object = keyring_object(c);
+
+ gnome_keyring_set_network_password_sync(
+ GNOME_KEYRING_DEFAULT,
+ c->username,
+ NULL /* domain */,
+ c->host,
+ object,
+ c->protocol,
+ NULL /* authtype */,
+ c->port,
+ c->password,
+ &item_id);
+
+ free(object);
+ return EXIT_SUCCESS;
+}
+
+int keyring_erase(struct credential *c)
+{
+ char *object = NULL;
+ GList *entries;
+ GnomeKeyringNetworkPasswordData *password_data;
+ GnomeKeyringResult result;
+
+ /*
+ * Sanity check that we actually have something to match
+ * against. The input we get is a restrictive pattern,
+ * so technically a blank credential means "erase everything".
+ * But it is too easy to accidentally send this, since it is equivalent
+ * to empty input. So explicitly disallow it, and require that the
+ * pattern have some actual content to match.
+ */
+ if (!c->protocol && !c->host && !c->path && !c->username)
+ return EXIT_FAILURE;
+
+ object = keyring_object(c);
+
+ result = gnome_keyring_find_network_password_sync(
+ c->username,
+ NULL /* domain */,
+ c->host,
+ object,
+ c->protocol,
+ NULL /* authtype */,
+ c->port,
+ &entries);
+
+ free(object);
+
+ if (result == GNOME_KEYRING_RESULT_NO_MATCH)
+ return EXIT_SUCCESS;
+
+ if (result == GNOME_KEYRING_RESULT_CANCELLED)
+ return EXIT_SUCCESS;
+
+ if (result != GNOME_KEYRING_RESULT_OK)
+ {
+ error("%s",gnome_keyring_result_to_message(result));
+ return EXIT_FAILURE;
+ }
+
+ /* pick the first one from the list (delete all matches?) */
+ password_data = (GnomeKeyringNetworkPasswordData *) entries->data;
+
+ result = gnome_keyring_item_delete_sync(
+ password_data->keyring, password_data->item_id);
+
+ gnome_keyring_network_password_list_free(entries);
+
+ if (result != GNOME_KEYRING_RESULT_OK)
+ {
+ error("%s",gnome_keyring_result_to_message(result));
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+/*
+ * Table with helper operation callbacks, used by generic
+ * credential helper main function.
+ */
+struct credential_operation const credential_helper_ops[] =
+{
+ { "get", keyring_get },
+ { "store", keyring_store },
+ { "erase", keyring_erase },
+ CREDENTIAL_OP_END
+};
+
+/* ------------------ credential functions ------------------ */
+
+void credential_init(struct credential *c)
+{
+ memset(c, 0, sizeof(*c));
+}
+
+void credential_clear(struct credential *c)
+{
+ free(c->protocol);
+ free(c->host);
+ free(c->path);
+ free(c->username);
+ free_password(c->password);
+
+ credential_init(c);
+}
+
+int credential_read(struct credential *c)
+{
+ char buf[1024];
+ ssize_t line_len = 0;
+ char *key = buf;
+ char *value;
+
+ while (fgets(buf, sizeof(buf), stdin))
+ {
+ line_len = strlen(buf);
+
+ if(buf[line_len-1]=='\n')
+ buf[--line_len]='\0';
+
+ if(!line_len)
+ break;
+
+ value = strchr(buf,'=');
+ if(!value) {
+ warning("invalid credential line: %s", key);
+ return -1;
+ }
+ *value++ = '\0';
+
+ if (!strcmp(key, "protocol")) {
+ free(c->protocol);
+ c->protocol = xstrdup(value);
+ } else if (!strcmp(key, "host")) {
+ free(c->host);
+ c->host = xstrdup(value);
+ value = strrchr(c->host,':');
+ if (value) {
+ *value++ = '\0';
+ c->port = atoi(value);
+ }
+ } else if (!strcmp(key, "path")) {
+ free(c->path);
+ c->path = xstrdup(value);
+ } else if (!strcmp(key, "username")) {
+ free(c->username);
+ c->username = xstrdup(value);
+ } else if (!strcmp(key, "password")) {
+ free_password(c->password);
+ c->password = xstrdup(value);
+ while (*value) *value++ = '\0';
+ }
+ /*
+ * Ignore other lines; we don't know what they mean, but
+ * this future-proofs us when later versions of git do
+ * learn new lines, and the helpers are updated to match.
+ */
+ }
+ return 0;
+}
+
+void credential_write_item(FILE *fp, const char *key, const char *value)
+{
+ if (!value)
+ return;
+ fprintf(fp, "%s=%s\n", key, value);
+}
+
+void credential_write(const struct credential *c)
+{
+ /* only write username/password, if set */
+ credential_write_item(stdout, "username", c->username);
+ credential_write_item(stdout, "password", c->password);
+}
+
+static void usage(const char *name)
+{
+ struct credential_operation const *try_op = credential_helper_ops;
+ const char *basename = strrchr(name,'/');
+
+ basename = (basename) ? basename + 1 : name;
+ fprintf(stderr, "Usage: %s <", basename);
+ while(try_op->name) {
+ fprintf(stderr,"%s",(try_op++)->name);
+ if(try_op->name)
+ fprintf(stderr,"%s","|");
+ }
+ fprintf(stderr,"%s",">\n");
+}
+
+int main(int argc, char *argv[])
+{
+ int ret = EXIT_SUCCESS;
+
+ struct credential_operation const *try_op = credential_helper_ops;
+ struct credential cred = CREDENTIAL_INIT;
+
+ if (!argv[1]) {
+ usage(argv[0]);
+ goto out;
+ }
+
+ /* lookup operation callback */
+ while(try_op->name && strcmp(argv[1], try_op->name))
+ try_op++;
+
+ /* unsupported operation given -- ignore silently */
+ if(!try_op->name || !try_op->op)
+ goto out;
+
+ ret = credential_read(&cred);
+ if(ret)
+ goto out;
+
+ /* perform credential operation */
+ ret = (*try_op->op)(&cred);
+
+ credential_write(&cred);
+
+out:
+ credential_clear(&cred);
+ return ret;
+}
--- /dev/null
+all: git-credential-wincred.exe
+
+CC = gcc
+RM = rm -f
+CFLAGS = -O2 -Wall
+
+-include ../../../config.mak.autogen
+-include ../../../config.mak
+
+git-credential-wincred.exe : git-credential-wincred.c
+ $(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@
+
+clean:
+ $(RM) git-credential-wincred.exe
--- /dev/null
+/*
+ * A git credential helper that interface with Windows' Credential Manager
+ *
+ */
+#include <windows.h>
+#include <stdio.h>
+#include <io.h>
+#include <fcntl.h>
+
+/* common helpers */
+
+static void die(const char *err, ...)
+{
+ char msg[4096];
+ va_list params;
+ va_start(params, err);
+ vsnprintf(msg, sizeof(msg), err, params);
+ fprintf(stderr, "%s\n", msg);
+ va_end(params);
+ exit(1);
+}
+
+static void *xmalloc(size_t size)
+{
+ void *ret = malloc(size);
+ if (!ret && !size)
+ ret = malloc(1);
+ if (!ret)
+ die("Out of memory");
+ return ret;
+}
+
+static char *xstrdup(const char *str)
+{
+ char *ret = strdup(str);
+ if (!ret)
+ die("Out of memory");
+ return ret;
+}
+
+/* MinGW doesn't have wincred.h, so we need to define stuff */
+
+typedef struct _CREDENTIAL_ATTRIBUTEW {
+ LPWSTR Keyword;
+ DWORD Flags;
+ DWORD ValueSize;
+ LPBYTE Value;
+} CREDENTIAL_ATTRIBUTEW, *PCREDENTIAL_ATTRIBUTEW;
+
+typedef struct _CREDENTIALW {
+ DWORD Flags;
+ DWORD Type;
+ LPWSTR TargetName;
+ LPWSTR Comment;
+ FILETIME LastWritten;
+ DWORD CredentialBlobSize;
+ LPBYTE CredentialBlob;
+ DWORD Persist;
+ DWORD AttributeCount;
+ PCREDENTIAL_ATTRIBUTEW Attributes;
+ LPWSTR TargetAlias;
+ LPWSTR UserName;
+} CREDENTIALW, *PCREDENTIALW;
+
+#define CRED_TYPE_GENERIC 1
+#define CRED_PERSIST_LOCAL_MACHINE 2
+#define CRED_MAX_ATTRIBUTES 64
+
+typedef BOOL (WINAPI *CredWriteWT)(PCREDENTIALW, DWORD);
+typedef BOOL (WINAPI *CredUnPackAuthenticationBufferWT)(DWORD, PVOID, DWORD,
+ LPWSTR, DWORD *, LPWSTR, DWORD *, LPWSTR, DWORD *);
+typedef BOOL (WINAPI *CredEnumerateWT)(LPCWSTR, DWORD, DWORD *,
+ PCREDENTIALW **);
+typedef BOOL (WINAPI *CredPackAuthenticationBufferWT)(DWORD, LPWSTR, LPWSTR,
+ PBYTE, DWORD *);
+typedef VOID (WINAPI *CredFreeT)(PVOID);
+typedef BOOL (WINAPI *CredDeleteWT)(LPCWSTR, DWORD, DWORD);
+
+static HMODULE advapi, credui;
+static CredWriteWT CredWriteW;
+static CredUnPackAuthenticationBufferWT CredUnPackAuthenticationBufferW;
+static CredEnumerateWT CredEnumerateW;
+static CredPackAuthenticationBufferWT CredPackAuthenticationBufferW;
+static CredFreeT CredFree;
+static CredDeleteWT CredDeleteW;
+
+static void load_cred_funcs(void)
+{
+ /* load DLLs */
+ advapi = LoadLibrary("advapi32.dll");
+ credui = LoadLibrary("credui.dll");
+ if (!advapi || !credui)
+ die("failed to load DLLs");
+
+ /* get function pointers */
+ CredWriteW = (CredWriteWT)GetProcAddress(advapi, "CredWriteW");
+ CredUnPackAuthenticationBufferW = (CredUnPackAuthenticationBufferWT)
+ GetProcAddress(credui, "CredUnPackAuthenticationBufferW");
+ CredEnumerateW = (CredEnumerateWT)GetProcAddress(advapi,
+ "CredEnumerateW");
+ CredPackAuthenticationBufferW = (CredPackAuthenticationBufferWT)
+ GetProcAddress(credui, "CredPackAuthenticationBufferW");
+ CredFree = (CredFreeT)GetProcAddress(advapi, "CredFree");
+ CredDeleteW = (CredDeleteWT)GetProcAddress(advapi, "CredDeleteW");
+ if (!CredWriteW || !CredUnPackAuthenticationBufferW ||
+ !CredEnumerateW || !CredPackAuthenticationBufferW || !CredFree ||
+ !CredDeleteW)
+ die("failed to load functions");
+}
+
+static char target_buf[1024];
+static char *protocol, *host, *path, *username;
+static WCHAR *wusername, *password, *target;
+
+static void write_item(const char *what, WCHAR *wbuf)
+{
+ char *buf;
+ int len = WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, NULL, 0, NULL,
+ FALSE);
+ buf = xmalloc(len);
+
+ if (!WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, buf, len, NULL, FALSE))
+ die("WideCharToMultiByte failed!");
+
+ printf("%s=", what);
+ fwrite(buf, 1, len - 1, stdout);
+ putchar('\n');
+ free(buf);
+}
+
+static int match_attr(const CREDENTIALW *cred, const WCHAR *keyword,
+ const char *want)
+{
+ int i;
+ if (!want)
+ return 1;
+
+ for (i = 0; i < cred->AttributeCount; ++i)
+ if (!wcscmp(cred->Attributes[i].Keyword, keyword))
+ return !strcmp((const char *)cred->Attributes[i].Value,
+ want);
+
+ return 0; /* not found */
+}
+
+static int match_cred(const CREDENTIALW *cred)
+{
+ return (!wusername || !wcscmp(wusername, cred->UserName)) &&
+ match_attr(cred, L"git_protocol", protocol) &&
+ match_attr(cred, L"git_host", host) &&
+ match_attr(cred, L"git_path", path);
+}
+
+static void get_credential(void)
+{
+ WCHAR *user_buf, *pass_buf;
+ DWORD user_buf_size = 0, pass_buf_size = 0;
+ CREDENTIALW **creds, *cred = NULL;
+ DWORD num_creds;
+ int i;
+
+ if (!CredEnumerateW(L"git:*", 0, &num_creds, &creds))
+ return;
+
+ /* search for the first credential that matches username */
+ for (i = 0; i < num_creds; ++i)
+ if (match_cred(creds[i])) {
+ cred = creds[i];
+ break;
+ }
+ if (!cred)
+ return;
+
+ CredUnPackAuthenticationBufferW(0, cred->CredentialBlob,
+ cred->CredentialBlobSize, NULL, &user_buf_size, NULL, NULL,
+ NULL, &pass_buf_size);
+
+ user_buf = xmalloc(user_buf_size * sizeof(WCHAR));
+ pass_buf = xmalloc(pass_buf_size * sizeof(WCHAR));
+
+ if (!CredUnPackAuthenticationBufferW(0, cred->CredentialBlob,
+ cred->CredentialBlobSize, user_buf, &user_buf_size, NULL, NULL,
+ pass_buf, &pass_buf_size))
+ die("CredUnPackAuthenticationBuffer failed");
+
+ CredFree(creds);
+
+ /* zero-terminate (sizes include zero-termination) */
+ user_buf[user_buf_size - 1] = L'\0';
+ pass_buf[pass_buf_size - 1] = L'\0';
+
+ write_item("username", user_buf);
+ write_item("password", pass_buf);
+
+ free(user_buf);
+ free(pass_buf);
+}
+
+static void write_attr(CREDENTIAL_ATTRIBUTEW *attr, const WCHAR *keyword,
+ const char *value)
+{
+ attr->Keyword = (LPWSTR)keyword;
+ attr->Flags = 0;
+ attr->ValueSize = strlen(value) + 1; /* store zero-termination */
+ attr->Value = (LPBYTE)value;
+}
+
+static void store_credential(void)
+{
+ CREDENTIALW cred;
+ BYTE *auth_buf;
+ DWORD auth_buf_size = 0;
+ CREDENTIAL_ATTRIBUTEW attrs[CRED_MAX_ATTRIBUTES];
+
+ if (!wusername || !password)
+ return;
+
+ /* query buffer size */
+ CredPackAuthenticationBufferW(0, wusername, password,
+ NULL, &auth_buf_size);
+
+ auth_buf = xmalloc(auth_buf_size);
+
+ if (!CredPackAuthenticationBufferW(0, wusername, password,
+ auth_buf, &auth_buf_size))
+ die("CredPackAuthenticationBuffer failed");
+
+ cred.Flags = 0;
+ cred.Type = CRED_TYPE_GENERIC;
+ cred.TargetName = target;
+ cred.Comment = L"saved by git-credential-wincred";
+ cred.CredentialBlobSize = auth_buf_size;
+ cred.CredentialBlob = auth_buf;
+ cred.Persist = CRED_PERSIST_LOCAL_MACHINE;
+ cred.AttributeCount = 1;
+ cred.Attributes = attrs;
+ cred.TargetAlias = NULL;
+ cred.UserName = wusername;
+
+ write_attr(attrs, L"git_protocol", protocol);
+
+ if (host) {
+ write_attr(attrs + cred.AttributeCount, L"git_host", host);
+ cred.AttributeCount++;
+ }
+
+ if (path) {
+ write_attr(attrs + cred.AttributeCount, L"git_path", path);
+ cred.AttributeCount++;
+ }
+
+ if (!CredWriteW(&cred, 0))
+ die("CredWrite failed");
+}
+
+static void erase_credential(void)
+{
+ CREDENTIALW **creds;
+ DWORD num_creds;
+ int i;
+
+ if (!CredEnumerateW(L"git:*", 0, &num_creds, &creds))
+ return;
+
+ for (i = 0; i < num_creds; ++i) {
+ if (match_cred(creds[i]))
+ CredDeleteW(creds[i]->TargetName, creds[i]->Type, 0);
+ }
+
+ CredFree(creds);
+}
+
+static WCHAR *utf8_to_utf16_dup(const char *str)
+{
+ int wlen = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
+ WCHAR *wstr = xmalloc(sizeof(WCHAR) * wlen);
+ MultiByteToWideChar(CP_UTF8, 0, str, -1, wstr, wlen);
+ return wstr;
+}
+
+static void read_credential(void)
+{
+ char buf[1024];
+
+ while (fgets(buf, sizeof(buf), stdin)) {
+ char *v;
+
+ if (!strcmp(buf, "\n"))
+ break;
+ buf[strlen(buf)-1] = '\0';
+
+ v = strchr(buf, '=');
+ if (!v)
+ die("bad input: %s", buf);
+ *v++ = '\0';
+
+ if (!strcmp(buf, "protocol"))
+ protocol = xstrdup(v);
+ else if (!strcmp(buf, "host"))
+ host = xstrdup(v);
+ else if (!strcmp(buf, "path"))
+ path = xstrdup(v);
+ else if (!strcmp(buf, "username")) {
+ username = xstrdup(v);
+ wusername = utf8_to_utf16_dup(v);
+ } else if (!strcmp(buf, "password"))
+ password = utf8_to_utf16_dup(v);
+ else
+ die("unrecognized input");
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ const char *usage =
+ "Usage: git credential-wincred <get|store|erase>\n";
+
+ if (!argv[1])
+ die(usage);
+
+ /* git use binary pipes to avoid CRLF-issues */
+ _setmode(_fileno(stdin), _O_BINARY);
+ _setmode(_fileno(stdout), _O_BINARY);
+
+ read_credential();
+
+ load_cred_funcs();
+
+ if (!protocol || !(host || path))
+ return 0;
+
+ /* prepare 'target', the unique key for the credential */
+ strncat(target_buf, "git:", sizeof(target_buf));
+ strncat(target_buf, protocol, sizeof(target_buf));
+ strncat(target_buf, "://", sizeof(target_buf));
+ if (username) {
+ strncat(target_buf, username, sizeof(target_buf));
+ strncat(target_buf, "@", sizeof(target_buf));
+ }
+ if (host)
+ strncat(target_buf, host, sizeof(target_buf));
+ if (path) {
+ strncat(target_buf, "/", sizeof(target_buf));
+ strncat(target_buf, path, sizeof(target_buf));
+ }
+
+ target = utf8_to_utf16_dup(target_buf);
+
+ if (!strcmp(argv[1], "get"))
+ get_credential();
+ else if (!strcmp(argv[1], "store"))
+ store_credential();
+ else if (!strcmp(argv[1], "erase"))
+ erase_credential();
+ /* otherwise, ignore unknown action */
+ return 0;
+}
" [--interpolated-path=<path>]\n"
" [--reuseaddr] [--pid-file=<file>]\n"
" [--(enable|disable|allow-override|forbid-override)=<service>]\n"
+" [--access-hook=<path>]\n"
" [--inetd | [--listen=<host_or_ipaddr>] [--port=<n>]\n"
" [--detach] [--user=<user> [--group=<group>]]\n"
" [<directory>...]";
return -1;
}
+static char *access_hook;
+
+static int run_access_hook(struct daemon_service *service, const char *dir, const char *path)
+{
+ struct child_process child;
+ struct strbuf buf = STRBUF_INIT;
+ const char *argv[8];
+ const char **arg = argv;
+ char *eol;
+ int seen_errors = 0;
+
+#define STRARG(x) ((x) ? (x) : "")
+ *arg++ = access_hook;
+ *arg++ = service->name;
+ *arg++ = path;
+ *arg++ = STRARG(hostname);
+ *arg++ = STRARG(canon_hostname);
+ *arg++ = STRARG(ip_address);
+ *arg++ = STRARG(tcp_port);
+ *arg = NULL;
+#undef STRARG
+
+ memset(&child, 0, sizeof(child));
+ child.use_shell = 1;
+ child.argv = argv;
+ child.no_stdin = 1;
+ child.no_stderr = 1;
+ child.out = -1;
+ if (start_command(&child)) {
+ logerror("daemon access hook '%s' failed to start",
+ access_hook);
+ goto error_return;
+ }
+ if (strbuf_read(&buf, child.out, 0) < 0) {
+ logerror("failed to read from pipe to daemon access hook '%s'",
+ access_hook);
+ strbuf_reset(&buf);
+ seen_errors = 1;
+ }
+ if (close(child.out) < 0) {
+ logerror("failed to close pipe to daemon access hook '%s'",
+ access_hook);
+ seen_errors = 1;
+ }
+ if (finish_command(&child))
+ seen_errors = 1;
+
+ if (!seen_errors) {
+ strbuf_release(&buf);
+ return 0;
+ }
+
+error_return:
+ strbuf_ltrim(&buf);
+ if (!buf.len)
+ strbuf_addstr(&buf, "service rejected");
+ eol = strchr(buf.buf, '\n');
+ if (eol)
+ *eol = '\0';
+ errno = EACCES;
+ daemon_error(dir, buf.buf);
+ strbuf_release(&buf);
+ return -1;
+}
+
static int run_service(char *dir, struct daemon_service *service)
{
const char *path;
return daemon_error(dir, "service not enabled");
}
+ /*
+ * Optionally, a hook can choose to deny access to the
+ * repository depending on the phase of the moon.
+ */
+ if (access_hook && run_access_hook(service, dir, path))
+ return -1;
+
/*
* We'll ignore SIGTERM from now on, we have a
* good client.
export_all_trees = 1;
continue;
}
+ if (!prefixcmp(arg, "--access-hook=")) {
+ access_hook = arg + 14;
+ continue;
+ }
if (!prefixcmp(arg, "--timeout=")) {
timeout = atoi(arg+10);
continue;
fd = open(fname, O_RDONLY);
if (fd < 0 || fstat(fd, &st) < 0) {
+ if (errno != ENOENT)
+ warn_on_inaccessible(fname);
if (0 <= fd)
close(fd);
if (!check_index ||
home_config_paths(NULL, &xdg_path, "ignore");
excludes_file = xdg_path;
}
- if (!access(path, R_OK))
+ if (!access_or_warn(path, R_OK))
add_excludes_from_file(dir, path);
- if (excludes_file && !access(excludes_file, R_OK))
+ if (excludes_file && !access_or_warn(excludes_file, R_OK))
add_excludes_from_file(dir, excludes_file);
}
static inline FORMAT_PRESERVING(1) const char *_(const char *msgid)
{
+ if (!*msgid)
+ return "";
return use_gettext_poison() ? "# GETTEXT POISON #" : gettext(msgid);
}
eval_gettextln 'Patch failed at $msgnum $FIRSTLINE'
if test "$(git config --bool advice.amworkdir)" != false
then
- eval_gettextln "The copy of the patch that failed is found in:
- $dotest/patch"
+ eval_gettextln 'The copy of the patch that failed is found in:
+ $dotest/patch'
fi
stop_here_user_resolve $this
fi
#define probe_utf8_pathname_composition(a,b)
#endif
+#ifdef MKDIR_WO_TRAILING_SLASH
+#define mkdir(a,b) compat_mkdir_wo_trailing_slash((a),(b))
+extern int compat_mkdir_wo_trailing_slash(const char*, mode_t);
+#endif
+
#ifndef NO_LIBGEN_H
#include <libgen.h>
#else
*/
int remove_or_warn(unsigned int mode, const char *path);
+/* Call access(2), but warn for any error besides ENOENT. */
+int access_or_warn(const char *path, int mode);
+
+/* Warn on an inaccessible file that ought to be accessible */
+void warn_on_inaccessible(const char *path);
+
/* Get the passwd entry for the UID of the current process. */
struct passwd *xgetpwuid_self(void);
use File::Compare;
use File::Find;
use File::stat;
-use File::Path qw(mkpath);
+use File::Path qw(mkpath rmtree);
use File::Temp qw(tempdir);
use Getopt::Long qw(:config pass_through);
use Git;
-my @tools;
-my @working_tree;
-my $rc;
-my $repo = Git->repository();
-my $repo_path = $repo->repo_path();
-
sub usage
{
my $exitcode = shift;
sub find_worktree
{
+ my ($repo) = @_;
+
# Git->repository->wc_path() does not honor changes to the working
# tree location made by $ENV{GIT_WORK_TREE} or the 'core.worktree'
# config variable.
return $worktree;
}
-my $workdir = find_worktree();
-
sub filter_tool_scripts
{
+ my ($tools) = @_;
if (-d $_) {
if ($_ ne ".") {
# Ignore files in subdirectories
}
} else {
if ((-f $_) && ($_ ne "defaults")) {
- push(@tools, $_);
+ push(@$tools, $_);
}
}
}
sub print_tool_help
{
- my ($cmd, @found, @notfound);
+ my ($cmd, @found, @notfound, @tools);
my $gitpath = Git::exec_path();
- find(\&filter_tool_scripts, "$gitpath/mergetools");
+ find(sub { filter_tool_scripts(\@tools) }, "$gitpath/mergetools");
foreach my $tool (@tools) {
$cmd = "TOOL_MODE=diff";
}
}
- print "'git difftool --tool=<tool>' may be set to one of the following:\n";
+ print << 'EOF';
+'git difftool --tool=<tool>' may be set to one of the following:
+EOF
print "\t$_\n" for (sort(@found));
- print "\nThe following tools are valid, but not currently available:\n";
+ print << 'EOF';
+
+The following tools are valid, but not currently available:
+EOF
print "\t$_\n" for (sort(@notfound));
- print "\nNOTE: Some of the tools listed above only work in a windowed\n";
- print "environment. If run in a terminal-only session, they will fail.\n";
+ print << 'EOF';
+NOTE: Some of the tools listed above only work in a windowed
+environment. If run in a terminal-only session, they will fail.
+EOF
exit(0);
}
+sub exit_cleanup
+{
+ my ($tmpdir, $status) = @_;
+ my $errno = $!;
+ rmtree($tmpdir);
+ if ($status and $errno) {
+ my ($package, $file, $line) = caller();
+ warn "$file line $line: $errno\n";
+ }
+ exit($status | ($status >> 8));
+}
+
sub setup_dir_diff
{
+ my ($repo, $workdir, $symlinks) = @_;
+
# Run the diff; exit immediately if no diff found
# 'Repository' and 'WorkingCopy' must be explicitly set to insure that
# if $GIT_DIR and $GIT_WORK_TREE are set in ENV, they are actually used
# by Git->repository->command*.
- my $diffrepo = Git->repository(Repository => $repo_path, WorkingCopy => $workdir);
- my $diffrtn = $diffrepo->command_oneline('diff', '--raw', '--no-abbrev', '-z', @ARGV);
- exit(0) if (length($diffrtn) == 0);
+ my $repo_path = $repo->repo_path();
+ my %repo_args = (Repository => $repo_path, WorkingCopy => $workdir);
+ my $diffrepo = Git->repository(%repo_args);
- # Setup temp directories
- my $tmpdir = tempdir('git-diffall.XXXXX', CLEANUP => 1, TMPDIR => 1);
- my $ldir = "$tmpdir/left";
- my $rdir = "$tmpdir/right";
- mkpath($ldir) or die $!;
- mkpath($rdir) or die $!;
+ my @gitargs = ('diff', '--raw', '--no-abbrev', '-z', @ARGV);
+ my $diffrtn = $diffrepo->command_oneline(@gitargs);
+ exit(0) unless defined($diffrtn);
# Build index info for left and right sides of the diff
my $submodule_mode = '160000';
my $rindex = '';
my %submodule;
my %symlink;
+ my @working_tree = ();
my @rawdiff = split('\0', $diffrtn);
my $i = 0;
while ($i < $#rawdiff) {
if ($rawdiff[$i] =~ /^::/) {
- print "Combined diff formats ('-c' and '--cc') are not supported in directory diff mode.\n";
+ warn << 'EOF';
+Combined diff formats ('-c' and '--cc') are not supported in
+directory diff mode ('-d' and '--dir-diff').
+EOF
exit(1);
}
- my ($lmode, $rmode, $lsha1, $rsha1, $status) = split(' ', substr($rawdiff[$i], 1));
+ my ($lmode, $rmode, $lsha1, $rsha1, $status) =
+ split(' ', substr($rawdiff[$i], 1));
my $src_path = $rawdiff[$i + 1];
my $dst_path;
$i += 2;
}
- if (($lmode eq $submodule_mode) or ($rmode eq $submodule_mode)) {
+ if ($lmode eq $submodule_mode or $rmode eq $submodule_mode) {
$submodule{$src_path}{left} = $lsha1;
if ($lsha1 ne $rsha1) {
$submodule{$dst_path}{right} = $rsha1;
}
if ($lmode eq $symlink_mode) {
- $symlink{$src_path}{left} = $diffrepo->command_oneline('show', "$lsha1");
+ $symlink{$src_path}{left} =
+ $diffrepo->command_oneline('show', "$lsha1");
}
if ($rmode eq $symlink_mode) {
- $symlink{$dst_path}{right} = $diffrepo->command_oneline('show', "$rsha1");
+ $symlink{$dst_path}{right} =
+ $diffrepo->command_oneline('show', "$rsha1");
}
- if (($lmode ne $null_mode) and ($status !~ /^C/)) {
+ if ($lmode ne $null_mode and $status !~ /^C/) {
$lindex .= "$lmode $lsha1\t$src_path\0";
}
}
}
+ # Setup temp directories
+ my $tmpdir = tempdir('git-difftool.XXXXX', CLEANUP => 0, TMPDIR => 1);
+ my $ldir = "$tmpdir/left";
+ my $rdir = "$tmpdir/right";
+ mkpath($ldir) or exit_cleanup($tmpdir, 1);
+ mkpath($rdir) or exit_cleanup($tmpdir, 1);
+
# If $GIT_DIR is not set prior to calling 'git update-index' and
# 'git checkout-index', then those commands will fail if difftool
# is called from a directory other than the repo root.
# Populate the left and right directories based on each index file
my ($inpipe, $ctx);
$ENV{GIT_INDEX_FILE} = "$tmpdir/lindex";
- ($inpipe, $ctx) = $repo->command_input_pipe(qw/update-index -z --index-info/);
+ ($inpipe, $ctx) =
+ $repo->command_input_pipe(qw(update-index -z --index-info));
print($inpipe $lindex);
$repo->command_close_pipe($inpipe, $ctx);
- $rc = system('git', 'checkout-index', '--all', "--prefix=$ldir/");
- exit($rc | ($rc >> 8)) if ($rc != 0);
+
+ my $rc = system('git', 'checkout-index', '--all', "--prefix=$ldir/");
+ exit_cleanup($tmpdir, $rc) if $rc != 0;
$ENV{GIT_INDEX_FILE} = "$tmpdir/rindex";
- ($inpipe, $ctx) = $repo->command_input_pipe(qw/update-index -z --index-info/);
+ ($inpipe, $ctx) =
+ $repo->command_input_pipe(qw(update-index -z --index-info));
print($inpipe $rindex);
$repo->command_close_pipe($inpipe, $ctx);
+
$rc = system('git', 'checkout-index', '--all', "--prefix=$rdir/");
- exit($rc | ($rc >> 8)) if ($rc != 0);
+ exit_cleanup($tmpdir, $rc) if $rc != 0;
# If $GIT_DIR was explicitly set just for the update/checkout
# commands, then it should be unset before continuing.
for my $file (@working_tree) {
my $dir = dirname($file);
unless (-d "$rdir/$dir") {
- mkpath("$rdir/$dir") or die $!;
+ mkpath("$rdir/$dir") or
+ exit_cleanup($tmpdir, 1);
+ }
+ if ($symlinks) {
+ symlink("$workdir/$file", "$rdir/$file") or
+ exit_cleanup($tmpdir, 1);
+ } else {
+ copy("$workdir/$file", "$rdir/$file") or
+ exit_cleanup($tmpdir, 1);
+
+ my $mode = stat("$workdir/$file")->mode;
+ chmod($mode, "$rdir/$file") or
+ exit_cleanup($tmpdir, 1);
}
- copy("$workdir/$file", "$rdir/$file") or die $!;
- chmod(stat("$workdir/$file")->mode, "$rdir/$file") or die $!;
}
# Changes to submodules require special treatment. This loop writes a
# temporary file to both the left and right directories to show the
# change in the recorded SHA1 for the submodule.
for my $path (keys %submodule) {
+ my $ok;
if (defined($submodule{$path}{left})) {
- write_to_file("$ldir/$path", "Subproject commit $submodule{$path}{left}");
+ $ok = write_to_file("$ldir/$path",
+ "Subproject commit $submodule{$path}{left}");
}
if (defined($submodule{$path}{right})) {
- write_to_file("$rdir/$path", "Subproject commit $submodule{$path}{right}");
+ $ok = write_to_file("$rdir/$path",
+ "Subproject commit $submodule{$path}{right}");
}
+ exit_cleanup($tmpdir, 1) if not $ok;
}
# Symbolic links require special treatment. The standard "git diff"
# shows only the link itself, not the contents of the link target.
# This loop replicates that behavior.
for my $path (keys %symlink) {
+ my $ok;
if (defined($symlink{$path}{left})) {
- write_to_file("$ldir/$path", $symlink{$path}{left});
+ $ok = write_to_file("$ldir/$path",
+ $symlink{$path}{left});
}
if (defined($symlink{$path}{right})) {
- write_to_file("$rdir/$path", $symlink{$path}{right});
+ $ok = write_to_file("$rdir/$path",
+ $symlink{$path}{right});
}
+ exit_cleanup($tmpdir, 1) if not $ok;
}
- return ($ldir, $rdir);
+ return ($ldir, $rdir, $tmpdir, @working_tree);
}
sub write_to_file
# Make sure the path to the file exists
my $dir = dirname($path);
unless (-d "$dir") {
- mkpath("$dir") or die $!;
+ mkpath("$dir") or return 0;
}
# If the file already exists in that location, delete it. This
# is required in the case of symbolic links.
- unlink("$path");
+ unlink($path);
- open(my $fh, '>', "$path") or die $!;
+ open(my $fh, '>', $path) or return 0;
print($fh $value);
close($fh);
-}
-# parse command-line options. all unrecognized options and arguments
-# are passed through to the 'git diff' command.
-my ($difftool_cmd, $dirdiff, $extcmd, $gui, $help, $prompt, $tool_help);
-GetOptions('g|gui!' => \$gui,
- 'd|dir-diff' => \$dirdiff,
- 'h' => \$help,
- 'prompt!' => \$prompt,
- 'y' => sub { $prompt = 0; },
- 't|tool:s' => \$difftool_cmd,
- 'tool-help' => \$tool_help,
- 'x|extcmd:s' => \$extcmd);
-
-if (defined($help)) {
- usage(0);
-}
-if (defined($tool_help)) {
- print_tool_help();
+ return 1;
}
-if (defined($difftool_cmd)) {
- if (length($difftool_cmd) > 0) {
- $ENV{GIT_DIFF_TOOL} = $difftool_cmd;
- } else {
- print "No <tool> given for --tool=<tool>\n";
- usage(1);
+
+sub main
+{
+ # parse command-line options. all unrecognized options and arguments
+ # are passed through to the 'git diff' command.
+ my %opts = (
+ difftool_cmd => undef,
+ dirdiff => undef,
+ extcmd => undef,
+ gui => undef,
+ help => undef,
+ prompt => undef,
+ symlinks => $^O ne 'cygwin' &&
+ $^O ne 'MSWin32' && $^O ne 'msys',
+ tool_help => undef,
+ );
+ GetOptions('g|gui!' => \$opts{gui},
+ 'd|dir-diff' => \$opts{dirdiff},
+ 'h' => \$opts{help},
+ 'prompt!' => \$opts{prompt},
+ 'y' => sub { $opts{prompt} = 0; },
+ 'symlinks' => \$opts{symlinks},
+ 'no-symlinks' => sub { $opts{symlinks} = 0; },
+ 't|tool:s' => \$opts{difftool_cmd},
+ 'tool-help' => \$opts{tool_help},
+ 'x|extcmd:s' => \$opts{extcmd});
+
+ if (defined($opts{help})) {
+ usage(0);
}
-}
-if (defined($extcmd)) {
- if (length($extcmd) > 0) {
- $ENV{GIT_DIFFTOOL_EXTCMD} = $extcmd;
- } else {
- print "No <cmd> given for --extcmd=<cmd>\n";
- usage(1);
+ if (defined($opts{tool_help})) {
+ print_tool_help();
}
-}
-if ($gui) {
- my $guitool = '';
- $guitool = Git::config('diff.guitool');
- if (length($guitool) > 0) {
- $ENV{GIT_DIFF_TOOL} = $guitool;
+ if (defined($opts{difftool_cmd})) {
+ if (length($opts{difftool_cmd}) > 0) {
+ $ENV{GIT_DIFF_TOOL} = $opts{difftool_cmd};
+ } else {
+ print "No <tool> given for --tool=<tool>\n";
+ usage(1);
+ }
+ }
+ if (defined($opts{extcmd})) {
+ if (length($opts{extcmd}) > 0) {
+ $ENV{GIT_DIFFTOOL_EXTCMD} = $opts{extcmd};
+ } else {
+ print "No <cmd> given for --extcmd=<cmd>\n";
+ usage(1);
+ }
+ }
+ if ($opts{gui}) {
+ my $guitool = Git::config('diff.guitool');
+ if (length($guitool) > 0) {
+ $ENV{GIT_DIFF_TOOL} = $guitool;
+ }
+ }
+
+ # In directory diff mode, 'git-difftool--helper' is called once
+ # to compare the a/b directories. In file diff mode, 'git diff'
+ # will invoke a separate instance of 'git-difftool--helper' for
+ # each file that changed.
+ if (defined($opts{dirdiff})) {
+ dir_diff($opts{extcmd}, $opts{symlinks});
+ } else {
+ file_diff($opts{prompt});
}
}
-# In directory diff mode, 'git-difftool--helper' is called once
-# to compare the a/b directories. In file diff mode, 'git diff'
-# will invoke a separate instance of 'git-difftool--helper' for
-# each file that changed.
-if (defined($dirdiff)) {
- my ($a, $b) = setup_dir_diff();
+sub dir_diff
+{
+ my ($extcmd, $symlinks) = @_;
+ my $rc;
+ my $error = 0;
+ my $repo = Git->repository();
+ my $workdir = find_worktree($repo);
+ my ($a, $b, $tmpdir, @worktree) =
+ setup_dir_diff($repo, $workdir, $symlinks);
+
if (defined($extcmd)) {
$rc = system($extcmd, $a, $b);
} else {
$ENV{GIT_DIFFTOOL_DIRDIFF} = 'true';
$rc = system('git', 'difftool--helper', $a, $b);
}
-
- exit($rc | ($rc >> 8)) if ($rc != 0);
-
# If the diff including working copy files and those
# files were modified during the diff, then the changes
- # should be copied back to the working tree
- for my $file (@working_tree) {
- if (-e "$b/$file" && compare("$b/$file", "$workdir/$file")) {
- copy("$b/$file", "$workdir/$file") or die $!;
- chmod(stat("$b/$file")->mode, "$workdir/$file") or die $!;
+ # should be copied back to the working tree.
+ # Do not copy back files when symlinks are used and the
+ # external tool did not replace the original link with a file.
+ for my $file (@worktree) {
+ next if $symlinks && -l "$b/$file";
+ next if ! -f "$b/$file";
+
+ my $diff = compare("$b/$file", "$workdir/$file");
+ if ($diff == 0) {
+ next;
+ } elsif ($diff == -1) {
+ my $errmsg = "warning: Could not compare ";
+ $errmsg += "'$b/$file' with '$workdir/$file'\n";
+ warn $errmsg;
+ $error = 1;
+ } elsif ($diff == 1) {
+ my $mode = stat("$b/$file")->mode;
+ copy("$b/$file", "$workdir/$file") or
+ exit_cleanup($tmpdir, 1);
+
+ chmod($mode, "$workdir/$file") or
+ exit_cleanup($tmpdir, 1);
}
}
-} else {
+ if ($error) {
+ warn "warning: Temporary files exist in '$tmpdir'.\n";
+ warn "warning: You may want to cleanup or recover these.\n";
+ exit(1);
+ } else {
+ exit_cleanup($tmpdir, $rc);
+ }
+}
+
+sub file_diff
+{
+ my ($prompt) = @_;
+
if (defined($prompt)) {
if ($prompt) {
$ENV{GIT_DIFFTOOL_PROMPT} = 'true';
my $rc = system('git', 'diff', @ARGV);
exit($rc | ($rc >> 8));
}
+
+main();
else
tools="opendiff kdiff3 tkdiff xxdiff meld $tools"
fi
- tools="$tools gvimdiff diffuse ecmerge p4merge araxis bc3"
+ tools="$tools gvimdiff diffuse ecmerge p4merge araxis bc3 codecompare"
fi
case "${VISUAL:-$EDITOR}" in
*vim*)
return files
def stripRepoPath(self, path, prefixes):
- if self.useClientSpec:
- return self.clientSpecDirs.map_in_client(path)
+ """When streaming files, this is called to map a p4 depot path
+ to where it should go in git. The prefixes are either
+ self.depotPaths, or self.branchPrefixes in the case of
+ branch detection."""
- if self.keepRepoPath:
- prefixes = [re.sub("^(//[^/]+/).*", r'\1', prefixes[0])]
+ if self.useClientSpec:
+ # branch detection moves files up a level (the branch name)
+ # from what client spec interpretation gives
+ path = self.clientSpecDirs.map_in_client(path)
+ if self.detectBranches:
+ for b in self.knownBranches:
+ if path.startswith(b + "/"):
+ path = path[len(b)+1:]
+
+ elif self.keepRepoPath:
+ # Preserve everything in relative path name except leading
+ # //depot/; just look at first prefix as they all should
+ # be in the same depot.
+ depot = re.sub("^(//[^/]+/).*", r'\1', prefixes[0])
+ if p4PathStartsWith(path, depot):
+ path = path[len(depot):]
- for p in prefixes:
- if p4PathStartsWith(path, p):
- path = path[len(p):]
+ else:
+ for p in prefixes:
+ if p4PathStartsWith(path, p):
+ path = path[len(p):]
+ break
+ path = wildcard_decode(path)
return path
def splitFilesIntoBranches(self, commit):
+ """Look at each depotFile in the commit to figure out to what
+ branch it belongs."""
+
branches = {}
fnum = 0
while commit.has_key("depotFile%s" % fnum):
file["type"] = commit["type%s" % fnum]
fnum = fnum + 1
- relPath = self.stripRepoPath(path, self.depotPaths)
- relPath = wildcard_decode(relPath)
+ # start with the full relative path where this file would
+ # go in a p4 client
+ if self.useClientSpec:
+ relPath = self.clientSpecDirs.map_in_client(path)
+ else:
+ relPath = self.stripRepoPath(path, self.depotPaths)
for branch in self.knownBranches.keys():
-
- # add a trailing slash so that a commit into qt/4.2foo doesn't end up in qt/4.2
+ # add a trailing slash so that a commit into qt/4.2foo
+ # doesn't end up in qt/4.2, e.g.
if relPath.startswith(branch + "/"):
if branch not in branches:
branches[branch] = []
def streamOneP4File(self, file, contents):
relPath = self.stripRepoPath(file['depotFile'], self.branchPrefixes)
- relPath = wildcard_decode(relPath)
if verbose:
sys.stderr.write("%s\n" % relPath)
def streamOneP4Deletion(self, file):
relPath = self.stripRepoPath(file['path'], self.branchPrefixes)
- relPath = wildcard_decode(relPath)
if verbose:
sys.stderr.write("delete %s\n" % relPath)
self.gitStream.write("D %s\n" % relPath)
gitStream.write(description)
gitStream.write("\n")
- def commit(self, details, files, branch, branchPrefixes, parent = ""):
+ def commit(self, details, files, branch, parent = ""):
epoch = details["time"]
author = details["user"]
- self.branchPrefixes = branchPrefixes
if self.verbose:
print "commit into %s" % branch
# create a commit.
new_files = []
for f in files:
- if [p for p in branchPrefixes if p4PathStartsWith(f['path'], p)]:
+ if [p for p in self.branchPrefixes if p4PathStartsWith(f['path'], p)]:
new_files.append (f)
else:
sys.stderr.write("Ignoring file outside of prefix: %s\n" % f['path'])
self.gitStream.write("data <<EOT\n")
self.gitStream.write(details["desc"])
- self.gitStream.write("\n[git-p4: depot-paths = \"%s\": change = %s"
- % (','.join (branchPrefixes), details["change"]))
+ self.gitStream.write("\n[git-p4: depot-paths = \"%s\": change = %s" %
+ (','.join(self.branchPrefixes), details["change"]))
if len(details['options']) > 0:
self.gitStream.write(": options = %s" % details['options'])
self.gitStream.write("]\nEOT\n\n")
print "Change %s is labelled %s" % (change, labelDetails)
files = p4CmdList(["files"] + ["%s...@%s" % (p, change)
- for p in branchPrefixes])
+ for p in self.branchPrefixes])
if len(files) == len(labelRevisions):
for branch in branches.keys():
## HACK --hwn
branchPrefix = self.depotPaths[0] + branch + "/"
+ self.branchPrefixes = [ branchPrefix ]
parent = ""
tempBranch = os.path.join(self.tempBranchLocation, "%d" % (change))
if self.verbose:
print "Creating temporary branch: " + tempBranch
- self.commit(description, filesForCommit, tempBranch, [branchPrefix])
+ self.commit(description, filesForCommit, tempBranch)
self.tempBranches.append(tempBranch)
self.checkpoint()
blob = self.searchParent(parent, branch, tempBranch)
if blob:
- self.commit(description, filesForCommit, branch, [branchPrefix], blob)
+ self.commit(description, filesForCommit, branch, blob)
else:
if self.verbose:
print "Parent of %s not found. Committing into head of %s" % (branch, parent)
- self.commit(description, filesForCommit, branch, [branchPrefix], parent)
+ self.commit(description, filesForCommit, branch, parent)
else:
files = self.extractFilesFromCommit(description)
- self.commit(description, files, self.branch, self.depotPaths,
+ self.commit(description, files, self.branch,
self.initialParent)
self.initialParent = ""
except IOError:
self.updateOptionDict(details)
try:
- self.commit(details, self.extractFilesFromCommit(details), self.branch, self.depotPaths)
+ self.commit(details, self.extractFilesFromCommit(details), self.branch)
except IOError:
print "IO error with git fast-import. Is your git version recent enough?"
print self.gitError.read()
self.depotPaths = newPaths
+ # --detect-branches may change this for each branch
+ self.branchPrefixes = self.depotPaths
+
self.loadUserMapFromCache()
self.labels = {}
if self.detectLabels:
my ($prompt, %arg) = @_;
my $valid_re = $arg{valid_re};
my $default = $arg{default};
+ my $confirm_only = $arg{confirm_only};
my $resp;
my $i = 0;
return defined $default ? $default : undef
if (!defined $valid_re or $resp =~ /$valid_re/) {
return $resp;
}
+ if ($confirm_only) {
+ my $yesno = $term->readline("Are you sure you want to use <$resp> [y/N]? ");
+ if (defined $yesno && $yesno =~ /y/i) {
+ return $resp;
+ }
+ }
}
return undef;
}
if (!defined $sender) {
$sender = $repoauthor || $repocommitter || '';
$sender = ask("Who should the emails appear to be from? [$sender] ",
- default => $sender);
+ default => $sender,
+ valid_re => qr/\@.*\./, confirm_only => 1);
print "Emails will be sent from: ", $sender, "\n";
$prompting++;
}
if (!@initial_to && !defined $to_cmd) {
- my $to = ask("Who should the emails be sent to? ");
+ my $to = ask("Who should the emails be sent to? ",
+ valid_re => qr/\@.*\./, confirm_only => 1);
push @initial_to, parse_address_line($to) if defined $to; # sanitized/validated later
$prompting++;
}
if ($thread && !defined $initial_reply_to && $prompting) {
$initial_reply_to = ask(
- "Message-ID to be used as In-Reply-To for the first email? ");
+ "Message-ID to be used as In-Reply-To for the first email? ",
+ valid_re => qr/\@.*\./, confirm_only => 1);
}
if (defined $initial_reply_to) {
$initial_reply_to =~ s/^\s*<?//;
use Git::SVN::Log;
use Git::SVN::Migration;
-use Git::SVN::Utils qw(fatal can_compress);
+use Git::SVN::Utils qw(
+ fatal
+ can_compress
+ canonicalize_path
+ canonicalize_url
+ join_paths
+ add_path_to_url
+ join_paths
+);
+
use Git qw(
git_cmd_try
command
my ($url, $rev, $uuid, $gs) = working_head_info('HEAD');
$gs ||= Git::SVN->new;
my $r = (defined $_revision ? $_revision : $gs->ra->get_latest_revnum);
- $gs->prop_walk($gs->{path}, $r, sub {
+ $gs->prop_walk($gs->path, $r, sub {
my ($gs, $path, $props) = @_;
print STDOUT "\n# $path\n";
my $s = $props->{'svn:ignore'} or return;
my ($url, $rev, $uuid, $gs) = working_head_info('HEAD');
$gs ||= Git::SVN->new;
my $r = (defined $_revision ? $_revision : $gs->ra->get_latest_revnum);
- $gs->prop_walk($gs->{path}, $r, sub {
+ $gs->prop_walk($gs->path, $r, sub {
my ($gs, $path, $props) = @_;
print STDOUT "\n# $path\n";
my $s = $props->{'svn:externals'} or return;
my ($url, $rev, $uuid, $gs) = working_head_info('HEAD');
$gs ||= Git::SVN->new;
my $r = (defined $_revision ? $_revision : $gs->ra->get_latest_revnum);
- $gs->prop_walk($gs->{path}, $r, sub {
+ $gs->prop_walk($gs->path, $r, sub {
my ($gs, $path, $props) = @_;
# $path is of the form /path/to/dir/
$path = '.' . $path;
$gs->mkemptydirs($_revision);
}
-sub canonicalize_path {
- my ($path) = @_;
- my $dot_slash_added = 0;
- if (substr($path, 0, 1) ne "/") {
- $path = "./" . $path;
- $dot_slash_added = 1;
- }
- # File::Spec->canonpath doesn't collapse x/../y into y (for a
- # good reason), so let's do this manually.
- $path =~ s#/+#/#g;
- $path =~ s#/\.(?:/|$)#/#g;
- $path =~ s#/[^/]+/\.\.##g;
- $path =~ s#/$##g;
- $path =~ s#^\./## if $dot_slash_added;
- $path =~ s#^/##;
- $path =~ s#^\.$##;
- return $path;
-}
-
-sub canonicalize_url {
- my ($url) = @_;
- $url =~ s#^([^:]+://[^/]*/)(.*)$#$1 . canonicalize_path($2)#e;
- return $url;
-}
-
# get_svnprops(PATH)
# ------------------
# Helper for cmd_propget and cmd_proplist below.
$path = $cmd_dir_prefix . $path;
fatal("No such file or directory: $path") unless -e $path;
my $is_dir = -d $path ? 1 : 0;
- $path = $gs->{path} . '/' . $path;
+ $path = join_paths($gs->{path}, $path);
# canonicalize the path (otherwise libsvn will abort or fail to
# find the file)
fatal("Needed URL or usable git-svn --id in ",
"the command-line\n", $usage);
}
- $url = $gs->{url};
- $svn_path = $gs->{path};
+ $url = $gs->url;
+ $svn_path = $gs->path;
}
unless (defined $_revision) {
fatal("-r|--revision is a required argument\n", $usage);
}
}
-sub escape_uri_only {
- my ($uri) = @_;
- my @tmp;
- foreach (split m{/}, $uri) {
- s/([^~\w.%+-]|%(?![a-fA-F0-9]{2}))/sprintf("%%%02X",ord($1))/eg;
- push @tmp, $_;
- }
- join('/', @tmp);
-}
-
-sub escape_url {
- my ($url) = @_;
- if ($url =~ m#^([^:]+)://([^/]*)(.*)$#) {
- my ($scheme, $domain, $uri) = ($1, $2, escape_uri_only($3));
- $url = "$scheme://$domain$uri";
- }
- $url;
-}
sub cmd_info {
my $path = canonicalize_path(defined($_[0]) ? $_[0] : ".");
# canonicalize_path() will return "" to make libsvn 1.5.x happy,
$path = "." if $path eq "";
- my $full_url = $url . ($fullpath eq "" ? "" : "/$fullpath");
+ my $full_url = canonicalize_url( add_path_to_url( $url, $fullpath ) );
if ($_url) {
- print escape_url($full_url), "\n";
+ print "$full_url\n";
return;
}
my $result = "Path: $path\n";
$result .= "Name: " . basename($path) . "\n" if $file_type ne "dir";
- $result .= "URL: " . escape_url($full_url) . "\n";
+ $result .= "URL: $full_url\n";
eval {
my $repos_root = $gs->repos_root;
Git::SVN::remove_username($repos_root);
- $result .= "Repository Root: " . escape_url($repos_root) . "\n";
+ $result .= "Repository Root: " . canonicalize_url($repos_root) . "\n";
};
if ($@) {
$result .= "Repository Root: (offline)\n";
sub complete_svn_url {
my ($url, $path) = @_;
- $path =~ s#/+$##;
+ $path = canonicalize_path($path);
+
+ # If the path is not a URL...
if ($path !~ m#^[a-z\+]+://#) {
if (!defined $url || $url !~ m#^[a-z\+]+://#) {
fatal("E: '$path' is not a complete URL ",
print STDERR "W: $switch not specified\n";
return;
}
- $repo_path =~ s#/+$##;
+ $repo_path = canonicalize_path($repo_path);
if ($repo_path =~ m#^[a-z\+]+://#) {
$ra = Git::SVN::Ra->new($repo_path);
$repo_path = '';
"and a separate URL is not specified");
}
}
- my $url = $ra->{url};
+ my $url = $ra->url;
my $gs = Git::SVN->init($url, undef, undef, undef, 1);
my $k = "svn-remote.$gs->{repo_id}.url";
my $orig_url = eval { command_oneline(qw/config --get/, $k) };
- if ($orig_url && ($orig_url ne $gs->{url})) {
+ if ($orig_url && ($orig_url ne $gs->url)) {
die "$k already set: $orig_url\n",
- "wanted to set to: $gs->{url}\n";
+ "wanted to set to: $gs->url\n";
}
- command_oneline('config', $k, $gs->{url}) unless $orig_url;
- my $remote_path = "$gs->{path}/$repo_path";
+ command_oneline('config', $k, $gs->url) unless $orig_url;
+
+ my $remote_path = join_paths( $gs->path, $repo_path );
$remote_path =~ s{%([0-9A-F]{2})}{chr hex($1)}ieg;
- $remote_path =~ s#/+#/#g;
$remote_path =~ s#^/##g;
$remote_path .= "/*" if $remote_path !~ /\*/;
my ($n) = ($switch =~ /^--(\w+)/);
GREP_NODE_OR
};
+enum grep_pattern_type {
+ GREP_PATTERN_TYPE_UNSPECIFIED = 0,
+ GREP_PATTERN_TYPE_BRE,
+ GREP_PATTERN_TYPE_ERE,
+ GREP_PATTERN_TYPE_FIXED,
+ GREP_PATTERN_TYPE_PCRE
+};
+
struct grep_expr {
enum grep_expr_node node;
unsigned hit;
int max_depth;
int funcname;
int funcbody;
+ int extended_regexp_option;
+ int pattern_type_option;
char color_context[COLOR_MAXLEN];
char color_filename[COLOR_MAXLEN];
char color_function[COLOR_MAXLEN];
return strbuf_detach(&buf, NULL);
}
+int handle_curl_result(struct active_request_slot *slot)
+{
+ struct slot_results *results = slot->results;
+
+ if (results->curl_result == CURLE_OK) {
+ credential_approve(&http_auth);
+ return HTTP_OK;
+ } else if (missing_target(results))
+ return HTTP_MISSING_TARGET;
+ else if (results->http_code == 401) {
+ if (http_auth.username && http_auth.password) {
+ credential_reject(&http_auth);
+ return HTTP_NOAUTH;
+ } else {
+ credential_fill(&http_auth);
+ init_curl_http_auth(slot->curl);
+ return HTTP_REAUTH;
+ }
+ } else {
+#if LIBCURL_VERSION_NUM >= 0x070c00
+ if (!curl_errorstr[0])
+ strlcpy(curl_errorstr,
+ curl_easy_strerror(results->curl_result),
+ sizeof(curl_errorstr));
+#endif
+ return HTTP_ERROR;
+ }
+}
+
/* http_request() targets */
#define HTTP_REQUEST_STRBUF 0
#define HTTP_REQUEST_FILE 1
if (start_active_slot(slot)) {
run_active_slot(slot);
- if (results.curl_result == CURLE_OK)
- ret = HTTP_OK;
- else if (missing_target(&results))
- ret = HTTP_MISSING_TARGET;
- else if (results.http_code == 401) {
- if (http_auth.username && http_auth.password) {
- credential_reject(&http_auth);
- ret = HTTP_NOAUTH;
- } else {
- credential_fill(&http_auth);
- init_curl_http_auth(slot->curl);
- ret = HTTP_REAUTH;
- }
- } else {
-#if LIBCURL_VERSION_NUM >= 0x070c00
- if (!curl_errorstr[0])
- strlcpy(curl_errorstr,
- curl_easy_strerror(results.curl_result),
- sizeof(curl_errorstr));
-#endif
- ret = HTTP_ERROR;
- }
+ ret = handle_curl_result(slot);
} else {
error("Unable to start HTTP request for %s", url);
ret = HTTP_START_FAILED;
curl_slist_free_all(headers);
strbuf_release(&buf);
- if (ret == HTTP_OK)
- credential_approve(&http_auth);
-
return ret;
}
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);
#ifdef USE_CURL_MULTI
extern void fill_active_slots(void);
--- /dev/null
+diff_cmd () {
+ "$merge_tool_path" "$LOCAL" "$REMOTE"
+}
+
+merge_cmd () {
+ touch "$BACKUP"
+ if $base_present
+ then
+ "$merge_tool_path" -MF="$LOCAL" -TF="$REMOTE" -BF="$BASE" \
+ -RF="$MERGED"
+ else
+ "$merge_tool_path" -MF="$LOCAL" -TF="$REMOTE" \
+ -RF="$MERGED"
+ fi
+ check_unchanged
+}
+
+translate_merge_tool_path() {
+ if merge_mode
+ then
+ echo CodeMerge
+ else
+ echo CodeCompare
+ fi
+}
#define OPT__COLOR(var, h) \
OPT_COLOR_FLAG(0, "color", (var), (h))
#define OPT_COLUMN(s, l, v, h) \
- { OPTION_CALLBACK, (s), (l), (v), "style", (h), PARSE_OPT_OPTARG, parseopt_column_callback }
+ { OPTION_CALLBACK, (s), (l), (v), N_("style"), (h), PARSE_OPT_OPTARG, parseopt_column_callback }
#endif
command_output_pipe
command_close_pipe
);
-use Git::SVN::Utils qw(fatal can_compress);
+use Git::SVN::Utils qw(
+ fatal
+ can_compress
+ join_paths
+ canonicalize_path
+ canonicalize_url
+ add_path_to_url
+);
my $can_use_yaml;
BEGIN {
} elsif (m!^(.+)\.usesvmprops=\s*(.*)\s*$!) {
$r->{$1}->{svm} = {};
} elsif (m!^(.+)\.url=\s*(.*)\s*$!) {
- $r->{$1}->{url} = $2;
+ $r->{$1}->{url} = canonicalize_url($2);
} elsif (m!^(.+)\.pushurl=\s*(.*)\s*$!) {
- $r->{$1}->{pushurl} = $2;
+ $r->{$1}->{pushurl} = canonicalize_url($2);
} elsif (m!^(.+)\.ignore-refs=\s*(.*)\s*$!) {
$r->{$1}->{ignore_refs_regex} = $2;
} elsif (m!^(.+)\.(branches|tags)=$svn_refspec$!) {
sub init_remote_config {
my ($self, $url, $no_write) = @_;
- $url =~ s!/+$!!; # strip trailing slash
+ $url = canonicalize_url($url);
my $r = read_all_remotes();
my $existing = find_existing_remote($url, $r);
if ($existing) {
print STDERR "Using higher level of URL: ",
"$url => $min_url\n";
}
- my $old_path = $self->{path};
- $self->{path} = $url;
- $self->{path} =~ s!^\Q$min_url\E(/|$)!!;
- if (length $old_path) {
- $self->{path} .= "/$old_path";
- }
+ my $old_path = $self->path;
+ $url =~ s!^\Q$min_url\E(/|$)!!;
+ $url = join_paths($url, $old_path);
+ $self->path($url);
$url = $min_url;
}
}
unless ($no_write) {
command_noisy('config',
"svn-remote.$self->{repo_id}.url", $url);
- $self->{path} =~ s{^/}{};
- $self->{path} =~ s{%([0-9A-F]{2})}{chr hex($1)}ieg;
+ my $path = $self->path;
+ $path =~ s{^/}{};
+ $path =~ s{%([0-9A-F]{2})}{chr hex($1)}ieg;
+ $self->path($path);
command_noisy('config', '--add',
"svn-remote.$self->{repo_id}.fetch",
- "$self->{path}:".$self->refname);
+ $self->path.":".$self->refname);
}
- $self->{url} = $url;
+ $self->url($url);
}
sub find_by_url { # repos_root and, path are optional
my ($class, $full_url, $repos_root, $path) = @_;
+ $full_url = canonicalize_url($full_url);
+
return undef unless defined $full_url;
remove_username($full_url);
remove_username($repos_root) if defined $repos_root;
}
$p =~ s#^\Q$z\E(?:/|$)#$prefix# or next;
}
+
+ # remote fetch paths are not URI escaped. Decode ours
+ # so they match
+ $p = uri_decode($p);
+
foreach my $f (keys %$fetch) {
next if $f ne $p;
return Git::SVN->new($fetch->{$f}, $repo_id, $f);
}
}
my $self = _new($class, $repo_id, $ref_id, $path);
- if (!defined $self->{path} || !length $self->{path}) {
+ if (!defined $self->path || !length $self->path) {
my $fetch = command_oneline('config', '--get',
"svn-remote.$repo_id.fetch",
":$ref_id\$") or
die "Failed to read \"svn-remote.$repo_id.fetch\" ",
"\":$ref_id\$\" in config\n";
- ($self->{path}, undef) = split(/\s*:\s*/, $fetch);
+ my($path) = split(/\s*:\s*/, $fetch);
+ $self->path($path);
}
- $self->{path} =~ s{/+}{/}g;
- $self->{path} =~ s{\A/}{};
- $self->{path} =~ s{/\z}{};
- $self->{url} = command_oneline('config', '--get',
- "svn-remote.$repo_id.url") or
+ {
+ my $path = $self->path;
+ $path =~ s{\A/}{};
+ $path =~ s{/\z}{};
+ $self->path($path);
+ }
+ my $url = command_oneline('config', '--get',
+ "svn-remote.$repo_id.url") or
die "Failed to read \"svn-remote.$repo_id.url\" in config\n";
+ $self->url($url);
$self->{pushurl} = eval { command_oneline('config', '--get',
"svn-remote.$repo_id.pushurl") };
$self->rebuild;
# username is of no interest
$src =~ s{(^[a-z\+]*://)[^/@]*@}{$1};
- my $replace = $ra->{url};
- $replace .= "/$path" if length $path;
+ my $replace = add_path_to_url($ra->url, $path);
my $section = "svn-remote.$self->{repo_id}";
tmp_config("$section.svm-source", $src);
}
my $r = $ra->get_latest_revnum;
- my $path = $self->{path};
+ my $path = $self->path;
my %tried;
while (length $path) {
- unless ($tried{"$self->{url}/$path"}) {
+ my $try = add_path_to_url($self->url, $path);
+ unless ($tried{$try}) {
return $ra if $self->read_svm_props($ra, $path, $r);
- $tried{"$self->{url}/$path"} = 1;
+ $tried{$try} = 1;
}
$path =~ s#/?[^/]+$##;
}
die "Path: '$path' should be ''\n" if $path ne '';
return $ra if $self->read_svm_props($ra, $path, $r);
- $tried{"$self->{url}/$path"} = 1;
+ $tried{ add_path_to_url($self->url, $path) } = 1;
- if ($ra->{repos_root} eq $self->{url}) {
+ if ($ra->{repos_root} eq $self->url) {
die @err, (map { " $_\n" } keys %tried), "\n";
}
$path = $ra->{svn_path};
$ra = Git::SVN::Ra->new($ra->{repos_root});
while (length $path) {
- unless ($tried{"$ra->{url}/$path"}) {
+ my $try = add_path_to_url($ra->url, $path);
+ unless ($tried{$try}) {
$ok = $self->read_svm_props($ra, $path, $r);
last if $ok;
- $tried{"$ra->{url}/$path"} = 1;
+ $tried{$try} = 1;
}
$path =~ s#/?[^/]+$##;
}
die "Path: '$path' should be ''\n" if $path ne '';
$ok ||= $self->read_svm_props($ra, $path, $r);
- $tried{"$ra->{url}/$path"} = 1;
+ $tried{ add_path_to_url($ra->url, $path) } = 1;
if (!$ok) {
die @err, (map { " $_\n" } keys %tried), "\n";
}
- Git::SVN::Ra->new($self->{url});
+ Git::SVN::Ra->new($self->url);
}
sub svnsync {
if (!$@ && $uuid && $uuid =~ /^([a-f\d\-]{30,})$/i) {
$self->{ra_uuid} = $uuid;
} else {
- die "ra_uuid called without URL\n" unless $self->{url};
+ die "ra_uuid called without URL\n" unless $self->url;
$self->{ra_uuid} = $self->ra->get_uuid;
tmp_config('--add', $key, $self->{ra_uuid});
}
sub ra {
my ($self) = shift;
- my $ra = Git::SVN::Ra->new($self->{url});
+ my $ra = Git::SVN::Ra->new($self->url);
$self->_set_repos_root($ra->{repos_root});
if ($self->use_svm_props && !$self->{svm}) {
if ($self->no_metadata) {
$path =~ s#^/*#/#g;
my $p = $path;
# Strip the irrelevant part of the path.
- $p =~ s#^/+\Q$self->{path}\E(/|$)#/#;
+ $p =~ s#^/+\Q@{[$self->path]}\E(/|$)#/#;
# Ensure the path is terminated by a `/'.
$p =~ s#/*$#/#;
foreach (sort keys %$dirent) {
next if $dirent->{$_}->{kind} != $SVN::Node::dir;
- $self->prop_walk($self->{path} . $p . $_, $rev, $sub);
+ $self->prop_walk($self->path . $p . $_, $rev, $sub);
}
}
sub metadata_url {
my ($self) = @_;
- ($self->rewrite_root || $self->{url}) .
- (length $self->{path} ? '/' . $self->{path} : '');
+ my $url = $self->rewrite_root || $self->url;
+ return canonicalize_url( add_path_to_url( $url, $self->path ) );
}
sub full_url {
my ($self) = @_;
- $self->{url} . (length $self->{path} ? '/' . $self->{path} : '');
+ return canonicalize_url( add_path_to_url( $self->url, $self->path ) );
}
sub full_pushurl {
my ($self) = @_;
if ($self->{pushurl}) {
- return $self->{pushurl} . (length $self->{path} ? '/' .
- $self->{path} : '');
+ return canonicalize_url( add_path_to_url( $self->{pushurl}, $self->path ) );
} else {
return $self->full_url;
}
sub match_paths {
my ($self, $paths, $r) = @_;
- return 1 if $self->{path} eq '';
- if (my $path = $paths->{"/$self->{path}"}) {
+ return 1 if $self->path eq '';
+ if (my $path = $paths->{"/".$self->path}) {
return ($path->{action} eq 'D') ? 0 : 1;
}
- $self->{path_regex} ||= qr/^\/\Q$self->{path}\E\//;
+ $self->{path_regex} ||= qr{^/\Q@{[$self->path]}\E/};
if (grep /$self->{path_regex}/, keys %$paths) {
return 1;
}
my $c = '';
- foreach (split m#/#, $self->{path}) {
+ foreach (split m#/#, $self->path) {
$c .= "/$_";
next unless ($paths->{$c} &&
($paths->{$c}->{action} =~ /^[AR]$/));
- if ($self->ra->check_path($self->{path}, $r) ==
+ if ($self->ra->check_path($self->path, $r) ==
$SVN::Node::dir) {
return 1;
}
unless (defined $paths) {
my $err_handler = $SVN::Error::handler;
$SVN::Error::handler = \&Git::SVN::Ra::skip_unknown_revs;
- $self->ra->get_log([$self->{path}], $rev, $rev, 0, 1, 1,
+ $self->ra->get_log([$self->path], $rev, $rev, 0, 1, 1,
sub { $paths = $_[0] });
$SVN::Error::handler = $err_handler;
}
return undef unless defined $paths;
# look for a parent from another branch:
- my @b_path_components = split m#/#, $self->{path};
+ my @b_path_components = split m#/#, $self->path;
my @a_path_components;
my $i;
while (@b_path_components) {
}
my $r = $i->{copyfrom_rev};
my $repos_root = $self->ra->{repos_root};
- my $url = $self->ra->{url};
- my $new_url = $url . $branch_from;
+ my $url = $self->ra->url;
+ my $new_url = canonicalize_url( add_path_to_url( $url, $branch_from ) );
print STDERR "Found possible branch point: ",
"$new_url => ", $self->full_url, ", $r\n"
unless $::_q > 1;
($base, $head) = parse_revision_argument(0, $r);
} else {
if ($r0 < $r) {
- $gs->ra->get_log([$gs->{path}], $r0 + 1, $r, 1,
+ $gs->ra->get_log([$gs->path], $r0 + 1, $r, 1,
0, 1, sub { $base = $_[1] - 1 });
}
}
# at the moment), so we can't rely on it
$self->{last_rev} = $r0;
$self->{last_commit} = $parent;
- $ed = Git::SVN::Fetcher->new($self, $gs->{path});
+ $ed = Git::SVN::Fetcher->new($self, $gs->path);
$gs->ra->gs_do_switch($r0, $rev, $gs,
$self->full_url, $ed)
or die "SVN connection failed somewhere...\n";
close $fh;
}
- my $strip = qr/\A\Q$self->{path}\E(?:\/|$)/;
+ my $strip = qr/\A\Q@{[$self->path]}\E(?:\/|$)/;
foreach my $d (sort keys %empty_dirs) {
$d = uri_decode($d);
$d =~ s/$strip//;
for my $ticket ( @tickets ) {
my ($uuid, $path, $rev) = split /:/, $ticket;
if ( $uuid eq $self->ra_uuid ) {
- my $url = $self->{url};
- my $repos_root = $url;
+ my $repos_root = $self->url;
my $branch_from = $path;
$branch_from =~ s{^/}{};
- my $gs = $self->other_gs($repos_root."/".$branch_from,
- $url,
+ my $gs = $self->other_gs(add_path_to_url( $repos_root, $branch_from ),
+ $repos_root,
$branch_from,
$rev,
$self->{ref_id});
# are now marked as merge, we can add the tip as a parent.
my @merges = split "\n", $mergeinfo;
my @merge_tips;
- my $url = $self->{url};
+ my $url = $self->url;
my $uuid = $self->ra_uuid;
my %ranges;
for my $merge ( @merges ) {
$email ||= "$author\@$uuid";
$commit_email ||= "$author\@$uuid";
} elsif ($self->use_svnsync_props) {
- my $full_url = $self->svnsync->{url};
- $full_url .= "/$self->{path}" if length $self->{path};
+ my $full_url = canonicalize_url(
+ add_path_to_url( $self->svnsync->{url}, $self->path )
+ );
remove_username($full_url);
my $uuid = $self->svnsync->{uuid};
$log_entry{metadata} = "$full_url\@$rev $uuid";
tree_b => $tree,
editor_cb => sub {
$self->set_tree_cb($log_entry, $tree, @_) },
- svn_path => $self->{path} );
+ svn_path => $self->path );
if (!Git::SVN::Editor->new(\%ed_opts)->apply_diff) {
print "No changes\nr$self->{last_rev} = $tree\n";
}
$_[3] = $path = '' unless (defined $path);
mkpath([$dir]);
- bless {
+ my $obj = bless {
ref_id => $ref_id, dir => $dir, index => "$dir/index",
- path => $path, config => "$ENV{GIT_DIR}/svn/config",
+ config => "$ENV{GIT_DIR}/svn/config",
map_root => "$dir/.rev_map", repo_id => $repo_id }, $class;
+
+ # Ensure it gets canonicalized
+ $obj->path($path);
+
+ return $obj;
+}
+
+sub path {
+ my $self = shift;
+
+ if (@_) {
+ my $path = shift;
+ $self->{path} = canonicalize_path($path);
+ return;
+ }
+
+ return $self->{path};
+}
+
+sub url {
+ my $self = shift;
+
+ if (@_) {
+ my $url = shift;
+ $self->{url} = canonicalize_url($url);
+ return;
+ }
+
+ return $self->{url};
}
# for read-only access of old .rev_db formats
chomp(my $empty_blob = `git hash-object -t blob --stdin < /dev/null`);
my ($ls, $ctx) = command_output_pipe(qw/ls-tree -r -z/, $cmt);
local $/ = "\0";
- my $pfx = defined($switch_path) ? $switch_path : $git_svn->{path};
+ my $pfx = defined($switch_path) ? $switch_path : $git_svn->path;
$pfx .= '/' if length($pfx);
while (<$ls>) {
chomp;
my $ra = Git::SVN::Ra->new($url);
# skip existing cases where we already connect to the root
- if (($ra->{url} eq $ra->{repos_root}) ||
+ if (($ra->url eq $ra->{repos_root}) ||
($ra->{repos_root} eq $repo_id)) {
- $root_repos->{$ra->{url}} = $repo_id;
+ $root_repos->{$ra->url} = $repo_id;
next;
}
my $root_ra = Git::SVN::Ra->new($ra->{repos_root});
- my $root_path = $ra->{url};
+ my $root_path = $ra->url;
$root_path =~ s#^\Q$ra->{repos_root}\E(/|$)##;
foreach my $path (keys %$fetch) {
my $ref_id = $fetch->{$path};
use strict;
use warnings;
use SVN::Client;
+use Git::SVN::Utils qw(
+ canonicalize_url
+ canonicalize_path
+ add_path_to_url
+);
+
use SVN::Ra;
BEGIN {
@ISA = qw(SVN::Ra);
\@rv;
}
-sub escape_uri_only {
- my ($uri) = @_;
- my @tmp;
- foreach (split m{/}, $uri) {
- s/([^~\w.%+-]|%(?![a-fA-F0-9]{2}))/sprintf("%%%02X",ord($1))/eg;
- push @tmp, $_;
- }
- join('/', @tmp);
-}
-
-sub escape_url {
- my ($url) = @_;
- if ($url =~ m#^(https?)://([^/]+)(.*)$#) {
- my ($scheme, $domain, $uri) = ($1, $2, escape_uri_only($3));
- $url = "$scheme://$domain$uri";
- }
- $url;
-}
sub new {
my ($class, $url) = @_;
- $url =~ s!/+$!!;
- return $RA if ($RA && $RA->{url} eq $url);
+ $url = canonicalize_url($url);
+ return $RA if ($RA && $RA->url eq $url);
::_req_svn();
$Git::SVN::Prompt::_no_auth_cache = 1;
}
} # no warnings 'once'
- my $self = SVN::Ra->new(url => escape_url($url), auth => $baton,
+
+ my $self = SVN::Ra->new(url => $url, auth => $baton,
config => $config,
pool => SVN::Pool->new,
auth_provider_callbacks => $callbacks);
- $self->{url} = $url;
+ $RA = bless $self, $class;
+
+ # Make sure its canonicalized
+ $self->url($url);
$self->{svn_path} = $url;
$self->{repos_root} = $self->get_repos_root;
$self->{svn_path} =~ s#^\Q$self->{repos_root}\E(/|$)##;
$self->{cache} = { check_path => { r => 0, data => {} },
get_dir => { r => 0, data => {} } };
- $RA = bless $self, $class;
+
+ return $RA;
+}
+
+sub url {
+ my $self = shift;
+
+ if (@_) {
+ my $url = shift;
+ $self->{url} = canonicalize_url($url);
+ return;
+ }
+
+ return $self->{url};
}
sub check_path {
qw/copyfrom_path copyfrom_rev action/;
if ($s{'copyfrom_path'}) {
$s{'copyfrom_path'} =~ s/$prefix_regex//;
+ $s{'copyfrom_path'} = canonicalize_path($s{'copyfrom_path'});
}
$_[0]{$p} = \%s;
}
sub gs_do_update {
my ($self, $rev_a, $rev_b, $gs, $editor) = @_;
my $new = ($rev_a == $rev_b);
- my $path = $gs->{path};
+ my $path = $gs->path;
if ($new && -e $gs->{index}) {
unlink $gs->{index} or die
# svn_ra_reparent didn't work before 1.4)
sub gs_do_switch {
my ($self, $rev_a, $rev_b, $gs, $url_b, $editor) = @_;
- my $path = $gs->{path};
+ my $path = $gs->path;
my $pool = SVN::Pool->new;
- my $full_url = $self->{url};
- my $old_url = $full_url;
- $full_url .= '/' . $path if length $path;
+ my $old_url = $self->url;
+ my $full_url = add_path_to_url( $self->url, $path );
my ($ra, $reparented);
if ($old_url =~ m#^svn(\+ssh)?://# ||
($full_url =~ m#^https?://# &&
- escape_url($full_url) ne $full_url)) {
+ canonicalize_url($full_url) ne $full_url)) {
$_[0] = undef;
$self = undef;
$RA = undef;
$ra = Git::SVN::Ra->new($full_url);
$ra_invalid = 1;
} elsif ($old_url ne $full_url) {
- SVN::_Ra::svn_ra_reparent($self->{session}, $full_url, $pool);
- $self->{url} = $full_url;
+ SVN::_Ra::svn_ra_reparent(
+ $self->{session},
+ canonicalize_url($full_url),
+ $pool
+ );
+ $self->url($full_url);
$reparented = 1;
}
$ra ||= $self;
- $url_b = escape_url($url_b);
+ $url_b = canonicalize_url($url_b);
my $reporter = $ra->do_switch($rev_b, '', 1, $url_b, $editor, $pool);
my @lock = (::compare_svn_version('1.2.0') >= 0) ? (undef) : ();
$reporter->set_path('', $rev_a, 0, @lock, $pool);
if ($reparented) {
SVN::_Ra::svn_ra_reparent($self->{session}, $old_url, $pool);
- $self->{url} = $old_url;
+ $self->url($old_url);
}
$pool->clear;
my $common_max = scalar @$gsv;
foreach my $gs (@$gsv) {
- my @tmp = split m#/#, $gs->{path};
+ my @tmp = split m#/#, $gs->path;
my $p = '';
foreach (@tmp) {
$p .= length($p) ? "/$_" : $_;
my $inc = $_log_window_size;
my ($min, $max) = ($base, $head < $base + $inc ? $head : $base + $inc);
my $longest_path = longest_common_path($gsv, $globs);
- my $ra_url = $self->{url};
+ my $ra_url = $self->url;
my $find_trailing_edge;
while (1) {
my %revs;
($self->check_path($p, $r) !=
$SVN::Node::dir));
next unless $p =~ /$g->{path}->{regex}/;
- $exists->{$p} = Git::SVN->init($self->{url}, $p, undef,
+ $exists->{$p} = Git::SVN->init($self->url, $p, undef,
$g->{ref}->full_path($de), 1);
}
}
next if ($self->check_path($pathname, $r) !=
$SVN::Node::dir);
$exists->{$pathname} = Git::SVN->init(
- $self->{url}, $pathname, undef,
+ $self->url, $pathname, undef,
$g->{ref}->full_path($p), 1);
}
my $c = '';
sub minimize_url {
my ($self) = @_;
- return $self->{url} if ($self->{url} eq $self->{repos_root});
+ return $self->url if ($self->url eq $self->{repos_root});
my $url = $self->{repos_root};
my @components = split(m!/!, $self->{svn_path});
my $c = '';
do {
- $url .= "/$c" if length $c;
+ $url = add_path_to_url($url, $c);
eval {
my $ra = (ref $self)->new($url);
my $latest = $ra->get_latest_revnum;
$ra->get_log("", $latest, 0, 1, 0, 1, sub {});
};
} while ($@ && ($c = shift @components));
- $url;
+
+ return canonicalize_url($url);
}
sub can_do_switch {
unless (defined $can_do_switch) {
my $pool = SVN::Pool->new;
my $rep = eval {
- $self->do_switch(1, '', 0, $self->{url},
+ $self->do_switch(1, '', 0, $self->url,
SVN::Delta::Editor->new, $pool);
};
if ($@) {
use strict;
use warnings;
+use SVN::Core;
+
use base qw(Exporter);
-our @EXPORT_OK = qw(fatal can_compress);
+our @EXPORT_OK = qw(
+ fatal
+ can_compress
+ canonicalize_path
+ canonicalize_url
+ join_paths
+ add_path_to_url
+);
=head1 NAME
}
+=head3 canonicalize_path
+
+ my $canoncalized_path = canonicalize_path($path);
+
+Converts $path into a canonical form which is safe to pass to the SVN
+API as a file path.
+
+=cut
+
+# Turn foo/../bar into bar
+sub _collapse_dotdot {
+ my $path = shift;
+
+ 1 while $path =~ s{/[^/]+/+\.\.}{};
+ 1 while $path =~ s{[^/]+/+\.\./}{};
+ 1 while $path =~ s{[^/]+/+\.\.}{};
+
+ return $path;
+}
+
+
+sub canonicalize_path {
+ my $path = shift;
+ my $rv;
+
+ # The 1.7 way to do it
+ if ( defined &SVN::_Core::svn_dirent_canonicalize ) {
+ $path = _collapse_dotdot($path);
+ $rv = SVN::_Core::svn_dirent_canonicalize($path);
+ }
+ # The 1.6 way to do it
+ # This can return undef on subversion-perl-1.4.2-2.el5 (CentOS 5.2)
+ elsif ( defined &SVN::_Core::svn_path_canonicalize ) {
+ $path = _collapse_dotdot($path);
+ $rv = SVN::_Core::svn_path_canonicalize($path);
+ }
+
+ return $rv if defined $rv;
+
+ # No SVN API canonicalization is available, or the SVN API
+ # didn't return a successful result, do it ourselves
+ return _canonicalize_path_ourselves($path);
+}
+
+
+sub _canonicalize_path_ourselves {
+ my ($path) = @_;
+ my $dot_slash_added = 0;
+ if (substr($path, 0, 1) ne "/") {
+ $path = "./" . $path;
+ $dot_slash_added = 1;
+ }
+ $path =~ s#/+#/#g;
+ $path =~ s#/\.(?:/|$)#/#g;
+ $path = _collapse_dotdot($path);
+ $path =~ s#/$##g;
+ $path =~ s#^\./## if $dot_slash_added;
+ $path =~ s#^/##;
+ $path =~ s#^\.$##;
+ return $path;
+}
+
+
+=head3 canonicalize_url
+
+ my $canonicalized_url = canonicalize_url($url);
+
+Converts $url into a canonical form which is safe to pass to the SVN
+API as a URL.
+
+=cut
+
+sub canonicalize_url {
+ my $url = shift;
+
+ # The 1.7 way to do it
+ if ( defined &SVN::_Core::svn_uri_canonicalize ) {
+ return SVN::_Core::svn_uri_canonicalize($url);
+ }
+ # There wasn't a 1.6 way to do it, so we do it ourself.
+ else {
+ return _canonicalize_url_ourselves($url);
+ }
+}
+
+
+sub _canonicalize_url_path {
+ my ($uri_path) = @_;
+
+ my @parts;
+ foreach my $part (split m{/+}, $uri_path) {
+ $part =~ s/([^~\w.%+-]|%(?![a-fA-F0-9]{2}))/sprintf("%%%02X",ord($1))/eg;
+ push @parts, $part;
+ }
+
+ return join('/', @parts);
+}
+
+sub _canonicalize_url_ourselves {
+ my ($url) = @_;
+ if ($url =~ m#^([^:]+)://([^/]*)(.*)$#) {
+ my ($scheme, $domain, $uri) = ($1, $2, _canonicalize_url_path(canonicalize_path($3)));
+ $url = "$scheme://$domain$uri";
+ }
+ $url;
+}
+
+
+=head3 join_paths
+
+ my $new_path = join_paths(@paths);
+
+Appends @paths together into a single path. Any empty paths are ignored.
+
+=cut
+
+sub join_paths {
+ my @paths = @_;
+
+ @paths = grep { defined $_ && length $_ } @paths;
+
+ return '' unless @paths;
+ return $paths[0] if @paths == 1;
+
+ my $new_path = shift @paths;
+ $new_path =~ s{/+$}{};
+
+ my $last_path = pop @paths;
+ $last_path =~ s{^/+}{};
+
+ for my $path (@paths) {
+ $path =~ s{^/+}{};
+ $path =~ s{/+$}{};
+ $new_path .= "/$path";
+ }
+
+ return $new_path .= "/$last_path";
+}
+
+
+=head3 add_path_to_url
+
+ my $new_url = add_path_to_url($url, $path);
+
+Appends $path onto the $url. If $path is empty, $url is returned unchanged.
+
+=cut
+
+sub add_path_to_url {
+ my($url, $path) = @_;
+
+ return $url if !defined $path or !length $path;
+
+ # Strip trailing and leading slashes so we don't
+ # wind up with http://x.com///path
+ $url =~ s{/+$}{};
+ $path =~ s{^/+}{};
+
+ # If a path has a % in it, URI escape it so it's not
+ # mistaken for a URI escape later.
+ $path =~ s{%}{%25}g;
+
+ return join '/', $url, $path;
+}
+
1;
static int run_slot(struct active_request_slot *slot)
{
- int err = 0;
+ int err;
struct slot_results results;
slot->results = &results;
slot->curl_result = curl_easy_perform(slot->curl);
finish_active_slot(slot);
- if (results.curl_result != CURLE_OK) {
- err |= error("RPC failed; result=%d, HTTP code = %ld",
- results.curl_result, results.http_code);
+ err = handle_curl_result(slot);
+ if (err != HTTP_OK && err != HTTP_REAUTH) {
+ error("RPC failed; result=%d, HTTP code = %ld",
+ results.curl_result, results.http_code);
}
return err;
}
if (large_request) {
- err = probe_rpc(rpc);
- if (err)
- return err;
+ do {
+ err = probe_rpc(rpc);
+ } while (err == HTTP_REAUTH);
+ if (err != HTTP_OK)
+ return -1;
}
slot = get_active_slot();
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, rpc_in);
curl_easy_setopt(slot->curl, CURLOPT_FILE, rpc);
- err = run_slot(slot);
+ do {
+ err = run_slot(slot);
+ } while (err == HTTP_REAUTH && !large_request && !use_gzip);
+ if (err != HTTP_OK)
+ err = -1;
curl_slist_free_all(headers);
free(gzip_body);
const char *this = arg;
int symmetric = *next == '.';
unsigned int flags_exclude = flags ^ UNINTERESTING;
+ static const char head_by_default[] = "HEAD";
unsigned int a_flags;
*dotdot = 0;
next += symmetric;
if (!*next)
- next = "HEAD";
+ next = head_by_default;
if (dotdot == arg)
- this = "HEAD";
+ this = head_by_default;
+ if (this == head_by_default && next == head_by_default &&
+ !symmetric) {
+ /*
+ * Just ".."? That is not a range but the
+ * pathspec for the parent directory.
+ */
+ if (!cant_be_filename) {
+ *dotdot = '.';
+ return -1;
+ }
+ }
if (!get_sha1_committish(this, from_sha1) &&
!get_sha1_committish(next, sha1)) {
struct commit *a, *b;
!strcmp(arg, "--no-walk") || !strcmp(arg, "--do-walk") ||
!strcmp(arg, "--bisect") || !prefixcmp(arg, "--glob=") ||
!prefixcmp(arg, "--branches=") || !prefixcmp(arg, "--tags=") ||
- !prefixcmp(arg, "--remotes="))
+ !prefixcmp(arg, "--remotes=") || !prefixcmp(arg, "--no-walk="))
{
unkv[(*unkc)++] = arg;
return 1;
} else if (!strcmp(arg, "--not")) {
*flags ^= UNINTERESTING;
} else if (!strcmp(arg, "--no-walk")) {
- revs->no_walk = 1;
+ revs->no_walk = REVISION_WALK_NO_WALK_SORTED;
+ } else if (!prefixcmp(arg, "--no-walk=")) {
+ /*
+ * Detached form ("--no-walk X" as opposed to "--no-walk=X")
+ * not allowed, since the argument is optional.
+ */
+ if (!strcmp(arg + 10, "sorted"))
+ revs->no_walk = REVISION_WALK_NO_WALK_SORTED;
+ else if (!strcmp(arg + 10, "unsorted"))
+ revs->no_walk = REVISION_WALK_NO_WALK_UNSORTED;
+ else
+ return error("invalid argument to --no-walk");
} else if (!strcmp(arg, "--do-walk")) {
revs->no_walk = 0;
} else {
}
e++;
}
- commit_list_sort_by_date(&revs->commits);
if (!revs->leak_pending)
free(list);
+ if (revs->no_walk != REVISION_WALK_NO_WALK_UNSORTED)
+ commit_list_sort_by_date(&revs->commits);
if (revs->no_walk)
return 0;
if (revs->limited)
} *rev;
};
+#define REVISION_WALK_WALK 0
+#define REVISION_WALK_NO_WALK_SORTED 1
+#define REVISION_WALK_NO_WALK_UNSORTED 2
+
struct rev_info {
/* Starting list */
struct commit_list *commits;
/* Traversal flags */
unsigned int dense:1,
prune:1,
- no_walk:1,
+ no_walk:2,
show_all:1,
remove_empty_trees:1,
simplify_history:1,
if (allow_empty)
argv_array_push(&array, "--allow-empty");
+ if (opts->allow_empty_message)
+ argv_array_push(&array, "--allow-empty-message");
+
rc = run_command_v_opt(array.argv, RUN_GIT_CMD);
argv_array_clear(&array);
return rc;
static void prepare_revs(struct replay_opts *opts)
{
- if (opts->action != REPLAY_REVERT)
+ /*
+ * picking (but not reverting) ranges (but not individual revisions)
+ * should be done in reverse
+ */
+ if (opts->action == REPLAY_PICK && !opts->revs->no_walk)
opts->revs->reverse ^= 1;
if (prepare_revision_walk(opts->revs))
int allow_ff;
int allow_rerere_auto;
int allow_empty;
+ int allow_empty_message;
int keep_redundant_commits;
int mainline;
--- /dev/null
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+
+use Test::More 'no_plan';
+
+use Git::SVN::Utils qw(
+ add_path_to_url
+);
+
+# A reference cannot be a hash key, so we use an array.
+my @tests = (
+ ["http://x.com", "bar"] => 'http://x.com/bar',
+ ["http://x.com", ""] => 'http://x.com',
+ ["http://x.com/foo/", undef] => 'http://x.com/foo/',
+ ["http://x.com/foo/", "/bar/baz/"] => 'http://x.com/foo/bar/baz/',
+ ["http://x.com", 'per%cent'] => 'http://x.com/per%25cent',
+);
+
+while(@tests) {
+ my($have, $want) = splice @tests, 0, 2;
+
+ my $args = join ", ", map { qq['$_'] } map { defined($_) ? $_ : 'undef' } @$have;
+ my $name = "add_path_to_url($args) eq $want";
+ is add_path_to_url(@$have), $want, $name;
+}
--- /dev/null
+#!/usr/bin/env perl
+
+# Test our own home rolled URL canonicalizer. Test the private one
+# directly because we can't predict what the SVN API is doing to do.
+
+use strict;
+use warnings;
+
+use Test::More 'no_plan';
+
+use Git::SVN::Utils;
+my $canonicalize_url = \&Git::SVN::Utils::_canonicalize_url_ourselves;
+
+my %tests = (
+ "http://x.com" => "http://x.com",
+ "http://x.com/" => "http://x.com",
+ "http://x.com/foo/bar" => "http://x.com/foo/bar",
+ "http://x.com//foo//bar//" => "http://x.com/foo/bar",
+ "http://x.com/ /%/" => "http://x.com/%20%20/%25",
+);
+
+for my $arg (keys %tests) {
+ my $want = $tests{$arg};
+
+ is $canonicalize_url->($arg), $want, "canonicalize_url('$arg') => $want";
+}
--- /dev/null
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+
+use Test::More 'no_plan';
+
+use Git::SVN::Utils;
+my $collapse_dotdot = \&Git::SVN::Utils::_collapse_dotdot;
+
+my %tests = (
+ "foo/bar/baz" => "foo/bar/baz",
+ ".." => "..",
+ "foo/.." => "",
+ "/foo/bar/../../baz" => "/baz",
+ "deeply/.././deeply/nested" => "./deeply/nested",
+);
+
+for my $arg (keys %tests) {
+ my $want = $tests{$arg};
+
+ is $collapse_dotdot->($arg), $want, "_collapse_dotdot('$arg') => $want";
+}
--- /dev/null
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+
+use Test::More 'no_plan';
+
+use Git::SVN::Utils qw(
+ join_paths
+);
+
+# A reference cannot be a hash key, so we use an array.
+my @tests = (
+ [] => '',
+ ["/x.com", "bar"] => '/x.com/bar',
+ ["x.com", ""] => 'x.com',
+ ["/x.com/foo/", undef, "bar"] => '/x.com/foo/bar',
+ ["x.com/foo/", "/bar/baz/"] => 'x.com/foo/bar/baz/',
+ ["foo", "bar"] => 'foo/bar',
+ ["/foo/bar", "baz", "/biff"] => '/foo/bar/baz/biff',
+ ["", undef, "."] => '.',
+ [] => '',
+
+);
+
+while(@tests) {
+ my($have, $want) = splice @tests, 0, 2;
+
+ my $args = join ", ", map { qq['$_'] } map { defined($_) ? $_ : 'undef' } @$have;
+ my $name = "join_paths($args) eq '$want'";
+ is join_paths(@$have), $want, $name;
+}
cat stderr &&
false
fi &&
+ if test_have_prereq MINGW
+ then
+ dos2unix -q stderr
+ fi &&
test_cmp expect-stdout stdout &&
test_cmp expect-stderr stderr
}
EOF
"$PYTHON_PATH" "$TRASH_DIRECTORY/marshal-dump.py"
}
+
+#
+# Construct a client with this list of View lines
+#
+client_view() {
+ (
+ cat <<-EOF &&
+ Client: client
+ Description: client
+ Root: $cli
+ View:
+ EOF
+ for arg ; do
+ printf "\t$arg\n"
+ done
+ ) | p4 client -i
+}
test_i18ngrep "Updates were rejected because" output
'
}
+
+setup_askpass_helper() {
+ test_expect_success 'setup askpass helper' '
+ write_script "$TRASH_DIRECTORY/askpass" <<-\EOF &&
+ echo >>"$TRASH_DIRECTORY/askpass-query" "askpass: $*" &&
+ cat "$TRASH_DIRECTORY/askpass-response"
+ EOF
+ GIT_ASKPASS="$TRASH_DIRECTORY/askpass" &&
+ export GIT_ASKPASS &&
+ export TRASH_DIRECTORY
+ '
+}
+
+set_askpass() {
+ >"$TRASH_DIRECTORY/askpass-query" &&
+ echo "$*" >"$TRASH_DIRECTORY/askpass-response"
+}
+
+expect_askpass() {
+ dest=$HTTPD_DEST
+ {
+ case "$1" in
+ none)
+ ;;
+ pass)
+ echo "askpass: Password for 'http://$2@$dest': "
+ ;;
+ both)
+ echo "askpass: Username for 'http://$dest': "
+ echo "askpass: Password for 'http://$2@$dest': "
+ ;;
+ *)
+ false
+ ;;
+ esac
+ } >"$TRASH_DIRECTORY/askpass-expect" &&
+ test_cmp "$TRASH_DIRECTORY/askpass-expect" \
+ "$TRASH_DIRECTORY/askpass-query"
+}
PassEnv GIT_VALGRIND_OPTIONS
Alias /dumb/ www/
-Alias /auth/ www/auth/
+Alias /auth/dumb/ www/auth/dumb/
-<Location /smart/>
+<LocationMatch /smart/>
SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}
SetEnv GIT_HTTP_EXPORT_ALL
-</Location>
-<Location /smart_noexport/>
+</LocationMatch>
+<LocationMatch /smart_noexport/>
SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}
-</Location>
-<Location /smart_custom_env/>
+</LocationMatch>
+<LocationMatch /smart_custom_env/>
SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}
SetEnv GIT_HTTP_EXPORT_ALL
SetEnv GIT_COMMITTER_NAME "Custom User"
SetEnv GIT_COMMITTER_EMAIL custom@example.com
-</Location>
-ScriptAlias /smart/ ${GIT_EXEC_PATH}/git-http-backend/
-ScriptAlias /smart_noexport/ ${GIT_EXEC_PATH}/git-http-backend/
-ScriptAlias /smart_custom_env/ ${GIT_EXEC_PATH}/git-http-backend/
+</LocationMatch>
+ScriptAliasMatch /smart_*[^/]*/(.*) ${GIT_EXEC_PATH}/git-http-backend/$1
<Directory ${GIT_EXEC_PATH}>
Options FollowSymlinks
</Directory>
Require valid-user
</Location>
+<LocationMatch "^/auth-push/.*/git-receive-pack$">
+ AuthType Basic
+ AuthName "git-auth"
+ AuthUserFile passwd
+ Require valid-user
+</LocationMatch>
+
<IfDefine DAV>
LoadModule dav_module modules/mod_dav.so
LoadModule dav_fs_module modules/mod_dav_fs.so
echo "$t -> $2" >expect
test_expect_${3:-success} "relative date ($2)" "
test-date show $t >actual &&
- test_cmp expect actual
+ test_i18ncmp expect actual
"
}
test_expect_success 'test help' '
test_must_fail test-parse-options -h > output 2> output.err &&
test ! -s output.err &&
- test_cmp expect output
+ test_i18ncmp expect output
'
mv expect expect.err
test_cmp expect output
}
+check_i18n() {
+ what="$1" &&
+ shift &&
+ expect="$1" &&
+ shift &&
+ sed "s/^$what .*/$what $expect/" <expect.template >expect &&
+ test-parse-options $* >output 2>output.err &&
+ test ! -s output.err &&
+ test_i18ncmp expect output
+}
+
check_unknown() {
case "$1" in
--*)
test_cmp expect output.err
}
+check_unknown_i18n() {
+ case "$1" in
+ --*)
+ echo error: unknown option \`${1#--}\' >expect ;;
+ -*)
+ echo error: unknown switch \`${1#-}\' >expect ;;
+ esac &&
+ cat expect.err >>expect &&
+ test_must_fail test-parse-options $* >output 2>output.err &&
+ test ! -s output &&
+ test_i18ncmp expect output.err
+}
+
test_expect_success 'OPT_BOOL() #1' 'check boolean: 1 --yes'
test_expect_success 'OPT_BOOL() #2' 'check boolean: 1 --no-doubt'
test_expect_success 'OPT_BOOL() #3' 'check boolean: 1 -D'
test_expect_success 'OPT_BOOL() negation #1' 'check boolean: 0 -D --no-yes'
test_expect_success 'OPT_BOOL() negation #2' 'check boolean: 0 -D --no-no-doubt'
-test_expect_success 'OPT_BOOL() no negation #1' 'check_unknown --fear'
-test_expect_success 'OPT_BOOL() no negation #2' 'check_unknown --no-no-fear'
+test_expect_success 'OPT_BOOL() no negation #1' 'check_unknown_i18n --fear'
+test_expect_success 'OPT_BOOL() no negation #2' 'check_unknown_i18n --no-no-fear'
test_expect_success 'OPT_BOOL() positivation' 'check boolean: 0 -D --doubt'
test_expect_success 'OPT_CALLBACK() and callback errors work' '
test_must_fail test-parse-options --no-length > output 2> output.err &&
- test_cmp expect output &&
- test_cmp expect.err output.err
+ test_i18ncmp expect output &&
+ test_i18ncmp expect.err output.err
'
cat > expect <<EOF
test_expect_success 'no arguments, but no crash' '
test_must_fail git config >output 2>&1 &&
- grep usage output
+ test_i18ngrep usage output
'
cat > .git/config << EOF
test_expect_success 'test --parseopt help output' '
test_expect_code 129 git rev-parse --parseopt -- -h > output < optionspec &&
- test_cmp expect output
+ test_i18ncmp expect output
'
cat > expect <<EOF
test_cmp expect actual
'
+test_expect_success 'dotdot is not an empty set' '
+ ( H=$(git rev-parse HEAD) && echo $H && echo ^$H ) >expect &&
+
+ git rev-parse HEAD.. >actual &&
+ test_cmp expect actual &&
+
+ git rev-parse ..HEAD >actual &&
+ test_cmp expect actual &&
+
+ echo .. >expect &&
+ git rev-parse .. >actual &&
+ test_cmp expect actual
+'
+
test_done
test_expect_success 'checkout-index --gobbledegook' '
test_expect_code 129 git checkout-index --gobbledegook 2>err &&
- grep "[Uu]sage" err
+ test_i18ngrep "[Uu]sage" err
'
test_expect_success 'checkout-index -h in broken repository' '
>.git/index &&
test_expect_code 129 git checkout-index -h >usage 2>&1
) &&
- grep "[Uu]sage" broken/usage
+ test_i18ngrep "[Uu]sage" broken/usage
'
test_done
test_expect_success 'update-index --nonsense dumps usage' '
test_expect_code 129 git update-index --nonsense 2>err &&
- grep "[Uu]sage: git update-index" err
+ test_i18ngrep "[Uu]sage: git update-index" err
'
test_expect_success 'update-index -h with corrupt index' '
>.git/index &&
test_expect_code 129 git update-index -h >usage 2>&1
) &&
- grep "[Uu]sage: git update-index" broken/usage
+ test_i18ngrep "[Uu]sage: git update-index" broken/usage
'
test_expect_success '--cacheinfo does not accept blob null sha1' '
test_expect_success 'ls-files with nonsense option' '
test_expect_code 129 git ls-files --nonsense 2>actual &&
- grep "[Uu]sage: git ls-files" actual
+ test_i18ngrep "[Uu]sage: git ls-files" actual
'
test_expect_success 'ls-files -h in corrupt repository' '
>.git/index &&
test_expect_code 129 git ls-files -h >usage 2>&1
) &&
- grep "[Uu]sage: git ls-files " broken/usage
+ test_i18ngrep "[Uu]sage: git ls-files " broken/usage
'
test_done
>.git/refs/heads/master &&
test_expect_code 129 git branch -h >usage 2>&1
) &&
- grep "[Uu]sage" broken/usage
+ test_i18ngrep "[Uu]sage" broken/usage
'
test_expect_success \
test_expect_success \
'git branch -m dumps usage' \
'test_expect_code 129 git branch -m 2>err &&
- grep "[Uu]sage: git branch" err'
+ test_i18ngrep "[Uu]sage: git branch" err'
test_expect_success \
'git branch -m m m/m should work' \
'git tag foobar &&
test_must_fail git branch --track my11 foobar'
+test_expect_success 'use --set-upstream-to modify HEAD' \
+ 'test_config branch.master.remote foo &&
+ test_config branch.master.merge foo &&
+ git branch my12
+ git branch --set-upstream-to my12 &&
+ test "$(git config branch.master.remote)" = "." &&
+ test "$(git config branch.master.merge)" = "refs/heads/my12"'
+
+test_expect_success 'use --set-upstream-to modify a particular branch' \
+ 'git branch my13
+ git branch --set-upstream-to master my13 &&
+ test "$(git config branch.my13.remote)" = "." &&
+ test "$(git config branch.my13.merge)" = "refs/heads/master"'
+
+test_expect_success '--unset-upstream should fail if given a non-existent branch' \
+ 'test_must_fail git branch --unset-upstream i-dont-exist'
+
+test_expect_success 'test --unset-upstream on HEAD' \
+ 'git branch my14
+ test_config branch.master.remote foo &&
+ test_config branch.master.merge foo &&
+ git branch --set-upstream-to my14 &&
+ git branch --unset-upstream &&
+ test_must_fail git config branch.master.remote &&
+ test_must_fail git config branch.master.merge &&
+ # fail for a branch without upstream set
+ test_must_fail git branch --unset-upstream
+'
+
+test_expect_success 'test --unset-upstream on a particular branch' \
+ 'git branch my15
+ git branch --set-upstream-to master my14 &&
+ git branch --unset-upstream my14 &&
+ test_must_fail git config branch.my14.remote &&
+ test_must_fail git config branch.my14.merge'
+
+test_expect_success '--set-upstream shows message when creating a new branch that exists as remote-tracking' \
+ 'git update-ref refs/remotes/origin/master HEAD &&
+ git branch --set-upstream origin/master 2>actual &&
+ test_when_finished git update-ref -d refs/remotes/origin/master &&
+ test_when_finished git branch -d origin/master &&
+ cat >expected <<EOF &&
+The --set-upstream flag is deprecated and will be removed. Consider using --track or --set-upstream-to
+
+If you wanted to make '"'master'"' track '"'origin/master'"', do this:
+
+ git branch -d origin/master
+ git branch --set-upstream-to origin/master
+EOF
+ test_cmp expected actual
+'
+
+test_expect_success '--set-upstream with two args only shows the deprecation message' \
+ 'git branch --set-upstream master my13 2>actual &&
+ test_when_finished git branch --unset-upstream master &&
+ cat >expected <<EOF &&
+The --set-upstream flag is deprecated and will be removed. Consider using --track or --set-upstream-to
+EOF
+ test_cmp expected actual
+'
+
+test_expect_success '--set-upstream with one arg only shows the deprecation message if the branch existed' \
+ 'git branch --set-upstream my13 2>actual &&
+ test_when_finished git branch --unset-upstream my13 &&
+ cat >expected <<EOF &&
+The --set-upstream flag is deprecated and will be removed. Consider using --track or --set-upstream-to
+EOF
+ test_cmp expected actual
+'
+
# Keep this test last, as it changes the current branch
cat >expect <<EOF
$_z40 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 branch: Created from master
git diff --exit-code HEAD &&
test_must_fail git cherry-pick --nonsense 2>msg &&
git diff --exit-code HEAD "$pos" &&
- grep '[Uu]sage:' msg
+ test_i18ngrep '[Uu]sage:' msg
'
test_expect_success 'revert --nonsense' '
git diff --exit-code HEAD &&
test_must_fail git revert --nonsense 2>msg &&
git diff --exit-code HEAD "$pos" &&
- grep '[Uu]sage:' msg
+ test_i18ngrep '[Uu]sage:' msg
'
test_expect_success 'cherry-pick after renaming branch' '
'
+test_expect_success 'cherry-pick a commit with an empty message with --allow-empty-message' '
+ git checkout -f master &&
+ git cherry-pick --allow-empty-message empty-branch
+'
+
test_expect_success 'cherry pick an empty non-ff commit without --allow-empty' '
git checkout master &&
echo fourth >>file2 &&
check_head_differs_from fourth
'
+test_expect_success 'cherry-pick three one two works' '
+ git checkout -f first &&
+ test_commit one &&
+ test_commit two &&
+ test_commit three &&
+ git checkout -f master &&
+ git reset --hard first &&
+ git cherry-pick three one two &&
+ git diff --quiet three &&
+ git diff --quiet HEAD three &&
+ test "$(git log --reverse --format=%s first..)" = "three
+one
+two"
+'
+
test_expect_success 'output to keep user entertained during multi-pick' '
cat <<-\EOF >expected &&
[master OBJID] second
git stash apply
) |
sed -e 1,2d >actual && # drop "Saved..." and "HEAD is now..."
- test_cmp expect actual
+ test_i18ncmp expect actual
'
cat > expect << EOF
test_chmod -x rezrov &&
echo " 0 files changed" >expect &&
git diff HEAD --stat >actual &&
- test_cmp expect actual
+ test_i18ncmp expect actual
'
test_expect_success '--shortstat output after text chmod' '
git diff HEAD --shortstat >actual &&
- test_cmp expect actual
+ test_i18ncmp expect actual
'
test_expect_success '--stat output after binary chmod' '
test_chmod +x binbin &&
echo " 0 files changed" >expect &&
git diff HEAD --stat >actual &&
- test_cmp expect actual
+ test_i18ncmp expect actual
'
test_expect_success '--shortstat output after binary chmod' '
git diff HEAD --shortstat >actual &&
- test_cmp expect actual
+ test_i18ncmp expect actual
'
test_done
# apply needs to be able to skip the binary material correctly
# in order to report the line number of a corrupt patch.
-test_expect_success 'apply detecting corrupt patch correctly' '
+test_expect_success C_LOCALE_OUTPUT 'apply detecting corrupt patch correctly' '
git diff >output &&
sed -e "s/-CIT/xCIT/" <output >broken &&
test_must_fail git apply --stat --summary broken 2>detected &&
test "$detected" = xCIT
'
-test_expect_success 'apply detecting corrupt patch correctly' '
+test_expect_success C_LOCALE_OUTPUT 'apply detecting corrupt patch correctly' '
git diff --binary | sed -e "s/-CIT/xCIT/" >broken &&
test_must_fail git apply --stat --summary broken 2>detected &&
detected=`cat detected` &&
'
. ./test-lib.sh
-# setup
-
-cat >file1 <<EOF
-A quick brown fox jumps over the lazy dog.
-A tiny little penguin runs around in circles.
-There is a flag with Linux written on it.
-A slow black-and-white panda just sits there,
-munching on his bamboo.
-EOF
-cat file1 >file2
-cat file1 >file4
-
-test_expect_success 'setup' "
+test_expect_success 'setup' '
+ cat >file1 <<-\EOF &&
+ A quick brown fox jumps over the lazy dog.
+ A tiny little penguin runs around in circles.
+ There is a flag with Linux written on it.
+ A slow black-and-white panda just sits there,
+ munching on his bamboo.
+ EOF
+ cat file1 >file2 &&
+ cat file1 >file4 &&
+
git update-index --add --remove file1 file2 file4 &&
- git commit -m 'Initial Version' 2>/dev/null &&
+ git commit -m "Initial Version" 2>/dev/null &&
git checkout -b binary &&
- "$PERL_PATH" -pe 'y/x/\000/' <file1 >file3 &&
+ "$PERL_PATH" -pe "y/x/\000/" <file1 >file3 &&
cat file3 >file4 &&
git add file2 &&
- "$PERL_PATH" -pe 'y/\000/v/' <file3 >file1 &&
+ "$PERL_PATH" -pe "y/\000/v/" <file3 >file1 &&
rm -f file2 &&
git update-index --add --remove file1 file2 file3 file4 &&
- git commit -m 'Second Version' &&
+ git commit -m "Second Version" &&
git diff-tree -p master binary >B.diff &&
git diff-tree -p -C master binary >C.diff &&
git diff-tree -p --full-index master binary >B-index.diff &&
git diff-tree -p -C --full-index master binary >C-index.diff &&
+ git diff-tree -p --binary --no-prefix master binary -- file3 >B0.diff &&
+
git init other-repo &&
- (cd other-repo &&
- git fetch .. master &&
- git reset --hard FETCH_HEAD
+ (
+ cd other-repo &&
+ git fetch .. master &&
+ git reset --hard FETCH_HEAD
)
-"
+'
test_expect_success 'stat binary diff -- should not fail.' \
'git checkout master &&
git apply --stat --summary B.diff'
+test_expect_success 'stat binary -p0 diff -- should not fail.' '
+ git checkout master &&
+ git apply --stat -p0 B0.diff
+'
+
test_expect_success 'stat binary diff (copy) -- should not fail.' \
'git checkout master &&
git apply --stat --summary C.diff'
git apply --allow-binary-replacement --index CF.diff &&
test -z "$(git diff --name-status binary)"'
+test_expect_success 'apply binary -p0 diff' '
+ do_reset &&
+ git apply -p0 --index B0.diff &&
+ test -z "$(git diff --name-status binary -- file3)"
+'
+
test_done
test_expect_success 'apply with too large -p' '
cp file1.saved file1 &&
test_must_fail git apply --stat -p3 patch.file 2>err &&
- grep "removing 3 leading" err
+ test_i18ngrep "removing 3 leading" err
'
test_expect_success 'apply (-p2) traditional diff with funny filenames' '
test_expect_success 'apply with too large -p and fancy filename' '
cp file1.saved file1 &&
test_must_fail git apply --stat -p3 patch.escaped 2>err &&
- grep "removing 3 leading" err
+ test_i18ngrep "removing 3 leading" err
'
test_expect_success 'apply (-p2) diff, mode change only' '
test_expect_success 'apply diff with inconsistent filenames in headers' '
test_must_fail git apply bad1.patch 2>err &&
- grep "inconsistent new filename" err &&
+ test_i18ngrep "inconsistent new filename" err &&
test_must_fail git apply bad2.patch 2>err &&
- grep "inconsistent old filename" err
+ test_i18ngrep "inconsistent old filename" err
'
test_done
git update-index --index-info <failedmerge &&
cp file3.conflict file3 &&
test_must_fail git rerere --no-no-rerere-autoupdate 2>err &&
- grep [Uu]sage err &&
+ test_i18ngrep [Uu]sage err &&
test_must_fail git update-index --refresh
'
test_expect_success 'rerere -h' '
test_must_fail git rerere -h >help &&
- grep [Uu]sage help
+ test_i18ngrep [Uu]sage help
'
test_done
test_cmp expect actual
'
+test_expect_success 'git log --no-walk=sorted <commits> sorts by commit time' '
+ git log --no-walk=sorted --oneline 5d31159 804a787 394ef78 > actual &&
+ test_cmp expect actual
+'
+
cat > expect << EOF
5d31159 fourth
804a787 sixth
394ef78 fifth
EOF
+test_expect_success 'git log --no-walk=unsorted <commits> leaves list of commits as given' '
+ git log --no-walk=unsorted --oneline 5d31159 804a787 394ef78 > actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'git show <commits> leaves list of commits as given' '
git show --oneline -s 5d31159 804a787 394ef78 > actual &&
test_cmp expect actual
test_expect_success 'log --graph with diff and stats' '
git log --graph --pretty=short --stat -p >actual &&
sanitize_output >actual.sanitized <actual &&
- test_cmp expect actual.sanitized
+ test_i18ncmp expect actual.sanitized
+'
+
+test_expect_success 'dotdot is a parent directory' '
+ mkdir -p a/b &&
+ ( echo sixth && echo fifth ) >expect &&
+ ( cd a/b && git log --format=%s .. ) >actual &&
+ test_cmp expect actual
'
test_done
stat1_part=$(git diff --stat --root HEAD^) &&
printf "add bar\n$stat0_part\n\0initial\n$stat1_part\n" >expected &&
git log -z --stat --pretty="format:%s" >actual &&
- test_cmp expected actual
+ test_i18ncmp expected actual
'
test_expect_failure 'NUL termination with --stat' '
stat1_part=$(git diff --stat --root HEAD^) &&
printf "add bar\n$stat0_part\n\0initial\n$stat1_part\n\0" >expected &&
git log -z --stat --pretty="tformat:%s" >actual &&
- test_cmp expected actual
+ test_i18ncmp expected actual
'
test_done
test_expect_success \
'make sure index-pack detects the SHA1 collision' \
'test_must_fail git index-pack -o bad.idx test-3.pack 2>msg &&
- grep "SHA1 COLLISION FOUND" msg'
+ test_i18ngrep "SHA1 COLLISION FOUND" msg'
test_expect_success \
'make sure index-pack detects the SHA1 collision (large blobs)' \
'test_must_fail git -c core.bigfilethreshold=1 index-pack -o bad.idx test-3.pack 2>msg &&
- grep "SHA1 COLLISION FOUND" msg'
+ test_i18ngrep "SHA1 COLLISION FOUND" msg'
test_done
'
-test_expect_success 'remote information for the origin' '
+test_expect_success C_LOCALE_OUTPUT 'remote information for the origin' '
(
cd test &&
tokens_match origin "$(git remote)" &&
cd test &&
git remote add -f second ../two &&
tokens_match "origin second" "$(git remote)" &&
- check_remote_track origin master side &&
- check_remote_track second master side another &&
check_tracking_branch second master side another &&
git for-each-ref "--format=%(refname)" refs/remotes |
sed -e "/^refs\/remotes\/origin\//d" \
)
'
+test_expect_success C_LOCALE_OUTPUT 'check remote tracking' '
+(
+ cd test &&
+ check_remote_track origin master side &&
+ check_remote_track second master side another
+)
+'
+
test_expect_success 'remote forces tracking branches' '
(
cd test &&
)
'
-test_expect_success 'remove remote' '
+test_expect_success C_LOCALE_OUTPUT 'remove remote' '
(
cd test &&
tokens_match origin "$(git remote)" &&
git remote rm oops 2>actual2 &&
git branch -d foobranch &&
git tag -d footag &&
- test_cmp expect1 actual1 &&
- test_cmp expect2 actual2
+ test_i18ncmp expect1 actual1 &&
+ test_i18ncmp expect2 actual2
)
'
git config --add remote.two.push refs/heads/master:refs/heads/another &&
git remote show origin two > output &&
git branch -d rebase octopus &&
- test_cmp expect output)
+ test_i18ncmp expect output)
'
cat > test/expect << EOF
cd test &&
git remote show -n origin > output &&
mv ../one.unreachable ../one &&
- test_cmp expect output)
+ test_i18ncmp expect output)
'
test_expect_success 'prune' '
test_expect_success 'set-head --auto fails w/multiple HEADs' '
(cd test &&
test_must_fail git remote set-head --auto two >output 2>&1 &&
- test_cmp expect output)
+ test_i18ncmp expect output)
'
cat >test/expect <<EOF
test_must_fail git rev-parse refs/remotes/origin/side &&
(cd ../one &&
git branch -m side side2) &&
- test_cmp expect output)
+ test_i18ncmp expect output)
'
test_expect_success 'add --mirror && prune' '
cd seven &&
git remote prune origin
) >err 2>&1 &&
- grep "has become dangling" err &&
+ test_i18ngrep "has become dangling" err &&
: And the dangling symref will not cause other annoying errors &&
(
printf "0032want %s\n00000009done\n0000" \
$(git rev-parse HEAD) >input &&
test_must_fail git upload-pack . <input >/dev/null 2>output.err &&
- grep "unable to read" output.err &&
- grep "pack-objects died" output.err
+ test_i18ngrep "unable to read" output.err &&
+ test_i18ngrep "pack-objects died" output.err
'
test_expect_success 'corrupt repo differently' '
"$HTTPD_DOCUMENT_ROOT_PATH/auth/dumb/test_repo.git"
'
-test_expect_success 'setup askpass helper' '
- cat >askpass <<-\EOF &&
- #!/bin/sh
- echo user@host
- EOF
- chmod +x askpass &&
- GIT_ASKPASS="$PWD/askpass" &&
- export GIT_ASKPASS
-'
+setup_askpass_helper
test_expect_success 'clone remote repository' '
cd "$ROOT_PATH" &&
test_expect_success 'push to password-protected repository (user in URL)' '
test_commit pw-user &&
+ set_askpass user@host &&
git push "$HTTPD_URL_USER/auth/dumb/test_repo.git" HEAD &&
git rev-parse --verify HEAD >expect &&
git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/auth/dumb/test_repo.git" \
test_cmp expect actual
'
+test_expect_failure 'user was prompted only once for password' '
+ expect_askpass pass user@host
+'
+
test_expect_failure 'push to password-protected repository (no user in URL)' '
test_commit pw-nouser &&
+ set_askpass user@host &&
git push "$HTTPD_URL/auth/dumb/test_repo.git" HEAD &&
+ expect_askpass both user@host
git rev-parse --verify HEAD >expect &&
git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/auth/dumb/test_repo.git" \
rev-parse --verify HEAD >actual &&
mv test_repo.git "$HTTPD_DOCUMENT_ROOT_PATH"
'
+setup_askpass_helper
+
cat >exp <<EOF
GET /smart/test_repo.git/info/refs?service=git-upload-pack HTTP/1.1 200
POST /smart/test_repo.git/git-upload-pack HTTP/1.1 200
test_expect_success 'clone remote repository' '
rm -rf test_repo_clone &&
- git clone $HTTPD_URL/smart/test_repo.git test_repo_clone
+ git clone $HTTPD_URL/smart/test_repo.git test_repo_clone &&
+ (
+ cd test_repo_clone && git config push.default matching
+ )
'
test_expect_success 'push to remote repository (standard)' '
test_cmp expect actual
'
+test_expect_success 'push over smart http with auth' '
+ cd "$ROOT_PATH/test_repo_clone" &&
+ echo push-auth-test >expect &&
+ test_commit push-auth-test &&
+ set_askpass user@host &&
+ git push "$HTTPD_URL"/auth/smart/test_repo.git &&
+ git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git" \
+ log -1 --format=%s >actual &&
+ expect_askpass both user@host &&
+ test_cmp expect actual
+'
+
+test_expect_success 'push to auth-only-for-push repo' '
+ cd "$ROOT_PATH/test_repo_clone" &&
+ echo push-half-auth >expect &&
+ test_commit push-half-auth &&
+ set_askpass user@host &&
+ git push "$HTTPD_URL"/auth-push/smart/test_repo.git &&
+ git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git" \
+ log -1 --format=%s >actual &&
+ expect_askpass both user@host &&
+ test_cmp expect actual
+'
+
stop_httpd
test_done
'
test_expect_success 'create password-protected repository' '
- mkdir "$HTTPD_DOCUMENT_ROOT_PATH/auth/" &&
+ mkdir -p "$HTTPD_DOCUMENT_ROOT_PATH/auth/dumb/" &&
cp -Rf "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \
- "$HTTPD_DOCUMENT_ROOT_PATH/auth/repo.git"
-'
-
-test_expect_success 'setup askpass helpers' '
- cat >askpass <<-EOF &&
- #!/bin/sh
- echo >>"$PWD/askpass-query" "askpass: \$*" &&
- cat "$PWD/askpass-response"
- EOF
- chmod +x askpass &&
- GIT_ASKPASS="$PWD/askpass" &&
- export GIT_ASKPASS
-'
-
-expect_askpass() {
- dest=$HTTPD_DEST
- {
- case "$1" in
- none)
- ;;
- pass)
- echo "askpass: Password for 'http://$2@$dest': "
- ;;
- both)
- echo "askpass: Username for 'http://$dest': "
- echo "askpass: Password for 'http://$2@$dest': "
- ;;
- *)
- false
- ;;
- esac
- } >askpass-expect &&
- test_cmp askpass-expect askpass-query
-}
+ "$HTTPD_DOCUMENT_ROOT_PATH/auth/dumb/repo.git"
+'
+
+setup_askpass_helper
test_expect_success 'cloning password-protected repository can fail' '
- >askpass-query &&
- echo wrong >askpass-response &&
- test_must_fail git clone "$HTTPD_URL/auth/repo.git" clone-auth-fail &&
+ set_askpass wrong &&
+ test_must_fail git clone "$HTTPD_URL/auth/dumb/repo.git" clone-auth-fail &&
expect_askpass both wrong
'
test_expect_success 'http auth can use user/pass in URL' '
- >askpass-query &&
- echo wrong >askpass-response &&
- git clone "$HTTPD_URL_USER_PASS/auth/repo.git" clone-auth-none &&
+ set_askpass wrong &&
+ git clone "$HTTPD_URL_USER_PASS/auth/dumb/repo.git" clone-auth-none &&
expect_askpass none
'
test_expect_success 'http auth can use just user in URL' '
- >askpass-query &&
- echo user@host >askpass-response &&
- git clone "$HTTPD_URL_USER/auth/repo.git" clone-auth-pass &&
+ set_askpass user@host &&
+ git clone "$HTTPD_URL_USER/auth/dumb/repo.git" clone-auth-pass &&
expect_askpass pass user@host
'
test_expect_success 'http auth can request both user and pass' '
- >askpass-query &&
- echo user@host >askpass-response &&
- git clone "$HTTPD_URL/auth/repo.git" clone-auth-both &&
+ set_askpass user@host &&
+ git clone "$HTTPD_URL/auth/dumb/repo.git" clone-auth-both &&
expect_askpass both user@host
'
echo username=user@host
echo password=user@host
}; f" &&
- >askpass-query &&
- echo wrong >askpass-response &&
- git clone "$HTTPD_URL/auth/repo.git" clone-auth-helper &&
+ set_askpass wrong &&
+ git clone "$HTTPD_URL/auth/dumb/repo.git" clone-auth-helper &&
expect_askpass none
'
test_expect_success 'http auth can get username from config' '
test_config_global "credential.$HTTPD_URL.username" user@host &&
- >askpass-query &&
- echo user@host >askpass-response &&
- git clone "$HTTPD_URL/auth/repo.git" clone-auth-user &&
+ set_askpass user@host &&
+ git clone "$HTTPD_URL/auth/dumb/repo.git" clone-auth-user &&
expect_askpass pass user@host
'
test_expect_success 'configured username does not override URL' '
test_config_global "credential.$HTTPD_URL.username" wrong &&
- >askpass-query &&
- echo user@host >askpass-response &&
- git clone "$HTTPD_URL_USER/auth/repo.git" clone-auth-user2 &&
+ set_askpass user@host &&
+ git clone "$HTTPD_URL_USER/auth/dumb/repo.git" clone-auth-user2 &&
expect_askpass pass user@host
'
git push public master:master
'
+setup_askpass_helper
+
cat >exp <<EOF
> GET /smart/repo.git/info/refs?service=git-upload-pack HTTP/1.1
> Accept: */*
git clone $HTTPD_URL/smart-redir-temp/repo.git --quiet repo-t
'
+test_expect_success 'clone from password-protected repository' '
+ echo two >expect &&
+ set_askpass user@host &&
+ git clone --bare "$HTTPD_URL/auth/smart/repo.git" smart-auth &&
+ expect_askpass both user@host &&
+ git --git-dir=smart-auth log -1 --format=%s >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'clone from auth-only-for-push repository' '
+ echo two >expect &&
+ set_askpass wrong &&
+ git clone --bare "$HTTPD_URL/auth-push/smart/repo.git" smart-noauth &&
+ expect_askpass none &&
+ git --git-dir=smart-noauth log -1 --format=%s >actual &&
+ test_cmp expect actual
+'
+
test -n "$GIT_TEST_LONG" && test_set_prereq EXPENSIVE
test_expect_success EXPENSIVE 'create 50,000 tags in the repo' '
body contents
$sig"
+cat >expected <<\EOF
+408fe76d02a785a006c2e9c669b7be5589ede96d <committer@example.com> refs/tags/master
+90b5ebede4899eda64893bc2a4c8f1d6fb6dfc40 <committer@example.com> refs/tags/bogo
+EOF
+
+test_expect_success 'Verify sort with multiple keys' '
+ git for-each-ref --format="%(objectname) %(taggeremail) %(refname)" --sort=objectname --sort=taggeremail \
+ refs/tags/bogo refs/tags/master > actual &&
+ test_cmp expected actual
+'
test_done
test_expect_success 'gc --gobbledegook' '
test_expect_code 129 git gc --nonsense 2>err &&
- grep "[Uu]sage: git gc" err
+ test_i18ngrep "[Uu]sage: git gc" err
'
test_expect_success 'gc -h with invalid configuration' '
echo "[gc] pruneexpire = CORRUPT" >>.git/config &&
test_expect_code 129 git gc -h >usage 2>&1
) &&
- grep "[Uu]sage" broken/usage
+ test_i18ngrep "[Uu]sage" broken/usage
'
test_done
test_cmp expect actual.filtered
'
+test_expect_success '-s suppresses diff' '
+ echo main3 >expect &&
+ git show -s --format=%s main3 >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success '--quiet suppresses diff' '
+ echo main3 >expect &&
+ git show --quiet --format=%s main3 >actual &&
+ test_cmp expect actual
+'
+
test_done
# dir1/untracked dir2/untracked untracked
# dir2/modified output
EOF
- test_cmp expect output
+ test_i18ncmp expect output
'
cat >expect <<\EOF
>.git/index &&
test_expect_code 129 git merge -h 2>usage
) &&
- grep "[Uu]sage: git merge" broken/usage
+ test_i18ngrep "[Uu]sage: git merge" broken/usage
'
test_expect_success 'reject non-strategy with a git-merge-foo name' '
git -c grep.extendedRegexp=true grep "a+b*c" ab >actual &&
test_cmp expected actual
'
+
+ test_expect_success "grep $L with grep.patterntype=basic" '
+ echo "ab:a+bc" >expected &&
+ git -c grep.patterntype=basic grep "a+b*c" ab >actual &&
+ test_cmp expected actual
+ '
+
+ test_expect_success "grep $L with grep.patterntype=extended" '
+ echo "ab:abc" >expected &&
+ git -c grep.patterntype=extended grep "a+b*c" ab >actual &&
+ test_cmp expected actual
+ '
+
+ test_expect_success "grep $L with grep.patterntype=fixed" '
+ echo "ab:a+b*c" >expected &&
+ git -c grep.patterntype=fixed grep "a+b*c" ab >actual &&
+ test_cmp expected actual
+ '
+
+ test_expect_success LIBPCRE "grep $L with grep.patterntype=perl" '
+ echo "ab:a+b*c" >expected &&
+ git -c grep.patterntype=perl grep "a\x{2b}b\x{2a}c" ab >actual &&
+ test_cmp expected actual
+ '
+
+ test_expect_success "grep $L with grep.patternType=default and grep.extendedRegexp=true" '
+ echo "ab:abc" >expected &&
+ git \
+ -c grep.patternType=default \
+ -c grep.extendedRegexp=true \
+ grep "a+b*c" ab >actual &&
+ test_cmp expected actual
+ '
+
+ test_expect_success "grep $L with grep.extendedRegexp=true and grep.patternType=default" '
+ echo "ab:abc" >expected &&
+ git \
+ -c grep.extendedRegexp=true \
+ -c grep.patternType=default \
+ grep "a+b*c" ab >actual &&
+ test_cmp expected actual
+ '
+
+ test_expect_success 'grep $L with grep.patternType=extended and grep.extendedRegexp=false' '
+ echo "ab:abc" >expected &&
+ git \
+ -c grep.patternType=extended \
+ -c grep.extendedRegexp=false \
+ grep "a+b*c" ab >actual &&
+ test_cmp expected actual
+ '
+
+ test_expect_success 'grep $L with grep.patternType=basic and grep.extendedRegexp=true' '
+ echo "ab:a+bc" >expected &&
+ git \
+ -c grep.patternType=basic \
+ -c grep.extendedRegexp=true \
+ grep "a+b*c" ab >actual &&
+ test_cmp expected actual
+ '
+
+ test_expect_success 'grep $L with grep.extendedRegexp=false and grep.patternType=extended' '
+ echo "ab:abc" >expected &&
+ git \
+ -c grep.extendedRegexp=false \
+ -c grep.patternType=extended \
+ grep "a+b*c" ab >actual &&
+ test_cmp expected actual
+ '
+
+ test_expect_success 'grep $L with grep.extendedRegexp=true and grep.patternType=basic' '
+ echo "ab:a+bc" >expected &&
+ git \
+ -c grep.extendedRegexp=true \
+ -c grep.patternType=basic \
+ grep "a+b*c" ab >actual &&
+ test_cmp expected actual
+ '
done
cat >expected <<EOF
test_must_fail git grep -G "a["
'
+test_expect_success 'grep invalidpattern properly dies with grep.patternType=basic' '
+ test_must_fail git -c grep.patterntype=basic grep "a["
+'
+
test_expect_success 'grep -E invalidpattern properly dies ' '
test_must_fail git grep -E "a["
'
+test_expect_success 'grep invalidpattern properly dies with grep.patternType=extended' '
+ test_must_fail git -c grep.patterntype=extended grep "a["
+'
+
test_expect_success LIBPCRE 'grep -P invalidpattern properly dies ' '
test_must_fail git grep -P "a["
'
+test_expect_success LIBPCRE 'grep invalidpattern properly dies with grep.patternType=perl' '
+ test_must_fail git -c grep.patterntype=perl grep "a["
+'
+
test_expect_success 'grep -G -E -F pattern' '
echo "ab:a+b*c" >expected &&
git grep -G -E -F "a+b*c" ab >actual &&
test_cmp expected actual
'
+test_expect_success 'grep pattern with grep.patternType=basic, =extended, =fixed' '
+ echo "ab:a+b*c" >expected &&
+ git \
+ -c grep.patterntype=basic \
+ -c grep.patterntype=extended \
+ -c grep.patterntype=fixed \
+ grep "a+b*c" ab >actual &&
+ test_cmp expected actual
+'
+
test_expect_success 'grep -E -F -G pattern' '
echo "ab:a+bc" >expected &&
git grep -E -F -G "a+b*c" ab >actual &&
test_cmp expected actual
'
+test_expect_success 'grep pattern with grep.patternType=extended, =fixed, =basic' '
+ echo "ab:a+bc" >expected &&
+ git \
+ -c grep.patterntype=extended \
+ -c grep.patterntype=fixed \
+ -c grep.patterntype=basic \
+ grep "a+b*c" ab >actual &&
+ test_cmp expected actual
+'
+
test_expect_success 'grep -F -G -E pattern' '
echo "ab:abc" >expected &&
git grep -F -G -E "a+b*c" ab >actual &&
test_cmp expected actual
'
+test_expect_success 'grep pattern with grep.patternType=fixed, =basic, =extended' '
+ echo "ab:abc" >expected &&
+ git \
+ -c grep.patterntype=fixed \
+ -c grep.patterntype=basic \
+ -c grep.patterntype=extended \
+ grep "a+b*c" ab >actual &&
+ test_cmp expected actual
+'
+
test_expect_success 'grep -G -F -P -E pattern' '
>empty &&
test_must_fail git grep -G -F -P -E "a\x{2b}b\x{2a}c" ab >actual &&
test_cmp empty actual
'
+test_expect_success 'grep pattern with grep.patternType=fixed, =basic, =perl, =extended' '
+ >empty &&
+ test_must_fail git \
+ -c grep.patterntype=fixed \
+ -c grep.patterntype=basic \
+ -c grep.patterntype=perl \
+ -c grep.patterntype=extended \
+ grep "a\x{2b}b\x{2a}c" ab >actual &&
+ test_cmp empty actual
+'
+
test_expect_success LIBPCRE 'grep -G -F -E -P pattern' '
echo "ab:a+b*c" >expected &&
git grep -G -F -E -P "a\x{2b}b\x{2a}c" ab >actual &&
test_cmp expected actual
'
+test_expect_success LIBPCRE 'grep pattern with grep.patternType=fixed, =basic, =extended, =perl' '
+ echo "ab:a+b*c" >expected &&
+ git \
+ -c grep.patterntype=fixed \
+ -c grep.patterntype=basic \
+ -c grep.patterntype=extended \
+ -c grep.patterntype=perl \
+ grep "a\x{2b}b\x{2a}c" ab >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success LIBPCRE 'grep -P pattern with grep.patternType=fixed' '
+ echo "ab:a+b*c" >expected &&
+ git \
+ -c grep.patterntype=fixed \
+ grep -P "a\x{2b}b\x{2a}c" ab >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'grep -F pattern with grep.patternType=basic' '
+ echo "ab:a+b*c" >expected &&
+ git \
+ -c grep.patterntype=basic \
+ grep -F "*c" ab >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'grep -G pattern with grep.patternType=fixed' '
+ {
+ echo "ab:a+b*c"
+ echo "ab:a+bc"
+ } >expected &&
+ git \
+ -c grep.patterntype=fixed \
+ grep -G "a+b" ab >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'grep -E pattern with grep.patternType=fixed' '
+ {
+ echo "ab:a+b*c"
+ echo "ab:a+bc"
+ echo "ab:abc"
+ } >expected &&
+ git \
+ -c grep.patterntype=fixed \
+ grep -E "a+" ab >actual &&
+ test_cmp expected actual
+'
+
test_config() {
git config "$1" "$2" &&
test_when_finished "git config --unset $1"
head=`git rev-parse --verify refs/heads/git-svn-HEAD^0`
test_expect_success 'git-svn-HEAD is a real HEAD' "test -n '$head'"
+svnrepo_escaped=`echo $svnrepo | sed 's/ /%20/'`
+
test_expect_success 'initialize old-style (v0) git svn layout' '
mkdir -p "$GIT_DIR"/git-svn/info "$GIT_DIR"/svn/info &&
echo "$svnrepo" > "$GIT_DIR"/git-svn/info/url &&
echo "$svnrepo" > "$GIT_DIR"/svn/info/url &&
git svn migrate &&
- ! test -d "$GIT_DIR"/git svn &&
+ ! test -d "$GIT_DIR"/git-svn &&
git rev-parse --verify refs/${remotes_git_svn}^0 &&
git rev-parse --verify refs/remotes/svn^0 &&
- test "$(git config --get svn-remote.svn.url)" = "$svnrepo" &&
+ test "$(git config --get svn-remote.svn.url)" = "$svnrepo_escaped" &&
test `git config --get svn-remote.svn.fetch` = \
":refs/${remotes_git_svn}"
'
start_httpd
'
+# SVN 1.7 will truncate "not-a%40{0]" to just "not-a".
+# Look at what SVN wound up naming the branch and use that.
+# Be sure to escape the @ if it shows up.
+non_reflog=`svn_cmd ls "$svnrepo/pr ject/branches" | grep not-a | sed 's/\///' | sed 's/@/%40/'`
+
test_expect_success 'test clone with funky branch names' '
git svn clone -s "$svnrepo/pr ject" project &&
(
git rev-parse "refs/remotes/%2Eleading_dot" &&
git rev-parse "refs/remotes/trailing_dot%2E" &&
git rev-parse "refs/remotes/trailing_dotlock%2Elock" &&
- git rev-parse "refs/remotes/not-a%40{0}reflog"
+ git rev-parse "refs/remotes/$non_reflog"
)
'
test_path_is_missing file3
)
'
+
+# From a report in http://stackoverflow.com/questions/11893688
+# where --use-client-spec caused branch prefixes not to be removed;
+# every file in git appeared into a subdirectory of the branch name.
+test_expect_success 'use-client-spec detect-branches setup' '
+ rm -rf "$cli" &&
+ mkdir "$cli" &&
+ (
+ cd "$cli" &&
+ client_view "//depot/usecs/... //client/..." &&
+ mkdir b1 &&
+ echo b1/b1-file1 >b1/b1-file1 &&
+ p4 add b1/b1-file1 &&
+ p4 submit -d "b1/b1-file1" &&
+
+ p4 integrate //depot/usecs/b1/... //depot/usecs/b2/... &&
+ p4 submit -d "b1 -> b2" &&
+ p4 branch -i <<-EOF &&
+ Branch: b2
+ View: //depot/usecs/b1/... //depot/usecs/b2/...
+ EOF
+
+ echo b2/b2-file2 >b2/b2-file2 &&
+ p4 add b2/b2-file2 &&
+ p4 submit -d "b2/b2-file2"
+ )
+'
+
+test_expect_success 'use-client-spec detect-branches files in top-level' '
+ test_when_finished cleanup_git &&
+ test_create_repo "$git" &&
+ (
+ cd "$git" &&
+ git p4 sync --detect-branches --use-client-spec //depot/usecs@all &&
+ git checkout -b master p4/usecs/b1 &&
+ test_path_is_file b1-file1 &&
+ test_path_is_missing b2-file2 &&
+ test_path_is_missing b1 &&
+ test_path_is_missing b2 &&
+
+ git checkout -b b2 p4/usecs/b2 &&
+ test_path_is_file b1-file1 &&
+ test_path_is_file b2-file2 &&
+ test_path_is_missing b1 &&
+ test_path_is_missing b2
+ )
+'
+
+test_expect_success 'use-client-spec detect-branches skips branches setup' '
+ (
+ cd "$cli" &&
+
+ p4 integrate //depot/usecs/b1/... //depot/usecs/b3/... &&
+ p4 submit -d "b1 -> b3" &&
+ p4 branch -i <<-EOF &&
+ Branch: b3
+ View: //depot/usecs/b1/... //depot/usecs/b3/...
+ EOF
+
+ echo b3/b3-file3 >b3/b3-file3 &&
+ p4 add b3/b3-file3 &&
+ p4 submit -d "b3/b3-file3"
+ )
+'
+
+test_expect_success 'use-client-spec detect-branches skips branches' '
+ client_view "//depot/usecs/... //client/..." \
+ "-//depot/usecs/b3/... //client/b3/..." &&
+ test_when_finished cleanup_git &&
+ test_create_repo "$git" &&
+ (
+ cd "$git" &&
+ git p4 sync --detect-branches --use-client-spec //depot/usecs@all &&
+ test_must_fail git rev-parse refs/remotes/p4/usecs/b3
+ )
+'
+
test_expect_success 'kill p4d' '
kill_p4d
'
start_p4d
'
-#
-# Construct a client with this list of View lines
-#
-client_view() {
- (
- cat <<-EOF &&
- Client: client
- Description: client
- Root: $cli
- View:
- EOF
- for arg ; do
- printf "\t$arg\n"
- done
- ) | p4 client -i
-}
-
#
# Verify these files exist, exactly. Caller creates
# a list of files in file "files".
return S_ISGITLINK(mode) ? rmdir_or_warn(file) : unlink_or_warn(file);
}
+void warn_on_inaccessible(const char *path)
+{
+ warning(_("unable to access '%s': %s"), path, strerror(errno));
+}
+
+int access_or_warn(const char *path, int mode)
+{
+ int ret = access(path, mode);
+ if (ret && errno != ENOENT)
+ warn_on_inaccessible(path);
+ return ret;
+}
+
struct passwd *xgetpwuid_self(void)
{
struct passwd *pw;