diff --git a/.gitignore b/.gitignore
index 10c273c2bc..2093b0809b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -39,6 +39,7 @@ edit-git-bash.exe
/msi/obj/
/msi/package-versions.txt
/msi/wix40-binaries.zip
+/msix/root/
/nuget/GitForWindows.nuspec
/nuget/Git-Windows-Minimal.nuspec
/nuget/Git-Windows-Minimal.nuspec.unmoved
diff --git a/msix/appxmanifest.xml.in b/msix/appxmanifest.xml.in
new file mode 100644
index 0000000000..c86012ed28
--- /dev/null
+++ b/msix/appxmanifest.xml.in
@@ -0,0 +1,161 @@
+
+
+
+
+
+
+ Git for Windows
+ The Git Development Community
+ Assets\StoreLogo.png
+ Git for Windows focuses on offering a lightweight, native set of tools that bring the full feature set of the Git to Windows while providing appropriate user interfaces for experienced users.
+ disabled
+ disabled
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/msix/release.sh b/msix/release.sh
new file mode 100644
index 0000000000..6f7cd257ee
--- /dev/null
+++ b/msix/release.sh
@@ -0,0 +1,110 @@
+#!/bin/sh
+
+# Build the MSIX package for Git for Windows.
+
+. "$(dirname "$0")/../release-common.sh"
+
+case "$MSYSTEM" in
+MINGW32) ARTIFACT_SUFFIX="x86";;
+MINGW64) ARTIFACT_SUFFIX="x64";;
+CLANGARM64) ARTIFACT_SUFFIX=arm64;;
+esac
+
+# MSIX requires version in X.X.X.X format (numeric only)
+# Convert Git for Windows versions like "2.47.1.windows.1" to "2.47.1.1"
+# and test versions like "0-test" to "0.0.0.0"
+MSIX_VERSION="$(echo "$VERSION" | sed -e 's/\.windows\./\./' -e 's/[^0-9.]//g')"
+# Ensure we have exactly 4 numeric segments
+while test "$(echo "$MSIX_VERSION" | tr -cd '.' | wc -c)" -lt 3
+do
+ MSIX_VERSION="$MSIX_VERSION.0"
+done
+
+TARGET="$output_directory"/Git.GitforWindows_"$VERSION"_"$ARTIFACT_SUFFIX".msix
+
+# Generate MSIX asset images from SVG
+ASSETS_DIR="$SCRIPT_PATH/Assets"
+mkdir -p "$ASSETS_DIR" ||
+die "Could not create Assets directory"
+
+type rsvg-convert ||
+case "$ARCH" in
+i686) pacman -Sy --noconfirm mingw-w64-i686-librsvg;;
+x86_64) pacman -Sy --noconfirm mingw-w64-x86_64-librsvg;;
+aarch64) pacman -Sy --noconfirm mingw-w64-clang-aarch64-librsvg;;
+esac ||
+die "Could not install librsvg"
+
+SVG_SOURCE="$SCRIPT_PATH/../git-for-windows.svg"
+for spec in \
+ LockScreenLogo.png:24 \
+ LockScreenLogo.scale-200.png:48 \
+ Square150x150Logo.png:150 \
+ Square150x150Logo.scale-200.png:300 \
+ Square44x44Logo.png:44 \
+ Square44x44Logo.scale-200.png:88 \
+ Square44x44Logo.targetsize-24_altform-unplated.png:24 \
+ StoreLogo.png:50
+do
+ name="${spec%%:*}"
+ size="${spec##*:}"
+ rsvg-convert -w "$size" -h "$size" "$SVG_SOURCE" \
+ -o "$ASSETS_DIR/$name" ||
+ die "Could not generate $name"
+done
+
+prepare_root
+
+init_etc_gitconfig
+generate_file_list "$@"
+copy_dlls_to_libexec
+unpack_pdbs
+
+# Find makeappx.exe from the Windows SDK
+MAKEAPPX=
+for sdk_dir in "/c/Program Files (x86)/Windows Kits/10/bin"/*/
+do
+ case "$ARCH" in
+ x86_64) sdk_arch=x64;;
+ i686) sdk_arch=x86;;
+ aarch64) sdk_arch=arm64;;
+ esac
+ if test -f "$sdk_dir$sdk_arch/makeappx.exe"
+ then
+ MAKEAPPX="$sdk_dir$sdk_arch/makeappx.exe"
+ fi
+done
+test -n "$MAKEAPPX" ||
+die "Could not find makeappx.exe in the Windows SDK"
+
+# Create MSIX
+
+MAPFILE=$SCRIPT_PATH/root/files.map
+MANIFESTIN=$SCRIPT_PATH/appxmanifest.xml.in
+MANIFESTOUT=$SCRIPT_PATH/root/appxmanifest.xml
+
+echo "Create MSIX"
+
+sed -e "s/@@VERSION@@/$MSIX_VERSION/g" <"$MANIFESTIN" >"$MANIFESTOUT"
+
+echo "[Files]" >"$MAPFILE" &&
+echo "\"$(cygpath -aw "$SCRIPT_PATH")/root/appxmanifest.xml\" \"AppxManifest.xml\"" >>"$MAPFILE" &&
+echo "\"$(cygpath -aw "$SCRIPT_PATH")/root/bin/git.exe\" \"bin/git.exe\"" >>"$MAPFILE" &&
+echo "\"$(cygpath -aw "$SCRIPT_PATH")/root/bin/sh.exe\" \"bin/sh.exe\"" >>"$MAPFILE" &&
+echo "\"$(cygpath -aw "$SCRIPT_PATH")/root/bin/bash.exe\" \"bin/bash.exe\"" >>"$MAPFILE" &&
+echo "\"$(cygpath -aw "$SCRIPT_PATH")/Assets/LockScreenLogo.png\" \"Assets/LockScreenLogo.png\"" >>"$MAPFILE" &&
+echo "\"$(cygpath -aw "$SCRIPT_PATH")/Assets/LockScreenLogo.scale-200.png\" \"Assets/LockScreenLogo.scale-200.png\"" >>"$MAPFILE" &&
+echo "\"$(cygpath -aw "$SCRIPT_PATH")/Assets/Square150x150Logo.png\" \"Assets/Square150x150Logo.png\"" >>"$MAPFILE" &&
+echo "\"$(cygpath -aw "$SCRIPT_PATH")/Assets/Square150x150Logo.scale-200.png\" \"Assets/Square150x150Logo.scale-200.png\"" >>"$MAPFILE" &&
+echo "\"$(cygpath -aw "$SCRIPT_PATH")/Assets/Square44x44Logo.png\" \"Assets/Square44x44Logo.png\"" >>"$MAPFILE" &&
+echo "\"$(cygpath -aw "$SCRIPT_PATH")/Assets/Square44x44Logo.scale-200.png\" \"Assets/Square44x44Logo.scale-200.png\"" >>"$MAPFILE" &&
+echo "\"$(cygpath -aw "$SCRIPT_PATH")/Assets/Square44x44Logo.targetsize-24_altform-unplated.png\" \"Assets/Square44x44Logo.targetsize-24_altform-unplated.png\"" >>"$MAPFILE" &&
+echo "\"$(cygpath -aw "$SCRIPT_PATH")/Assets/StoreLogo.png\" \"Assets/StoreLogo.png\"" >>"$MAPFILE" &&
+MSYS_ROOT="$(cygpath -aw /)" &&
+echo "$LIST" | while IFS= read -r entry; do
+ winpath="${entry//\//\\}"
+ echo "\"$MSYS_ROOT\\$winpath\" \"$winpath\""
+done >>"$MAPFILE"
+
+MSYS_NO_PATHCONV=1 "$MAKEAPPX" pack /v /o /f "$(cygpath -aw "$MAPFILE")" /p "$(cygpath -aw "$TARGET")" &&
+echo "Package created at $TARGET"
\ No newline at end of file
diff --git a/portable/release.sh b/portable/release.sh
index 0b0248fa81..af91adcbe7 100755
--- a/portable/release.sh
+++ b/portable/release.sh
@@ -2,156 +2,27 @@
# Build the portable Git for Windows.
-die () {
- echo "$*" >&1
- exit 1
-}
-
-output_directory="$HOME"
-include_pdbs=
-while test $# -gt 0
-do
- case "$1" in
- --output)
- shift
- output_directory="$1"
- ;;
- --output=*)
- output_directory="${1#*=}"
- ;;
- --include-pdbs)
- include_pdbs=t
- ;;
- -*)
- die "Unknown option: $1"
- ;;
- *)
- break
- esac
- shift
-done
-
-test $# -gt 0 ||
-die "Usage: $0 [--output=] [optional components]"
-
-test -d "$output_directory" ||
-die "Directory inaccessible: '$output_directory'"
+. "$(dirname "$0")/../release-common.sh"
case "$MSYSTEM" in
-MINGW32)
- BITNESS=32
- ARCH=i686
- ARTIFACT_SUFFIX="32-bit"
- MD_ARG=128M
- MINGW_PREFIX=mingw-w64-i686-
- ;;
-MINGW64)
- BITNESS=64
- ARCH=x86_64
- ARTIFACT_SUFFIX="64-bit"
- MD_ARG=256M
- MINGW_PREFIX=mingw-w64-x86_64-
- ;;
-CLANGARM64)
- BITNESS=64
- ARCH=aarch64
- ARTIFACT_SUFFIX=arm64
- MD_ARG=256M
- MINGW_PREFIX=mingw-w64-clang-aarch64-
- ;;
-*)
- die "Unhandled MSYSTEM: $MSYSTEM"
- ;;
+MINGW32) ARTIFACT_SUFFIX="32-bit";;
+MINGW64) ARTIFACT_SUFFIX="64-bit";;
+CLANGARM64) ARTIFACT_SUFFIX=arm64;;
esac
-MSYSTEM_LOWER=${MSYSTEM,,}
-VERSION=$1
-shift
+
TARGET="$output_directory"/PortableGit-"$VERSION"-"$ARTIFACT_SUFFIX".7z.exe
OPTS7="-m0=lzma -mqs -mlc=8 -mx=9 -md=$MD_ARG -mfb=273 -ms=256M "
TMPPACK=/tmp.7z
-SCRIPT_PATH="$(cd "$(dirname "$0")" && pwd)"
-
-case "$SCRIPT_PATH" in
-*" "*)
- die "This script cannot handle spaces in $SCRIPT_PATH"
- ;;
-esac
-
-
-# Generate a couple of files dynamically
-
-cp "$SCRIPT_PATH/../LICENSE.txt" "$SCRIPT_PATH/root/" ||
-die "Could not copy license file"
-
-mkdir -p "$SCRIPT_PATH/root/dev/mqueue" ||
-die "Could not make /dev/mqueue directory"
-
-mkdir -p "$SCRIPT_PATH/root/dev/shm" ||
-die "Could not make /dev/shm/ directory"
-mkdir -p "$SCRIPT_PATH/root/etc" ||
-die "Could not make etc/ directory"
-
-mkdir -p "$SCRIPT_PATH/root/tmp" ||
-die "Could not make tmp/ directory"
-
-mkdir -p "$SCRIPT_PATH/root/bin" ||
-die "Could not make bin/ directory"
-
-cp /cmd/git.exe "$SCRIPT_PATH/root/bin/git.exe" &&
-cp /$MSYSTEM_LOWER/share/git/compat-bash.exe "$SCRIPT_PATH/root/bin/bash.exe" &&
-cp /$MSYSTEM_LOWER/share/git/compat-bash.exe "$SCRIPT_PATH/root/bin/sh.exe" ||
-die "Could not install bin/ redirectors"
+prepare_root
cp "$SCRIPT_PATH/../post-install.bat" "$SCRIPT_PATH/root/" ||
die "Could not copy post-install script"
-etc_gitconfig="$(git -c core.editor=echo config --system -e 2>/dev/null)" &&
-etc_gitconfig="$(cygpath -au "$etc_gitconfig")" &&
-etc_gitconfig="${etc_gitconfig#/}" ||
-die "Could not determine the path of the system config"
-
-# Make a list of files to include
-LIST="$(ARCH=$ARCH ETC_GITCONFIG="$etc_gitconfig" \
- PACKAGE_VERSIONS_FILE="$SCRIPT_PATH"/root/etc/package-versions.txt \
- sh "$SCRIPT_PATH"/../make-file-list.sh "$@" |
- grep -v "^$etc_gitconfig$")" ||
-die "Could not generate file list"
-
-mkdir -p "$SCRIPT_PATH/root/${etc_gitconfig%/*}" &&
-cp /"$etc_gitconfig" "$SCRIPT_PATH/root/$etc_gitconfig" &&
-git config -f "$SCRIPT_PATH/root/$etc_gitconfig" \
- credential.helper manager ||
-die "Could not configure Git-Credential-Manager as default"
-test 64 != $BITNESS ||
-git config -f "$SCRIPT_PATH/root/$etc_gitconfig" --unset pack.packSizeLimit
-git config -f "$SCRIPT_PATH/root/$etc_gitconfig" core.fscache true
-
-case "$LIST" in
-*/git-credential-helper-selector.exe*)
- git config -f "$SCRIPT_PATH/root/$etc_gitconfig" \
- credential.helper helper-selector
- ;;
-esac
-
-git_core="$SCRIPT_PATH/root/$MSYSTEM_LOWER/libexec/git-core" &&
-rm -rf "$git_core" &&
-mkdir -p "$git_core" &&
-if test "$(stat -c %D /$MSYSTEM_LOWER/bin)" = "$(stat -c %D "$git_core")"
-then
- ln_or_cp=ln
-else
- ln_or_cp=cp
-fi &&
-$ln_or_cp $(echo "$LIST" | sed -n "s|^$MSYSTEM_LOWER/bin/[^/]*\.dll$|/&|p") "$git_core" ||
-die "Could not copy .dll files into libexec/git-core/"
-
-test -z "$include_pdbs" || {
- find "$SCRIPT_PATH/root" -name \*.pdb -exec rm {} \; &&
- "$SCRIPT_PATH"/../please.sh bundle-pdbs \
- --arch=$ARCH --unpack="$SCRIPT_PATH"/root
-} ||
-die "Could not unpack .pdb files"
+init_etc_gitconfig
+generate_file_list "$@"
+copy_dlls_to_libexec
+unpack_pdbs
TITLE="$BITNESS-bit"
test $ARCH == "aarch64" && TITLE="ARM64"
diff --git a/release-common.sh b/release-common.sh
new file mode 100644
index 0000000000..75a5772601
--- /dev/null
+++ b/release-common.sh
@@ -0,0 +1,171 @@
+# Common helpers for release scripts.
+# Source this file; it consumes the shared command-line flags and
+# leaves the remaining positional parameters (optional components) in "$@".
+#
+# After sourcing, the following variables are set:
+# output_directory, include_pdbs, VERSION,
+# BITNESS, ARCH, MD_ARG, MINGW_PREFIX, MSYSTEM_LOWER, SCRIPT_PATH
+#
+# The following functions are available:
+# die, prepare_root, init_etc_gitconfig,
+# generate_file_list, copy_dlls_to_libexec, unpack_pdbs
+
+die () {
+ echo "$*" >&1
+ exit 1
+}
+
+output_directory="$HOME"
+include_pdbs=
+while test $# -gt 0
+do
+ case "$1" in
+ --output)
+ shift
+ output_directory="$1"
+ ;;
+ --output=*)
+ output_directory="${1#*=}"
+ ;;
+ --include-pdbs)
+ include_pdbs=t
+ ;;
+ -*)
+ die "Unknown option: $1"
+ ;;
+ *)
+ break
+ esac
+ shift
+done
+
+test $# -gt 0 ||
+die "Usage: $0 [--output=] [optional components]"
+
+test -d "$output_directory" ||
+die "Directory inaccessible: '$output_directory'"
+
+case "$MSYSTEM" in
+MINGW32)
+ BITNESS=32
+ ARCH=i686
+ MD_ARG=128M
+ MINGW_PREFIX=mingw-w64-i686-
+ ;;
+MINGW64)
+ BITNESS=64
+ ARCH=x86_64
+ MD_ARG=256M
+ MINGW_PREFIX=mingw-w64-x86_64-
+ ;;
+CLANGARM64)
+ BITNESS=64
+ ARCH=aarch64
+ MD_ARG=256M
+ MINGW_PREFIX=mingw-w64-clang-aarch64-
+ ;;
+*)
+ die "Unhandled MSYSTEM: $MSYSTEM"
+ ;;
+esac
+MSYSTEM_LOWER=${MSYSTEM,,}
+VERSION=$1
+shift
+
+SCRIPT_PATH="$(cd "$(dirname "$0")" && pwd)"
+
+case "$SCRIPT_PATH" in
+*" "*)
+ die "This script cannot handle spaces in $SCRIPT_PATH"
+ ;;
+esac
+
+# Set up the root directory with common files and redirectors.
+prepare_root () {
+ mkdir -p "$SCRIPT_PATH/root/" ||
+ die "Could not make root"
+
+ cp "$SCRIPT_PATH/../LICENSE.txt" "$SCRIPT_PATH/root/" ||
+ die "Could not copy license file"
+
+ mkdir -p "$SCRIPT_PATH/root/dev/mqueue" ||
+ die "Could not make /dev/mqueue directory"
+
+ mkdir -p "$SCRIPT_PATH/root/dev/shm" ||
+ die "Could not make /dev/shm/ directory"
+
+ mkdir -p "$SCRIPT_PATH/root/etc" ||
+ die "Could not make etc/ directory"
+
+ mkdir -p "$SCRIPT_PATH/root/tmp" ||
+ die "Could not make tmp/ directory"
+
+ mkdir -p "$SCRIPT_PATH/root/bin" ||
+ die "Could not make bin/ directory"
+
+ cp /cmd/git.exe "$SCRIPT_PATH/root/bin/git.exe" &&
+ cp /$MSYSTEM_LOWER/share/git/compat-bash.exe "$SCRIPT_PATH/root/bin/bash.exe" &&
+ cp /$MSYSTEM_LOWER/share/git/compat-bash.exe "$SCRIPT_PATH/root/bin/sh.exe" ||
+ die "Could not install bin/ redirectors"
+}
+
+# Detect the system gitconfig path.
+# Sets: etc_gitconfig
+init_etc_gitconfig () {
+ etc_gitconfig="$(git -c core.editor=echo config --system -e 2>/dev/null)" &&
+ etc_gitconfig="$(cygpath -au "$etc_gitconfig")" &&
+ etc_gitconfig="${etc_gitconfig#/}" ||
+ die "Could not determine the path of the system config"
+}
+
+# Generate the file list and configure the system gitconfig.
+# Pass any optional components as arguments.
+# Sets: LIST
+generate_file_list () {
+ LIST="$(ARCH=$ARCH ETC_GITCONFIG="$etc_gitconfig" \
+ PACKAGE_VERSIONS_FILE="$SCRIPT_PATH"/root/etc/package-versions.txt \
+ sh "$SCRIPT_PATH"/../make-file-list.sh "$@" |
+ grep -v "^$etc_gitconfig$")" ||
+ die "Could not generate file list"
+
+ mkdir -p "$SCRIPT_PATH/root/${etc_gitconfig%/*}" &&
+ cp /"$etc_gitconfig" "$SCRIPT_PATH/root/$etc_gitconfig" &&
+ git config -f "$SCRIPT_PATH/root/$etc_gitconfig" \
+ credential.helper manager ||
+ die "Could not configure Git-Credential-Manager as default"
+ test 64 != $BITNESS ||
+ git config -f "$SCRIPT_PATH/root/$etc_gitconfig" --unset pack.packSizeLimit
+ git config -f "$SCRIPT_PATH/root/$etc_gitconfig" core.fscache true
+
+ case "$LIST" in
+ */git-credential-helper-selector.exe*)
+ git config -f "$SCRIPT_PATH/root/$etc_gitconfig" \
+ credential.helper helper-selector
+ ;;
+ esac
+}
+
+# Copy DLL files into libexec/git-core for runtime.
+copy_dlls_to_libexec () {
+ git_core="$SCRIPT_PATH/root/$MSYSTEM_LOWER/libexec/git-core" &&
+ rm -rf "$git_core" &&
+ mkdir -p "$git_core" &&
+ if test "$(stat -c %D /$MSYSTEM_LOWER/bin)" = "$(stat -c %D "$git_core")"
+ then
+ ln_or_cp=ln
+ else
+ ln_or_cp=cp
+ fi &&
+ $ln_or_cp $(echo "$LIST" | sed -n "s|^$MSYSTEM_LOWER/bin/[^/]*\.dll$|/&|p") "$git_core" ||
+ die "Could not copy .dll files into libexec/git-core/"
+}
+
+# Unpack PDB files if --include-pdbs was given.
+unpack_pdbs () {
+ test -z "$include_pdbs" || {
+ find "$SCRIPT_PATH/root" -name \*.pdb -exec rm {} \; &&
+ "$SCRIPT_PATH"/../please.sh bundle-pdbs \
+ --arch=$ARCH --unpack="$SCRIPT_PATH"/root
+ } ||
+ die "Could not unpack .pdb files"
+}