diff --git a/.gitignore b/.gitignore
index ff241d0cec571f..0ba169f30a5830 100644
--- a/.gitignore
+++ b/.gitignore
@@ -245,3 +245,4 @@ Release/
 *.dSYM
 /contrib/buildsystems/out
 CMakeSettings.json
+build*/
diff --git a/compat/vcbuild/vcpkg_install.bat b/compat/vcbuild/vcpkg_install.bat
index 575c65c20ba307..ac06d6ac012c3b 100644
--- a/compat/vcbuild/vcpkg_install.bat
+++ b/compat/vcbuild/vcpkg_install.bat
@@ -4,25 +4,26 @@ REM This script installs the "vcpkg" source package manager and uses
 REM it to build the third-party libraries that git requires when it
 REM is built using MSVC.
 REM
-REM [1] Install VCPKG.
-REM     [a] Create <root>/compat/vcbuild/vcpkg/
+REM [1] Install VCPKG (unless already exists.)
+REM     [a] Create %VCPKG_ROOT% defaulting to
+REM         <root>/compat/vcbuild/vcpkg/.
 REM     [b] Download "vcpkg".
 REM     [c] Compile using the currently installed version of VS.
-REM     [d] Create <root>/compat/vcbuild/vcpkg/vcpkg.exe
+REM     [d] Create %VCPKG_ROOT%/vcpkg.exe
 REM
-REM [2] Install third-party libraries.
+REM [2] Install third-party libraries (unless already installed.)
 REM     [a] Download each (which may also install CMAKE).
 REM     [b] Compile in RELEASE mode and install in:
-REM         vcpkg/installed/<arch>/{bin,lib}
+REM         %VCPKG_ROOT%/installed/<arch>/{bin,lib}
 REM     [c] Compile in DEBUG mode and install in:
-REM         vcpkg/installed/<arch>/debug/{bin,lib}
+REM         %VCPKG_ROOT%/installed/<arch>/debug/{bin,lib}
 REM     [d] Install headers in:
-REM         vcpkg/installed/<arch>/include
+REM         %VCPKG_ROOT%/installed/<arch>/include
 REM
 REM [3] Create a set of MAKE definitions for the top-level
 REM     Makefile to allow "make MSVC=1" to find the above
 REM     third-party libraries.
-REM     [a] Write vcpkg/VCPGK-DEFS
+REM     [a] Write %VCPKG_ROOT%/VCPGK-DEFS
 REM
 REM https://blogs.msdn.microsoft.com/vcblog/2016/09/19/vcpkg-a-tool-to-acquire-and-build-c-open-source-libraries-on-windows/
 REM https://github.com/Microsoft/vcpkg
@@ -33,45 +34,55 @@ REM ================================================================
 
 	SET arch=%1
 	IF NOT DEFINED arch (
-		echo defaulting to 'x64-windows`. Invoke %0 with 'x86-windows', 'x64-windows', or 'arm64-windows'
+		echo defaulting to 'x64-windows`. Invoke %0 with 'x86-windows', 'x64-windows', or 'arm64-windows', append '-static' for static builds. >&2
 		set arch=x64-windows
 	)
 
 	@FOR /F "delims=" %%D IN ("%~dp0") DO @SET cwd=%%~fD
 	cd %cwd%
 
-	dir vcpkg\vcpkg.exe >nul 2>nul && GOTO :install_libraries
+	IF NOT DEFINED VCPKG_ROOT (
+		set VCPKG_ROOT=%cwd%\vcpkg
+	) ELSE (IF NOT EXIST %VCPKG_ROOT%\..\ (
+		echo Invalid VCPKG_ROOT: %VCPKG_ROOT%, not under a valid directory. >&2
+		exit /B 1
+	))
+
+	IF EXIST %VCPKG_ROOT%\vcpkg.exe goto :install_libraries
 
 	git.exe version 2>nul
 	IF ERRORLEVEL 1 (
-	echo "***"
-	echo "Git not found. Please adjust your CMD path or Git install option."
-	echo "***"
-	EXIT /B 1 )
+		echo *** >&2
+		echo Git not found. Please adjust your CMD path or Git install option. >&2
+		echo *** >&2
+		EXIT /B 1
+	)
 
