Clean up option descriptions in "git cmd --help".
* zh/arg-help-format:
builtin/*: update usage format
parse-options: format argh like error messages
--- /dev/null
+Git v2.30.1 Release Notes
+=========================
+
+This release is primarily to merge fixes accumulated on the 'master'
+front to prepare for 2.31 release that are still relevant to 2.30.x
+maintenance track.
+
+Fixes since v2.30
+-----------------
+
+ * "git fetch --recurse-submodules" failed to update a submodule
+ when it has an uninitialized (hence of no interest to the user)
+ sub-submodule, which has been corrected.
+
+ * Command line error of "git rebase" are diagnosed earlier.
+
+ * "git stash" did not work well in a sparsely checked out working
+ tree.
+
+ * Some tests expect that "ls -l" output has either '-' or 'x' for
+ group executable bit, but setgid bit can be inherited from parent
+ directory and make these fields 'S' or 's' instead, causing test
+ failures.
+
+ * "git for-each-repo --config=<var> <cmd>" should not run <cmd> for
+ any repository when the configuration variable <var> is not defined
+ even once.
+
+ * "git mergetool --tool-help" was broken in 2.29 and failed to list
+ all the available tools.
+
+ * Fix for procedure to building CI test environment for mac.
+
+ * Newline characters in the host and path part of git:// URL are
+ now forbidden.
+
+ * When more than one commit with the same patch ID appears on one
+ side, "git log --cherry-pick A...B" did not exclude them all when a
+ commit with the same patch ID appears on the other side. Now it
+ does.
+
+ * Documentation for "git fsck" lost stale bits that has become
+ incorrect.
+
+ * Doc for packfile URI feature has been clarified.
+
+Also contains minor documentation updates and code clean-ups.
as ours, by "signing off" your patch. Without sign-off, we cannot
accept your patches.
-If you can certify the below D-C-O:
+If (and only if) you certify the below D-C-O:
[[dco]]
.Developer's Certificate of Origin 1.1
http.proxySSLCertPasswordProtected::
Enable Git's password prompt for the proxy SSL certificate. Otherwise OpenSSL
will prompt the user, possibly many times, if the certificate or private key
- is encrypted. Can be overriden by the `GIT_PROXY_SSL_CERT_PASSWORD_PROTECTED`
+ is encrypted. Can be overridden by the `GIT_PROXY_SSL_CERT_PASSWORD_PROTECTED`
environment variable.
http.proxySSLCAInfo::
Pathname to the file containing the certificate bundle that should be used to
- verify the proxy with when using an HTTPS proxy. Can be overriden by the
+ verify the proxy with when using an HTTPS proxy. Can be overridden by the
`GIT_PROXY_SSL_CAINFO` environment variable.
http.emptyAuth::
`GIT_HTTP_USER_AGENT,GIT_CONFIG` would cause the trace2 output to
contain events listing the overrides for HTTP user agent and the
location of the Git configuration file (assuming any are set). May be
- overriden by the `GIT_TRACE2_ENV_VARS` environment variable. Unset by
+ overridden by the `GIT_TRACE2_ENV_VARS` environment variable. Unset by
default.
trace2.destinationDebug::
never use the local optimizations). Specifying `--no-local` will
override the default when `/path/to/repo` is given, using the regular
Git transport instead.
++
+*NOTE*: this operation can race with concurrent modification to the
+source repository, similar to running `cp -r src dst` while modifying
+`src`.
--no-hardlinks::
Force the cloning process from a repository on a local
Extracted Diagnostics
---------------------
-expect dangling commits - potential heads - due to lack of head information::
- You haven't specified any nodes as heads so it won't be
- possible to differentiate between un-parented commits and
- root nodes.
-
-missing sha1 directory '<dir>'::
- The directory holding the sha1 objects is missing.
-
unreachable <type> <object>::
The <type> object <object>, isn't actually referred to directly
or indirectly in any of the trees or commits seen. This can
DESCRIPTION
-----------
-This merges the file listing in the directory cache index with the
-actual working directory list, and shows different combinations of the
-two.
+This merges the file listing in the index with the actual working
+directory list, and shows different combinations of the two.
One or more of the options below may be used to determine the files
shown:
for running in the background without disrupting foreground
processes.
+
-The `register` subcomand will also set the `maintenance.strategy` config
+The `register` subcommand will also set the `maintenance.strategy` config
value to `incremental`, if this value is not previously set. The
`incremental` strategy uses the following schedule for each maintenance
task:
will abort the process.
The purpose of the hook is to edit the message file in place,
-and it is not supressed by the `--no-verify` option. This hook
+and it is not suppressed by the `--no-verify` option. This hook
is called even if `--prepare-p4-only` is set.
p4-changelist
smtpServerPort = 587
----
-If you have multifactor authentication setup on your gmail account, you will
+If you have multi-factor authentication set up on your Gmail account, you will
need to generate an app-specific password for use with 'git send-email'. Visit
https://security.google.com/settings/security/apppasswords to create it.
+If you do not have multi-factor authentication set up on your Gmail account,
+you will need to allow less secure app access. Visit
+https://myaccount.google.com/lesssecureapps to enable it.
+
Once your commits are ready to be sent to the mailing list, run the
following commands:
literal: surrounded by ASCII double quote (34) characters, and with
interior special characters backslash-escaped.
-For paths with merge conflicts, `X` and `Y` show the modification
-states of each side of the merge. For paths that do not have merge
-conflicts, `X` shows the status of the index, and `Y` shows the status
-of the work tree. For untracked paths, `XY` are `??`. Other status
-codes can be interpreted as follows:
+There are three different types of states that are shown using this format, and
+each one uses the `XY` syntax differently:
+
+* When a merge is occurring and the merge was successful, or outside of a merge
+ situation, `X` shows the status of the index and `Y` shows the status of the
+ working tree.
+* When a merge conflict has occurred and has not yet been resolved, `X` and `Y`
+ show the state introduced by each head of the merge, relative to the common
+ ancestor. These paths are said to be _unmerged_.
+* When a path is untracked, `X` and `Y` are always the same, since they are
+ unknown to the index. `??` is used for untracked paths. Ignored files are
+ not listed unless `--ignored` is used; if it is, ignored files are indicated
+ by `!!`.
+
+Note that the term _merge_ here also includes rebases using the default
+`--merge` strategy, cherry-picks, and anything else using the merge machinery.
+
+In the following table, these three classes are shown in separate sections, and
+these characters are used for `X` and `Y` fields for the first two sections that
+show tracked paths:
* ' ' = unmodified
* 'M' = modified
* 'C' = copied
* 'U' = updated but unmerged
-Ignored files are not listed, unless `--ignored` option is in effect,
-in which case `XY` are `!!`.
-
....
X Y Meaning
-------------------------------------------------
DESCRIPTION
-----------
-Modifies the index or directory cache. Each file mentioned is updated
-into the index and any 'unmerged' or 'needs updating' state is
-cleared.
+Modifies the index. Each file mentioned is updated into the index and
+any 'unmerged' or 'needs updating' state is cleared.
See also linkgit:git-add[1] for a more user-friendly way to do some of
the most common operations on the index.
will abort the process.
The purpose of the hook is to edit the message file in place,
-and it is not supressed by the `--no-verify` option. This hook
+and it is not suppressed by the `--no-verify` option. This hook
is called even if `--prepare-p4-only` is set.
Run `git-p4 submit --help` for details.
SYNOPSIS
--------
-$GIT_WORK_DIR/.gitmodules
+$GIT_WORK_TREE/.gitmodules
DESCRIPTION
Defines the path, relative to the top-level directory of the Git
working tree, where the submodule is expected to be checked out.
The path name must not end with a `/`. All submodule paths must
- be unique within the .gitmodules file.
+ be unique within the `.gitmodules` file.
submodule.<name>.url::
Defines a URL from which the submodule repository can be cloned.
This may be either an absolute URL ready to be passed to
- linkgit:git-clone[1] or (if it begins with ./ or ../) a location
+ linkgit:git-clone[1] or (if it begins with `./` or `../`) a location
relative to the superproject's origin repository.
In addition, there are a number of optional keys:
submodule.<name>.update::
Defines the default update procedure for the named submodule,
- i.e. how the submodule is updated by "git submodule update"
+ i.e. how the submodule is updated by the `git submodule update`
command in the superproject. This is only used by `git
submodule init` to initialize the configuration variable of
the same name. Allowed values here are 'checkout', 'rebase',
submodule.<name>.branch::
A remote branch name for tracking updates in the upstream submodule.
- If the option is not specified, it defaults to the remote 'HEAD'.
+ If the option is not specified, it defaults to the remote `HEAD`.
A special value of `.` is used to indicate that the name of the branch
in the submodule should be the same name as the current branch in the
current repository. See the `--remote` documentation in
submodule.<name>.fetchRecurseSubmodules::
This option can be used to control recursive fetching of this
- submodule. If this option is also present in the submodules entry in
- .git/config of the superproject, the setting there will override the
- one found in .gitmodules.
+ submodule. If this option is also present in the submodule's entry in
+ `.git/config` of the superproject, the setting there will override the
+ one found in `.gitmodules`.
Both settings can be overridden on the command line by using the
- "--[no-]recurse-submodules" option to "git fetch" and "git pull".
+ `--[no-]recurse-submodules` option to `git fetch` and `git pull`.
submodule.<name>.ignore::
- Defines under what circumstances "git status" and the diff family show
+ Defines under what circumstances `git status` and the diff family show
a submodule as modified. The following values are supported:
+
--
been staged).
dirty;; All changes to the submodule's work tree will be ignored, only
- committed differences between the HEAD of the submodule and its
+ committed differences between the `HEAD` of the submodule and its
recorded state in the superproject are taken into account.
untracked;; Only untracked files in submodules will be ignored.
differences, and modifications to tracked and untracked files are
shown. This is the default option.
-If this option is also present in the submodules entry in .git/config
+If this option is also present in the submodule's entry in `.git/config`
of the superproject, the setting there will override the one found in
-.gitmodules.
+`.gitmodules`.
Both settings can be overridden on the command line by using the
-"--ignore-submodules" option. The 'git submodule' commands are not
+`--ignore-submodules` option. The `git submodule` commands are not
affected by this setting.
--
EXAMPLES
--------
-Consider the following .gitmodules file:
+Consider the following `.gitmodules` file:
----
[submodule "libfoo"]
Type 5 is reserved for future expansion. Type 0 is invalid.
+=== Size encoding
+
+This document uses the following "size encoding" of non-negative
+integers: From each byte, the seven least significant bits are
+used to form the resulting integer. As long as the most significant
+bit is 1, this process continues; the byte with MSB 0 provides the
+last seven bits. The seven-bit chunks are concatenated. Later
+values are more significant.
+
+This size encoding should not be confused with the "offset encoding",
+which is also used in this document.
+
=== Deltified representation
Conceptually there are only four object types: commit, tree, tag and
so-called "thin pack"). When stored on disk however, the pack should
be self contained to avoid cyclic dependency.
-The delta data is a sequence of instructions to reconstruct an object
+The delta data starts with the size of the base object and the
+size of the object to be reconstructed. These sizes are
+encoded using the size encoding from above. The remainder of
+the delta data is a sequence of instructions to reconstruct the object
from the base object. If the base object is deltified, it must be
converted to canonical form first. Each instruction appends more and
more data to the target object until it's complete. There are two
This is the implementation: a feature, marked experimental, that allows the
server to be configured by one or more `uploadpack.blobPackfileUri=<sha1>
<uri>` entries. Whenever the list of objects to be sent is assembled, all such
-blobs are excluded, replaced with URIs. The client will download those URIs,
-expecting them to each point to packfiles containing single blobs.
+blobs are excluded, replaced with URIs. As noted in "Future work" below, the
+server can evolve in the future to support excluding other objects (or other
+implementations of servers could be made that support excluding other objects)
+without needing a protocol change, so clients should not expect that packfiles
+downloaded in this way only contain single blobs.
Client design
-------------
Object blocks use unique, abbreviated 2-32 object name keys, mapping to
ref blocks containing references pointing to that object directly, or as
the peeled value of an annotated tag. Like ref blocks, object blocks use
-the file's standard block size. The abbrevation length is available in
+the file's standard block size. The abbreviation length is available in
the footer as `obj_id_len`.
To save space in small files, object blocks may be omitted if the ref
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v2.30.0
+DEF_VER=v2.30.1pre
LF='
'
BUILT_INS += git-switch$X
BUILT_INS += git-whatchanged$X
-# what 'all' will build and 'install' will install in gitexecdir,
-# excluding programs for built-in commands
-ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
-ALL_COMMANDS_TO_INSTALL = $(ALL_PROGRAMS)
-ifeq (,$(SKIP_DASHED_BUILT_INS))
-ALL_COMMANDS_TO_INSTALL += $(BUILT_INS)
-else
-# git-upload-pack, git-receive-pack and git-upload-archive are special: they
-# are _expected_ to be present in the `bin/` directory in their dashed form.
-ALL_COMMANDS_TO_INSTALL += git-receive-pack$(X)
-ALL_COMMANDS_TO_INSTALL += git-upload-archive$(X)
-ALL_COMMANDS_TO_INSTALL += git-upload-pack$(X)
-endif
-
# what 'all' will build but not install in gitexecdir
OTHER_PROGRAMS = git$X
include config.mak.dev
endif
+# what 'all' will build and 'install' will install in gitexecdir,
+# excluding programs for built-in commands
+ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
+ALL_COMMANDS_TO_INSTALL = $(ALL_PROGRAMS)
+ifeq (,$(SKIP_DASHED_BUILT_INS))
+ALL_COMMANDS_TO_INSTALL += $(BUILT_INS)
+else
+# git-upload-pack, git-receive-pack and git-upload-archive are special: they
+# are _expected_ to be present in the `bin/` directory in their dashed form.
+ALL_COMMANDS_TO_INSTALL += git-receive-pack$(X)
+ALL_COMMANDS_TO_INSTALL += git-upload-archive$(X)
+ALL_COMMANDS_TO_INSTALL += git-upload-pack$(X)
+endif
+
ALL_CFLAGS = $(DEVELOPER_CFLAGS) $(CPPFLAGS) $(CFLAGS)
ALL_LDFLAGS = $(LDFLAGS)
ifdef NO_SYMLINK_HEAD
BASIC_CFLAGS += -DNO_SYMLINK_HEAD
endif
-ifdef GETTEXT_POISON
-$(warning The GETTEXT_POISON option has been removed in favor of runtime GIT_TEST_GETTEXT_POISON. See t/README!)
-endif
ifdef NO_GETTEXT
BASIC_CFLAGS += -DNO_GETTEXT
USE_GETTEXT_SCHEME ?= fallthrough
-Documentation/RelNotes/2.30.0.txt
\ No newline at end of file
+Documentation/RelNotes/2.30.1.txt
\ No newline at end of file
values = repo_config_get_value_multi(the_repository,
config_key);
+ /*
+ * Do nothing on an empty list, which is equivalent to the case
+ * where the config variable does not exist at all.
+ */
+ if (!values)
+ return 0;
+
for (i = 0; !result && i < values->nr; i++)
result = run_command_on_repo(values->items[i].string, &args);
die_if_checked_out(buf.buf, 1);
options.head_name = xstrdup(buf.buf);
/* If not is it a valid ref (branch or commit)? */
- } else if (!get_oid(branch_name, &options.orig_head))
+ } else if (!get_oid(branch_name, &options.orig_head) &&
+ lookup_commit_reference(the_repository,
+ &options.orig_head))
options.head_name = NULL;
else
die(_("fatal: no such branch/commit '%s'"),
}
}
-static int get_newly_staged(struct strbuf *out, struct object_id *c_tree)
-{
- struct child_process cp = CHILD_PROCESS_INIT;
- const char *c_tree_hex = oid_to_hex(c_tree);
-
- /*
- * diff-index is very similar to diff-tree above, and should be
- * converted together with update_index.
- */
- cp.git_cmd = 1;
- strvec_pushl(&cp.args, "diff-index", "--cached", "--name-only",
- "--diff-filter=A", NULL);
- strvec_push(&cp.args, c_tree_hex);
- return pipe_command(&cp, NULL, 0, out, 0, NULL, 0);
-}
-
-static int update_index(struct strbuf *out)
-{
- struct child_process cp = CHILD_PROCESS_INIT;
-
- /*
- * Update-index is very complicated and may need to have a public
- * function exposed in order to remove this forking.
- */
- cp.git_cmd = 1;
- strvec_pushl(&cp.args, "update-index", "--add", "--stdin", NULL);
- return pipe_command(&cp, out->buf, out->len, NULL, 0, NULL, 0);
-}
-
static int restore_untracked(struct object_id *u_tree)
{
int res;
return res;
}
+static void unstage_changes_unless_new(struct object_id *orig_tree)
+{
+ /*
+ * When we enter this function, there has been a clean merge of
+ * relevant trees, and the merge logic always stages whatever merges
+ * cleanly. We want to unstage those changes, unless it corresponds
+ * to a file that didn't exist as of orig_tree.
+ *
+ * However, if any SKIP_WORKTREE path is modified relative to
+ * orig_tree, then we want to clear the SKIP_WORKTREE bit and write
+ * it to the worktree before unstaging.
+ */
+
+ struct checkout state = CHECKOUT_INIT;
+ struct diff_options diff_opts;
+ struct lock_file lock = LOCK_INIT;
+ int i;
+
+ /* If any entries have skip_worktree set, we'll have to check 'em out */
+ state.force = 1;
+ state.quiet = 1;
+ state.refresh_cache = 1;
+ state.istate = &the_index;
+
+ /*
+ * Step 1: get a difference between orig_tree (which corresponding
+ * to the index before a merge was run) and the current index
+ * (reflecting the changes brought in by the merge).
+ */
+ diff_setup(&diff_opts);
+ diff_opts.flags.recursive = 1;
+ diff_opts.detect_rename = 0;
+ diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
+ diff_setup_done(&diff_opts);
+
+ do_diff_cache(orig_tree, &diff_opts);
+ diffcore_std(&diff_opts);
+
+ /* Iterate over the paths that changed due to the merge... */
+ for (i = 0; i < diff_queued_diff.nr; i++) {
+ struct diff_filepair *p;
+ struct cache_entry *ce;
+ int pos;
+
+ /* Look up the path's position in the current index. */
+ p = diff_queued_diff.queue[i];
+ pos = index_name_pos(&the_index, p->two->path,
+ strlen(p->two->path));
+
+ /*
+ * Step 2: Place changes in the working tree
+ *
+ * Stash is about restoring changes *to the working tree*.
+ * So if the merge successfully got a new version of some
+ * path, but left it out of the working tree, then clear the
+ * SKIP_WORKTREE bit and write it to the working tree.
+ */
+ if (pos >= 0 && ce_skip_worktree(active_cache[pos])) {
+ struct stat st;
+
+ ce = active_cache[pos];
+ if (!lstat(ce->name, &st)) {
+ /* Conflicting path present; relocate it */
+ struct strbuf new_path = STRBUF_INIT;
+ int fd;
+
+ strbuf_addf(&new_path,
+ "%s.stash.XXXXXX", ce->name);
+ fd = xmkstemp(new_path.buf);
+ close(fd);
+ printf(_("WARNING: Untracked file in way of "
+ "tracked file! Renaming\n "
+ " %s -> %s\n"
+ " to make room.\n"),
+ ce->name, new_path.buf);
+ if (rename(ce->name, new_path.buf))
+ die("Failed to move %s to %s\n",
+ ce->name, new_path.buf);
+ strbuf_release(&new_path);
+ }
+ checkout_entry(ce, &state, NULL, NULL);
+ ce->ce_flags &= ~CE_SKIP_WORKTREE;
+ }
+
+ /*
+ * Step 3: "unstage" changes, as long as they are still tracked
+ */
+ if (p->one->oid_valid) {
+ /*
+ * Path existed in orig_tree; restore index entry
+ * from that tree in order to "unstage" the changes.
+ */
+ int option = ADD_CACHE_OK_TO_REPLACE;
+ if (pos < 0)
+ option = ADD_CACHE_OK_TO_ADD;
+
+ ce = make_cache_entry(&the_index,
+ p->one->mode,
+ &p->one->oid,
+ p->one->path,
+ 0, 0);
+ add_index_entry(&the_index, ce, option);
+ }
+ }
+ diff_flush(&diff_opts);
+
+ /*
+ * Step 4: write the new index to disk
+ */
+ repo_hold_locked_index(the_repository, &lock, LOCK_DIE_ON_ERROR);
+ if (write_locked_index(&the_index, &lock,
+ COMMIT_LOCK | SKIP_IF_UNCHANGED))
+ die(_("Unable to write index."));
+}
+
static int do_apply_stash(const char *prefix, struct stash_info *info,
int index, int quiet)
{
if (reset_tree(&index_tree, 0, 0))
return -1;
} else {
- struct strbuf out = STRBUF_INIT;
-
- if (get_newly_staged(&out, &c_tree)) {
- strbuf_release(&out);
- return -1;
- }
-
- if (reset_tree(&c_tree, 0, 1)) {
- strbuf_release(&out);
- return -1;
- }
-
- ret = update_index(&out);
- strbuf_release(&out);
- if (ret)
- return -1;
-
- /* read back the result of update_index() back from the disk */
- discard_cache();
- read_cache();
+ unstage_changes_unless_new(&c_tree);
}
if (!quiet) {
test -z "$BREW_INSTALL_PACKAGES" ||
brew install $BREW_INSTALL_PACKAGES
brew link --force gettext
- brew cask install --no-quarantine perforce || {
+ brew install --cask --no-quarantine perforce || {
# Update the definitions and try again
cask_repo="$(brew --repository)"/Library/Taps/homebrew/homebrew-cask &&
- git -C "$cask_repo" pull --no-stat &&
- brew cask install --no-quarantine perforce
+ git -C "$cask_repo" pull --no-stat --ff-only &&
+ brew install --cask --no-quarantine perforce
} ||
- brew install caskroom/cask/perforce
+ brew install homebrew/cask/perforce
case "$jobname" in
osx-gcc)
brew install gcc@9
target_host = xstrdup(hostandport);
transport_check_allowed("git");
+ if (strchr(target_host, '\n') || strchr(path, '\n'))
+ die(_("newline is forbidden in git:// hosts and repo paths"));
/*
* These underlying connection commands die() if they
if (looks_like_command_line_option(url))
return -1;
- if (submodule_url_is_relative(url)) {
+ if (submodule_url_is_relative(url) || starts_with(url, "git://")) {
char *decoded;
const char *next;
int has_nl;
static void init_gettext_charset(const char *domain)
{
- /*
- This trick arranges for messages to be emitted in the user's
- requested encoding, but avoids setting LC_CTYPE from the
- environment for the whole program.
-
- This primarily done to avoid a bug in vsnprintf in the GNU C
- Library [1]. which triggered a "your vsnprintf is broken" error
- on Git's own repository when inspecting v0.99.6~1 under a UTF-8
- locale.
-
- That commit contains a ISO-8859-1 encoded author name, which
- the locale aware vsnprintf(3) won't interpolate in the format
- argument, due to mismatch between the data encoding and the
- locale.
-
- Even if it wasn't for that bug we wouldn't want to use LC_CTYPE at
- this point, because it'd require auditing all the code that uses C
- functions whose semantics are modified by LC_CTYPE.
-
- But only setting LC_MESSAGES as we do creates a problem, since
- we declare the encoding of our PO files[2] the gettext
- implementation will try to recode it to the user's locale, but
- without LC_CTYPE it'll emit something like this on 'git init'
- under the Icelandic locale:
-
- Bj? til t?ma Git lind ? /hlagh/.git/
-
- Gettext knows about the encoding of our PO file, but we haven't
- told it about the user's encoding, so all the non-US-ASCII
- characters get encoded to question marks.
-
- But we're in luck! We can set LC_CTYPE from the environment
- only while we call nl_langinfo and
- bind_textdomain_codeset. That suffices to tell gettext what
- encoding it should emit in, so it'll now say:
-
- Bjó til tóma Git lind à /hlagh/.git/
-
- And the equivalent ISO-8859-1 string will be emitted under a
- ISO-8859-1 locale.
-
- With this change way we get the advantages of setting LC_CTYPE
- (talk to the user in his language/encoding), without the major
- drawbacks (changed semantics for C functions we rely on).
-
- However foreign functions using other message catalogs that
- aren't using our neat trick will still have a problem, e.g. if
- we have to call perror(3):
-
- #include <stdio.h>
- #include <locale.h>
- #include <errno.h>
-
- int main(void)
- {
- setlocale(LC_MESSAGES, "");
- setlocale(LC_CTYPE, "C");
- errno = ENODEV;
- perror("test");
- return 0;
- }
-
- Running that will give you a message with question marks:
-
- $ LANGUAGE= LANG=de_DE.utf8 ./test
- test: Kein passendes Ger?t gefunden
-
- The vsnprintf bug has been fixed since glibc 2.17.
-
- Then we could simply set LC_CTYPE from the environment, which would
- make things like the external perror(3) messages work.
-
- See t/t0203-gettext-setlocale-sanity.sh's "gettext.c" tests for
- regression tests.
-
- 1. http://sourceware.org/bugzilla/show_bug.cgi?id=6530
- 2. E.g. "Content-Type: text/plain; charset=UTF-8\n" in po/is.po
- */
setlocale(LC_CTYPE, "");
charset = locale_charset();
bind_textdomain_codeset(domain, charset);
- /* the string is taken from v0.99.6~1 */
+
+ /*
+ * Work around an old bug fixed in glibc 2.17 (released on
+ * 2012-12-24), at the cost of potentially making translated
+ * messages from external functions like perror() emitted in
+ * the wrong encoding.
+ *
+ * The bug affected e.g. git.git's own 7eb93c89651 ([PATCH]
+ * Simplify git script, 2005-09-07), which is the origin of
+ * the "David_K\345gedal" test string.
+ *
+ * See a much longer comment added to this file in 5e9637c6297
+ * (i18n: add infrastructure for translating Git with gettext,
+ * 2011-11-18) for more details.
+ */
if (test_vsnprintf("%.*s", 13, "David_K\345gedal") < 0)
setlocale(LC_CTYPE, "C");
}
while read scriptname
do
setup_tool "$scriptname" 2>/dev/null
- variants="$variants$(list_tool_variants)\n"
+ # We need an actual line feed here
+ variants="$variants
+$(list_tool_variants)"
done
- variants="$(echo "$variants" | sort | uniq)"
+ variants="$(echo "$variants" | sort -u)"
for toolname in $variants
do
return 0;
}
-struct patch_id *has_commit_patch_id(struct commit *commit,
+struct patch_id *patch_id_iter_first(struct commit *commit,
struct patch_ids *ids)
{
struct patch_id patch;
return hashmap_get_entry(&ids->patches, &patch, ent, NULL);
}
+struct patch_id *patch_id_iter_next(struct patch_id *cur,
+ struct patch_ids *ids)
+{
+ return hashmap_get_next_entry(&ids->patches, cur, ent);
+}
+
+int has_commit_patch_id(struct commit *commit,
+ struct patch_ids *ids)
+{
+ return !!patch_id_iter_first(commit, ids);
+}
+
struct patch_id *add_commit_patch_id(struct commit *commit,
struct patch_ids *ids)
{
struct object_id *oid, int, int);
int init_patch_ids(struct repository *, struct patch_ids *);
int free_patch_ids(struct patch_ids *);
+
+/* Add a patch_id for a single commit to the set. */
struct patch_id *add_commit_patch_id(struct commit *, struct patch_ids *);
-struct patch_id *has_commit_patch_id(struct commit *, struct patch_ids *);
+
+/* Returns true if the patch-id of "commit" is present in the set. */
+int has_commit_patch_id(struct commit *commit, struct patch_ids *);
+
+/*
+ * Iterate over all commits in the set whose patch id matches that of
+ * "commit", like:
+ *
+ * struct patch_id *cur;
+ * for (cur = patch_id_iter_first(commit, ids);
+ * cur;
+ * cur = patch_id_iter_next(cur, ids) {
+ * ... look at cur->commit
+ * }
+ */
+struct patch_id *patch_id_iter_first(struct commit *commit, struct patch_ids *);
+struct patch_id *patch_id_iter_next(struct patch_id *cur, struct patch_ids *);
#endif /* PATCH_IDS_H */
/*
* Have we seen the same patch id?
*/
- id = has_commit_patch_id(commit, &ids);
+ id = patch_id_iter_first(commit, &ids);
if (!id)
continue;
commit->object.flags |= cherry_flag;
- id->commit->object.flags |= cherry_flag;
+ do {
+ id->commit->object.flags |= cherry_flag;
+ } while ((id = patch_id_iter_next(id, &ids)));
}
free_patch_ids(&ids);
strbuf_release(&submodule_prefix);
return 1;
} else {
+ struct strbuf empty_submodule_path = STRBUF_INIT;
fetch_task_release(task);
free(task);
* An empty directory is normal,
* the submodule is not initialized
*/
+ strbuf_addf(&empty_submodule_path, "%s/%s/",
+ spf->r->worktree,
+ ce->name);
if (S_ISGITLINK(ce->ce_mode) &&
- !is_empty_dir(ce->name)) {
+ !is_empty_dir(empty_submodule_path.buf)) {
spf->result = 1;
strbuf_addf(err,
_("Could not access submodule '%s'\n"),
ce->name);
}
+ strbuf_release(&empty_submodule_path);
}
}
command="$1"
######################### Appearing submodule #########################
# Switching to a commit letting a submodule appear creates empty dir ...
- if test "$KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES" = 1
- then
- # Restoring stash fails to restore submodule index entry
- RESULT="failure"
- else
- RESULT="success"
- fi
- test_expect_$RESULT "$command: added submodule creates empty directory" '
+ test_expect_success "$command: added submodule creates empty directory" '
prolog &&
reset_work_tree_to no_submodule &&
(
)
'
# ... and doesn't care if it already exists.
+ if test "$KNOWN_FAILURE_STASH_DOES_IGNORE_SUBMODULE_CHANGES" = 1
+ then
+ # Restoring stash fails to restore submodule index entry
+ RESULT="failure"
+ else
+ RESULT="success"
+ fi
test_expect_$RESULT "$command: added submodule leaves existing empty directory alone" '
prolog &&
reset_work_tree_to no_submodule &&
git config core.fsmonitor "$INTEGRATION_SCRIPT" &&
git update-index --fsmonitor 2>error &&
- test_must_be_empty error # ensure no silent error
+ if test_have_prereq WATCHMAN
+ then
+ test_must_be_empty error # ensure no silent error
+ else
+ grep "Empty last update token" error
+ fi
}
test_perf_w_drop_caches () {
grep again message
'
+test_expect_success 'do nothing on empty config' '
+ # the whole thing would fail if for-each-ref iterated even
+ # once, because "git help --no-such-option" would fail
+ git for-each-repo --config=bogus.config -- help --no-such-option
+'
+
test_done
'
cat > expect << EOF
-[core]
+[section]
penguin = little blue
EOF
test_expect_success 'initial' '
- git config core.penguin "little blue" &&
+ git config section.penguin "little blue" &&
test_cmp expect .git/config
'
cat > expect << EOF
-[core]
+[section]
penguin = little blue
Movie = BadPhysics
EOF
test_expect_success 'mixed case' '
- git config Core.Movie BadPhysics &&
+ git config Section.Movie BadPhysics &&
test_cmp expect .git/config
'
cat > expect << EOF
-[core]
+[section]
penguin = little blue
Movie = BadPhysics
-[Cores]
+[Sections]
WhatEver = Second
EOF
test_expect_success 'similar section' '
- git config Cores.WhatEver Second &&
+ git config Sections.WhatEver Second &&
test_cmp expect .git/config
'
cat > expect << EOF
-[core]
+[section]
penguin = little blue
Movie = BadPhysics
UPPERCASE = true
-[Cores]
+[Sections]
WhatEver = Second
EOF
test_expect_success 'uppercase section' '
- git config CORE.UPPERCASE true &&
+ git config SECTION.UPPERCASE true &&
test_cmp expect .git/config
'
test_expect_success 'replace with non-match' '
- git config core.penguin kingpin !blue
+ git config section.penguin kingpin !blue
'
test_expect_success 'replace with non-match (actually matching)' '
- git config core.penguin "very blue" !kingpin
+ git config section.penguin "very blue" !kingpin
'
cat > expect << EOF
-[core]
+[section]
penguin = very blue
Movie = BadPhysics
UPPERCASE = true
penguin = kingpin
-[Cores]
+[Sections]
WhatEver = Second
EOF
test_expect_success 'non-match result' 'test_cmp expect .git/config'
test_expect_success 'find mixed-case key by canonical name' '
- test_cmp_config Second cores.whatever
+ test_cmp_config Second sections.whatever
'
test_expect_success 'find mixed-case key by non-canonical name' '
- test_cmp_config Second CoReS.WhAtEvEr
+ test_cmp_config Second SeCtIoNs.WhAtEvEr
'
test_expect_success 'subsections are not canonicalized by git-config' '
'
test_expect_success 'alternative --file (non-existing file should fail)' '
- test_must_fail git config --file non-existing-config -l
+ test_must_fail git config --file non-existing-config -l &&
+ test_must_fail git config --file non-existing-config test.xyzzy
'
cat > other-config << EOF
test_expect_success 'refer config from subdirectory' '
mkdir x &&
- test_cmp_config -C x strasse --get --file ../other-config ein.bahn
-'
-
-test_expect_success 'refer config from subdirectory via --file' '
test_cmp_config -C x strasse --file=../other-config --get ein.bahn
'
test_cmp expect actual
'
-test_expect_success 'nonexistent configuration' '
- test_must_fail git config --file=doesnotexist --list &&
- test_must_fail git config --file=doesnotexist test.xyzzy
-'
-
test_expect_success SYMLINKS 'symlink to nonexistent configuration' '
ln -s doesnotexist linktonada &&
ln -s linktonada linktolinktonada &&
true
EOF
{
- git -c core.name=value config core.name &&
+ git -c section.name=value config section.name &&
git -c foo.CamelCase=value config foo.camelcase &&
git -c foo.flag config --bool foo.flag
} >actual &&
test_cmp expect actual &&
- test_must_fail git -c name=value config core.name
+ test_must_fail git -c name=value config section.name
'
# We just need a type-specifier here that cares about the
test_expect_success 'git -c does not split values on equals' '
echo "value with = in it" >expect &&
- git -c core.foo="value with = in it" config core.foo >actual &&
+ git -c section.foo="value with = in it" config section.foo >actual &&
test_cmp expect actual
'
done
cat >.git/config <<-\EOF &&
-[core]
+[section]
foo = true
number = 10
big = 1M
EOF
test_expect_success 'identical modern --type specifiers are allowed' '
- test_cmp_config 1048576 --type=int --type=int core.big
+ test_cmp_config 1048576 --type=int --type=int section.big
'
test_expect_success 'identical legacy --type specifiers are allowed' '
- test_cmp_config 1048576 --int --int core.big
+ test_cmp_config 1048576 --int --int section.big
'
test_expect_success 'identical mixed --type specifiers are allowed' '
- test_cmp_config 1048576 --int --type=int core.big
+ test_cmp_config 1048576 --int --type=int section.big
'
test_expect_success 'non-identical modern --type specifiers are not allowed' '
- test_must_fail git config --type=int --type=bool core.big 2>error &&
+ test_must_fail git config --type=int --type=bool section.big 2>error &&
test_i18ngrep "only one type at a time" error
'
test_expect_success 'non-identical legacy --type specifiers are not allowed' '
- test_must_fail git config --int --bool core.big 2>error &&
+ test_must_fail git config --int --bool section.big 2>error &&
test_i18ngrep "only one type at a time" error
'
test_expect_success 'non-identical mixed --type specifiers are not allowed' '
- test_must_fail git config --type=int --bool core.big 2>error &&
+ test_must_fail git config --type=int --bool section.big 2>error &&
test_i18ngrep "only one type at a time" error
'
test_expect_success '--type allows valid type specifiers' '
- test_cmp_config true --type=bool core.foo
+ test_cmp_config true --type=bool section.foo
'
test_expect_success '--no-type unsets type specifiers' '
- test_cmp_config 10 --type=bool --no-type core.number
+ test_cmp_config 10 --type=bool --no-type section.number
'
test_expect_success 'unset type specifiers may be reset to conflicting ones' '
- test_cmp_config 1048576 --type=bool --no-type --type=int core.big
+ test_cmp_config 1048576 --type=bool --no-type --type=int section.big
'
test_expect_success '--type rejects unknown specifiers' '
- test_must_fail git config --type=nonsense core.foo 2>error &&
+ test_must_fail git config --type=nonsense section.foo 2>error &&
test_i18ngrep "unrecognized --type argument" error
'
test_config core.sharedRepository 0666 &&
(
# Remove a default ACL if possible.
- (setfacl -k newdir 2>/dev/null || true) &&
+ (setfacl -k . 2>/dev/null || true) &&
umask 0077 &&
# Test both files (f1) and leading dirs (d)
git cat-file commit $SHA1_2 &&
test_must_fail env GIT_TEST_PROTOCOL_VERSION=0 \
git fetch ../testrepo/.git $SHA1_3 2>err &&
- test_i18ngrep "remote error:.*not our ref.*$SHA1_3\$" err
+ # ideally we would insist this be on a "remote error:"
+ # line, but it is racy; see the commit message
+ test_i18ngrep "not our ref.*$SHA1_3\$" err
)
'
done
)
'
+add_commit_push () {
+ dir="$1" &&
+ msg="$2" &&
+ shift 2 &&
+ git -C "$dir" add "$@" &&
+ git -C "$dir" commit -a -m "$msg" &&
+ git -C "$dir" push
+}
+
+compare_refs_in_dir () {
+ fail= &&
+ if test "x$1" = 'x!'
+ then
+ fail='!' &&
+ shift
+ fi &&
+ git -C "$1" rev-parse --verify "$2" >expect &&
+ git -C "$3" rev-parse --verify "$4" >actual &&
+ eval $fail test_cmp expect actual
+}
+
+
+test_expect_success 'setup nested submodule fetch test' '
+ # does not depend on any previous test setups
+
+ for repo in outer middle inner
+ do
+ git init --bare $repo &&
+ git clone $repo ${repo}_content &&
+ echo "$repo" >"${repo}_content/file" &&
+ add_commit_push ${repo}_content "initial" file ||
+ return 1
+ done &&
+
+ git clone outer A &&
+ git -C A submodule add "$pwd/middle" &&
+ git -C A/middle/ submodule add "$pwd/inner" &&
+ add_commit_push A/middle/ "adding inner sub" .gitmodules inner &&
+ add_commit_push A/ "adding middle sub" .gitmodules middle &&
+
+ git clone outer B &&
+ git -C B/ submodule update --init middle &&
+
+ compare_refs_in_dir A HEAD B HEAD &&
+ compare_refs_in_dir A/middle HEAD B/middle HEAD &&
+ test_path_is_file B/file &&
+ test_path_is_file B/middle/file &&
+ test_path_is_missing B/middle/inner/file &&
+
+ echo "change on inner repo of A" >"A/middle/inner/file" &&
+ add_commit_push A/middle/inner "change on inner" file &&
+ add_commit_push A/middle "change on inner" inner &&
+ add_commit_push A "change on inner" middle
+'
+
+test_expect_success 'fetching a superproject containing an uninitialized sub/sub project' '
+ # depends on previous test for setup
+
+ git -C B/ fetch &&
+ compare_refs_in_dir A origin/HEAD B origin/HEAD
+'
+
+fetch_with_recursion_abort () {
+ # In a regression the following git call will run into infinite recursion.
+ # To handle that, we connect the sed command to the git call by a pipe
+ # so that sed can kill the infinite recursion when detected.
+ # The recursion creates git output like:
+ # Fetching submodule sub
+ # Fetching submodule sub/sub <-- [1]
+ # Fetching submodule sub/sub/sub
+ # ...
+ # [1] sed will stop reading and cause git to eventually stop and die
+
+ git -C "$1" fetch --recurse-submodules 2>&1 |
+ sed "/Fetching submodule $2[^$]/q" >out &&
+ ! grep "Fetching submodule $2[^$]" out
+}
+
+test_expect_success 'setup recursive fetch with uninit submodule' '
+ # does not depend on any previous test setups
+
+ test_create_repo super &&
+ test_commit -C super initial &&
+ test_create_repo sub &&
+ test_commit -C sub initial &&
+ git -C sub rev-parse HEAD >expect &&
+
+ git -C super submodule add ../sub &&
+ git -C super commit -m "add sub" &&
+
+ git clone super superclone &&
+ git -C superclone submodule status >out &&
+ sed -e "s/^-//" -e "s/ sub.*$//" out >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'recursive fetch with uninit submodule' '
+ # depends on previous test for setup
+
+ fetch_with_recursion_abort superclone sub &&
+ git -C superclone submodule status >out &&
+ sed -e "s/^-//" -e "s/ sub$//" out >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'recursive fetch after deinit a submodule' '
+ # depends on previous test for setup
+
+ git -C superclone submodule update --init sub &&
+ git -C superclone submodule deinit -f sub &&
+
+ fetch_with_recursion_abort superclone sub &&
+ git -C superclone submodule status >out &&
+ sed -e "s/^-//" -e "s/ sub$//" out >actual &&
+ test_cmp expect actual
+'
+
test_done
)
'
+test_expect_success 'client refuses to ask for repo with newline' '
+ test_must_fail git clone "$GIT_DAEMON_URL/repo$LF.git" dst 2>stderr &&
+ test_i18ngrep newline.is.forbidden stderr
+'
+
test_remote_error()
{
do_export=YesPlease
test_cmp expect actual
'
+test_expect_success '--cherry-pick with duplicates on each side' '
+ git checkout -b dup-orig &&
+ test_commit dup-base &&
+ git revert dup-base &&
+ git cherry-pick dup-base &&
+ git checkout -b dup-side HEAD~3 &&
+ test_tick &&
+ git cherry-pick -3 dup-orig &&
+ git rev-list --cherry-pick dup-orig...dup-side >actual &&
+ test_must_be_empty actual
+'
+
# Corrupt the object store deliberately to make sure
# the object is not even checked for its existence.
remove_loose_object () {
git bisect bad $HASH4 &&
git bisect reset &&
test -z "$(git for-each-ref "refs/bisect/*")" &&
- test_path_is_missing "$GIT_DIR/BISECT_EXPECTED_REV" &&
- test_path_is_missing "$GIT_DIR/BISECT_ANCESTORS_OK" &&
- test_path_is_missing "$GIT_DIR/BISECT_LOG" &&
- test_path_is_missing "$GIT_DIR/BISECT_RUN" &&
- test_path_is_missing "$GIT_DIR/BISECT_TERMS" &&
- test_path_is_missing "$GIT_DIR/head-name" &&
- test_path_is_missing "$GIT_DIR/BISECT_HEAD" &&
- test_path_is_missing "$GIT_DIR/BISECT_START"
+ test_path_is_missing ".git/BISECT_EXPECTED_REV" &&
+ test_path_is_missing ".git/BISECT_ANCESTORS_OK" &&
+ test_path_is_missing ".git/BISECT_LOG" &&
+ test_path_is_missing ".git/BISECT_RUN" &&
+ test_path_is_missing ".git/BISECT_TERMS" &&
+ test_path_is_missing ".git/head-name" &&
+ test_path_is_missing ".git/BISECT_HEAD" &&
+ test_path_is_missing ".git/BISECT_START"
'
test_done
--diff-filter=D -- keep-me.t
'
+test_expect_success 'stash restore in sparse checkout' '
+ test_create_repo stash-restore &&
+ (
+ cd stash-restore &&
+
+ mkdir subdir &&
+ echo A >subdir/A &&
+ echo untouched >untouched &&
+ echo removeme >removeme &&
+ echo modified >modified &&
+ git add . &&
+ git commit -m Initial &&
+
+ echo AA >>subdir/A &&
+ echo addme >addme &&
+ echo tweaked >>modified &&
+ rm removeme &&
+ git add addme &&
+
+ git stash push &&
+
+ git sparse-checkout set subdir &&
+
+ # Ensure after sparse-checkout we only have expected files
+ cat >expect <<-EOF &&
+ S modified
+ S removeme
+ H subdir/A
+ S untouched
+ EOF
+ git ls-files -t >actual &&
+ test_cmp expect actual &&
+
+ test_path_is_missing addme &&
+ test_path_is_missing modified &&
+ test_path_is_missing removeme &&
+ test_path_is_file subdir/A &&
+ test_path_is_missing untouched &&
+
+ # Put a file in the working directory in the way
+ echo in the way >modified &&
+ git stash apply &&
+
+ # Ensure stash vivifies modifies paths...
+ cat >expect <<-EOF &&
+ H addme
+ H modified
+ H removeme
+ H subdir/A
+ S untouched
+ EOF
+ git ls-files -t >actual &&
+ test_cmp expect actual &&
+
+ # ...and that the paths show up in status as changed...
+ cat >expect <<-EOF &&
+ A addme
+ M modified
+ D removeme
+ M subdir/A
+ ?? actual
+ ?? expect
+ ?? modified.stash.XXXXXX
+ EOF
+ git status --porcelain | \
+ sed -e s/stash......./stash.XXXXXX/ >actual &&
+ test_cmp expect actual &&
+
+ # ...and that working directory reflects the files correctly
+ test_path_is_file addme &&
+ test_path_is_file modified &&
+ test_path_is_missing removeme &&
+ test_path_is_file subdir/A &&
+ test_path_is_missing untouched &&
+
+ # ...including that we have the expected "modified" file...
+ cat >expect <<-EOF &&
+ modified
+ tweaked
+ EOF
+ test_cmp expect modified &&
+
+ # ...and that the other "modified" file is still present...
+ echo in the way >expect &&
+ test_cmp expect modified.stash.*
+ )
+'
+
#TODO test_expect_failure 'git-apply adds file' false
#TODO test_expect_failure 'git-apply updates file' false
#TODO test_expect_failure 'git-apply removes file' false
grep gitmodulesUrl err
'
+test_expect_success 'fsck rejects embedded newline in git url' '
+ git checkout --orphan git-newline &&
+ cat >.gitmodules <<-\EOF &&
+ [submodule "foo"]
+ url = "git://example.com:1234/repo%0a.git"
+ EOF
+ git add .gitmodules &&
+ git commit -m "git url with newline" &&
+ test_when_finished "rm -rf dst" &&
+ git init --bare dst &&
+ git -C dst config transfer.fsckObjects true &&
+ test_must_fail git push dst HEAD 2>err &&
+ grep gitmodulesUrl err
+'
+
test_done
test_cmp expect actual
'
+test_expect_success 'mergetool --tool-help shows recognized tools' '
+ # Check a few known tools are correctly shown
+ git mergetool --tool-help >mergetools &&
+ grep vimdiff mergetools &&
+ grep vimdiff3 mergetools &&
+ grep gvimdiff2 mergetools &&
+ grep araxis mergetools &&
+ grep xxdiff mergetools &&
+ grep meld mergetools
+'
+
test_done
git update-index --add "--chmod=$@"
}
-# Get the modebits from a file or directory.
+# Get the modebits from a file or directory, ignoring the setgid bit (g+s).
+# This bit is inherited by subdirectories at their creation. So we remove it
+# from the returning string to prevent callers from having to worry about the
+# state of the bit in the test directory.
+#
test_modebits () {
- ls -ld "$1" | sed -e 's|^\(..........\).*|\1|'
+ ls -ld "$1" | sed -e 's|^\(..........\).*|\1|' \
+ -e 's|^\(......\)S|\1-|' -e 's|^\(......\)s|\1x|'
}
# Unset a configuration variable, but don't fail if it doesn't exist.