mirror of
https://github.com/git/git.git
synced 2026-01-21 16:06:04 +00:00
Merge branch 'ready-for-upstream'
This is the branch thicket of patches in Git for Windows that are considered ready for upstream. To keep them in a ready-to-submit shape, they are kept as close to the beginning of the branch thicket as possible.
This commit is contained in:
@@ -909,6 +909,12 @@ relatively high IO latencies. When enabled, Git will do the
|
||||
index comparison to the filesystem data in parallel, allowing
|
||||
overlapping IO's. Defaults to true.
|
||||
|
||||
core.unsetenvvars::
|
||||
EXPERIMENTAL, Windows-only: comma-separated list of environment
|
||||
variables' names that need to be unset before spawning any other
|
||||
process. Defaults to `PERL5LIB` to account for the fact that Git
|
||||
for Windows insists on using its own Perl interpreter.
|
||||
|
||||
core.createObject::
|
||||
You can set this to 'link', in which case a hardlink followed by
|
||||
a delete of the source are used to make sure that object creation
|
||||
@@ -2236,6 +2242,27 @@ http.sslCAPath::
|
||||
with when fetching or pushing over HTTPS. Can be overridden
|
||||
by the `GIT_SSL_CAPATH` environment variable.
|
||||
|
||||
http.sslBackend::
|
||||
Name of the SSL backend to use (e.g. "openssl" or "schannel").
|
||||
This option is ignored if cURL lacks support for choosing the SSL
|
||||
backend at runtime.
|
||||
|
||||
http.schannelCheckRevoke::
|
||||
Used to enforce or disable certificate revocation checks in cURL
|
||||
when http.sslBackend is set to "schannel". Defaults to `true` if
|
||||
unset. Only necessary to disable this if Git consistently errors
|
||||
and the message is about checking the revocation status of a
|
||||
certificate. This option is ignored if cURL lacks support for
|
||||
setting the relevant SSL option at runtime.
|
||||
|
||||
http.schannelUseSSLCAInfo::
|
||||
As of cURL v7.60.0, the Secure Channel backend can use the
|
||||
certificate bundle provided via `http.sslCAInfo`, but that would
|
||||
override the Windows Certificate Store. Since this is not desirable
|
||||
by default, Git will tell cURL not to use that bundle by default
|
||||
when the `schannel` backend was configured via `http.sslBackend`,
|
||||
unless `http.schannelUseSSLCAInfo` overrides this behavior.
|
||||
|
||||
http.pinnedpubkey::
|
||||
Public key of the https service. It may either be the filename of
|
||||
a PEM or DER encoded public key file or a string starting with
|
||||
@@ -3754,3 +3781,9 @@ worktree.guessRemote::
|
||||
such a branch exists, it is checked out and set as "upstream"
|
||||
for the new branch. If no such match can be found, it falls
|
||||
back to creating a new branch from the current HEAD.
|
||||
|
||||
sendpack.sideband::
|
||||
Allows to disable the side-band-64k capability for send-pack even
|
||||
when it is advertised by the server. Makes it possible to work
|
||||
around a limitation in the git for windows implementation together
|
||||
with the dump git protocol. Defaults to true.
|
||||
|
||||
@@ -10,6 +10,7 @@ SYNOPSIS
|
||||
[verse]
|
||||
'git reset' [-q] [<tree-ish>] [--] <paths>...
|
||||
'git reset' (--patch | -p) [<tree-ish>] [--] [<paths>...]
|
||||
EXPERIMENTAL: 'git reset' [-q] [--stdin [-z]] [<tree-ish>]
|
||||
'git reset' [--soft | --mixed [-N] | --hard | --merge | --keep] [-q] [<commit>]
|
||||
|
||||
DESCRIPTION
|
||||
@@ -97,6 +98,15 @@ OPTIONS
|
||||
--quiet::
|
||||
Be quiet, only report errors.
|
||||
|
||||
--stdin::
|
||||
EXPERIMENTAL: Instead of taking list of paths from the
|
||||
command line, read list of paths from the standard input.
|
||||
Paths are separated by LF (i.e. one path per line) by
|
||||
default.
|
||||
|
||||
-z::
|
||||
EXPERIMENTAL: Only meaningful with `--stdin`; paths are
|
||||
separated with NUL character instead of LF.
|
||||
|
||||
EXAMPLES
|
||||
--------
|
||||
|
||||
3
Makefile
3
Makefile
@@ -2087,7 +2087,7 @@ $(SCRIPT_LIB) : % : %.sh GIT-SCRIPT-DEFINES
|
||||
$(QUIET_GEN)$(cmd_munge_script) && \
|
||||
mv $@+ $@
|
||||
|
||||
git.res: git.rc GIT-VERSION-FILE
|
||||
git.res: git.rc GIT-VERSION-FILE GIT-PREFIX
|
||||
$(QUIET_RC)$(RC) \
|
||||
$(join -DMAJOR= -DMINOR= -DMICRO= -DPATCHLEVEL=, $(wordlist 1, 4, \
|
||||
$(shell echo $(GIT_VERSION) 0 0 0 0 | tr '.a-zA-Z-' ' '))) \
|
||||
@@ -2567,6 +2567,7 @@ GIT-BUILD-OPTIONS: FORCE
|
||||
@echo NO_UNIX_SOCKETS=\''$(subst ','\'',$(subst ','\'',$(NO_UNIX_SOCKETS)))'\' >>$@+
|
||||
@echo PAGER_ENV=\''$(subst ','\'',$(subst ','\'',$(PAGER_ENV)))'\' >>$@+
|
||||
@echo DC_SHA1=\''$(subst ','\'',$(subst ','\'',$(DC_SHA1)))'\' >>$@+
|
||||
@echo X=\'$(X)\' >>$@+
|
||||
ifdef TEST_OUTPUT_DIRECTORY
|
||||
@echo TEST_OUTPUT_DIRECTORY=\''$(subst ','\'',$(subst ','\'',$(TEST_OUTPUT_DIRECTORY)))'\' >>$@+
|
||||
endif
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
[](https://dev.azure.com/git/git/_build/latest?definitionId=2)
|
||||
|
||||
Git - fast, scalable, distributed revision control system
|
||||
=========================================================
|
||||
|
||||
|
||||
325
azure-pipelines.yml
Normal file
325
azure-pipelines.yml
Normal file
@@ -0,0 +1,325 @@
|
||||
resources:
|
||||
- repo: self
|
||||
fetchDepth: 1
|
||||
|
||||
phases:
|
||||
- phase: linux_clang
|
||||
displayName: linux-clang
|
||||
condition: succeeded()
|
||||
queue:
|
||||
name: Hosted Ubuntu 1604
|
||||
steps:
|
||||
- bash: |
|
||||
test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
|
||||
|
||||
sudo apt-get update &&
|
||||
sudo rm /var/lib/apt/lists/lock &&
|
||||
sudo apt-get -y install git gcc make libssl-dev libcurl4-openssl-dev libexpat-dev tcl tk gettext git-email zlib1g-dev apache2-bin &&
|
||||
|
||||
export CC=clang || exit 1
|
||||
|
||||
ci/install-dependencies.sh
|
||||
ci/run-build-and-tests.sh || {
|
||||
ci/print-test-failures.sh
|
||||
exit 1
|
||||
}
|
||||
|
||||
test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || sudo umount "$HOME/test-cache" || exit 1
|
||||
displayName: 'ci/run-build-and-tests.sh'
|
||||
env:
|
||||
GITFILESHAREPWD: $(gitfileshare.pwd)
|
||||
- task: PublishTestResults@2
|
||||
displayName: 'Publish Test Results **/TEST-*.xml'
|
||||
inputs:
|
||||
mergeTestResults: true
|
||||
testRunTitle: 'linux-clang'
|
||||
platform: Linux
|
||||
publishRunAttachments: false
|
||||
condition: succeededOrFailed()
|
||||
|
||||
- phase: linux_gcc
|
||||
displayName: linux-gcc
|
||||
condition: succeeded()
|
||||
queue:
|
||||
name: Hosted Ubuntu 1604
|
||||
steps:
|
||||
- bash: |
|
||||
test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
|
||||
|
||||
sudo apt-get update &&
|
||||
sudo rm /var/lib/apt/lists/lock &&
|
||||
sudo apt-get -y install git gcc make libssl-dev libcurl4-openssl-dev libexpat-dev tcl tk gettext git-email zlib1g-dev apache2-bin || exit 1
|
||||
|
||||
ci/install-dependencies.sh
|
||||
ci/run-build-and-tests.sh || {
|
||||
ci/print-test-failures.sh
|
||||
exit 1
|
||||
}
|
||||
|
||||
test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || sudo umount "$HOME/test-cache" || exit 1
|
||||
displayName: 'ci/run-build-and-tests.sh'
|
||||
env:
|
||||
GITFILESHAREPWD: $(gitfileshare.pwd)
|
||||
- task: PublishTestResults@2
|
||||
displayName: 'Publish Test Results **/TEST-*.xml'
|
||||
inputs:
|
||||
mergeTestResults: true
|
||||
testRunTitle: 'linux-gcc'
|
||||
platform: Linux
|
||||
publishRunAttachments: false
|
||||
condition: succeededOrFailed()
|
||||
|
||||
- phase: osx_clang
|
||||
displayName: osx-clang
|
||||
condition: succeeded()
|
||||
queue:
|
||||
name: Hosted macOS
|
||||
steps:
|
||||
- bash: |
|
||||
test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
|
||||
|
||||
export CC=clang
|
||||
|
||||
ci/install-dependencies.sh
|
||||
ci/run-build-and-tests.sh || {
|
||||
ci/print-test-failures.sh
|
||||
exit 1
|
||||
}
|
||||
|
||||
test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || umount "$HOME/test-cache" || exit 1
|
||||
displayName: 'ci/run-build-and-tests.sh'
|
||||
env:
|
||||
GITFILESHAREPWD: $(gitfileshare.pwd)
|
||||
- task: PublishTestResults@2
|
||||
displayName: 'Publish Test Results **/TEST-*.xml'
|
||||
inputs:
|
||||
mergeTestResults: true
|
||||
testRunTitle: 'osx-clang'
|
||||
platform: macOS
|
||||
publishRunAttachments: false
|
||||
condition: succeededOrFailed()
|
||||
|
||||
- phase: osx_gcc
|
||||
displayName: osx-gcc
|
||||
condition: succeeded()
|
||||
queue:
|
||||
name: Hosted macOS
|
||||
steps:
|
||||
- bash: |
|
||||
test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
|
||||
|
||||
ci/install-dependencies.sh
|
||||
ci/run-build-and-tests.sh || {
|
||||
ci/print-test-failures.sh
|
||||
exit 1
|
||||
}
|
||||
|
||||
test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || umount "$HOME/test-cache" || exit 1
|
||||
displayName: 'ci/run-build-and-tests.sh'
|
||||
env:
|
||||
GITFILESHAREPWD: $(gitfileshare.pwd)
|
||||
- task: PublishTestResults@2
|
||||
displayName: 'Publish Test Results **/TEST-*.xml'
|
||||
inputs:
|
||||
mergeTestResults: true
|
||||
testRunTitle: 'osx-gcc'
|
||||
platform: macOS
|
||||
publishRunAttachments: false
|
||||
condition: succeededOrFailed()
|
||||
|
||||
- phase: gettext_poison
|
||||
displayName: GETTEXT_POISON
|
||||
condition: succeeded()
|
||||
queue:
|
||||
name: Hosted Ubuntu 1604
|
||||
steps:
|
||||
- bash: |
|
||||
test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
|
||||
|
||||
sudo apt-get update &&
|
||||
sudo rm /var/lib/apt/lists/lock &&
|
||||
sudo apt-get -y install git gcc make libssl-dev libcurl4-openssl-dev libexpat-dev tcl tk gettext git-email zlib1g-dev &&
|
||||
|
||||
export jobname=GETTEXT_POISON || exit 1
|
||||
|
||||
ci/run-build-and-tests.sh || {
|
||||
ci/print-test-failures.sh
|
||||
exit 1
|
||||
}
|
||||
|
||||
test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || sudo umount "$HOME/test-cache" || exit 1
|
||||
displayName: 'ci/run-build-and-tests.sh'
|
||||
env:
|
||||
GITFILESHAREPWD: $(gitfileshare.pwd)
|
||||
- task: PublishTestResults@2
|
||||
displayName: 'Publish Test Results **/TEST-*.xml'
|
||||
inputs:
|
||||
mergeTestResults: true
|
||||
testRunTitle: 'gettext-poison'
|
||||
platform: Linux
|
||||
publishRunAttachments: false
|
||||
condition: succeededOrFailed()
|
||||
|
||||
- phase: windows
|
||||
displayName: Windows
|
||||
condition: succeeded()
|
||||
queue:
|
||||
name: Hosted
|
||||
timeoutInMinutes: 240
|
||||
steps:
|
||||
- powershell: |
|
||||
# Helper to check the error level of the latest command (exit with error when appropriate)
|
||||
function c() { if (!$?) { exit(1) } }
|
||||
|
||||
if ("$GITFILESHAREPWD" -ne "" -and "$GITFILESHAREPWD" -ne "`$`(gitfileshare.pwd)") {
|
||||
net use s: \\gitfileshare.file.core.windows.net\test-cache "$GITFILESHAREPWD" /user:AZURE\gitfileshare /persistent:no; c
|
||||
cmd /c mklink /d "$(Build.SourcesDirectory)\test-cache" S:\; c
|
||||
}
|
||||
|
||||
# Add build agent's MinGit to PATH
|
||||
$env:PATH = $env:AGENT_HOMEDIRECTORY +"\externals\\git\cmd;" +$env:PATH
|
||||
|
||||
# Helper to initialize (or update) a Git worktree
|
||||
function init ($path, $url, $set_origin) {
|
||||
if (Test-Path $path) {
|
||||
cd $path; c
|
||||
if (Test-Path .git) {
|
||||
git init; c
|
||||
} else {
|
||||
git status
|
||||
}
|
||||
} else {
|
||||
git init $path; c
|
||||
cd $path; c
|
||||
}
|
||||
git config core.autocrlf false; c
|
||||
git config core.untrackedCache true; c
|
||||
if (($set_origin -ne 0) -and !(git config remote.origin.url)) {
|
||||
git remote add origin $url; c
|
||||
}
|
||||
git fetch --depth=1 $url master; c
|
||||
git reset --hard FETCH_HEAD; c
|
||||
git clean -df; c
|
||||
}
|
||||
|
||||
# Initialize Git for Windows' SDK
|
||||
$sdk_path = "$(Build.SourcesDirectory)\git-sdk-64"
|
||||
init "$sdk_path" "https://dev.azure.com/git-for-windows/git-sdk-64/_git/git-sdk-64" 0
|
||||
init usr\src\build-extra https://github.com/git-for-windows/build-extra 1
|
||||
|
||||
cd "$(Build.SourcesDirectory)"; c
|
||||
|
||||
$env:HOME = "$(Build.SourcesDirectory)"
|
||||
$env:MSYSTEM = "MINGW64"
|
||||
git-sdk-64\git-cmd --command=usr\\bin\\bash.exe -lc @"
|
||||
. ci/lib.sh
|
||||
|
||||
make -j10 DEVELOPER=1 NO_PERL=1 || exit 1
|
||||
NO_PERL=1 NO_SVN_TESTS=1 GIT_TEST_OPTS=\"--no-chain-lint --no-bin-wrappers --quiet --write-junit-xml\" time make -j15 -k DEVELOPER=1 test || {
|
||||
NO_PERL=1 NO_SVN_TESTS=1 GIT_TEST_OPTS=\"-i -v -x\" make -k -C t failed; exit 1
|
||||
}
|
||||
|
||||
save_good_tree
|
||||
"@
|
||||
c
|
||||
|
||||
if ("$GITFILESHAREPWD" -ne "" -and "$GITFILESHAREPWD" -ne "`$`(gitfileshare.pwd)") {
|
||||
cmd /c rmdir "$(Build.SourcesDirectory)\test-cache"
|
||||
}
|
||||
displayName: 'build & test'
|
||||
env:
|
||||
GITFILESHAREPWD: $(gitfileshare.pwd)
|
||||
- task: PublishTestResults@2
|
||||
displayName: 'Publish Test Results **/TEST-*.xml'
|
||||
inputs:
|
||||
mergeTestResults: true
|
||||
testRunTitle: 'windows'
|
||||
platform: Windows
|
||||
publishRunAttachments: false
|
||||
condition: succeededOrFailed()
|
||||
|
||||
- phase: linux32
|
||||
displayName: Linux32
|
||||
condition: succeeded()
|
||||
queue:
|
||||
name: Hosted Ubuntu 1604
|
||||
steps:
|
||||
- bash: |
|
||||
test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
|
||||
|
||||
sudo apt-get update &&
|
||||
sudo rm /var/lib/apt/lists/lock &&
|
||||
sudo apt-get -y install \
|
||||
apt-transport-https \
|
||||
ca-certificates \
|
||||
curl \
|
||||
software-properties-common &&
|
||||
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - &&
|
||||
sudo add-apt-repository \
|
||||
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
|
||||
$(lsb_release -cs) \
|
||||
stable" &&
|
||||
sudo apt-get update &&
|
||||
sudo apt-get -y install docker-ce &&
|
||||
|
||||
sudo AGENT_OS="$AGENT_OS" BUILD_BUILDNUMBER="$BUILD_BUILDNUMBER" BUILD_REPOSITORY_URI="$BUILD_REPOSITORY_URI" BUILD_SOURCEBRANCH="$BUILD_SOURCEBRANCH" BUILD_SOURCEVERSION="$BUILD_SOURCEVERSION" SYSTEM_PHASENAME="$SYSTEM_PHASENAME" SYSTEM_TASKDEFINITIONSURI="$SYSTEM_TASKDEFINITIONSURI" SYSTEM_TEAMPROJECT="$SYSTEM_TEAMPROJECT" CC=$CC MAKEFLAGS=-j3 bash -lxc ci/run-linux32-docker.sh || exit 1
|
||||
|
||||
sudo chmod a+r t/out/TEST-*.xml
|
||||
|
||||
test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || sudo umount "$HOME/test-cache" || exit 1
|
||||
displayName: 'ci/run-linux32-docker.sh'
|
||||
env:
|
||||
GITFILESHAREPWD: $(gitfileshare.pwd)
|
||||
- task: PublishTestResults@2
|
||||
displayName: 'Publish Test Results **/TEST-*.xml'
|
||||
inputs:
|
||||
mergeTestResults: true
|
||||
testRunTitle: 'linux32'
|
||||
platform: Linux
|
||||
publishRunAttachments: false
|
||||
condition: succeededOrFailed()
|
||||
|
||||
- phase: static_analysis
|
||||
displayName: StaticAnalysis
|
||||
condition: succeeded()
|
||||
queue:
|
||||
name: Hosted Ubuntu 1604
|
||||
steps:
|
||||
- bash: |
|
||||
test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
|
||||
|
||||
sudo apt-get update &&
|
||||
sudo rm /var/lib/apt/lists/lock &&
|
||||
sudo apt-get install -y coccinelle &&
|
||||
|
||||
export jobname=StaticAnalysis &&
|
||||
|
||||
ci/run-static-analysis.sh || exit 1
|
||||
|
||||
test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || sudo umount "$HOME/test-cache" || exit 1
|
||||
displayName: 'ci/run-static-analysis.sh'
|
||||
env:
|
||||
GITFILESHAREPWD: $(gitfileshare.pwd)
|
||||
|
||||
- phase: documentation
|
||||
displayName: Documentation
|
||||
condition: succeeded()
|
||||
queue:
|
||||
name: Hosted Ubuntu 1604
|
||||
steps:
|
||||
- bash: |
|
||||
test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
|
||||
|
||||
sudo apt-get update &&
|
||||
sudo rm /var/lib/apt/lists/lock &&
|
||||
sudo apt-get install -y asciidoc xmlto asciidoctor &&
|
||||
|
||||
export ALREADY_HAVE_ASCIIDOCTOR=yes. &&
|
||||
export jobname=Documentation &&
|
||||
|
||||
ci/test-documentation.sh || exit 1
|
||||
|
||||
test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || sudo umount "$HOME/test-cache" || exit 1
|
||||
displayName: 'ci/test-documentation.sh'
|
||||
env:
|
||||
GITFILESHAREPWD: $(gitfileshare.pwd)
|
||||
@@ -239,7 +239,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
|
||||
rev.diffopt.output_format = DIFF_FORMAT_PATCH;
|
||||
rev.diffopt.use_color = 0;
|
||||
rev.diffopt.flags.ignore_dirty_submodules = 1;
|
||||
out = open(file, O_CREAT | O_WRONLY, 0666);
|
||||
out = open(file, O_CREAT | O_WRONLY | O_TRUNC, 0666);
|
||||
if (out < 0)
|
||||
die(_("Could not open '%s' for writing."), file);
|
||||
rev.diffopt.file = xfdopen(out, "w");
|
||||
|
||||
@@ -1166,7 +1166,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
|
||||
if (!is_local && !complete_refs_before_fetch)
|
||||
transport_fetch_refs(transport, mapped_refs);
|
||||
if (transport_fetch_refs(transport, mapped_refs))
|
||||
die(_("could not fetch refs from %s"),
|
||||
transport->url);
|
||||
|
||||
remote_head = find_ref_by_name(refs, "HEAD");
|
||||
remote_head_points_at =
|
||||
|
||||
@@ -874,9 +874,20 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_reset(const char *name, struct object *object)
|
||||
{
|
||||
int mark = get_object_mark(object);
|
||||
|
||||
if (mark)
|
||||
printf("reset %s\nfrom :%d\n\n", name,
|
||||
get_object_mark(object));
|
||||
else
|
||||
printf("reset %s\nfrom %s\n\n", name,
|
||||
oid_to_hex(&object->oid));
|
||||
}
|
||||
|
||||
static void handle_tags_and_duplicates(void)
|
||||
{
|
||||
struct commit *commit;
|
||||
int i;
|
||||
|
||||
for (i = extra_refs.nr - 1; i >= 0; i--) {
|
||||
@@ -890,9 +901,7 @@ static void handle_tags_and_duplicates(void)
|
||||
if (anonymize)
|
||||
name = anonymize_refname(name);
|
||||
/* create refs pointing to already seen commits */
|
||||
commit = (struct commit *)object;
|
||||
printf("reset %s\nfrom :%d\n\n", name,
|
||||
get_object_mark(&commit->object));
|
||||
handle_reset(name, object);
|
||||
show_progress();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -642,8 +642,10 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
|
||||
|
||||
report_garbage = report_pack_garbage;
|
||||
reprepare_packed_git(the_repository);
|
||||
if (pack_garbage.nr > 0)
|
||||
if (pack_garbage.nr > 0) {
|
||||
close_all_packs(the_repository->objects);
|
||||
clean_pack_garbage();
|
||||
}
|
||||
|
||||
if (gc_write_commit_graph)
|
||||
write_commit_graph_reachable(get_object_directory(), 0);
|
||||
|
||||
@@ -155,6 +155,9 @@ static int git_init_db_config(const char *k, const char *v, void *cb)
|
||||
if (!strcmp(k, "init.templatedir"))
|
||||
return git_config_pathname(&init_db_template_dir, k, v);
|
||||
|
||||
if (starts_with(k, "core."))
|
||||
return platform_core_config(k, v, cb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -361,6 +364,9 @@ int init_db(const char *git_dir, const char *real_git_dir,
|
||||
}
|
||||
startup_info->have_repository = 1;
|
||||
|
||||
/* Just look for `init.templatedir` and `core.hidedotfiles` */
|
||||
git_config(git_init_db_config, NULL);
|
||||
|
||||
safe_create_dir(git_dir, 0);
|
||||
|
||||
init_is_bare_repository = is_bare_repository();
|
||||
|
||||
@@ -2299,7 +2299,6 @@ static void init_threaded_search(void)
|
||||
pthread_mutex_init(&cache_mutex, NULL);
|
||||
pthread_mutex_init(&progress_mutex, NULL);
|
||||
pthread_cond_init(&progress_cond, NULL);
|
||||
pthread_mutex_init(&to_pack.lock, NULL);
|
||||
old_try_to_free_routine = set_try_to_free_routine(try_to_free_from_threads);
|
||||
}
|
||||
|
||||
|
||||
@@ -408,6 +408,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
|
||||
if (!names.nr && !po_args.quiet)
|
||||
printf("Nothing new to pack.\n");
|
||||
|
||||
close_all_packs(the_repository->objects);
|
||||
|
||||
/*
|
||||
* Ok we have prepared all new packfiles.
|
||||
* First see if there are packs of the same name and if so
|
||||
|
||||
@@ -24,10 +24,13 @@
|
||||
#include "cache-tree.h"
|
||||
#include "submodule.h"
|
||||
#include "submodule-config.h"
|
||||
#include "strbuf.h"
|
||||
#include "quote.h"
|
||||
|
||||
static const char * const git_reset_usage[] = {
|
||||
N_("git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"),
|
||||
N_("git reset [-q] [<tree-ish>] [--] <paths>..."),
|
||||
N_("EXPERIMENTAL: git reset [-q] [--stdin [-z]] [<tree-ish>]"),
|
||||
N_("git reset --patch [<tree-ish>] [--] [<paths>...]"),
|
||||
NULL
|
||||
};
|
||||
@@ -280,7 +283,9 @@ static int git_reset_config(const char *var, const char *value, void *cb)
|
||||
int cmd_reset(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int reset_type = NONE, update_ref_status = 0, quiet = 0;
|
||||
int patch_mode = 0, unborn;
|
||||
int patch_mode = 0, nul_term_line = 0, read_from_stdin = 0, unborn;
|
||||
char **stdin_paths = NULL;
|
||||
int stdin_nr = 0, stdin_alloc = 0;
|
||||
const char *rev;
|
||||
struct object_id oid;
|
||||
struct pathspec pathspec;
|
||||
@@ -302,6 +307,10 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
|
||||
OPT_BOOL('p', "patch", &patch_mode, N_("select hunks interactively")),
|
||||
OPT_BOOL('N', "intent-to-add", &intent_to_add,
|
||||
N_("record only the fact that removed paths will be added later")),
|
||||
OPT_BOOL('z', NULL, &nul_term_line,
|
||||
N_("EXPERIMENTAL: paths are separated with NUL character")),
|
||||
OPT_BOOL(0, "stdin", &read_from_stdin,
|
||||
N_("EXPERIMENTAL: read paths from <stdin>")),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
@@ -311,6 +320,42 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
|
||||
PARSE_OPT_KEEP_DASHDASH);
|
||||
parse_args(&pathspec, argv, prefix, patch_mode, &rev);
|
||||
|
||||
if (read_from_stdin) {
|
||||
strbuf_getline_fn getline_fn = nul_term_line ?
|
||||
strbuf_getline_nul : strbuf_getline_lf;
|
||||
int flags = PATHSPEC_PREFER_FULL;
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
struct strbuf unquoted = STRBUF_INIT;
|
||||
|
||||
if (patch_mode)
|
||||
die(_("--stdin is incompatible with --patch"));
|
||||
|
||||
if (pathspec.nr)
|
||||
die(_("--stdin is incompatible with path arguments"));
|
||||
|
||||
while (getline_fn(&buf, stdin) != EOF) {
|
||||
if (!nul_term_line && buf.buf[0] == '"') {
|
||||
strbuf_reset(&unquoted);
|
||||
if (unquote_c_style(&unquoted, buf.buf, NULL))
|
||||
die(_("line is badly quoted"));
|
||||
strbuf_swap(&buf, &unquoted);
|
||||
}
|
||||
ALLOC_GROW(stdin_paths, stdin_nr + 1, stdin_alloc);
|
||||
stdin_paths[stdin_nr++] = xstrdup(buf.buf);
|
||||
strbuf_reset(&buf);
|
||||
}
|
||||
strbuf_release(&unquoted);
|
||||
strbuf_release(&buf);
|
||||
|
||||
ALLOC_GROW(stdin_paths, stdin_nr + 1, stdin_alloc);
|
||||
stdin_paths[stdin_nr++] = NULL;
|
||||
flags |= PATHSPEC_LITERAL_PATH;
|
||||
parse_pathspec(&pathspec, 0, flags, prefix,
|
||||
(const char **)stdin_paths);
|
||||
|
||||
} else if (nul_term_line)
|
||||
die(_("-z requires --stdin"));
|
||||
|
||||
unborn = !strcmp(rev, "HEAD") && get_oid("HEAD", &oid);
|
||||
if (unborn) {
|
||||
/* reset on unborn branch: treat as reset to empty tree */
|
||||
@@ -401,5 +446,11 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
|
||||
if (!pathspec.nr)
|
||||
remove_branch_state();
|
||||
|
||||
if (stdin_paths) {
|
||||
while (stdin_nr)
|
||||
free(stdin_paths[--stdin_nr]);
|
||||
free(stdin_paths);
|
||||
}
|
||||
|
||||
return update_ref_status;
|
||||
}
|
||||
|
||||
39
bundle.c
39
bundle.c
@@ -243,7 +243,7 @@ out:
|
||||
}
|
||||
|
||||
|
||||
/* Write the pack data to bundle_fd, then close it if it is > 1. */
|
||||
/* Write the pack data to bundle_fd */
|
||||
static int write_pack_data(int bundle_fd, struct rev_info *revs)
|
||||
{
|
||||
struct child_process pack_objects = CHILD_PROCESS_INIT;
|
||||
@@ -256,6 +256,20 @@ static int write_pack_data(int bundle_fd, struct rev_info *revs)
|
||||
pack_objects.in = -1;
|
||||
pack_objects.out = bundle_fd;
|
||||
pack_objects.git_cmd = 1;
|
||||
|
||||
/*
|
||||
* start_command() will close our descriptor if it's >1. Duplicate it
|
||||
* to avoid surprising the caller.
|
||||
*/
|
||||
if (pack_objects.out > 1) {
|
||||
pack_objects.out = dup(pack_objects.out);
|
||||
if (pack_objects.out < 0) {
|
||||
error_errno(_("unable to dup bundle descriptor"));
|
||||
child_process_clear(&pack_objects);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (start_command(&pack_objects))
|
||||
return error(_("Could not spawn pack-objects"));
|
||||
|
||||
@@ -421,21 +435,10 @@ int create_bundle(struct bundle_header *header, const char *path,
|
||||
bundle_to_stdout = !strcmp(path, "-");
|
||||
if (bundle_to_stdout)
|
||||
bundle_fd = 1;
|
||||
else {
|
||||
else
|
||||
bundle_fd = hold_lock_file_for_update(&lock, path,
|
||||
LOCK_DIE_ON_ERROR);
|
||||
|
||||
/*
|
||||
* write_pack_data() will close the fd passed to it,
|
||||
* but commit_lock_file() will also try to close the
|
||||
* lockfile's fd. So make a copy of the file
|
||||
* descriptor to avoid trying to close it twice.
|
||||
*/
|
||||
bundle_fd = dup(bundle_fd);
|
||||
if (bundle_fd < 0)
|
||||
die_errno("unable to dup file descriptor");
|
||||
}
|
||||
|
||||
/* write signature */
|
||||
write_or_die(bundle_fd, bundle_signature, strlen(bundle_signature));
|
||||
|
||||
@@ -463,10 +466,8 @@ int create_bundle(struct bundle_header *header, const char *path,
|
||||
goto err;
|
||||
|
||||
/* write pack */
|
||||
if (write_pack_data(bundle_fd, &revs)) {
|
||||
bundle_fd = -1; /* already closed by the above call */
|
||||
if (write_pack_data(bundle_fd, &revs))
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!bundle_to_stdout) {
|
||||
if (commit_lock_file(&lock))
|
||||
@@ -474,11 +475,7 @@ int create_bundle(struct bundle_header *header, const char *path,
|
||||
}
|
||||
return 0;
|
||||
err:
|
||||
if (!bundle_to_stdout) {
|
||||
if (0 <= bundle_fd)
|
||||
close(bundle_fd);
|
||||
rollback_lock_file(&lock);
|
||||
}
|
||||
rollback_lock_file(&lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
8
cache.h
8
cache.h
@@ -901,14 +901,6 @@ int use_optional_locks(void);
|
||||
extern char comment_line_char;
|
||||
extern int auto_comment_line_char;
|
||||
|
||||
/* Windows only */
|
||||
enum hide_dotfiles_type {
|
||||
HIDE_DOTFILES_FALSE = 0,
|
||||
HIDE_DOTFILES_TRUE,
|
||||
HIDE_DOTFILES_DOTGITONLY
|
||||
};
|
||||
extern enum hide_dotfiles_type hide_dotfiles;
|
||||
|
||||
enum log_refs_config {
|
||||
LOG_REFS_UNSET = -1,
|
||||
LOG_REFS_NONE = 0,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Install dependencies required to build and test Git on Linux and macOS
|
||||
#
|
||||
|
||||
. ${0%/*}/lib-travisci.sh
|
||||
. ${0%/*}/lib.sh
|
||||
|
||||
P4WHENCE=http://filehost.perforce.com/perforce/r$LINUX_P4_VERSION
|
||||
LFSWHENCE=https://github.com/github/git-lfs/releases/download/v$LINUX_GIT_LFS_VERSION
|
||||
@@ -28,7 +28,8 @@ osx-clang|osx-gcc)
|
||||
brew update --quiet
|
||||
# Uncomment this if you want to run perf tests:
|
||||
# brew install gnu-time
|
||||
brew install git-lfs gettext
|
||||
test -z "$BREW_INSTALL_PACKAGES" ||
|
||||
brew install $BREW_INSTALL_PACKAGES
|
||||
brew link --force gettext
|
||||
brew install caskroom/cask/perforce
|
||||
;;
|
||||
|
||||
@@ -1,5 +1,49 @@
|
||||
# Library of functions shared by all CI scripts
|
||||
|
||||
if test true = "$TRAVIS"
|
||||
then
|
||||
# We are running within Travis CI
|
||||
CI_BRANCH="${TRAVIS_PULL_REQUEST_BRANCH:-$TRAVIS_BRANCH}"
|
||||
CI_COMMIT="$TRAVIS_COMMIT"
|
||||
CI_JOB_ID="$TRAVIS_JOB_ID"
|
||||
CI_JOB_NUMBER="$TRAVIS_JOB_NUMBER"
|
||||
CI_OS_NAME="$TRAVIS_OS_NAME"
|
||||
CI_REPO_SLUG="$TRAVIS_REPO_SLUG"
|
||||
|
||||
cache_dir="$HOME/travis-cache"
|
||||
|
||||
url_for_job_id () {
|
||||
echo "https://travis-ci.org/$CI_REPO_SLUG/jobs/$1"
|
||||
}
|
||||
|
||||
BREW_INSTALL_PACKAGES="git-lfs gettext"
|
||||
export GIT_PROVE_OPTS="--timer --jobs 3 --state=failed,slow,save"
|
||||
export GIT_TEST_OPTS="--verbose-log -x --immediate"
|
||||
elif test -n "$SYSTEM_TASKDEFINITIONSURI"
|
||||
then
|
||||
# We are running in Azure Pipelines
|
||||
CI_BRANCH="$BUILD_SOURCEBRANCH"
|
||||
CI_COMMIT="$BUILD_SOURCEVERSION"
|
||||
CI_JOB_ID="$BUILD_BUILDID"
|
||||
CI_JOB_NUMBER="$BUILD_BUILDNUMBER"
|
||||
CI_OS_NAME="$(echo "$AGENT_OS" | tr A-Z a-z)"
|
||||
test darwin != "$CI_OS_NAME" || CI_OS_NAME=osx
|
||||
CI_REPO_SLUG="$(expr "$BUILD_REPOSITORY_URI" : '.*/\([^/]*/[^/]*\)$')"
|
||||
CC="${CC:-gcc}"
|
||||
|
||||
# use a subdirectory of the cache dir (because the file share is shared
|
||||
# among *all* phases)
|
||||
cache_dir="$HOME/test-cache/$SYSTEM_PHASENAME"
|
||||
|
||||
url_for_job_id () {
|
||||
echo "$SYSTEM_TASKDEFINITIONSURI$SYSTEM_TEAMPROJECT/_build/results?buildId=$1"
|
||||
}
|
||||
|
||||
BREW_INSTALL_PACKAGES=
|
||||
export GIT_PROVE_OPTS="--timer --jobs 10 --state=failed,slow,save"
|
||||
export GIT_TEST_OPTS="--quiet --write-junit-xml"
|
||||
fi
|
||||
|
||||
skip_branch_tip_with_tag () {
|
||||
# Sometimes, a branch is pushed at the same time the tag that points
|
||||
# at the same commit as the tip of the branch is pushed, and building
|
||||
@@ -13,10 +57,10 @@ skip_branch_tip_with_tag () {
|
||||
# we can skip the build because we won't be skipping a build
|
||||
# of a tag.
|
||||
|
||||
if TAG=$(git describe --exact-match "$TRAVIS_BRANCH" 2>/dev/null) &&
|
||||
test "$TAG" != "$TRAVIS_BRANCH"
|
||||
if TAG=$(git describe --exact-match "$CI_BRANCH" 2>/dev/null) &&
|
||||
test "$TAG" != "$CI_BRANCH"
|
||||
then
|
||||
echo "$(tput setaf 2)Tip of $TRAVIS_BRANCH is exactly at $TAG$(tput sgr0)"
|
||||
echo "$(tput setaf 2)Tip of $CI_BRANCH is exactly at $TAG$(tput sgr0)"
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
@@ -25,7 +69,7 @@ skip_branch_tip_with_tag () {
|
||||
# job if we encounter the same tree again and can provide a useful info
|
||||
# message.
|
||||
save_good_tree () {
|
||||
echo "$(git rev-parse $TRAVIS_COMMIT^{tree}) $TRAVIS_COMMIT $TRAVIS_JOB_NUMBER $TRAVIS_JOB_ID" >>"$good_trees_file"
|
||||
echo "$(git rev-parse $CI_COMMIT^{tree}) $CI_COMMIT $CI_JOB_NUMBER $CI_JOB_ID" >>"$good_trees_file"
|
||||
# limit the file size
|
||||
tail -1000 "$good_trees_file" >"$good_trees_file".tmp
|
||||
mv "$good_trees_file".tmp "$good_trees_file"
|
||||
@@ -35,7 +79,7 @@ save_good_tree () {
|
||||
# successfully before (e.g. because the branch got rebased, changing only
|
||||
# the commit messages).
|
||||
skip_good_tree () {
|
||||
if ! good_tree_info="$(grep "^$(git rev-parse $TRAVIS_COMMIT^{tree}) " "$good_trees_file")"
|
||||
if ! good_tree_info="$(grep "^$(git rev-parse $CI_COMMIT^{tree}) " "$good_trees_file")"
|
||||
then
|
||||
# Haven't seen this tree yet, or no cached good trees file yet.
|
||||
# Continue the build job.
|
||||
@@ -45,18 +89,18 @@ skip_good_tree () {
|
||||
echo "$good_tree_info" | {
|
||||
read tree prev_good_commit prev_good_job_number prev_good_job_id
|
||||
|
||||
if test "$TRAVIS_JOB_ID" = "$prev_good_job_id"
|
||||
if test "$CI_JOB_ID" = "$prev_good_job_id"
|
||||
then
|
||||
cat <<-EOF
|
||||
$(tput setaf 2)Skipping build job for commit $TRAVIS_COMMIT.$(tput sgr0)
|
||||
$(tput setaf 2)Skipping build job for commit $CI_COMMIT.$(tput sgr0)
|
||||
This commit has already been built and tested successfully by this build job.
|
||||
To force a re-build delete the branch's cache and then hit 'Restart job'.
|
||||
EOF
|
||||
else
|
||||
cat <<-EOF
|
||||
$(tput setaf 2)Skipping build job for commit $TRAVIS_COMMIT.$(tput sgr0)
|
||||
$(tput setaf 2)Skipping build job for commit $CI_COMMIT.$(tput sgr0)
|
||||
This commit's tree has already been built and tested successfully in build job $prev_good_job_number for commit $prev_good_commit.
|
||||
The log of that build job is available at https://travis-ci.org/$TRAVIS_REPO_SLUG/jobs/$prev_good_job_id
|
||||
The log of that build job is available at $(url_for_job_id $prev_good_job_id)
|
||||
To force a re-build delete the branch's cache and then hit 'Restart job'.
|
||||
EOF
|
||||
fi
|
||||
@@ -81,7 +125,6 @@ check_unignored_build_artifacts ()
|
||||
# and installing dependencies.
|
||||
set -ex
|
||||
|
||||
cache_dir="$HOME/travis-cache"
|
||||
good_trees_file="$cache_dir/good-trees"
|
||||
|
||||
mkdir -p "$cache_dir"
|
||||
@@ -91,13 +134,11 @@ skip_good_tree
|
||||
|
||||
if test -z "$jobname"
|
||||
then
|
||||
jobname="$TRAVIS_OS_NAME-$CC"
|
||||
jobname="$CI_OS_NAME-$CC"
|
||||
fi
|
||||
|
||||
export DEVELOPER=1
|
||||
export DEFAULT_TEST_TARGET=prove
|
||||
export GIT_PROVE_OPTS="--timer --jobs 3 --state=failed,slow,save"
|
||||
export GIT_TEST_OPTS="--verbose-log -x --immediate"
|
||||
export GIT_TEST_CLONE_2GB=YesPlease
|
||||
if [ "$jobname" = linux-gcc ]; then
|
||||
export CC=gcc-8
|
||||
26
ci/mount-fileshare.sh
Executable file
26
ci/mount-fileshare.sh
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/bin/sh
|
||||
|
||||
die () {
|
||||
echo "$*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
test $# = 4 ||
|
||||
die "Usage: $0 <share> <username> <password> <mountpoint"
|
||||
|
||||
mkdir -p "$4" || die "Could not create $4"
|
||||
|
||||
case "$(uname -s)" in
|
||||
Linux)
|
||||
sudo mount -t cifs -o vers=3.0,username="$2",password="$3",dir_mode=0777,file_mode=0777,serverino "$1" "$4"
|
||||
;;
|
||||
Darwin)
|
||||
pass="$(echo "$3" | sed -e 's/\//%2F/g' -e 's/+/%2B/g')" &&
|
||||
mount -t smbfs,soft "smb://$2:$pass@${1#//}" "$4"
|
||||
;;
|
||||
*)
|
||||
die "No support for $(uname -s)"
|
||||
;;
|
||||
esac ||
|
||||
die "Could not mount $4"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Print output of failing tests
|
||||
#
|
||||
|
||||
. ${0%/*}/lib-travisci.sh
|
||||
. ${0%/*}/lib.sh
|
||||
|
||||
# Tracing executed commands would produce too much noise in the loop below.
|
||||
set +x
|
||||
@@ -69,7 +69,7 @@ do
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $combined_trash_size -gt 0 ]
|
||||
if [ -n "$TRAVIS_JOB_ID" -a $combined_trash_size -gt 0 ]
|
||||
then
|
||||
echo "------------------------------------------------------------------------"
|
||||
echo "Trash directories embedded in this log can be extracted by running:"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Build and test Git
|
||||
#
|
||||
|
||||
. ${0%/*}/lib-travisci.sh
|
||||
. ${0%/*}/lib.sh
|
||||
|
||||
ln -s "$cache_dir/.prove" t/.prove
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Download and run Docker image to build and test 32-bit Git
|
||||
#
|
||||
|
||||
. ${0%/*}/lib-travisci.sh
|
||||
. ${0%/*}/lib.sh
|
||||
|
||||
docker pull daald/ubuntu32:xenial
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Perform various static code analysis checks
|
||||
#
|
||||
|
||||
. ${0%/*}/lib-travisci.sh
|
||||
. ${0%/*}/lib.sh
|
||||
|
||||
make --jobs=2 coccicheck
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
# supported) and a commit hash.
|
||||
#
|
||||
|
||||
. ${0%/*}/lib-travisci.sh
|
||||
. ${0%/*}/lib.sh
|
||||
|
||||
test $# -ne 2 && echo "Unexpected number of parameters" && exit 1
|
||||
test -z "$GFW_CI_TOKEN" && echo "GFW_CI_TOKEN not defined" && exit
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
# Perform sanity checks on documentation and build it.
|
||||
#
|
||||
|
||||
. ${0%/*}/lib-travisci.sh
|
||||
. ${0%/*}/lib.sh
|
||||
|
||||
test -n "$ALREADY_HAVE_ASCIIDOCTOR" ||
|
||||
gem install asciidoctor
|
||||
|
||||
make check-builtins
|
||||
|
||||
643
compat/mingw.c
643
compat/mingw.c
@@ -5,6 +5,8 @@
|
||||
#include "../strbuf.h"
|
||||
#include "../run-command.h"
|
||||
#include "../cache.h"
|
||||
#include "win32/lazyload.h"
|
||||
#include "../config.h"
|
||||
|
||||
#define HCAST(type, handle) ((type)(intptr_t)handle)
|
||||
|
||||
@@ -202,6 +204,60 @@ static int ask_yes_no_if_possible(const char *format, ...)
|
||||
}
|
||||
}
|
||||
|
||||
/* Windows only */
|
||||
enum hide_dotfiles_type {
|
||||
HIDE_DOTFILES_FALSE = 0,
|
||||
HIDE_DOTFILES_TRUE,
|
||||
HIDE_DOTFILES_DOTGITONLY
|
||||
};
|
||||
|
||||
static enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
|
||||
static char *unset_environment_variables;
|
||||
|
||||
int mingw_core_config(const char *var, const char *value, void *cb)
|
||||
{
|
||||
if (!strcmp(var, "core.hidedotfiles")) {
|
||||
if (value && !strcasecmp(value, "dotgitonly"))
|
||||
hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
|
||||
else
|
||||
hide_dotfiles = git_config_bool(var, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(var, "core.unsetenvvars")) {
|
||||
free(unset_environment_variables);
|
||||
unset_environment_variables = xstrdup(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Normalizes NT paths as returned by some low-level APIs. */
|
||||
static wchar_t *normalize_ntpath(wchar_t *wbuf)
|
||||
{
|
||||
int i;
|
||||
/* fix absolute path prefixes */
|
||||
if (wbuf[0] == '\\') {
|
||||
/* strip NT namespace prefixes */
|
||||
if (!wcsncmp(wbuf, L"\\??\\", 4) ||
|
||||
!wcsncmp(wbuf, L"\\\\?\\", 4))
|
||||
wbuf += 4;
|
||||
else if (!wcsnicmp(wbuf, L"\\DosDevices\\", 12))
|
||||
wbuf += 12;
|
||||
/* replace remaining '...UNC\' with '\\' */
|
||||
if (!wcsnicmp(wbuf, L"UNC\\", 4)) {
|
||||
wbuf += 2;
|
||||
*wbuf = '\\';
|
||||
}
|
||||
}
|
||||
/* convert backslashes to slashes */
|
||||
for (i = 0; wbuf[i]; i++)
|
||||
if (wbuf[i] == '\\')
|
||||
wbuf[i] = '/';
|
||||
return wbuf;
|
||||
}
|
||||
|
||||
int mingw_unlink(const char *pathname)
|
||||
{
|
||||
int ret, tries = 0;
|
||||
@@ -562,9 +618,11 @@ static inline long long filetime_to_hnsec(const FILETIME *ft)
|
||||
return winTime - 116444736000000000LL;
|
||||
}
|
||||
|
||||
static inline time_t filetime_to_time_t(const FILETIME *ft)
|
||||
static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts)
|
||||
{
|
||||
return (time_t)(filetime_to_hnsec(ft) / 10000000);
|
||||
long long hnsec = filetime_to_hnsec(ft);
|
||||
ts->tv_sec = (time_t)(hnsec / 10000000);
|
||||
ts->tv_nsec = (hnsec % 10000000) * 100;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -623,9 +681,9 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
|
||||
buf->st_size = fdata.nFileSizeLow |
|
||||
(((off_t)fdata.nFileSizeHigh)<<32);
|
||||
buf->st_dev = buf->st_rdev = 0; /* not used by Git */
|
||||
buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
|
||||
buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
|
||||
buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
|
||||
filetime_to_timespec(&(fdata.ftLastAccessTime), &(buf->st_atim));
|
||||
filetime_to_timespec(&(fdata.ftLastWriteTime), &(buf->st_mtim));
|
||||
filetime_to_timespec(&(fdata.ftCreationTime), &(buf->st_ctim));
|
||||
if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
|
||||
WIN32_FIND_DATAW findbuf;
|
||||
HANDLE handle = FindFirstFileW(wfilename, &findbuf);
|
||||
@@ -706,6 +764,29 @@ static int do_stat_internal(int follow, const char *file_name, struct stat *buf)
|
||||
return do_lstat(follow, alt_name, buf);
|
||||
}
|
||||
|
||||
static int get_file_info_by_handle(HANDLE hnd, struct stat *buf)
|
||||
{
|
||||
BY_HANDLE_FILE_INFORMATION fdata;
|
||||
|
||||
if (!GetFileInformationByHandle(hnd, &fdata)) {
|
||||
errno = err_win_to_posix(GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf->st_ino = 0;
|
||||
buf->st_gid = 0;
|
||||
buf->st_uid = 0;
|
||||
buf->st_nlink = 1;
|
||||
buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
|
||||
buf->st_size = fdata.nFileSizeLow |
|
||||
(((off_t)fdata.nFileSizeHigh)<<32);
|
||||
buf->st_dev = buf->st_rdev = 0; /* not used by Git */
|
||||
filetime_to_timespec(&(fdata.ftLastAccessTime), &(buf->st_atim));
|
||||
filetime_to_timespec(&(fdata.ftLastWriteTime), &(buf->st_mtim));
|
||||
filetime_to_timespec(&(fdata.ftCreationTime), &(buf->st_ctim));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mingw_lstat(const char *file_name, struct stat *buf)
|
||||
{
|
||||
return do_stat_internal(0, file_name, buf);
|
||||
@@ -718,32 +799,31 @@ int mingw_stat(const char *file_name, struct stat *buf)
|
||||
int mingw_fstat(int fd, struct stat *buf)
|
||||
{
|
||||
HANDLE fh = (HANDLE)_get_osfhandle(fd);
|
||||
BY_HANDLE_FILE_INFORMATION fdata;
|
||||
DWORD avail, type = GetFileType(fh) & ~FILE_TYPE_REMOTE;
|
||||
|
||||
if (fh == INVALID_HANDLE_VALUE) {
|
||||
switch (type) {
|
||||
case FILE_TYPE_DISK:
|
||||
return get_file_info_by_handle(fh, buf);
|
||||
|
||||
case FILE_TYPE_CHAR:
|
||||
case FILE_TYPE_PIPE:
|
||||
/* initialize stat fields */
|
||||
memset(buf, 0, sizeof(*buf));
|
||||
buf->st_nlink = 1;
|
||||
|
||||
if (type == FILE_TYPE_CHAR) {
|
||||
buf->st_mode = _S_IFCHR;
|
||||
} else {
|
||||
buf->st_mode = _S_IFIFO;
|
||||
if (PeekNamedPipe(fh, NULL, 0, NULL, &avail, NULL))
|
||||
buf->st_size = avail;
|
||||
}
|
||||
return 0;
|
||||
|
||||
default:
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
/* direct non-file handles to MS's fstat() */
|
||||
if (GetFileType(fh) != FILE_TYPE_DISK)
|
||||
return _fstati64(fd, buf);
|
||||
|
||||
if (GetFileInformationByHandle(fh, &fdata)) {
|
||||
buf->st_ino = 0;
|
||||
buf->st_gid = 0;
|
||||
buf->st_uid = 0;
|
||||
buf->st_nlink = 1;
|
||||
buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
|
||||
buf->st_size = fdata.nFileSizeLow |
|
||||
(((off_t)fdata.nFileSizeHigh)<<32);
|
||||
buf->st_dev = buf->st_rdev = 0; /* not used by Git */
|
||||
buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
|
||||
buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
|
||||
buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
|
||||
return 0;
|
||||
}
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline void time_t_to_filetime(time_t t, FILETIME *ft)
|
||||
@@ -818,11 +898,19 @@ unsigned int sleep (unsigned int seconds)
|
||||
char *mingw_mktemp(char *template)
|
||||
{
|
||||
wchar_t wtemplate[MAX_PATH];
|
||||
int offset = 0;
|
||||
|
||||
if (xutftowcs_path(wtemplate, template) < 0)
|
||||
return NULL;
|
||||
|
||||
if (is_dir_sep(template[0]) && !is_dir_sep(template[1]) &&
|
||||
iswalpha(wtemplate[0]) && wtemplate[1] == L':') {
|
||||
/* We have an absolute path missing the drive prefix */
|
||||
offset = 2;
|
||||
}
|
||||
if (!_wmktemp(wtemplate))
|
||||
return NULL;
|
||||
if (xwcstoutf(template, wtemplate, strlen(template) + 1) < 0)
|
||||
if (xwcstoutf(template, wtemplate + offset, strlen(template) + 1) < 0)
|
||||
return NULL;
|
||||
return template;
|
||||
}
|
||||
@@ -887,8 +975,29 @@ struct tm *localtime_r(const time_t *timep, struct tm *result)
|
||||
|
||||
char *mingw_getcwd(char *pointer, int len)
|
||||
{
|
||||
wchar_t wpointer[MAX_PATH];
|
||||
if (!_wgetcwd(wpointer, ARRAY_SIZE(wpointer)))
|
||||
wchar_t cwd[MAX_PATH], wpointer[MAX_PATH];
|
||||
DWORD ret = GetCurrentDirectoryW(ARRAY_SIZE(cwd), cwd);
|
||||
|
||||
if (!ret || ret >= ARRAY_SIZE(cwd)) {
|
||||
errno = ret ? ENAMETOOLONG : err_win_to_posix(GetLastError());
|
||||
return NULL;
|
||||
}
|
||||
ret = GetLongPathNameW(cwd, wpointer, ARRAY_SIZE(wpointer));
|
||||
if (!ret && GetLastError() == ERROR_ACCESS_DENIED) {
|
||||
HANDLE hnd = CreateFileW(cwd, 0,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
|
||||
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
||||
if (hnd == INVALID_HANDLE_VALUE)
|
||||
return NULL;
|
||||
ret = GetFinalPathNameByHandleW(hnd, wpointer, ARRAY_SIZE(wpointer), 0);
|
||||
CloseHandle(hnd);
|
||||
if (!ret || ret >= ARRAY_SIZE(wpointer))
|
||||
return NULL;
|
||||
if (xwcstoutf(pointer, normalize_ntpath(wpointer), len) < 0)
|
||||
return NULL;
|
||||
return pointer;
|
||||
}
|
||||
if (!ret || ret >= ARRAY_SIZE(wpointer))
|
||||
return NULL;
|
||||
if (xwcstoutf(pointer, wpointer, len) < 0)
|
||||
return NULL;
|
||||
@@ -897,10 +1006,10 @@ char *mingw_getcwd(char *pointer, int len)
|
||||
}
|
||||
|
||||
/*
|
||||
* See http://msdn2.microsoft.com/en-us/library/17w5ykft(vs.71).aspx
|
||||
* (Parsing C++ Command-Line Arguments)
|
||||
* See "Parsing C++ Command-Line Arguments" at Microsoft's Docs:
|
||||
* https://docs.microsoft.com/en-us/cpp/cpp/parsing-cpp-command-line-arguments
|
||||
*/
|
||||
static const char *quote_arg(const char *arg)
|
||||
static const char *quote_arg_msvc(const char *arg)
|
||||
{
|
||||
/* count chars to quote */
|
||||
int len = 0, n = 0;
|
||||
@@ -955,6 +1064,37 @@ static const char *quote_arg(const char *arg)
|
||||
return q;
|
||||
}
|
||||
|
||||
#include "quote.h"
|
||||
|
||||
static const char *quote_arg_msys2(const char *arg)
|
||||
{
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
const char *p2 = arg, *p;
|
||||
|
||||
for (p = arg; *p; p++) {
|
||||
int ws = isspace(*p);
|
||||
if (!ws && *p != '\\' && *p != '"' && *p != '{')
|
||||
continue;
|
||||
if (!buf.len)
|
||||
strbuf_addch(&buf, '"');
|
||||
if (p != p2)
|
||||
strbuf_add(&buf, p2, p - p2);
|
||||
if (!ws && *p != '{')
|
||||
strbuf_addch(&buf, '\\');
|
||||
p2 = p;
|
||||
}
|
||||
|
||||
if (p == arg)
|
||||
strbuf_addch(&buf, '"');
|
||||
else if (!buf.len)
|
||||
return arg;
|
||||
else
|
||||
strbuf_add(&buf, p2, p - p2),
|
||||
|
||||
strbuf_addch(&buf, '"');
|
||||
return strbuf_detach(&buf, 0);
|
||||
}
|
||||
|
||||
static const char *parse_interpreter(const char *cmd)
|
||||
{
|
||||
static char buf[100];
|
||||
@@ -998,14 +1138,21 @@ static char *lookup_prog(const char *dir, int dirlen, const char *cmd,
|
||||
int isexe, int exe_only)
|
||||
{
|
||||
char path[MAX_PATH];
|
||||
wchar_t wpath[MAX_PATH];
|
||||
snprintf(path, sizeof(path), "%.*s\\%s.exe", dirlen, dir, cmd);
|
||||
|
||||
if (!isexe && access(path, F_OK) == 0)
|
||||
if (xutftowcs_path(wpath, path) < 0)
|
||||
return NULL;
|
||||
|
||||
if (!isexe && _waccess(wpath, F_OK) == 0)
|
||||
return xstrdup(path);
|
||||
path[strlen(path)-4] = '\0';
|
||||
if ((!exe_only || isexe) && access(path, F_OK) == 0)
|
||||
if (!(GetFileAttributes(path) & FILE_ATTRIBUTE_DIRECTORY))
|
||||
wpath[wcslen(wpath)-4] = '\0';
|
||||
if ((!exe_only || isexe) && _waccess(wpath, F_OK) == 0) {
|
||||
if (!(GetFileAttributesW(wpath) & FILE_ATTRIBUTE_DIRECTORY)) {
|
||||
path[strlen(path)-4] = '\0';
|
||||
return xstrdup(path);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1040,44 +1187,142 @@ static char *path_lookup(const char *cmd, int exe_only)
|
||||
return prog;
|
||||
}
|
||||
|
||||
static int do_putenv(char **env, const char *name, int size, int free_old);
|
||||
static const wchar_t *wcschrnul(const wchar_t *s, wchar_t c)
|
||||
{
|
||||
while (*s && *s != c)
|
||||
s++;
|
||||
return s;
|
||||
}
|
||||
|
||||
/* used number of elements of environ array, including terminating NULL */
|
||||
static int environ_size = 0;
|
||||
/* allocated size of environ array, in bytes */
|
||||
static int environ_alloc = 0;
|
||||
/* Compare only keys */
|
||||
static int wenvcmp(const void *a, const void *b)
|
||||
{
|
||||
wchar_t *p = *(wchar_t **)a, *q = *(wchar_t **)b;
|
||||
size_t p_len, q_len;
|
||||
|
||||
/* Find the keys */
|
||||
p_len = wcschrnul(p, L'=') - p;
|
||||
q_len = wcschrnul(q, L'=') - q;
|
||||
|
||||
/* If the length differs, include the shorter key's NUL */
|
||||
if (p_len < q_len)
|
||||
p_len++;
|
||||
else if (p_len > q_len)
|
||||
p_len = q_len + 1;
|
||||
|
||||
return _wcsnicmp(p, q, p_len);
|
||||
}
|
||||
|
||||
/* We need a stable sort to convert the environment between UTF-16 <-> UTF-8 */
|
||||
#ifndef INTERNAL_QSORT
|
||||
#include "qsort.c"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Create environment block suitable for CreateProcess. Merges current
|
||||
* process environment and the supplied environment changes.
|
||||
* Build an environment block combining the inherited environment
|
||||
* merged with the given list of settings.
|
||||
*
|
||||
* Values of the form "KEY=VALUE" in deltaenv override inherited values.
|
||||
* Values of the form "KEY" in deltaenv delete inherited values.
|
||||
*
|
||||
* Multiple entries in deltaenv for the same key are explicitly allowed.
|
||||
*
|
||||
* We return a contiguous block of UNICODE strings with a final trailing
|
||||
* zero word.
|
||||
*/
|
||||
static wchar_t *make_environment_block(char **deltaenv)
|
||||
{
|
||||
wchar_t *wenvblk = NULL;
|
||||
char **tmpenv;
|
||||
int i = 0, size = environ_size, wenvsz = 0, wenvpos = 0;
|
||||
wchar_t *wenv = GetEnvironmentStringsW(), *wdeltaenv, *result, *p;
|
||||
size_t wlen, s, delta_size, size;
|
||||
|
||||
while (deltaenv && deltaenv[i])
|
||||
i++;
|
||||
wchar_t **array = NULL;
|
||||
size_t alloc = 0, nr = 0, i;
|
||||
|
||||
/* copy the environment, leaving space for changes */
|
||||
ALLOC_ARRAY(tmpenv, size + i);
|
||||
memcpy(tmpenv, environ, size * sizeof(char*));
|
||||
size = 1; /* for extra NUL at the end */
|
||||
|
||||
/* merge supplied environment changes into the temporary environment */
|
||||
for (i = 0; deltaenv && deltaenv[i]; i++)
|
||||
size = do_putenv(tmpenv, deltaenv[i], size, 0);
|
||||
/* If there is no deltaenv to apply, simply return a copy. */
|
||||
if (!deltaenv || !*deltaenv) {
|
||||
for (p = wenv; p && *p; ) {
|
||||
size_t s = wcslen(p) + 1;
|
||||
size += s;
|
||||
p += s;
|
||||
}
|
||||
|
||||
/* create environment block from temporary environment */
|
||||
for (i = 0; tmpenv[i]; i++) {
|
||||
size = 2 * strlen(tmpenv[i]) + 2; /* +2 for final \0 */
|
||||
ALLOC_GROW(wenvblk, (wenvpos + size) * sizeof(wchar_t), wenvsz);
|
||||
wenvpos += xutftowcs(&wenvblk[wenvpos], tmpenv[i], size) + 1;
|
||||
ALLOC_ARRAY(result, size);
|
||||
memcpy(result, wenv, size * sizeof(*wenv));
|
||||
FreeEnvironmentStringsW(wenv);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there is a deltaenv, let's accumulate all keys into `array`,
|
||||
* sort them using the stable git_qsort() and then copy, skipping
|
||||
* duplicate keys
|
||||
*/
|
||||
for (p = wenv; p && *p; ) {
|
||||
ALLOC_GROW(array, nr + 1, alloc);
|
||||
s = wcslen(p) + 1;
|
||||
array[nr++] = p;
|
||||
p += s;
|
||||
size += s;
|
||||
}
|
||||
|
||||
/* (over-)assess size needed for wchar version of deltaenv */
|
||||
for (delta_size = 0, i = 0; deltaenv[i]; i++)
|
||||
delta_size += strlen(deltaenv[i]) * 2 + 1;
|
||||
ALLOC_ARRAY(wdeltaenv, delta_size);
|
||||
|
||||
/* convert the deltaenv, appending to array */
|
||||
for (i = 0, p = wdeltaenv; deltaenv[i]; i++) {
|
||||
ALLOC_GROW(array, nr + 1, alloc);
|
||||
wlen = xutftowcs(p, deltaenv[i], wdeltaenv + delta_size - p);
|
||||
array[nr++] = p;
|
||||
p += wlen + 1;
|
||||
}
|
||||
|
||||
git_qsort(array, nr, sizeof(*array), wenvcmp);
|
||||
ALLOC_ARRAY(result, size + delta_size);
|
||||
|
||||
for (p = result, i = 0; i < nr; i++) {
|
||||
/* Skip any duplicate keys; last one wins */
|
||||
while (i + 1 < nr && !wenvcmp(array + i, array + i + 1))
|
||||
i++;
|
||||
|
||||
/* Skip "to delete" entry */
|
||||
if (!wcschr(array[i], L'='))
|
||||
continue;
|
||||
|
||||
size = wcslen(array[i]) + 1;
|
||||
memcpy(p, array[i], size * sizeof(*p));
|
||||
p += size;
|
||||
}
|
||||
*p = L'\0';
|
||||
|
||||
free(array);
|
||||
free(wdeltaenv);
|
||||
FreeEnvironmentStringsW(wenv);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void do_unset_environment_variables(void)
|
||||
{
|
||||
static int done;
|
||||
char *p = unset_environment_variables;
|
||||
|
||||
if (done || !p)
|
||||
return;
|
||||
done = 1;
|
||||
|
||||
for (;;) {
|
||||
char *comma = strchr(p, ',');
|
||||
|
||||
if (comma)
|
||||
*comma = '\0';
|
||||
unsetenv(p);
|
||||
if (!comma)
|
||||
break;
|
||||
p = comma + 1;
|
||||
}
|
||||
/* add final \0 terminator */
|
||||
wenvblk[wenvpos] = 0;
|
||||
free(tmpenv);
|
||||
return wenvblk;
|
||||
}
|
||||
|
||||
struct pinfo_t {
|
||||
@@ -1088,6 +1333,34 @@ struct pinfo_t {
|
||||
static struct pinfo_t *pinfo = NULL;
|
||||
CRITICAL_SECTION pinfo_cs;
|
||||
|
||||
static int is_msys2_sh(const char *cmd)
|
||||
{
|
||||
if (cmd && !strcmp(cmd, "sh")) {
|
||||
static int ret = -1;
|
||||
char *p;
|
||||
|
||||
if (ret >= 0)
|
||||
return ret;
|
||||
|
||||
p = path_lookup(cmd, 0);
|
||||
if (!p)
|
||||
ret = 0;
|
||||
else {
|
||||
size_t len = strlen(p);
|
||||
ret = len > 15 &&
|
||||
is_dir_sep(p[len - 15]) &&
|
||||
!strncasecmp(p + len - 14, "usr", 3) &&
|
||||
is_dir_sep(p[len - 11]) &&
|
||||
!strncasecmp(p + len - 10, "bin", 3) &&
|
||||
is_dir_sep(p[len - 7]) &&
|
||||
!strcasecmp(p + len - 6, "sh.exe");
|
||||
free(p);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaenv,
|
||||
const char *dir,
|
||||
int prepend_cmd, int fhin, int fhout, int fherr)
|
||||
@@ -1098,9 +1371,14 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
|
||||
wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs, *wenvblk = NULL;
|
||||
unsigned flags = CREATE_UNICODE_ENVIRONMENT;
|
||||
BOOL ret;
|
||||
HANDLE cons;
|
||||
const char *(*quote_arg)(const char *arg) =
|
||||
is_msys2_sh(*argv) ? quote_arg_msys2 : quote_arg_msvc;
|
||||
|
||||
do_unset_environment_variables();
|
||||
|
||||
/* Determine whether or not we are associated to a console */
|
||||
HANDLE cons = CreateFile("CONOUT$", GENERIC_WRITE,
|
||||
cons = CreateFile("CONOUT$", GENERIC_WRITE,
|
||||
FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (cons == INVALID_HANDLE_VALUE) {
|
||||
@@ -1319,87 +1597,83 @@ int mingw_kill(pid_t pid, int sig)
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare environment entries by key (i.e. stopping at '=' or '\0').
|
||||
* UTF-8 versions of getenv(), putenv() and unsetenv().
|
||||
* Internally, they use the CRT's stock UNICODE routines
|
||||
* to avoid data loss.
|
||||
*/
|
||||
static int compareenv(const void *v1, const void *v2)
|
||||
{
|
||||
const char *e1 = *(const char**)v1;
|
||||
const char *e2 = *(const char**)v2;
|
||||
|
||||
for (;;) {
|
||||
int c1 = *e1++;
|
||||
int c2 = *e2++;
|
||||
c1 = (c1 == '=') ? 0 : tolower(c1);
|
||||
c2 = (c2 == '=') ? 0 : tolower(c2);
|
||||
if (c1 > c2)
|
||||
return 1;
|
||||
if (c1 < c2)
|
||||
return -1;
|
||||
if (c1 == 0)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int bsearchenv(char **env, const char *name, size_t size)
|
||||
{
|
||||
unsigned low = 0, high = size;
|
||||
while (low < high) {
|
||||
unsigned mid = low + ((high - low) >> 1);
|
||||
int cmp = compareenv(&env[mid], &name);
|
||||
if (cmp < 0)
|
||||
low = mid + 1;
|
||||
else if (cmp > 0)
|
||||
high = mid;
|
||||
else
|
||||
return mid;
|
||||
}
|
||||
return ~low; /* not found, return 1's complement of insert position */
|
||||
}
|
||||
|
||||
/*
|
||||
* If name contains '=', then sets the variable, otherwise it unsets it
|
||||
* Size includes the terminating NULL. Env must have room for size + 1 entries
|
||||
* (in case of insert). Returns the new size. Optionally frees removed entries.
|
||||
*/
|
||||
static int do_putenv(char **env, const char *name, int size, int free_old)
|
||||
{
|
||||
int i = bsearchenv(env, name, size - 1);
|
||||
|
||||
/* optionally free removed / replaced entry */
|
||||
if (i >= 0 && free_old)
|
||||
free(env[i]);
|
||||
|
||||
if (strchr(name, '=')) {
|
||||
/* if new value ('key=value') is specified, insert or replace entry */
|
||||
if (i < 0) {
|
||||
i = ~i;
|
||||
memmove(&env[i + 1], &env[i], (size - i) * sizeof(char*));
|
||||
size++;
|
||||
}
|
||||
env[i] = (char*) name;
|
||||
} else if (i >= 0) {
|
||||
/* otherwise ('key') remove existing entry */
|
||||
size--;
|
||||
memmove(&env[i], &env[i + 1], (size - i) * sizeof(char*));
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
char *mingw_getenv(const char *name)
|
||||
{
|
||||
#define GETENV_MAX_RETAIN 30
|
||||
static char *values[GETENV_MAX_RETAIN];
|
||||
static int value_counter;
|
||||
int len_key, len_value;
|
||||
wchar_t *w_key;
|
||||
char *value;
|
||||
int pos = bsearchenv(environ, name, environ_size - 1);
|
||||
if (pos < 0)
|
||||
wchar_t w_value[32768];
|
||||
|
||||
if (!name || !*name)
|
||||
return NULL;
|
||||
value = strchr(environ[pos], '=');
|
||||
return value ? &value[1] : NULL;
|
||||
|
||||
len_key = strlen(name) + 1;
|
||||
/* We cannot use xcalloc() here because that uses getenv() itself */
|
||||
w_key = calloc(len_key, sizeof(wchar_t));
|
||||
if (!w_key)
|
||||
die("Out of memory, (tried to allocate %u wchar_t's)", len_key);
|
||||
xutftowcs(w_key, name, len_key);
|
||||
len_value = GetEnvironmentVariableW(w_key, w_value, ARRAY_SIZE(w_value));
|
||||
if (!len_value && GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
|
||||
free(w_key);
|
||||
return NULL;
|
||||
}
|
||||
free(w_key);
|
||||
|
||||
len_value = len_value * 3 + 1;
|
||||
/* We cannot use xcalloc() here because that uses getenv() itself */
|
||||
value = calloc(len_value, sizeof(char));
|
||||
if (!value)
|
||||
die("Out of memory, (tried to allocate %u bytes)", len_value);
|
||||
xwcstoutf(value, w_value, len_value);
|
||||
|
||||
/*
|
||||
* We return `value` which is an allocated value and the caller is NOT
|
||||
* expecting to have to free it, so we keep a round-robin array,
|
||||
* invalidating the buffer after GETENV_MAX_RETAIN getenv() calls.
|
||||
*/
|
||||
free(values[value_counter]);
|
||||
values[value_counter++] = value;
|
||||
if (value_counter >= ARRAY_SIZE(values))
|
||||
value_counter = 0;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
int mingw_putenv(const char *namevalue)
|
||||
{
|
||||
ALLOC_GROW(environ, (environ_size + 1) * sizeof(char*), environ_alloc);
|
||||
environ_size = do_putenv(environ, namevalue, environ_size, 1);
|
||||
return 0;
|
||||
int size;
|
||||
wchar_t *wide, *equal;
|
||||
BOOL result;
|
||||
|
||||
if (!namevalue || !*namevalue)
|
||||
return 0;
|
||||
|
||||
size = strlen(namevalue) * 2 + 1;
|
||||
wide = calloc(size, sizeof(wchar_t));
|
||||
if (!wide)
|
||||
die("Out of memory, (tried to allocate %u wchar_t's)", size);
|
||||
xutftowcs(wide, namevalue, size);
|
||||
equal = wcschr(wide, L'=');
|
||||
if (!equal)
|
||||
result = SetEnvironmentVariableW(wide, NULL);
|
||||
else {
|
||||
*equal = L'\0';
|
||||
result = SetEnvironmentVariableW(wide, equal + 1);
|
||||
}
|
||||
free(wide);
|
||||
|
||||
if (!result)
|
||||
errno = err_win_to_posix(GetLastError());
|
||||
|
||||
return result ? 0 : -1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1547,7 +1821,8 @@ static void ensure_socket_initialization(void)
|
||||
WSAGetLastError());
|
||||
|
||||
for (name = libraries; *name; name++) {
|
||||
ipv6_dll = LoadLibrary(*name);
|
||||
ipv6_dll = LoadLibraryExA(*name, NULL,
|
||||
LOAD_LIBRARY_SEARCH_SYSTEM32);
|
||||
if (!ipv6_dll)
|
||||
continue;
|
||||
|
||||
@@ -1768,18 +2043,63 @@ int mingw_getpagesize(void)
|
||||
return si.dwAllocationGranularity;
|
||||
}
|
||||
|
||||
/* See https://msdn.microsoft.com/en-us/library/windows/desktop/ms724435.aspx */
|
||||
enum EXTENDED_NAME_FORMAT {
|
||||
NameDisplay = 3,
|
||||
NameUserPrincipal = 8
|
||||
};
|
||||
|
||||
static char *get_extended_user_info(enum EXTENDED_NAME_FORMAT type)
|
||||
{
|
||||
DECLARE_PROC_ADDR(secur32.dll, BOOL, GetUserNameExW,
|
||||
enum EXTENDED_NAME_FORMAT, LPCWSTR, PULONG);
|
||||
static wchar_t wbuffer[1024];
|
||||
DWORD len;
|
||||
|
||||
if (!INIT_PROC_ADDR(GetUserNameExW))
|
||||
return NULL;
|
||||
|
||||
len = ARRAY_SIZE(wbuffer);
|
||||
if (GetUserNameExW(type, wbuffer, &len)) {
|
||||
char *converted = xmalloc((len *= 3));
|
||||
if (xwcstoutf(converted, wbuffer, len) >= 0)
|
||||
return converted;
|
||||
free(converted);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *mingw_query_user_email(void)
|
||||
{
|
||||
return get_extended_user_info(NameUserPrincipal);
|
||||
}
|
||||
|
||||
struct passwd *getpwuid(int uid)
|
||||
{
|
||||
static unsigned initialized;
|
||||
static char user_name[100];
|
||||
static struct passwd p;
|
||||
static struct passwd *p;
|
||||
DWORD len;
|
||||
|
||||
DWORD len = sizeof(user_name);
|
||||
if (!GetUserName(user_name, &len))
|
||||
if (initialized)
|
||||
return p;
|
||||
|
||||
len = sizeof(user_name);
|
||||
if (!GetUserName(user_name, &len)) {
|
||||
initialized = 1;
|
||||
return NULL;
|
||||
p.pw_name = user_name;
|
||||
p.pw_gecos = "unknown";
|
||||
p.pw_dir = NULL;
|
||||
return &p;
|
||||
}
|
||||
|
||||
p = xmalloc(sizeof(*p));
|
||||
p->pw_name = user_name;
|
||||
p->pw_gecos = get_extended_user_info(NameDisplay);
|
||||
if (!p->pw_gecos)
|
||||
p->pw_gecos = "unknown";
|
||||
p->pw_dir = NULL;
|
||||
|
||||
initialized = 1;
|
||||
return p;
|
||||
}
|
||||
|
||||
static HANDLE timer_event;
|
||||
@@ -1937,24 +2257,12 @@ int mingw_raise(int sig)
|
||||
|
||||
int link(const char *oldpath, const char *newpath)
|
||||
{
|
||||
typedef BOOL (WINAPI *T)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES);
|
||||
static T create_hard_link = NULL;
|
||||
wchar_t woldpath[MAX_PATH], wnewpath[MAX_PATH];
|
||||
if (xutftowcs_path(woldpath, oldpath) < 0 ||
|
||||
xutftowcs_path(wnewpath, newpath) < 0)
|
||||
return -1;
|
||||
|
||||
if (!create_hard_link) {
|
||||
create_hard_link = (T) GetProcAddress(
|
||||
GetModuleHandle("kernel32.dll"), "CreateHardLinkW");
|
||||
if (!create_hard_link)
|
||||
create_hard_link = (T)-1;
|
||||
}
|
||||
if (create_hard_link == (T)-1) {
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
if (!create_hard_link(wnewpath, woldpath, NULL)) {
|
||||
if (!CreateHardLinkW(wnewpath, woldpath, NULL)) {
|
||||
errno = err_win_to_posix(GetLastError());
|
||||
return -1;
|
||||
}
|
||||
@@ -2261,17 +2569,6 @@ void mingw_startup(void)
|
||||
maxlen = wcslen(wargv[0]);
|
||||
for (i = 1; i < argc; i++)
|
||||
maxlen = max(maxlen, wcslen(wargv[i]));
|
||||
for (i = 0; wenv[i]; i++)
|
||||
maxlen = max(maxlen, wcslen(wenv[i]));
|
||||
|
||||
/*
|
||||
* nedmalloc can't free CRT memory, allocate resizable environment
|
||||
* list. Note that xmalloc / xmemdupz etc. call getenv, so we cannot
|
||||
* use it while initializing the environment itself.
|
||||
*/
|
||||
environ_size = i + 1;
|
||||
environ_alloc = alloc_nr(environ_size * sizeof(char*));
|
||||
environ = malloc_startup(environ_alloc);
|
||||
|
||||
/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
|
||||
maxlen = 3 * maxlen + 1;
|
||||
@@ -2280,17 +2577,13 @@ void mingw_startup(void)
|
||||
/* convert command line arguments and environment to UTF-8 */
|
||||
for (i = 0; i < argc; i++)
|
||||
__argv[i] = wcstoutfdup_startup(buffer, wargv[i], maxlen);
|
||||
for (i = 0; wenv[i]; i++)
|
||||
environ[i] = wcstoutfdup_startup(buffer, wenv[i], maxlen);
|
||||
environ[i] = NULL;
|
||||
free(buffer);
|
||||
|
||||
/* sort environment for O(log n) getenv / putenv */
|
||||
qsort(environ, i, sizeof(char*), compareenv);
|
||||
|
||||
/* fix Windows specific environment settings */
|
||||
setup_windows_environment();
|
||||
|
||||
unset_environment_variables = xstrdup("PERL5LIB");
|
||||
|
||||
/* initialize critical section for waitpid pinfo_t list */
|
||||
InitializeCriticalSection(&pinfo_cs);
|
||||
|
||||
|
||||
@@ -11,6 +11,9 @@ typedef _sigset_t sigset_t;
|
||||
#undef _POSIX_THREAD_SAFE_FUNCTIONS
|
||||
#endif
|
||||
|
||||
extern int mingw_core_config(const char *var, const char *value, void *cb);
|
||||
#define platform_core_config mingw_core_config
|
||||
|
||||
/*
|
||||
* things that are not available in header files
|
||||
*/
|
||||
@@ -257,11 +260,35 @@ char *mingw_mktemp(char *template);
|
||||
char *mingw_getcwd(char *pointer, int len);
|
||||
#define getcwd mingw_getcwd
|
||||
|
||||
#ifdef NO_UNSETENV
|
||||
#error "NO_UNSETENV is incompatible with the Windows-specific startup code!"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We bind *env() routines (even the mingw_ ones) to private mingw_ versions.
|
||||
* These talk to the CRT using UNICODE/wchar_t, but maintain the original
|
||||
* narrow-char API.
|
||||
*
|
||||
* Note that the MSCRT maintains both ANSI (getenv()) and UNICODE (_wgetenv())
|
||||
* routines and stores both versions of each environment variable in parallel
|
||||
* (and secretly updates both when you set one or the other), but it uses CP_ACP
|
||||
* to do the conversion rather than CP_UTF8.
|
||||
*
|
||||
* Since everything in the git code base is UTF8, we define the mingw_ routines
|
||||
* to access the CRT using the UNICODE routines and manually convert them to
|
||||
* UTF8. This also avoids round-trip problems.
|
||||
*
|
||||
* This also helps with our linkage, since "_wenviron" is publicly exported
|
||||
* from the CRT. But to access "_environ" we would have to statically link
|
||||
* to the CRT (/MT).
|
||||
*
|
||||
* We require NO_SETENV (and let gitsetenv() call our mingw_putenv).
|
||||
*/
|
||||
#define getenv mingw_getenv
|
||||
#define putenv mingw_putenv
|
||||
#define unsetenv mingw_putenv
|
||||
char *mingw_getenv(const char *name);
|
||||
#define getenv mingw_getenv
|
||||
int mingw_putenv(const char *namevalue);
|
||||
#define putenv mingw_putenv
|
||||
#define unsetenv mingw_putenv
|
||||
int mingw_putenv(const char *name);
|
||||
|
||||
int mingw_gethostname(char *host, int namelen);
|
||||
#define gethostname mingw_gethostname
|
||||
@@ -327,18 +354,41 @@ static inline int getrlimit(int resource, struct rlimit *rlp)
|
||||
}
|
||||
|
||||
/*
|
||||
* Use mingw specific stat()/lstat()/fstat() implementations on Windows.
|
||||
* Use mingw specific stat()/lstat()/fstat() implementations on Windows,
|
||||
* including our own struct stat with 64 bit st_size and nanosecond-precision
|
||||
* file times.
|
||||
*/
|
||||
#ifndef __MINGW64_VERSION_MAJOR
|
||||
#define off_t off64_t
|
||||
#define lseek _lseeki64
|
||||
struct timespec {
|
||||
time_t tv_sec;
|
||||
long tv_nsec;
|
||||
};
|
||||
#endif
|
||||
|
||||
/* use struct stat with 64 bit st_size */
|
||||
struct mingw_stat {
|
||||
_dev_t st_dev;
|
||||
_ino_t st_ino;
|
||||
_mode_t st_mode;
|
||||
short st_nlink;
|
||||
short st_uid;
|
||||
short st_gid;
|
||||
_dev_t st_rdev;
|
||||
off64_t st_size;
|
||||
struct timespec st_atim;
|
||||
struct timespec st_mtim;
|
||||
struct timespec st_ctim;
|
||||
};
|
||||
|
||||
#define st_atime st_atim.tv_sec
|
||||
#define st_mtime st_mtim.tv_sec
|
||||
#define st_ctime st_ctim.tv_sec
|
||||
|
||||
#ifdef stat
|
||||
#undef stat
|
||||
#endif
|
||||
#define stat _stati64
|
||||
#define stat mingw_stat
|
||||
int mingw_lstat(const char *file_name, struct stat *buf);
|
||||
int mingw_stat(const char *file_name, struct stat *buf);
|
||||
int mingw_fstat(int fd, struct stat *buf);
|
||||
@@ -351,13 +401,6 @@ int mingw_fstat(int fd, struct stat *buf);
|
||||
#endif
|
||||
#define lstat mingw_lstat
|
||||
|
||||
#ifndef _stati64
|
||||
# define _stati64(x,y) mingw_stat(x,y)
|
||||
#elif defined (_USE_32BIT_TIME_T)
|
||||
# define _stat32i64(x,y) mingw_stat(x,y)
|
||||
#else
|
||||
# define _stat64(x,y) mingw_stat(x,y)
|
||||
#endif
|
||||
|
||||
int mingw_utime(const char *file_name, const struct utimbuf *times);
|
||||
#define utime mingw_utime
|
||||
@@ -390,6 +433,9 @@ int mingw_raise(int sig);
|
||||
int winansi_isatty(int fd);
|
||||
#define isatty winansi_isatty
|
||||
|
||||
int winansi_dup2(int oldfd, int newfd);
|
||||
#define dup2 winansi_dup2
|
||||
|
||||
void winansi_init(void);
|
||||
HANDLE winansi_get_osfhandle(int fd);
|
||||
|
||||
@@ -424,6 +470,8 @@ static inline void convert_slashes(char *path)
|
||||
int mingw_offset_1st_component(const char *path);
|
||||
#define offset_1st_component mingw_offset_1st_component
|
||||
#define PATH_SEP ';'
|
||||
extern char *mingw_query_user_email(void);
|
||||
#define query_user_email mingw_query_user_email
|
||||
#if !defined(__MINGW64_VERSION_MAJOR) && (!defined(_MSC_VER) || _MSC_VER < 1800)
|
||||
#define PRIuMAX "I64u"
|
||||
#define PRId64 "I64d"
|
||||
|
||||
@@ -29,9 +29,6 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
/* Specification. */
|
||||
#include <poll.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <assert.h>
|
||||
@@ -55,6 +52,9 @@
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
/* Specification. */
|
||||
#include "poll.h"
|
||||
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
# include <sys/ioctl.h>
|
||||
#endif
|
||||
@@ -266,6 +266,20 @@ win32_compute_revents_socket (SOCKET h, int sought, long lNetworkEvents)
|
||||
return happened;
|
||||
}
|
||||
|
||||
#include <windows.h>
|
||||
#include "compat/win32/lazyload.h"
|
||||
|
||||
static ULONGLONG CompatGetTickCount64(void)
|
||||
{
|
||||
DECLARE_PROC_ADDR(kernel32.dll, ULONGLONG, GetTickCount64, void);
|
||||
|
||||
if (!INIT_PROC_ADDR(GetTickCount64))
|
||||
return (ULONGLONG)GetTickCount();
|
||||
|
||||
return GetTickCount64();
|
||||
}
|
||||
#define GetTickCount64 CompatGetTickCount64
|
||||
|
||||
#else /* !MinGW */
|
||||
|
||||
/* Convert select(2) returned fd_sets into poll(2) revents values. */
|
||||
@@ -449,7 +463,8 @@ poll (struct pollfd *pfd, nfds_t nfd, int timeout)
|
||||
static HANDLE hEvent;
|
||||
WSANETWORKEVENTS ev;
|
||||
HANDLE h, handle_array[FD_SETSIZE + 2];
|
||||
DWORD ret, wait_timeout, nhandles, start = 0, elapsed, orig_timeout = 0;
|
||||
DWORD ret, wait_timeout, nhandles, elapsed, orig_timeout = 0;
|
||||
ULONGLONG start = 0;
|
||||
fd_set rfds, wfds, xfds;
|
||||
BOOL poll_again;
|
||||
MSG msg;
|
||||
@@ -465,7 +480,7 @@ poll (struct pollfd *pfd, nfds_t nfd, int timeout)
|
||||
if (timeout != INFTIM)
|
||||
{
|
||||
orig_timeout = timeout;
|
||||
start = GetTickCount();
|
||||
start = GetTickCount64();
|
||||
}
|
||||
|
||||
if (!hEvent)
|
||||
@@ -614,7 +629,7 @@ restart:
|
||||
|
||||
if (!rc && orig_timeout && timeout != INFTIM)
|
||||
{
|
||||
elapsed = GetTickCount() - start;
|
||||
elapsed = (DWORD)(GetTickCount64() - start);
|
||||
timeout = elapsed >= orig_timeout ? 0 : orig_timeout - elapsed;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,21 @@
|
||||
#ifndef _GL_POLL_H
|
||||
#define _GL_POLL_H
|
||||
|
||||
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x600
|
||||
/* Vista has its own, socket-only poll() */
|
||||
#undef POLLIN
|
||||
#undef POLLPRI
|
||||
#undef POLLOUT
|
||||
#undef POLLERR
|
||||
#undef POLLHUP
|
||||
#undef POLLNVAL
|
||||
#undef POLLRDNORM
|
||||
#undef POLLRDBAND
|
||||
#undef POLLWRNORM
|
||||
#undef POLLWRBAND
|
||||
#define pollfd compat_pollfd
|
||||
#endif
|
||||
|
||||
/* fake a poll(2) environment */
|
||||
#define POLLIN 0x0001 /* any readable data available */
|
||||
#define POLLPRI 0x0002 /* OOB/Urgent readable data */
|
||||
|
||||
@@ -56,141 +56,3 @@ pthread_t pthread_self(void)
|
||||
t.tid = GetCurrentThreadId();
|
||||
return t;
|
||||
}
|
||||
|
||||
int pthread_cond_init(pthread_cond_t *cond, const void *unused)
|
||||
{
|
||||
cond->waiters = 0;
|
||||
cond->was_broadcast = 0;
|
||||
InitializeCriticalSection(&cond->waiters_lock);
|
||||
|
||||
cond->sema = CreateSemaphore(NULL, 0, LONG_MAX, NULL);
|
||||
if (!cond->sema)
|
||||
die("CreateSemaphore() failed");
|
||||
|
||||
cond->continue_broadcast = CreateEvent(NULL, /* security */
|
||||
FALSE, /* auto-reset */
|
||||
FALSE, /* not signaled */
|
||||
NULL); /* name */
|
||||
if (!cond->continue_broadcast)
|
||||
die("CreateEvent() failed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_cond_destroy(pthread_cond_t *cond)
|
||||
{
|
||||
CloseHandle(cond->sema);
|
||||
CloseHandle(cond->continue_broadcast);
|
||||
DeleteCriticalSection(&cond->waiters_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_cond_wait(pthread_cond_t *cond, CRITICAL_SECTION *mutex)
|
||||
{
|
||||
int last_waiter;
|
||||
|
||||
EnterCriticalSection(&cond->waiters_lock);
|
||||
cond->waiters++;
|
||||
LeaveCriticalSection(&cond->waiters_lock);
|
||||
|
||||
/*
|
||||
* Unlock external mutex and wait for signal.
|
||||
* NOTE: we've held mutex locked long enough to increment
|
||||
* waiters count above, so there's no problem with
|
||||
* leaving mutex unlocked before we wait on semaphore.
|
||||
*/
|
||||
LeaveCriticalSection(mutex);
|
||||
|
||||
/* let's wait - ignore return value */
|
||||
WaitForSingleObject(cond->sema, INFINITE);
|
||||
|
||||
/*
|
||||
* Decrease waiters count. If we are the last waiter, then we must
|
||||
* notify the broadcasting thread that it can continue.
|
||||
* But if we continued due to cond_signal, we do not have to do that
|
||||
* because the signaling thread knows that only one waiter continued.
|
||||
*/
|
||||
EnterCriticalSection(&cond->waiters_lock);
|
||||
cond->waiters--;
|
||||
last_waiter = cond->was_broadcast && cond->waiters == 0;
|
||||
LeaveCriticalSection(&cond->waiters_lock);
|
||||
|
||||
if (last_waiter) {
|
||||
/*
|
||||
* cond_broadcast was issued while mutex was held. This means
|
||||
* that all other waiters have continued, but are contending
|
||||
* for the mutex at the end of this function because the
|
||||
* broadcasting thread did not leave cond_broadcast, yet.
|
||||
* (This is so that it can be sure that each waiter has
|
||||
* consumed exactly one slice of the semaphor.)
|
||||
* The last waiter must tell the broadcasting thread that it
|
||||
* can go on.
|
||||
*/
|
||||
SetEvent(cond->continue_broadcast);
|
||||
/*
|
||||
* Now we go on to contend with all other waiters for
|
||||
* the mutex. Auf in den Kampf!
|
||||
*/
|
||||
}
|
||||
/* lock external mutex again */
|
||||
EnterCriticalSection(mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* IMPORTANT: This implementation requires that pthread_cond_signal
|
||||
* is called while the mutex is held that is used in the corresponding
|
||||
* pthread_cond_wait calls!
|
||||
*/
|
||||
int pthread_cond_signal(pthread_cond_t *cond)
|
||||
{
|
||||
int have_waiters;
|
||||
|
||||
EnterCriticalSection(&cond->waiters_lock);
|
||||
have_waiters = cond->waiters > 0;
|
||||
LeaveCriticalSection(&cond->waiters_lock);
|
||||
|
||||
/*
|
||||
* Signal only when there are waiters
|
||||
*/
|
||||
if (have_waiters)
|
||||
return ReleaseSemaphore(cond->sema, 1, NULL) ?
|
||||
0 : err_win_to_posix(GetLastError());
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* DOUBLY IMPORTANT: This implementation requires that pthread_cond_broadcast
|
||||
* is called while the mutex is held that is used in the corresponding
|
||||
* pthread_cond_wait calls!
|
||||
*/
|
||||
int pthread_cond_broadcast(pthread_cond_t *cond)
|
||||
{
|
||||
EnterCriticalSection(&cond->waiters_lock);
|
||||
|
||||
if ((cond->was_broadcast = cond->waiters > 0)) {
|
||||
/* wake up all waiters */
|
||||
ReleaseSemaphore(cond->sema, cond->waiters, NULL);
|
||||
LeaveCriticalSection(&cond->waiters_lock);
|
||||
/*
|
||||
* At this point all waiters continue. Each one takes its
|
||||
* slice of the semaphor. Now it's our turn to wait: Since
|
||||
* the external mutex is held, no thread can leave cond_wait,
|
||||
* yet. For this reason, we can be sure that no thread gets
|
||||
* a chance to eat *more* than one slice. OTOH, it means
|
||||
* that the last waiter must send us a wake-up.
|
||||
*/
|
||||
WaitForSingleObject(cond->continue_broadcast, INFINITE);
|
||||
/*
|
||||
* Since the external mutex is held, no thread can enter
|
||||
* cond_wait, and, hence, it is safe to reset this flag
|
||||
* without cond->waiters_lock held.
|
||||
*/
|
||||
cond->was_broadcast = 0;
|
||||
} else {
|
||||
LeaveCriticalSection(&cond->waiters_lock);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -32,27 +32,13 @@ typedef int pthread_mutexattr_t;
|
||||
#define pthread_mutexattr_settype(a, t) 0
|
||||
#define PTHREAD_MUTEX_RECURSIVE 0
|
||||
|
||||
/*
|
||||
* Implement simple condition variable for Windows threads, based on ACE
|
||||
* implementation.
|
||||
*
|
||||
* See original implementation: http://bit.ly/1vkDjo
|
||||
* ACE homepage: http://www.cse.wustl.edu/~schmidt/ACE.html
|
||||
* See also: http://www.cse.wustl.edu/~schmidt/win32-cv-1.html
|
||||
*/
|
||||
typedef struct {
|
||||
LONG waiters;
|
||||
int was_broadcast;
|
||||
CRITICAL_SECTION waiters_lock;
|
||||
HANDLE sema;
|
||||
HANDLE continue_broadcast;
|
||||
} pthread_cond_t;
|
||||
#define pthread_cond_t CONDITION_VARIABLE
|
||||
|
||||
extern int pthread_cond_init(pthread_cond_t *cond, const void *unused);
|
||||
extern int pthread_cond_destroy(pthread_cond_t *cond);
|
||||
extern int pthread_cond_wait(pthread_cond_t *cond, CRITICAL_SECTION *mutex);
|
||||
extern int pthread_cond_signal(pthread_cond_t *cond);
|
||||
extern int pthread_cond_broadcast(pthread_cond_t *cond);
|
||||
#define pthread_cond_init(a,b) InitializeConditionVariable((a))
|
||||
#define pthread_cond_destroy(a) do {} while (0)
|
||||
#define pthread_cond_wait(a,b) return_0(SleepConditionVariableCS((a), (b), INFINITE))
|
||||
#define pthread_cond_signal WakeConditionVariable
|
||||
#define pthread_cond_broadcast WakeAllConditionVariable
|
||||
|
||||
/*
|
||||
* Simple thread creation implementation using pthread API
|
||||
|
||||
@@ -474,6 +474,18 @@ static void die_lasterr(const char *fmt, ...)
|
||||
va_end(params);
|
||||
}
|
||||
|
||||
#undef dup2
|
||||
int winansi_dup2(int oldfd, int newfd)
|
||||
{
|
||||
int ret = dup2(oldfd, newfd);
|
||||
|
||||
if (!ret && newfd >= 0 && newfd <= 2)
|
||||
fd_is_interactive[newfd] = oldfd < 0 || oldfd > 2 ?
|
||||
0 : fd_is_interactive[oldfd];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static HANDLE duplicate_handle(HANDLE hnd)
|
||||
{
|
||||
HANDLE hresult, hproc = GetCurrentProcess();
|
||||
|
||||
20
config.c
20
config.c
@@ -1093,7 +1093,7 @@ int git_config_color(char *dest, const char *var, const char *value)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int git_default_core_config(const char *var, const char *value)
|
||||
static int git_default_core_config(const char *var, const char *value, void *cb)
|
||||
{
|
||||
/* This needs a better name */
|
||||
if (!strcmp(var, "core.filemode")) {
|
||||
@@ -1344,14 +1344,6 @@ static int git_default_core_config(const char *var, const char *value)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(var, "core.hidedotfiles")) {
|
||||
if (value && !strcasecmp(value, "dotgitonly"))
|
||||
hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
|
||||
else
|
||||
hide_dotfiles = git_config_bool(var, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(var, "core.partialclonefilter")) {
|
||||
return git_config_string(&core_partial_clone_filter_default,
|
||||
var, value);
|
||||
@@ -1363,7 +1355,7 @@ static int git_default_core_config(const char *var, const char *value)
|
||||
}
|
||||
|
||||
/* Add other config variables here and to Documentation/config.txt. */
|
||||
return 0;
|
||||
return platform_core_config(var, value, cb);
|
||||
}
|
||||
|
||||
static int git_default_i18n_config(const char *var, const char *value)
|
||||
@@ -1448,13 +1440,13 @@ static int git_default_mailmap_config(const char *var, const char *value)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_default_config(const char *var, const char *value, void *dummy)
|
||||
int git_default_config(const char *var, const char *value, void *cb)
|
||||
{
|
||||
if (starts_with(var, "core."))
|
||||
return git_default_core_config(var, value);
|
||||
return git_default_core_config(var, value, cb);
|
||||
|
||||
if (starts_with(var, "user."))
|
||||
return git_ident_config(var, value, dummy);
|
||||
return git_ident_config(var, value, cb);
|
||||
|
||||
if (starts_with(var, "i18n."))
|
||||
return git_default_i18n_config(var, value);
|
||||
@@ -1676,6 +1668,8 @@ static int do_git_config_sequence(const struct config_options *opts,
|
||||
|
||||
if (opts->commondir)
|
||||
repo_config = mkpathdup("%s/config", opts->commondir);
|
||||
else if (opts->git_dir)
|
||||
BUG("git_dir without commondir");
|
||||
else
|
||||
repo_config = NULL;
|
||||
|
||||
|
||||
@@ -370,7 +370,6 @@ ifeq ($(uname_S),Windows)
|
||||
RUNTIME_PREFIX = YesPlease
|
||||
HAVE_WPGMPTR = YesWeDo
|
||||
NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
|
||||
NO_NSEC = YesPlease
|
||||
USE_WIN32_MMAP = YesPlease
|
||||
MMAP_PREVENTS_DELETE = UnfortunatelyYes
|
||||
# USE_NED_ALLOCATOR = YesPlease
|
||||
@@ -381,8 +380,6 @@ ifeq ($(uname_S),Windows)
|
||||
NO_PYTHON = YesPlease
|
||||
BLK_SHA1 = YesPlease
|
||||
ETAGS_TARGET = ETAGS
|
||||
NO_INET_PTON = YesPlease
|
||||
NO_INET_NTOP = YesPlease
|
||||
NO_POSIX_GOODIES = UnfortunatelyYes
|
||||
NATIVE_CRLF = YesPlease
|
||||
DEFAULT_HELP_FORMAT = html
|
||||
@@ -520,7 +517,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
|
||||
RUNTIME_PREFIX = YesPlease
|
||||
HAVE_WPGMPTR = YesWeDo
|
||||
NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
|
||||
NO_NSEC = YesPlease
|
||||
USE_WIN32_MMAP = YesPlease
|
||||
MMAP_PREVENTS_DELETE = UnfortunatelyYes
|
||||
USE_NED_ALLOCATOR = YesPlease
|
||||
@@ -529,8 +525,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
|
||||
NO_REGEX = YesPlease
|
||||
NO_PYTHON = YesPlease
|
||||
ETAGS_TARGET = ETAGS
|
||||
NO_INET_PTON = YesPlease
|
||||
NO_INET_NTOP = YesPlease
|
||||
NO_POSIX_GOODIES = UnfortunatelyYes
|
||||
DEFAULT_HELP_FORMAT = html
|
||||
COMPAT_CFLAGS += -DNOGDI -Icompat -Icompat/win32
|
||||
@@ -560,11 +554,19 @@ else
|
||||
ifeq ($(shell expr "$(uname_R)" : '2\.'),2)
|
||||
# MSys2
|
||||
prefix = /usr/
|
||||
# Enable DEP
|
||||
BASIC_LDFLAGS += -Wl,--nxcompat
|
||||
# Enable ASLR (unless debugging)
|
||||
ifneq (,$(findstring -O,$(CFLAGS)))
|
||||
BASIC_LDFLAGS += -Wl,--dynamicbase
|
||||
endif
|
||||
ifeq (MINGW32,$(MSYSTEM))
|
||||
prefix = /mingw32
|
||||
BASIC_LDFLAGS += -Wl,--pic-executable,-e,_mainCRTStartup
|
||||
endif
|
||||
ifeq (MINGW64,$(MSYSTEM))
|
||||
prefix = /mingw64
|
||||
BASIC_LDFLAGS += -Wl,--pic-executable,-e,mainCRTStartup
|
||||
else
|
||||
COMPAT_CFLAGS += -D_USE_32BIT_TIME_T
|
||||
BASIC_LDFLAGS += -Wl,--large-address-aware
|
||||
|
||||
@@ -918,6 +918,10 @@ static enum protocol parse_connect_url(const char *url_orig, char **ret_host,
|
||||
|
||||
if (protocol == PROTO_LOCAL)
|
||||
path = end;
|
||||
else if (protocol == PROTO_FILE && *host != '/' &&
|
||||
!has_dos_drive_prefix(host) &&
|
||||
offset_1st_component(host - 2) > 1)
|
||||
path = host - 2; /* include the leading "//" */
|
||||
else if (protocol == PROTO_FILE && has_dos_drive_prefix(end))
|
||||
path = end; /* "file://$(pwd)" may be "file://C:/projects/repo" */
|
||||
else
|
||||
|
||||
@@ -75,7 +75,8 @@ static CredDeleteWT CredDeleteW;
|
||||
static void load_cred_funcs(void)
|
||||
{
|
||||
/* load DLLs */
|
||||
advapi = LoadLibrary("advapi32.dll");
|
||||
advapi = LoadLibraryExA("advapi32.dll", NULL,
|
||||
LOAD_LIBRARY_SEARCH_SYSTEM32);
|
||||
if (!advapi)
|
||||
die("failed to load advapi32.dll");
|
||||
|
||||
|
||||
@@ -136,7 +136,9 @@ static void credential_getpass(struct credential *c)
|
||||
{
|
||||
if (!c->username)
|
||||
c->username = credential_ask_one("Username", c,
|
||||
PROMPT_ASKPASS|PROMPT_ECHO);
|
||||
(getenv("GIT_ASKPASS") ?
|
||||
PROMPT_ASKPASS : 0) |
|
||||
PROMPT_ECHO);
|
||||
if (!c->password)
|
||||
c->password = credential_ask_one("Password", c,
|
||||
PROMPT_ASKPASS);
|
||||
|
||||
@@ -82,6 +82,18 @@ static struct diff_rename_src *register_rename_src(struct diff_filepair *p)
|
||||
|
||||
first = 0;
|
||||
last = rename_src_nr;
|
||||
|
||||
if (last > 0) {
|
||||
struct diff_rename_src *src = &(rename_src[last-1]);
|
||||
int cmp = strcmp(one->path, src->p->one->path);
|
||||
if (!cmp)
|
||||
return src;
|
||||
if (cmp > 0) {
|
||||
first = last;
|
||||
goto append_it;
|
||||
}
|
||||
}
|
||||
|
||||
while (last > first) {
|
||||
int next = (last + first) >> 1;
|
||||
struct diff_rename_src *src = &(rename_src[next]);
|
||||
@@ -95,6 +107,7 @@ static struct diff_rename_src *register_rename_src(struct diff_filepair *p)
|
||||
first = next+1;
|
||||
}
|
||||
|
||||
append_it:
|
||||
/* insert to make it at "first" */
|
||||
ALLOC_GROW(rename_src, rename_src_nr + 1, rename_src_alloc);
|
||||
rename_src_nr++;
|
||||
|
||||
@@ -71,7 +71,6 @@ int core_apply_sparse_checkout;
|
||||
int merge_log_config = -1;
|
||||
int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */
|
||||
unsigned long pack_size_limit_cfg;
|
||||
enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
|
||||
enum log_refs_config log_all_ref_updates = LOG_REFS_UNSET;
|
||||
|
||||
#ifndef PROTECT_HFS_DEFAULT
|
||||
|
||||
@@ -146,8 +146,8 @@
|
||||
#define _SGI_SOURCE 1
|
||||
|
||||
#if defined(WIN32) && !defined(__CYGWIN__) /* Both MinGW and MSVC */
|
||||
# if defined (_MSC_VER) && !defined(_WIN32_WINNT)
|
||||
# define _WIN32_WINNT 0x0502
|
||||
# if !defined(_WIN32_WINNT)
|
||||
# define _WIN32_WINNT 0x0600
|
||||
# endif
|
||||
#define WIN32_LEAN_AND_MEAN /* stops windows.h including winsock.h */
|
||||
#include <winsock2.h>
|
||||
@@ -342,6 +342,14 @@ typedef uintmax_t timestamp_t;
|
||||
#define _PATH_DEFPATH "/usr/local/bin:/usr/bin:/bin"
|
||||
#endif
|
||||
|
||||
#ifndef platform_core_config
|
||||
static inline int noop_core_config(const char *var, const char *value, void *cb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#define platform_core_config noop_core_config
|
||||
#endif
|
||||
|
||||
#ifndef has_dos_drive_prefix
|
||||
static inline int git_has_dos_drive_prefix(const char *path)
|
||||
{
|
||||
@@ -382,6 +390,10 @@ static inline char *git_find_last_dir_sep(const char *path)
|
||||
#define find_last_dir_sep git_find_last_dir_sep
|
||||
#endif
|
||||
|
||||
#ifndef query_user_email
|
||||
#define query_user_email() NULL
|
||||
#endif
|
||||
|
||||
#if defined(__HP_cc) && (__HP_cc >= 61000)
|
||||
#define NORETURN __attribute__((noreturn))
|
||||
#define NORETURN_PTR
|
||||
|
||||
@@ -431,6 +431,7 @@ END
|
||||
sub safe_pipe_capture {
|
||||
my @output;
|
||||
if (my $pid = open my $child, '-|') {
|
||||
binmode($child, ":crlf");
|
||||
@output = (<$child>);
|
||||
close $child or die join(' ',@_).": $! $?";
|
||||
} else {
|
||||
|
||||
71
http.c
71
http.c
@@ -155,6 +155,16 @@ static struct active_request_slot *active_queue_head;
|
||||
|
||||
static char *cached_accept_language;
|
||||
|
||||
static char *http_ssl_backend;
|
||||
|
||||
static int http_schannel_check_revoke = 1;
|
||||
/*
|
||||
* With the backend being set to `schannel`, setting sslCAinfo would override
|
||||
* the Certificate Store in cURL v7.60.0 and later, which is not what we want
|
||||
* by default.
|
||||
*/
|
||||
static int http_schannel_use_ssl_cainfo;
|
||||
|
||||
size_t fread_buffer(char *ptr, size_t eltsize, size_t nmemb, void *buffer_)
|
||||
{
|
||||
size_t size = eltsize * nmemb;
|
||||
@@ -302,6 +312,22 @@ static int http_options(const char *var, const char *value, void *cb)
|
||||
curl_ssl_try = git_config_bool(var, value);
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp("http.sslbackend", var)) {
|
||||
free(http_ssl_backend);
|
||||
http_ssl_backend = xstrdup_or_null(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp("http.schannelcheckrevoke", var)) {
|
||||
http_schannel_check_revoke = git_config_bool(var, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp("http.schannelusesslcainfo", var)) {
|
||||
http_schannel_use_ssl_cainfo = git_config_bool(var, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp("http.minsessions", var)) {
|
||||
min_curl_sessions = git_config_int(var, value);
|
||||
#ifndef USE_CURL_MULTI
|
||||
@@ -803,6 +829,16 @@ static CURL *get_curl_handle(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (http_ssl_backend && !strcmp("schannel", http_ssl_backend) &&
|
||||
!http_schannel_check_revoke) {
|
||||
#if LIBCURL_VERSION_NUM >= 0x072c00
|
||||
curl_easy_setopt(result, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NO_REVOKE);
|
||||
#else
|
||||
warning("CURLSSLOPT_NO_REVOKE not applied to curl SSL options because\n"
|
||||
"your curl version is too old (< 7.44.0)");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (http_proactive_auth)
|
||||
init_curl_http_auth(result);
|
||||
|
||||
@@ -844,7 +880,13 @@ static CURL *get_curl_handle(void)
|
||||
if (ssl_pinnedkey != NULL)
|
||||
curl_easy_setopt(result, CURLOPT_PINNEDPUBLICKEY, ssl_pinnedkey);
|
||||
#endif
|
||||
if (ssl_cainfo != NULL)
|
||||
if (http_ssl_backend && !strcmp("schannel", http_ssl_backend) &&
|
||||
!http_schannel_use_ssl_cainfo) {
|
||||
curl_easy_setopt(result, CURLOPT_CAINFO, NULL);
|
||||
#if LIBCURL_VERSION_NUM >= 0x073400
|
||||
curl_easy_setopt(result, CURLOPT_PROXY_CAINFO, NULL);
|
||||
#endif
|
||||
} else if (ssl_cainfo != NULL)
|
||||
curl_easy_setopt(result, CURLOPT_CAINFO, ssl_cainfo);
|
||||
|
||||
if (curl_low_speed_limit > 0 && curl_low_speed_time > 0) {
|
||||
@@ -995,6 +1037,33 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
|
||||
git_config(urlmatch_config_entry, &config);
|
||||
free(normalized_url);
|
||||
|
||||
#if LIBCURL_VERSION_NUM >= 0x073800
|
||||
if (http_ssl_backend) {
|
||||
const curl_ssl_backend **backends;
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
int i;
|
||||
|
||||
switch (curl_global_sslset(-1, http_ssl_backend, &backends)) {
|
||||
case CURLSSLSET_UNKNOWN_BACKEND:
|
||||
strbuf_addf(&buf, _("Unsupported SSL backend '%s'. "
|
||||
"Supported SSL backends:"),
|
||||
http_ssl_backend);
|
||||
for (i = 0; backends[i]; i++)
|
||||
strbuf_addf(&buf, "\n\t%s", backends[i]->name);
|
||||
die("%s", buf.buf);
|
||||
case CURLSSLSET_NO_BACKENDS:
|
||||
die(_("Could not set SSL backend to '%s': "
|
||||
"cURL was built without SSL backends"),
|
||||
http_ssl_backend);
|
||||
case CURLSSLSET_TOO_LATE:
|
||||
die(_("Could not set SSL backend to '%s': already set"),
|
||||
http_ssl_backend);
|
||||
case CURLSSLSET_OK:
|
||||
break; /* Okay! */
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK)
|
||||
die("curl_global_init failed");
|
||||
|
||||
|
||||
3
ident.c
3
ident.c
@@ -168,6 +168,9 @@ const char *ident_default_email(void)
|
||||
strbuf_addstr(&git_default_email, email);
|
||||
committer_ident_explicitly_given |= IDENT_MAIL_GIVEN;
|
||||
author_ident_explicitly_given |= IDENT_MAIL_GIVEN;
|
||||
} else if ((email = query_user_email()) && email[0]) {
|
||||
strbuf_addstr(&git_default_email, email);
|
||||
free((char *)email);
|
||||
} else
|
||||
copy_email(xgetpwuid_self(&default_email_is_bogus),
|
||||
&git_default_email, &default_email_is_bogus);
|
||||
|
||||
@@ -148,6 +148,9 @@ void prepare_packing_data(struct packing_data *pdata)
|
||||
1U << OE_SIZE_BITS);
|
||||
pdata->oe_delta_size_limit = git_env_ulong("GIT_TEST_OE_DELTA_SIZE",
|
||||
1UL << OE_DELTA_SIZE_BITS);
|
||||
#ifndef NO_PTHREADS
|
||||
pthread_mutex_init(&pdata->lock, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
struct object_entry *packlist_alloc(struct packing_data *pdata,
|
||||
|
||||
@@ -356,7 +356,7 @@ static inline unsigned long oe_delta_size(struct packing_data *pack,
|
||||
return e->delta_size_;
|
||||
|
||||
/*
|
||||
* pack->detla_size[] can't be NULL because oe_set_delta_size()
|
||||
* pack->delta_size[] can't be NULL because oe_set_delta_size()
|
||||
* must have been called when a new delta is saved with
|
||||
* oe_set_delta().
|
||||
* If oe_delta() returns NULL (i.e. default state, which means
|
||||
|
||||
5
path.c
5
path.c
@@ -11,6 +11,7 @@
|
||||
#include "path.h"
|
||||
#include "packfile.h"
|
||||
#include "object-store.h"
|
||||
#include "exec-cmd.h"
|
||||
|
||||
static int get_st_mode_bits(const char *path, int *mode)
|
||||
{
|
||||
@@ -709,6 +710,10 @@ char *expand_user_path(const char *path, int real_home)
|
||||
|
||||
if (path == NULL)
|
||||
goto return_null;
|
||||
#ifdef __MINGW32__
|
||||
if (path[0] == '/')
|
||||
return system_path(path + 1);
|
||||
#endif
|
||||
if (path[0] == '~') {
|
||||
const char *first_slash = strchrnul(path, '/');
|
||||
const char *username = path + 1;
|
||||
|
||||
14
send-pack.c
14
send-pack.c
@@ -38,6 +38,16 @@ int option_parse_push_signed(const struct option *opt,
|
||||
die("bad %s argument: %s", opt->long_name, arg);
|
||||
}
|
||||
|
||||
static int config_use_sideband = 1;
|
||||
|
||||
static int send_pack_config(const char *var, const char *value, void *unused)
|
||||
{
|
||||
if (!strcmp("sendpack.sideband", var))
|
||||
config_use_sideband = git_config_bool(var, value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void feed_object(const struct object_id *oid, FILE *fh, int negative)
|
||||
{
|
||||
if (negative && !has_sha1_file(oid->hash))
|
||||
@@ -392,6 +402,8 @@ int send_pack(struct send_pack_args *args,
|
||||
struct async demux;
|
||||
const char *push_cert_nonce = NULL;
|
||||
|
||||
git_config(send_pack_config, NULL);
|
||||
|
||||
/* Does the other end support the reporting? */
|
||||
if (server_supports("report-status"))
|
||||
status_report = 1;
|
||||
@@ -399,7 +411,7 @@ int send_pack(struct send_pack_args *args,
|
||||
allow_deleting_refs = 1;
|
||||
if (server_supports("ofs-delta"))
|
||||
args->use_ofs_delta = 1;
|
||||
if (server_supports("side-band-64k"))
|
||||
if (config_use_sideband && server_supports("side-band-64k"))
|
||||
use_sideband = 1;
|
||||
if (server_supports("quiet"))
|
||||
quiet_supported = 1;
|
||||
|
||||
16
setup.c
16
setup.c
@@ -39,7 +39,7 @@ static int abspath_part_inside_repo(char *path)
|
||||
off = offset_1st_component(path);
|
||||
|
||||
/* check if work tree is already the prefix */
|
||||
if (wtlen <= len && !strncmp(path, work_tree, wtlen)) {
|
||||
if (wtlen <= len && !fspathncmp(path, work_tree, wtlen)) {
|
||||
if (path[wtlen] == '/') {
|
||||
memmove(path, path + wtlen + 1, len - wtlen);
|
||||
return 0;
|
||||
@@ -59,7 +59,7 @@ static int abspath_part_inside_repo(char *path)
|
||||
path++;
|
||||
if (*path == '/') {
|
||||
*path = '\0';
|
||||
if (strcmp(real_path(path0), work_tree) == 0) {
|
||||
if (fspathcmp(real_path(path0), work_tree) == 0) {
|
||||
memmove(path0, path + 1, len - (path - path0));
|
||||
return 0;
|
||||
}
|
||||
@@ -68,7 +68,7 @@ static int abspath_part_inside_repo(char *path)
|
||||
}
|
||||
|
||||
/* check whole path */
|
||||
if (strcmp(real_path(path0), work_tree) == 0) {
|
||||
if (fspathcmp(real_path(path0), work_tree) == 0) {
|
||||
*path0 = '\0';
|
||||
return 0;
|
||||
}
|
||||
@@ -760,7 +760,7 @@ static const char *setup_discovered_git_dir(const char *gitdir,
|
||||
set_git_dir(gitdir);
|
||||
inside_git_dir = 0;
|
||||
inside_work_tree = 1;
|
||||
if (offset == cwd->len)
|
||||
if (offset >= cwd->len)
|
||||
return NULL;
|
||||
|
||||
/* Make "offset" point past the '/' (already the case for root dirs) */
|
||||
@@ -892,7 +892,7 @@ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
|
||||
const char *env_ceiling_dirs = getenv(CEILING_DIRECTORIES_ENVIRONMENT);
|
||||
struct string_list ceiling_dirs = STRING_LIST_INIT_DUP;
|
||||
const char *gitdirenv;
|
||||
int ceil_offset = -1, min_offset = has_dos_drive_prefix(dir->buf) ? 3 : 1;
|
||||
int ceil_offset = -1, min_offset = offset_1st_component(dir->buf);
|
||||
dev_t current_device = 0;
|
||||
int one_filesystem = 1;
|
||||
|
||||
@@ -920,6 +920,12 @@ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
|
||||
if (ceil_offset < 0)
|
||||
ceil_offset = min_offset - 2;
|
||||
|
||||
if (min_offset && min_offset == dir->len &&
|
||||
!is_dir_sep(dir->buf[min_offset - 1])) {
|
||||
strbuf_addch(dir, '/');
|
||||
min_offset++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test in the following order (relative to the dir):
|
||||
* - .git (file containing "gitdir: <path>")
|
||||
|
||||
1
t/.gitignore
vendored
1
t/.gitignore
vendored
@@ -2,3 +2,4 @@
|
||||
/test-results
|
||||
/.prove
|
||||
/chainlinttmp
|
||||
/out/
|
||||
|
||||
9
t/README
9
t/README
@@ -169,6 +169,15 @@ appropriately before running "make".
|
||||
implied by other options like --valgrind and
|
||||
GIT_TEST_INSTALLED.
|
||||
|
||||
--no-bin-wrappers::
|
||||
By default, the test suite uses the wrappers in
|
||||
`../bin-wrappers/` to execute `git` and friends. With this option,
|
||||
`../git` and friends are run directly. This is not recommended
|
||||
in general, as the wrappers contain safeguards to ensure that no
|
||||
files from an installed Git are used, but can speed up test runs
|
||||
especially on platforms where running shell scripts is expensive
|
||||
(most notably, Windows).
|
||||
|
||||
--root=<directory>::
|
||||
Create "trash" directories used to store all temporary data during
|
||||
testing under <directory>, instead of the t/ directory.
|
||||
|
||||
@@ -7,6 +7,7 @@ static const char *usage_msg = "\n"
|
||||
" test-tool date parse [date]...\n"
|
||||
" test-tool date approxidate [date]...\n"
|
||||
" test-tool date timestamp [date]...\n"
|
||||
" test-tool date getnanos [start-nanos]\n"
|
||||
" test-tool date is64bit\n"
|
||||
" test-tool date time_t-is64bit\n";
|
||||
|
||||
@@ -82,6 +83,15 @@ static void parse_approx_timestamp(const char **argv, struct timeval *now)
|
||||
}
|
||||
}
|
||||
|
||||
static void getnanos(const char **argv, struct timeval *now)
|
||||
{
|
||||
double seconds = getnanotime() / 1.0e9;
|
||||
|
||||
if (*argv)
|
||||
seconds -= strtod(*argv, NULL);
|
||||
printf("%lf\n", seconds);
|
||||
}
|
||||
|
||||
int cmd__date(int argc, const char **argv)
|
||||
{
|
||||
struct timeval now;
|
||||
@@ -108,6 +118,8 @@ int cmd__date(int argc, const char **argv)
|
||||
parse_approxidate(argv+1, &now);
|
||||
else if (!strcmp(*argv, "timestamp"))
|
||||
parse_approx_timestamp(argv+1, &now);
|
||||
else if (!strcmp(*argv, "getnanos"))
|
||||
getnanos(argv+1, &now);
|
||||
else if (!strcmp(*argv, "is64bit"))
|
||||
return sizeof(timestamp_t) == 8 ? 0 : 1;
|
||||
else if (!strcmp(*argv, "time_t-is64bit"))
|
||||
|
||||
@@ -37,5 +37,4 @@ test_expect_success "fetch with $VERSION_B" '
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
stop_git_daemon
|
||||
test_done
|
||||
|
||||
@@ -10,7 +10,12 @@ GIT_TEXTDOMAINDIR="$GIT_BUILD_DIR/po/build/locale"
|
||||
GIT_PO_PATH="$GIT_BUILD_DIR/po"
|
||||
export GIT_TEXTDOMAINDIR GIT_PO_PATH
|
||||
|
||||
. "$GIT_BUILD_DIR"/git-sh-i18n
|
||||
if test -n "$GIT_TEST_INSTALLED"
|
||||
then
|
||||
. "$(git --exec-path)"/git-sh-i18n
|
||||
else
|
||||
. "$GIT_BUILD_DIR"/git-sh-i18n
|
||||
fi
|
||||
|
||||
if test_have_prereq GETTEXT && ! test_have_prereq GETTEXT_POISON
|
||||
then
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#
|
||||
# test_expect_success ...
|
||||
#
|
||||
# stop_git_daemon
|
||||
# test_done
|
||||
|
||||
test_tristate GIT_TEST_GIT_DAEMON
|
||||
@@ -43,7 +42,7 @@ start_git_daemon() {
|
||||
|
||||
mkdir -p "$GIT_DAEMON_DOCUMENT_ROOT_PATH"
|
||||
|
||||
trap 'code=$?; stop_git_daemon; (exit $code); die' EXIT
|
||||
test_atexit 'stop_git_daemon'
|
||||
|
||||
say >&3 "Starting git daemon ..."
|
||||
mkfifo git_daemon_output
|
||||
|
||||
@@ -74,15 +74,6 @@ cli="$TRASH_DIRECTORY/cli"
|
||||
git="$TRASH_DIRECTORY/git"
|
||||
pidfile="$TRASH_DIRECTORY/p4d.pid"
|
||||
|
||||
# Sometimes "prove" seems to hang on exit because p4d is still running
|
||||
cleanup () {
|
||||
if test -f "$pidfile"
|
||||
then
|
||||
kill -9 $(cat "$pidfile") 2>/dev/null && exit 255
|
||||
fi
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
# git p4 submit generates a temp file, which will
|
||||
# not get cleaned up if the submission fails. Don't
|
||||
# clutter up /tmp on the test machine.
|
||||
@@ -141,6 +132,7 @@ start_p4d () {
|
||||
# p4d failed to start
|
||||
return 1
|
||||
fi
|
||||
test_atexit kill_p4d
|
||||
|
||||
# build a p4 user so author@example.com has an entry
|
||||
p4_add_user author
|
||||
|
||||
@@ -134,6 +134,7 @@ check_sub_test_lib_test_err () {
|
||||
)
|
||||
}
|
||||
|
||||
cat >/dev/null <<\DDD
|
||||
test_expect_success 'pretend we have a fully passing test suite' "
|
||||
run_sub_test_lib_test full-pass '3 passing tests' <<-\\EOF &&
|
||||
for i in 1 2 3
|
||||
@@ -820,6 +821,25 @@ test_expect_success 'tests clean up even on failures' "
|
||||
> 1..2
|
||||
EOF
|
||||
"
|
||||
DDD
|
||||
|
||||
test_expect_success 'test_atexit is run' "
|
||||
test_must_fail run_sub_test_lib_test \
|
||||
atexit-cleanup 'Run atexit commands' -i <<-\\EOF &&
|
||||
test_expect_success 'tests clean up even after a failure' '
|
||||
> ../../clean-atexit &&
|
||||
test_atexit rm ../../clean-atexit &&
|
||||
> ../../also-clean-atexit &&
|
||||
test_atexit rm ../../also-clean-atexit &&
|
||||
> ../../dont-clean-atexit &&
|
||||
(exit 1)
|
||||
'
|
||||
test_done
|
||||
EOF
|
||||
test_path_exists dont-clean-atexit &&
|
||||
test_path_is_missing clean-atexit &&
|
||||
test_path_is_missing also-clean-atexit
|
||||
"
|
||||
|
||||
################################################################
|
||||
# Basics of the basics
|
||||
|
||||
@@ -453,6 +453,18 @@ test_expect_success 're-init from a linked worktree' '
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success MINGW 'core.hidedotfiles = false' '
|
||||
git config --global core.hidedotfiles false &&
|
||||
rm -rf newdir &&
|
||||
(
|
||||
sane_unset GIT_DIR GIT_WORK_TREE GIT_CONFIG &&
|
||||
mkdir newdir &&
|
||||
cd newdir &&
|
||||
git init
|
||||
) &&
|
||||
! is_hidden newdir/.git
|
||||
'
|
||||
|
||||
test_expect_success MINGW 'redirect std handles' '
|
||||
GIT_REDIRECT_STDOUT=output.txt git rev-parse --git-dir &&
|
||||
test .git = "$(cat output.txt)" &&
|
||||
|
||||
30
t/t0029-core-unsetenvvars.sh
Executable file
30
t/t0029-core-unsetenvvars.sh
Executable file
@@ -0,0 +1,30 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='test the Windows-only core.unsetenvvars setting'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
if ! test_have_prereq MINGW
|
||||
then
|
||||
skip_all='skipping Windows-specific tests'
|
||||
test_done
|
||||
fi
|
||||
|
||||
test_expect_success 'setup' '
|
||||
mkdir -p "$TRASH_DIRECTORY/.git/hooks" &&
|
||||
write_script "$TRASH_DIRECTORY/.git/hooks/pre-commit" <<-\EOF
|
||||
echo $HOBBES >&2
|
||||
EOF
|
||||
'
|
||||
|
||||
test_expect_success 'core.unsetenvvars works' '
|
||||
HOBBES=Calvin &&
|
||||
export HOBBES &&
|
||||
git commit --allow-empty -m with 2>err &&
|
||||
grep Calvin err &&
|
||||
git -c core.unsetenvvars=FINDUS,HOBBES,CALVIN \
|
||||
commit --allow-empty -m without 2>err &&
|
||||
! grep Calvin err
|
||||
'
|
||||
|
||||
test_done
|
||||
@@ -144,7 +144,8 @@ test_trace () {
|
||||
expect="$1"
|
||||
shift
|
||||
GIT_TRACE=1 test-tool run-command "$@" run-command true 2>&1 >/dev/null | \
|
||||
sed -e 's/.* run_command: //' -e '/trace: .*/d' >actual &&
|
||||
sed -e 's/.* run_command: //' -e '/trace: .*/d' \
|
||||
-e '/RUNTIME_PREFIX requested/d' >actual &&
|
||||
echo "$expect true" >expect &&
|
||||
test_cmp expect actual
|
||||
}
|
||||
@@ -177,4 +178,14 @@ test_expect_success 'GIT_TRACE with environment variables' '
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success MINGW 'verify curlies are quoted properly' '
|
||||
: force the rev-parse through the MSYS2 Bash &&
|
||||
git -c alias.r="!git rev-parse" r -- a{b}c >actual &&
|
||||
cat >expect <<-\EOF &&
|
||||
--
|
||||
a{b}c
|
||||
EOF
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -402,4 +402,11 @@ test_expect_success 'all statuses changed in folder if . is given' '
|
||||
test $(git ls-files --stage | grep ^100755 | wc -l) -eq 0
|
||||
'
|
||||
|
||||
test_expect_success MINGW 'path is case-insensitive' '
|
||||
path="$(pwd)/BLUB" &&
|
||||
touch "$path" &&
|
||||
downcased="$(echo "$path" | tr A-Z a-z)" &&
|
||||
git add "$downcased"
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
32
t/t5319-pack-large-objects.sh
Executable file
32
t/t5319-pack-large-objects.sh
Executable file
@@ -0,0 +1,32 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2018 Johannes Schindelin
|
||||
#
|
||||
|
||||
test_description='git pack-object with "large" deltas
|
||||
|
||||
'
|
||||
. ./test-lib.sh
|
||||
. "$TEST_DIRECTORY"/lib-pack.sh
|
||||
|
||||
# Two similar-ish objects that we have computed deltas between.
|
||||
A=01d7713666f4de822776c7622c10f1b07de280dc
|
||||
B=e68fe8129b546b101aee9510c5328e7f21ca1d18
|
||||
|
||||
test_expect_success 'setup' '
|
||||
clear_packs &&
|
||||
{
|
||||
pack_header 2 &&
|
||||
pack_obj $A $B &&
|
||||
pack_obj $B
|
||||
} >ab.pack &&
|
||||
pack_trailer ab.pack &&
|
||||
git index-pack --stdin <ab.pack
|
||||
'
|
||||
|
||||
test_expect_success 'repack large deltas' '
|
||||
printf "%s\\n" $A $B |
|
||||
GIT_TEST_OE_DELTA_SIZE=2 git pack-objects tmp-pack
|
||||
'
|
||||
|
||||
test_done
|
||||
@@ -695,13 +695,22 @@ do
|
||||
# file with scheme
|
||||
for p in file
|
||||
do
|
||||
test_expect_success "fetch-pack --diag-url $p://$h/$r" '
|
||||
test_expect_success !MINGW "fetch-pack --diag-url $p://$h/$r" '
|
||||
check_prot_path $p://$h/$r $p "/$r"
|
||||
'
|
||||
test_expect_success MINGW "fetch-pack --diag-url $p://$h/$r" '
|
||||
check_prot_path $p://$h/$r $p "//$h/$r"
|
||||
'
|
||||
test_expect_success MINGW "fetch-pack --diag-url $p:///$r" '
|
||||
check_prot_path $p:///$r $p "/$r"
|
||||
'
|
||||
# No "/~" -> "~" conversion for file
|
||||
test_expect_success "fetch-pack --diag-url $p://$h/~$r" '
|
||||
test_expect_success !MINGW "fetch-pack --diag-url $p://$h/~$r" '
|
||||
check_prot_path $p://$h/~$r $p "/~$r"
|
||||
'
|
||||
test_expect_success MINGW "fetch-pack --diag-url $p://$h/~$r" '
|
||||
check_prot_path $p://$h/~$r $p "//$h/~$r"
|
||||
'
|
||||
done
|
||||
# file without scheme
|
||||
for h in nohost nohost:12 [::1] [::1]:23 [ [:aa
|
||||
|
||||
@@ -211,5 +211,4 @@ test_expect_success FAKENC 'hostname interpolation works after LF-stripping' '
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
stop_git_daemon
|
||||
test_done
|
||||
|
||||
@@ -17,14 +17,11 @@ fi
|
||||
UNCPATH="$(winpwd)"
|
||||
case "$UNCPATH" in
|
||||
[A-Z]:*)
|
||||
WITHOUTDRIVE="${UNCPATH#?:}"
|
||||
# Use administrative share e.g. \\localhost\C$\git-sdk-64\usr\src\git
|
||||
# (we use forward slashes here because MSYS2 and Git accept them, and
|
||||
# they are easier on the eyes)
|
||||
UNCPATH="//localhost/${UNCPATH%%:*}\$/${UNCPATH#?:}"
|
||||
test -d "$UNCPATH" || {
|
||||
skip_all='could not access administrative share; skipping'
|
||||
test_done
|
||||
}
|
||||
UNCPATH="//localhost/${UNCPATH%%:*}\$$WITHOUTDRIVE"
|
||||
;;
|
||||
*)
|
||||
skip_all='skipping UNC path tests, cannot determine current path as UNC'
|
||||
@@ -32,6 +29,18 @@ case "$UNCPATH" in
|
||||
;;
|
||||
esac
|
||||
|
||||
test_expect_success 'clone into absolute path lacking a drive prefix' '
|
||||
USINGBACKSLASHES="$(echo "$WITHOUTDRIVE"/without-drive-prefix |
|
||||
tr / \\\\)" &&
|
||||
git clone . "$USINGBACKSLASHES" &&
|
||||
test -f without-drive-prefix/.git/HEAD
|
||||
'
|
||||
|
||||
test -d "$UNCPATH" || {
|
||||
skip_all='could not access administrative share; skipping'
|
||||
test_done
|
||||
}
|
||||
|
||||
test_expect_success setup '
|
||||
test_commit initial
|
||||
'
|
||||
@@ -40,6 +49,23 @@ test_expect_success clone '
|
||||
git clone "file://$UNCPATH" clone
|
||||
'
|
||||
|
||||
test_expect_success 'clone without file://' '
|
||||
git clone "$UNCPATH" clone-without-file
|
||||
'
|
||||
|
||||
test_expect_success 'clone with backslashed path' '
|
||||
BACKSLASHED="$(echo "$UNCPATH" | tr / \\\\)" &&
|
||||
git clone "$BACKSLASHED" backslashed
|
||||
'
|
||||
|
||||
test_expect_success fetch '
|
||||
git init to-fetch &&
|
||||
(
|
||||
cd to-fetch &&
|
||||
git fetch "$UNCPATH" master
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success push '
|
||||
(
|
||||
cd clone &&
|
||||
@@ -57,4 +83,16 @@ test_expect_success MINGW 'remote nick cannot contain backslashes' '
|
||||
test_i18ngrep ! "unable to access" err
|
||||
'
|
||||
|
||||
test_expect_success 'unc alternates' '
|
||||
tree="$(git rev-parse HEAD:)" &&
|
||||
mkdir test-unc-alternate &&
|
||||
(
|
||||
cd test-unc-alternate &&
|
||||
git init &&
|
||||
test_must_fail git show $tree &&
|
||||
echo "$UNCPATH/.git/objects" >.git/objects/info/alternates &&
|
||||
git show $tree
|
||||
)
|
||||
'
|
||||
|
||||
test_done
|
||||
@@ -71,4 +71,10 @@ test_expect_success 'prerequisites with an empty commit message' '
|
||||
git bundle verify bundle
|
||||
'
|
||||
|
||||
test_expect_success 'failed bundle creation does not leave cruft' '
|
||||
# This fails because the bundle would be empty.
|
||||
test_must_fail git bundle create fail.bundle master..master &&
|
||||
test_path_is_missing fail.bundle.lock
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -228,7 +228,7 @@ test_expect_success 'push update refs failure' '
|
||||
echo "update fail" >>file &&
|
||||
git commit -a -m "update fail" &&
|
||||
git rev-parse --verify testgit/origin/heads/update >expect &&
|
||||
test_expect_code 1 env GIT_REMOTE_TESTGIT_FAILURE="non-fast forward" \
|
||||
test_must_fail env GIT_REMOTE_TESTGIT_FAILURE="non-fast forward" \
|
||||
git push origin update &&
|
||||
git rev-parse --verify testgit/origin/heads/update >actual &&
|
||||
test_cmp expect actual
|
||||
|
||||
32
t/t7108-reset-stdin.sh
Executable file
32
t/t7108-reset-stdin.sh
Executable file
@@ -0,0 +1,32 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='reset --stdin'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success 'reset --stdin' '
|
||||
test_commit hello &&
|
||||
git rm hello.t &&
|
||||
test -z "$(git ls-files hello.t)" &&
|
||||
echo hello.t | git reset --stdin &&
|
||||
test hello.t = "$(git ls-files hello.t)"
|
||||
'
|
||||
|
||||
test_expect_success 'reset --stdin -z' '
|
||||
test_commit world &&
|
||||
git rm hello.t world.t &&
|
||||
test -z "$(git ls-files hello.t world.t)" &&
|
||||
printf world.tQworld.tQhello.tQ | q_to_nul | git reset --stdin -z &&
|
||||
printf "hello.t\nworld.t\n" >expect &&
|
||||
git ls-files >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success '--stdin requires --mixed' '
|
||||
echo hello.t >list &&
|
||||
test_must_fail git reset --soft --stdin <list &&
|
||||
test_must_fail git reset --hard --stdin <list &&
|
||||
git reset --mixed --stdin <list
|
||||
'
|
||||
|
||||
test_done
|
||||
@@ -332,7 +332,7 @@ test_expect_success 'difftool --extcmd cat arg1' '
|
||||
test_expect_success 'difftool --extcmd cat arg2' '
|
||||
echo branch >expect &&
|
||||
git difftool --no-prompt \
|
||||
--extcmd sh\ -c\ \"cat\ \$2\" branch >actual &&
|
||||
--extcmd sh\ -c\ \"cat\ \\\"\$2\\\"\" branch >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
|
||||
@@ -556,4 +556,15 @@ test_expect_success 'merge commit gets exported with --import-marks' '
|
||||
)
|
||||
'
|
||||
|
||||
cat > expected << EOF
|
||||
reset refs/heads/master
|
||||
from $(git rev-parse master)
|
||||
|
||||
EOF
|
||||
|
||||
test_expect_failure 'refs are updated even if no commits need to be exported' '
|
||||
git fast-export master..master > actual &&
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -326,8 +326,4 @@ test_expect_success 'submit from worktree' '
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'kill p4d' '
|
||||
kill_p4d
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -610,8 +610,4 @@ test_expect_success 'Update a file in git side and submit to P4 using client vie
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'kill p4d' '
|
||||
kill_p4d
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -333,8 +333,4 @@ test_expect_success SYMLINKS 'empty symlink target' '
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'kill p4d' '
|
||||
kill_p4d
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -105,8 +105,4 @@ test_expect_success 'branch with shell char' '
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'kill p4d' '
|
||||
kill_p4d
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -108,8 +108,4 @@ test_expect_failure 'two labels on the same changelist' '
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'kill p4d' '
|
||||
kill_p4d
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -98,8 +98,4 @@ test_expect_success 'no config, edited' '
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'kill p4d' '
|
||||
kill_p4d
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -300,9 +300,4 @@ test_expect_success 'use --git-dir option and GIT_DIR' '
|
||||
test_path_is_file "$git"/cli_file2.t
|
||||
'
|
||||
|
||||
|
||||
test_expect_success 'kill p4d' '
|
||||
kill_p4d
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -542,8 +542,4 @@ test_expect_success 'submit --update-shelve' '
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'kill p4d' '
|
||||
kill_p4d
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -83,8 +83,4 @@ test_expect_success SYMLINKS 'p4 client root symlink should stay symbolic' '
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'kill p4d' '
|
||||
kill_p4d
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -836,8 +836,4 @@ test_expect_success 'quotes on both sides' '
|
||||
git_verify "cdir 1/file11" "cdir 1/file12"
|
||||
'
|
||||
|
||||
test_expect_success 'kill p4d' '
|
||||
kill_p4d
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -360,8 +360,4 @@ test_expect_failure 'Add keywords in git which do not match the default p4 value
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'kill p4d' '
|
||||
kill_p4d
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -259,9 +259,4 @@ test_expect_success 'importing labels with missing revisions' '
|
||||
)
|
||||
'
|
||||
|
||||
|
||||
test_expect_success 'kill p4d' '
|
||||
kill_p4d
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -211,8 +211,4 @@ test_expect_success 'wildcard files requiring keyword scrub' '
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'kill p4d' '
|
||||
kill_p4d
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -138,8 +138,4 @@ test_expect_success 'not preserving user with mixed authorship' '
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'kill p4d' '
|
||||
kill_p4d
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -242,8 +242,4 @@ test_expect_success P4D_HAVE_CONFIGURABLE_RUN_MOVE_ALLOW \
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'kill p4d' '
|
||||
kill_p4d
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -422,8 +422,4 @@ test_expect_success 'cleanup chmod after submit cancel' '
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'kill p4d' '
|
||||
kill_p4d
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -138,8 +138,4 @@ test_expect_failure 'move with lock taken' '
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'kill p4d' '
|
||||
kill_p4d
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -64,8 +64,4 @@ test_expect_success 'clone, then sync with exclude' '
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'kill p4d' '
|
||||
kill_p4d
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -146,8 +146,4 @@ test_expect_success 'Clone repo with self-sizing block size' '
|
||||
test_line_count \> 10 log
|
||||
'
|
||||
|
||||
test_expect_success 'kill p4d' '
|
||||
kill_p4d
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -53,8 +53,4 @@ test_expect_failure 'Clone UC repo with lc name' '
|
||||
test_must_fail git p4 clone //depot/uc/...
|
||||
'
|
||||
|
||||
test_expect_success 'kill p4d' '
|
||||
kill_p4d
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -31,8 +31,4 @@ test_expect_success 'EDITOR with options' '
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'kill p4d' '
|
||||
kill_p4d
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -193,8 +193,4 @@ test_expect_success 'Add a new file and clone path with new file (ignorecase)' '
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'kill p4d' '
|
||||
kill_p4d
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -67,8 +67,4 @@ test_expect_success 'Delete iso8859-1 encoded paths and clone' '
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'kill p4d' '
|
||||
kill_p4d
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -185,8 +185,4 @@ test_expect_success 'Run git p4 submit in repo configured with large file system
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'kill p4d' '
|
||||
kill_p4d
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -287,8 +287,4 @@ test_expect_success 'Add big files to repo and store files in LFS based on compr
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'kill p4d' '
|
||||
kill_p4d
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -43,8 +43,4 @@ test_expect_failure 'clone depot with invalid UTF-16 file in non-verbose mode' '
|
||||
git p4 clone --dest="$git" //depot
|
||||
'
|
||||
|
||||
test_expect_success 'kill p4d' '
|
||||
kill_p4d
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -127,8 +127,4 @@ test_expect_success 'Clone repo subdir with all history' '
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'kill p4d' '
|
||||
kill_p4d
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -59,8 +59,4 @@ test_expect_success SYMLINKS 'change symbolic link to file' '
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'kill p4d' '
|
||||
kill_p4d
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -54,8 +54,4 @@ test_expect_success 'Clone repo root path with all history' '
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'kill p4d' '
|
||||
kill_p4d
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -92,8 +92,4 @@ test_expect_success 'check log message of changelist with more jobs' '
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'kill p4d' '
|
||||
kill_p4d
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -36,8 +36,4 @@ test_expect_success 'symlinked directory' '
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'kill p4d' '
|
||||
kill_p4d
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
@@ -96,8 +96,4 @@ test_expect_success 'submit description with extra info lines from verbose p4 ch
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'kill p4d' '
|
||||
kill_p4d
|
||||
'
|
||||
|
||||
test_done
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user