-	echo Fetching vcpkg in %cwd%vcpkg
-	git.exe clone https://github.com/Microsoft/vcpkg vcpkg
+	echo Fetching vcpkg in %VCPKG_ROOT%
+	git.exe clone https://github.com/Microsoft/vcpkg %VCPKG_ROOT%
 	IF ERRORLEVEL 1 ( EXIT /B 1 )
 
-	cd vcpkg
+	cd %VCPKG_ROOT%
 	echo Building vcpkg
 	powershell -exec bypass scripts\bootstrap.ps1
 	IF ERRORLEVEL 1 ( EXIT /B 1 )
 
-	echo Successfully installed %cwd%vcpkg\vcpkg.exe
+	echo Successfully installed %VCPKG_ROOT%\vcpkg.exe
 
 :install_libraries
 
-	echo Installing third-party libraries(%arch%)...
-	FOR %%i IN (zlib expat libiconv openssl libssh2 curl) DO (
-	    cd %cwd%vcpkg
-	    IF NOT EXIST "packages\%%i_%arch%" CALL :sub__install_one %%i
-	    IF ERRORLEVEL 1 ( EXIT /B 1 )
+	echo Installing third-party libraries(%arch%), this may take a while...
+	FOR %%i IN (zlib expat libiconv openssl libssh2 curl gettext) DO (
+	    IF NOT DEFINED NO_%%i (
+		cd %VCPKG_ROOT%
+		IF NOT EXIST "packages\%%i_%arch%" CALL :sub__install_one %%i
+		IF ERRORLEVEL 1 ( EXIT /B 1 )
+	    )
 	)
 
 :install_defines
 	cd %cwd%
-	SET inst=%cwd%vcpkg\installed\%arch%
+	SET inst=%VCPKG_ROOT%\installed\%arch%
 
 	echo vcpkg_inc=-I"%inst%\include">VCPKG-DEFS
 	echo vcpkg_rel_lib=-L"%inst%\lib">>VCPKG-DEFS
@@ -129,3 +140,7 @@ goto :EOF
 :curl_features
 set features=[core,openssl,schannel]
 goto :EOF
+
+:gettext_features
+set features=[tools]
+goto :EOF
diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt
index 8ee457258485b9..c0d0888f3e35d0 100644
--- a/contrib/buildsystems/CMakeLists.txt
+++ b/contrib/buildsystems/CMakeLists.txt
@@ -44,8 +44,19 @@ This process generates a Makefile(Linux/*BSD/MacOS), Visual Studio solution(Wind
 Run `make` to build Git on Linux/*BSD/MacOS.
 Open git.sln on Windows and build Git.
 
-NOTE: By default CMake will install vcpkg locally to your source tree on configuration,
-to avoid this, add `-DNO_VCPKG=TRUE` to the command line when configuring.
+NOTE: By default CMake will install vcpkg locally to your source
+tree on configuration, to avoid this, add `-DUSE_VCPKG=FALSE` to
+the command line when configuring.
+
+To use your own vcpkg clone, set the environment variable VCPKG_ROOT
+to the path or pass the path as `-DVCPKG_DIR=/your/clone/of/vcpkg`.
+
+To set the vcpkg arch (target triplet) pass `VCPKG_ARCH` or
+`VCPKG_TARGET_TRIPLET` e.g.: `-DVCPKG_ARCH=x64-windows`.
+
+By default for vcpkg, gettext is not built and translations do not
+work because gettext is a very long compile. To enable translations
+pass `-DNO_GETTEXT=FALSE`.
 
 The Visual Studio default generator changed in v16.6 from its Visual Studio
 implemenation to `Ninja` This required changes to many CMake scripts.
@@ -56,35 +67,57 @@ cmake_minimum_required(VERSION 3.14)
 #set the source directory to root of git
 set(CMAKE_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/../..)
 
+list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake)
+
+include(Utilities)
+
 option(USE_VCPKG "Whether or not to use vcpkg for obtaining dependencies.  Only applicable to Windows platforms" ON)
 if(NOT WIN32)
 	set(USE_VCPKG OFF CACHE BOOL FORCE)
 endif()
 
+set(gettext_default TRUE)
+
+# Turn off gettext by default when using vcpkg because it's a very
+# long compile.
+if(NOT USE_VCPKG)
+	set(gettext_default FALSE)
+endif()
+
+build_option(
+	NO_GETTEXT
+	BOOL "Set to TRUE/ON to disable internationalization support using gettext and building translations using msgfmt from gettext-tools."
+	${gettext_default}
+	ALIASES ENV{NO_GETTEXT}
+)
+
 if(NOT DEFINED CMAKE_EXPORT_COMPILE_COMMANDS)
 	set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)
 	message("settting CMAKE_EXPORT_COMPILE_COMMANDS: ${CMAKE_EXPORT_COMPILE_COMMANDS}")
 endif()
 
 if(USE_VCPKG)
-	set(VCPKG_DIR "${CMAKE_SOURCE_DIR}/compat/vcbuild/vcpkg")
-	message("WIN32: ${WIN32}") # show its underlying text values
-	message("VCPKG_DIR: ${VCPKG_DIR}")
-	message("VCPKG_ARCH: ${VCPKG_ARCH}") # maybe unset
-	message("MSVC: ${MSVC}")
-	message("CMAKE_GENERATOR: ${CMAKE_GENERATOR}")
-	message("CMAKE_CXX_COMPILER_ID: ${CMAKE_CXX_COMPILER_ID}")
-	message("CMAKE_GENERATOR_PLATFORM: ${CMAKE_GENERATOR_PLATFORM}")
-	message("CMAKE_EXPORT_COMPILE_COMMANDS: ${CMAKE_EXPORT_COMPILE_COMMANDS}")
-	message("ENV(CMAKE_EXPORT_COMPILE_COMMANDS): $ENV{CMAKE_EXPORT_COMPILE_COMMANDS}")
-	if(NOT EXISTS ${VCPKG_DIR})
-		message("Initializing vcpkg and building the Git's dependencies (this will take a while...)")
-		execute_process(COMMAND ${CMAKE_SOURCE_DIR}/compat/vcbuild/vcpkg_install.bat ${VCPKG_ARCH})
-	endif()
-	if(NOT EXISTS ${VCPKG_ARCH})
-		message("VCPKG_ARCH: unset, using 'x64-windows'")
-		set(VCPKG_ARCH "x64-windows") # default from vcpkg_install.bat
-	endif()
+	build_option(
+		VCPKG_DIR
+		PATH "Path to vcpkg clone."
+		"${CMAKE_SOURCE_DIR}/compat/vcbuild/vcpkg"
+		ALIASES ENV{VCPKG_ROOT}
+	)
+
+	build_option(
+		VCPKG_ARCH
+		STRING "vcpkg arch/triplet, e.g. x64-windows."
+		x64-windows
+		ALIASES VCPKG_TARGET_TRIPLET
+	)
+
+	message(STATUS "WIN32: ${WIN32}")
+	message(STATUS "VCPKG_DIR: ${VCPKG_DIR}")
+	message(STATUS "VCPKG_ARCH: ${VCPKG_ARCH}")
+	message(STATUS "CMAKE_GENERATOR: ${CMAKE_GENERATOR}")
+	message(STATUS "CMAKE_EXPORT_COMPILE_COMMANDS: ${CMAKE_EXPORT_COMPILE_COMMANDS}")
+	message(STATUS "ENV(CMAKE_EXPORT_COMPILE_COMMANDS): $ENV{CMAKE_EXPORT_COMPILE_COMMANDS}")
+	execute_process(COMMAND ${CMAKE_SOURCE_DIR}/compat/vcbuild/vcpkg_install.bat ${VCPKG_ARCH})
 	list(APPEND CMAKE_PREFIX_PATH "${VCPKG_DIR}/installed/${VCPKG_ARCH}")
 
 	# In the vcpkg edition, we need this to be able to link to libcurl
@@ -123,6 +156,14 @@ project(git
 	VERSION ${git_version}
 	LANGUAGES C)
 
+# Some diagnostic output about the detected toolchain, must be
+# below project() call.
+if(WIN32)
+	message(STATUS "MSVC: ${MSVC}")
+endif()
+message(STATUS "CMAKE_C_COMPILER_ID: ${CMAKE_C_COMPILER_ID}")
+message(STATUS "CMAKE_GENERATOR_PLATFORM: ${CMAKE_GENERATOR_PLATFORM}")
+
 
 #TODO gitk git-gui gitweb
 #TODO Enable NLS on windows natively
@@ -173,8 +214,7 @@ find_package(CURL)
 find_package(EXPAT)
 find_package(Iconv)
 
-#Don't use libintl on Windows Visual Studio and Clang builds
-if(NOT (WIN32 AND (CMAKE_C_COMPILER_ID STREQUAL "MSVC" OR CMAKE_C_COMPILER_ID STREQUAL "Clang")))
+if(NOT NO_GETTEXT)
 	find_package(Intl)
 endif()
 
@@ -207,18 +247,10 @@ if(WIN32 AND NOT MSVC)#not required for visual studio builds
 	endif()
 endif()
 
-if(NO_GETTEXT)
-	message(STATUS "msgfmt not used under NO_GETTEXT")
-else()
+if(NOT NO_GETTEXT)
 	find_program(MSGFMT_EXE msgfmt)
 	if(NOT MSGFMT_EXE)
-		if(USE_VCPKG)
-			set(MSGFMT_EXE ${CMAKE_SOURCE_DIR}/compat/vcbuild/vcpkg/downloads/tools/msys2/msys64/usr/bin/msgfmt.exe)
-		endif()
-		if(NOT EXISTS ${MSGFMT_EXE})
-			message(WARNING "Text Translations won't be built")
-			unset(MSGFMT_EXE)
-		endif()
+		message(WARNING "msgfmt not available and/or could not be installed, text translations won't be built.")
 	endif()
 endif()
 
@@ -813,7 +845,8 @@ endif()
 
 add_custom_command(OUTPUT ${git_links} ${git_http_links}
 		COMMAND ${CMAKE_COMMAND} -P ${CMAKE_BINARY_DIR}/CreateLinks.cmake
-		DEPENDS git git-remote-http)
+		DEPENDS git git-remote-http
+		WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
 add_custom_target(git-links ALL DEPENDS ${git_links} ${git_http_links})
 
 
@@ -1033,7 +1066,6 @@ set(NO_PYTHON )
 set(PAGER_ENV "LESS=FRX LV=-c")
 set(DC_SHA1 YesPlease)
 set(RUNTIME_PREFIX true)
-set(NO_GETTEXT )
 
 if(NOT CURL_FOUND)
 	set(NO_CURL 1)
@@ -1043,10 +1075,6 @@ if(NOT EXPAT_FOUND)
 	set(NO_EXPAT 1)
 endif()
 
-if(NOT Intl_FOUND)
-	set(NO_GETTEXT 1)
-endif()
-
 if(NOT PERL_TESTS)
 	set(NO_PERL 1)
 endif()
@@ -1074,7 +1102,7 @@ file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "RUNTIME_PREFIX='${RUNTIME_PRE
 file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "NO_PYTHON='${NO_PYTHON}'\n")
 file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "SUPPORTS_SIMPLE_IPC='${SUPPORTS_SIMPLE_IPC}'\n")
 if(USE_VCPKG)
-	file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "PATH=\"$PATH:$TEST_DIRECTORY/../compat/vcbuild/vcpkg/installed/${VCPKG_ARCH}/bin\"\n")
+	file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "PATH=\"$PATH:${VCPKG_DIR}/installed/${VCPKG_ARCH}/bin\"\n")
 endif()
 
 #Make the tests work when building out of the source tree
@@ -1106,3 +1134,5 @@ foreach(tsh ${test_scipts})
 endforeach()
 
 endif()#BUILD_TESTING
+
+# vim:set sw=8 ts=8 noet:
diff --git a/contrib/buildsystems/cmake/Utilities.cmake b/contrib/buildsystems/cmake/Utilities.cmake
new file mode 100644
index 00000000000000..f90019b7b20c52
--- /dev/null
+++ b/contrib/buildsystems/cmake/Utilities.cmake
@@ -0,0 +1,102 @@
+#
+# build_option(
+#	opt_name type help_string [default]
+#	ALIASES alias1 [alias2 ...]]
+# )
+#
+# If PRIMARY_OPT is not set, uses the value of any alias name
+# provided, in order of precedence provides, to set PRIMARY_OPT and
+# all listed aliases. Otherwise set all aliases to the value of
+# PRIMARY_OPT, or the default if not set either. If the default is
+# empty string or not provided, the value "OFF" is used, this is
+# the behavior of option() in cmake.
+#
+# An alias can be an environment variable, specify ENV{ENV_VAR} in
+# this case. If the type is BOOL and the found/default value is
+# OFF/FALSE the environment variable will be unset.
+#
+# On cmake >= 3.13 precedence is given to CACHE variables, and the
+# namesake normal variable is overwritten with the CACHE value. On
+# earlier versions, the cache variable will be overwritten with the
+# normal variable.
+#
+function(build_option opt type help_string default)
+	set(aliases "${ARGN}")
+
+	if(default STREQUAL ALIASES)
+		if(ARGC LESS 5)
+			message(FATAL_ERROR "build_option: ALIASES specified with no alias names.")
+		endif()
+
+		unset(default)
+	elseif(NOT ARGV4 STREQUAL ALIASES)
+		message(FATAL_ERROR "build_option: Syntax error.")
+	elseif(ARGC LESS 6)
+		message(FATAL_ERROR "build_option: ALIASES specified with no alias names.")
+	else()
+		list(REMOVE_AT aliases 0)
+	endif()
+
+	if(default STREQUAL "")
+		if(NOT type STREQUAL BOOL)
+			message(FATAL_ERROR "build_option: Empty or unspecified default options must be of type BOOL.")
+		endif()
+
+		set(default OFF)
+	endif()
+
+	# First find the first non-empty value in the option and
+	# aliases, with the priority being the order listed.
+	# If not found, use the default.
+	unset(val)
+
+	foreach(var IN LISTS opt aliases)
+		if(var STREQUAL "")
+			message(FATAL_ERROR "build_option: Option or alias names cannot be empty string.")
+		endif()
+
+		set(env_var "")
+		if(var MATCHES "^ENV\\{")
+			string(
+				REGEX REPLACE "^ENV\\{([^}]+)}$"
+				"\\1" env_var "${var}"
+			)
+		endif()
+
+		if(NOT env_var STREQUAL "")
+			set(val "$ENV{${env_var}}")
+		else()
+			if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.13)
+				set(val "$CACHE{${var}}")
+			endif()
+
+			if(val STREQUAL "")
+				set(val "${${var}}")
+			endif()
+		endif()
+
+		if(NOT val STREQUAL "")
+			break()
+		endif()
+	endforeach()
+
+	if(val STREQUAL "")
+		set(val "${default}")
+	endif()
+
+	foreach(var IN LISTS opt aliases)
+		if(var MATCHES "^ENV\\{")
+			# Unset env var for bool OFF/FALSE.
+			if(type STREQUAL BOOL AND NOT val)
+				unset("${var}")
+			else()
+				set("${var}" "${val}")
+			endif()
+		else()
+			set("${var}" "${val}" PARENT_SCOPE)
+			set("${var}" "${val}" CACHE "${type}" "${help_string}" FORCE)
+		endif()
+	endforeach()
+endfunction()
+
+# vim:set sw=8 ts=8 noet: