diff --git a/.github/scripts/sign-debian-packages.py b/.github/scripts/sign-debian-packages.py new file mode 100644 index 00000000000000..2bdc86650d4e5c --- /dev/null +++ b/.github/scripts/sign-debian-packages.py @@ -0,0 +1,117 @@ +import json +import os +import glob +import pprint +import subprocess +import sys + +esrp_tool = os.path.join("esrp", "tools", "EsrpClient.exe") + +AAD_ID = "38aa33bc-a7e7-4007-bfb2-e8b17f04aadc" +WORKSPACE = os.environ['GITHUB_WORKSPACE'].strip() +ARTIFACTS_DIR = os.environ['ARTIFACTS_DIR'].strip() + +def main(): + source_root_location = os.path.join(WORKSPACE, ARTIFACTS_DIR, "unsigned") + destination_location = os.path.join(WORKSPACE, ARTIFACTS_DIR) + + files = glob.glob(os.path.join(source_root_location, "*.deb")) + + print("Found files:") + pprint.pp(files) + + if len(files) < 1 or not files[0].endswith(".deb"): + print("Error: cannot find .deb to sign") + exit(1) + + file_to_sign = os.path.basename(files[0]) + + auth_json = { + "Version": "1.0.0", + "AuthenticationType": "AAD_CERT", + "TenantId": "72f988bf-86f1-41af-91ab-2d7cd011db47", + "ClientId": AAD_ID, + "AuthCert": { + "SubjectName": f"CN={AAD_ID}.microsoft.com", + "StoreLocation": "LocalMachine", + "StoreName": "My", + }, + "RequestSigningCert": { + "SubjectName": f"CN={AAD_ID}", + "StoreLocation": "LocalMachine", + "StoreName": "My", + } + } + + input_json = { + "Version": "1.0.0", + "SignBatches": [ + { + "SourceLocationType": "UNC", + "SourceRootDirectory": source_root_location, + "DestinationLocationType": "UNC", + "DestinationRootDirectory": destination_location, + "SignRequestFiles": [ + { + "CustomerCorrelationId": "01A7F55F-6CDD-4123-B255-77E6F212CDAD", + "SourceLocation": file_to_sign, + "DestinationLocation": os.path.join("signed", file_to_sign), + } + ], + "SigningInfo": { + "Operations": [ + { + "KeyCode": "CP-450779-Pgp", + "OperationCode": "LinuxSign", + "Parameters": {}, + "ToolName": "sign", + "ToolVersion": "1.0", + } + ] + } + } + ] + } + + policy_json = { + "Version": "1.0.0", + "Intent": "production release", + "ContentType": "Debian package", + } + + configs = [ + ("auth.json", auth_json), + ("input.json", input_json), + ("policy.json", policy_json), + ] + + for filename, data in configs: + with open(filename, 'w') as fp: + json.dump(data, fp) + + # Run ESRP Client + esrp_out = "esrp_out.json" + result = subprocess.run( + [esrp_tool, "sign", + "-a", "auth.json", + "-i", "input.json", + "-p", "policy.json", + "-o", esrp_out, + "-l", "Verbose"], + cwd=WORKSPACE) + + if result.returncode != 0: + print("Failed to run ESRPClient.exe") + sys.exit(1) + + if os.path.isfile(esrp_out): + print("ESRP output json:") + with open(esrp_out, 'r') as fp: + pprint.pp(json.load(fp)) + + signed_file = os.path.join(destination_location, "signed", file_to_sign) + if os.path.isfile(signed_file): + print(f"Success!\nSigned {signed_file}") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/.github/workflows/build-git-installers.yml b/.github/workflows/build-git-installers.yml new file mode 100644 index 00000000000000..8b538bba590747 --- /dev/null +++ b/.github/workflows/build-git-installers.yml @@ -0,0 +1,505 @@ +name: build-git-installers + +on: + push: + tags: + - 'v[0-9]*vfs*' # matches "vvfs" + +env: + INCLUDE_SCALAR: 1 + +jobs: + # Check prerequisites for the workflow + prereqs: + runs-on: ubuntu-latest + env: + AZ_SUB: ${{ secrets.AZURE_SUBSCRIPTION }} + AZ_CREDS: ${{ secrets.AZURE_CREDENTIALS }} + outputs: + tag_name: ${{ steps.tag.outputs.name }} # The full name of the tag, e.g. v2.32.0.vfs.0.0 + tag_version: ${{ steps.tag.outputs.version }} # The version number (without preceding "v"), e.g. 2.32.0.vfs.0.0 + deb_signable: ${{ steps.deb.outputs.signable }} # Whether the credentials needed to sign the .deb package are available + steps: + - name: Determine tag to build + run: | + echo "::set-output name=name::${GITHUB_REF#refs/tags/}" + echo "::set-output name=version::${GITHUB_REF#refs/tags/v}" + id: tag + - name: Determine whether signing certificates are present + run: echo "::set-output name=signable::$([[ $AZ_SUB != '' && $AZ_CREDS != '' ]] && echo 'true' || echo 'false')" + id: deb + - name: Clone git + uses: actions/checkout@v2 + - name: Validate the tag identified with trigger + run: | + die () { + echo "::error::$*" >&2 + exit 1 + } + + # `actions/checkout` only downloads the peeled tag (i.e. the commit) + git fetch origin +$GITHUB_REF:$GITHUB_REF + + # Verify that the tag is annotated + test $(git cat-file -t "$GITHUB_REF") == "tag" || die "Tag ${{ steps.tag.outputs.name }} is not annotated" + + # Verify tag follows rules in GIT-VERSION-GEN (i.e., matches the specified "DEF_VER" in + # GIT-VERSION-FILE) and matches tag determined from trigger + make GIT-VERSION-FILE + test "${{ steps.tag.outputs.version }}" == "$(sed -n 's/^GIT_VERSION = //p'< GIT-VERSION-FILE)" || die "GIT-VERSION-FILE tag does not match ${{ steps.tag.outputs.name }}" + # End check prerequisites for the workflow + + # Build Windows installers (x86_64 installer & portable) + windows_pkg: + runs-on: windows-latest + needs: prereqs + env: + GPG_OPTIONS: "--batch --yes --no-tty --list-options no-show-photos --verify-options no-show-photos --pinentry-mode loopback" + HOME: "${{github.workspace}}\\home" + USERPROFILE: "${{github.workspace}}\\home" + steps: + - name: Configure user + shell: bash + run: + USER_NAME="${{github.actor}}" && + USER_EMAIL="${{github.actor}}@users.noreply.github.com" && + mkdir -p "$HOME" && + git config --global user.name "$USER_NAME" && + git config --global user.email "$USER_EMAIL" && + echo "PACKAGER=$USER_NAME <$USER_EMAIL>" >>$GITHUB_ENV + - uses: git-for-windows/setup-git-for-windows-sdk@v1 + with: + flavor: build-installers + - name: Clone build-extra + shell: bash + run: | + git clone --single-branch -b main https://github.com/git-for-windows/build-extra /usr/src/build-extra + - name: Clone git + shell: bash + run: | + # Since we cannot directly clone a specified tag (as we would a branch with `git clone -b `), + # this clone has to be done manually (via init->fetch->reset). + + tag_name="${{ needs.prereqs.outputs.tag_name }}" && + git -c init.defaultBranch=main init && + git remote add -f origin https://github.com/git-for-windows/git && + git fetch "https://github.com/${{github.repository}}" refs/tags/${tag_name}:refs/tags/${tag_name} && + git reset --hard ${tag_name} + - name: Prepare home directory for code-signing + env: + CODESIGN_P12: ${{secrets.CODESIGN_P12}} + CODESIGN_PASS: ${{secrets.CODESIGN_PASS}} + if: env.CODESIGN_P12 != '' && env.CODESIGN_PASS != '' + shell: bash + run: | + cd home && + mkdir -p .sig && + echo -n "$CODESIGN_P12" | tr % '\n' | base64 -d >.sig/codesign.p12 && + echo -n "$CODESIGN_PASS" >.sig/codesign.pass + git config --global alias.signtool '!sh "/usr/src/build-extra/signtool.sh"' + - name: Prepare home directory for GPG signing + if: env.GPGKEY != '' + shell: bash + run: | + # This section ensures that the identity for the GPG key matches the git user identity, otherwise + # signing will fail + + echo '${{secrets.PRIVGPGKEY}}' | tr % '\n' | gpg $GPG_OPTIONS --import && + info="$(gpg --list-keys --with-colons "${GPGKEY%% *}" | cut -d : -f 1,10 | sed -n '/^uid/{s|uid:||p;q}')" && + git config --global user.name "${info% <*}" && + git config --global user.email "<${info#*<}" + env: + GPGKEY: ${{secrets.GPGKEY}} + - name: Build mingw-w64-x86_64-git + env: + GPGKEY: "${{secrets.GPGKEY}}" + shell: bash + run: | + set -x + + # Make sure that there is a `/usr/bin/git` that can be used by `makepkg-mingw` + printf '#!/bin/sh\n\nexec /mingw64/bin/git.exe "$@"\n' >/usr/bin/git && + + # Restrict `PATH` to MSYS2 and to Visual Studio (to let `cv2pdb` find the relevant DLLs) + PATH="/mingw64/bin:/usr/bin:/C/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin/amd64:/C/Windows/system32" + + type -p mspdb140.dll || exit 1 + + sh -x /usr/src/build-extra/please.sh build-mingw-w64-git --only-64-bit --build-src-pkg -o artifacts HEAD && + if test -n "$GPGKEY" + then + for tar in artifacts/*.tar* + do + /usr/src/build-extra/gnupg-with-gpgkey.sh --detach-sign --no-armor $tar + done + fi && + + b=$PWD/artifacts && + version=${{ needs.prereqs.outputs.tag_name }} && + (cd /usr/src/MINGW-packages/mingw-w64-git && + cp PKGBUILD.$version PKGBUILD && + git commit -s -m "mingw-w64-git: new version ($version)" PKGBUILD && + git bundle create "$b"/MINGW-packages.bundle origin/main..main) + - name: Publish mingw-w64-x86_64-git + uses: actions/upload-artifact@v2 + with: + name: pkg-x86_64 + path: artifacts + windows_artifacts: + runs-on: windows-latest + needs: [prereqs, windows_pkg] + env: + HOME: "${{github.workspace}}\\home" + strategy: + matrix: + artifact: + - name: installer + fileprefix: Git + - name: portable + fileprefix: PortableGit + fail-fast: false + steps: + - name: Download pkg-x86_64 + uses: actions/download-artifact@v2 + with: + name: pkg-x86_64 + path: pkg-x86_64 + - uses: git-for-windows/setup-git-for-windows-sdk@v1 + with: + flavor: build-installers + - name: Clone build-extra + shell: bash + run: | + git clone --single-branch -b main https://github.com/git-for-windows/build-extra /usr/src/build-extra + - name: Prepare home directory for code-signing + env: + CODESIGN_P12: ${{secrets.CODESIGN_P12}} + CODESIGN_PASS: ${{secrets.CODESIGN_PASS}} + if: env.CODESIGN_P12 != '' && env.CODESIGN_PASS != '' + shell: bash + run: | + mkdir -p home/.sig && + echo -n "$CODESIGN_P12" | tr % '\n' | base64 -d >home/.sig/codesign.p12 && + echo -n "$CODESIGN_PASS" >home/.sig/codesign.pass && + git config --global alias.signtool '!sh "/usr/src/build-extra/signtool.sh"' + - name: Build 64-bit ${{matrix.artifact.name}} + shell: bash + run: | + set -x + + # Copy the PDB archive to the directory where `--include-pdbs` expects it + b=/usr/src/build-extra && + mkdir -p $b/cached-source-packages && + cp pkg-x86_64/*-pdb* $b/cached-source-packages/ && + + # Build the installer, embedding PDBs + eval $b/please.sh make_installers_from_mingw_w64_git --include-pdbs \ + --version=${{ needs.prereqs.outputs.tag_version }} \ + -o artifacts --${{matrix.artifact.name}} \ + --pkg=pkg-x86_64/mingw-w64-x86_64-git-[0-9]*.tar.xz \ + --pkg=pkg-x86_64/mingw-w64-x86_64-git-doc-html-[0-9]*.tar.xz && + + if test portable = '${{matrix.artifact.name}}' && test -n "$(git config alias.signtool)" + then + git signtool artifacts/PortableGit-*.exe + fi && + openssl dgst -sha256 artifacts/${{matrix.artifact.fileprefix}}-*.exe | sed "s/.* //" >artifacts/sha-256.txt + - name: Publish ${{matrix.artifact.name}}-x86_64 + uses: actions/upload-artifact@v2 + with: + name: win-${{matrix.artifact.name}}-x86_64 + path: artifacts + # End build Windows installers + + # Build Mac OSX installers & upload artifacts + mac_artifacts: + runs-on: macos-latest + needs: prereqs + env: + # `gettext` is keg-only + LDFLAGS: -L/usr/local/opt/gettext/lib + CFLAGS: -I/usr/local/opt/gettext/include + # Link with cURL + CURL_LDFLAGS: -lcurl + # To make use of the catalogs... + XML_CATALOG_FILES: /usr/local/etc/xml/catalog + # Enable a bit stricter compile flags + DEVELOPER: 1 + # For the osx-installer build + OSX_VERSION: 10.6 + V: 1 + steps: + - name: Install git dependencies + run: | + set -x + brew install -v automake asciidoc xmlto + brew link --force gettext + - name: Clone git + uses: actions/checkout@v2 + with: + path: 'git' + - name: Build GIT-VERSION-FILE and .tar.gz files + run: | + set -x + PATH=/usr/local/bin:$PATH + + # Write to "version" file to force match with trigger payload version + echo "${{ needs.prereqs.outputs.tag_version }}" >>git/version + make -C git -j$(sysctl -n hw.physicalcpu) GIT-VERSION-FILE dist dist-doc + - name: Clone installer repository + uses: actions/checkout@v2 + with: + path: 'git_osx_installer' + repository: 'derrickstolee/git_osx_installer' + - name: Bundle .dmg + run: | + die () { + echo "$*" >&2 + exit 1 + } + + VERSION="${{ needs.prereqs.outputs.tag_version }}" + export VERSION + + dir=git_osx_installer/git-$VERSION + test ! -e $dir || + rm $dir || + die "Could not remove $dir" + ln -s .. $dir + + mkdir -p git_osx_installer/build && + cp git/git-$VERSION.tar.gz git/git-manpages-$VERSION.tar.gz git_osx_installer/build/ || + die "Could not copy .tar.gz files" + + # drop the -isysroot `GIT_SDK` hack + sed -i .bak -e 's/ -isysroot .(SDK_PATH)//' git_osx_installer/Makefile || die "Could not drop the -isysroot hack" + + # make sure that .../usr/local/git/share/man/ exists + sed -i .bak -e 's/\(tar .*-C \)\(.*\/share\/man\)$/mkdir -p \2 \&\& &/' git_osx_installer/Makefile || die "Could not edit git_osx_installer/Makefile" + cat git_osx_installer/Makefile + + make -C git_osx_installer vars + + PATH=/usr/local/bin:/System/Library/Frameworks:$PATH \ + make -C git_osx_installer \ + OSX_VERSION=10.6 C_INCLUDE_PATH="$C_INCLUDE_PATH" V=1 \ + build/intel-universal-snow-leopard/git-$VERSION/osx-built-keychain || + die "Build failed" + + PATH=/usr/local/bin:$PATH \ + make -C git_osx_installer \ + OSX_VERSION=10.6 C_INCLUDE_PATH="$C_INCLUDE_PATH" V=1 image || + die "Build failed" + + mkdir -p artifacts + mv git_osx_installer/*.dmg artifacts/ + mv git_osx_installer/disk-image/*.pkg artifacts/ + - name: Publish OSX installer + uses: actions/upload-artifact@v2 + with: + name: osx-installer + path: artifacts + # End build Mac OSX installers + + # Build & sign Ubuntu package + ubuntu_build: + runs-on: ubuntu-latest + needs: prereqs + steps: + - name: Install git dependencies + run: | + set -ex + + sudo apt-get update -q + sudo apt-get install -y -q --no-install-recommends gettext libcurl4-gnutls-dev libpcre3-dev asciidoc xmlto + - name: Clone git + uses: actions/checkout@v2 + with: + path: git + - name: Build and package .deb + run: | + set -ex + + die () { + echo "$*" >&2 + exit 1 + } + + echo "${{ needs.prereqs.outputs.tag_version }}" >>git/version + make -C git GIT-VERSION-FILE + + VERSION="${{ needs.prereqs.outputs.tag_version }}" + + ARCH="$(dpkg-architecture -q DEB_HOST_ARCH)" + if test -z "$ARCH"; then + die "Could not determine host architecture!" + fi + + PKGNAME="microsoft-git_$VERSION" + PKGDIR="$(dirname $(pwd))/$PKGNAME" + + rm -rf "$PKGDIR" + mkdir -p "$PKGDIR" + + DESTDIR="$PKGDIR" make -C git -j5 V=1 DEVELOPER=1 \ + USE_LIBPCRE=1 \ + NO_CROSS_DIRECTORY_HARDLINKS=1 \ + ASCIIDOC8=1 ASCIIDOC_NO_ROFF=1 \ + ASCIIDOC='TZ=UTC asciidoc' \ + prefix=/usr/local \ + gitexecdir=/usr/local/lib/git-core \ + libexecdir=/usr/local/lib/git-core \ + htmldir=/usr/local/share/doc/git/html \ + install install-doc install-html + + cd .. + mkdir "$PKGNAME/DEBIAN" + + # Based on https://packages.ubuntu.com/xenial/vcs/git + cat >"$PKGNAME/DEBIAN/control" < + Description: Git client built from the https://github.com/microsoft/git repository, + specialized in supporting monorepo scenarios. Includes the Scalar CLI. + EOF + + dpkg-deb --build "$PKGNAME" + + mkdir $GITHUB_WORKSPACE/artifacts + mv "$PKGNAME.deb" $GITHUB_WORKSPACE/artifacts/ + - name: Publish unsigned .deb package + uses: actions/upload-artifact@v2 + with: + name: deb-package-unsigned + path: artifacts/ + ubuntu_sign-artifacts: + runs-on: windows-latest # Must be run on Windows due to ESRP executable OS compatibility + needs: [ubuntu_build, prereqs] + if: needs.prereqs.outputs.deb_signable == 'true' + env: + ARTIFACTS_DIR: artifacts + steps: + - name: Clone repository + uses: actions/checkout@v2 + - name: Download unsigned packages + uses: actions/download-artifact@v2 + with: + name: deb-package-unsigned + path: ${{ env.ARTIFACTS_DIR }}/unsigned + - uses: azure/login@v1 + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} + - name: Download ESRP client + run: | + az storage blob download --subscription "${{ secrets.AZURE_SUBSCRIPTION }}" --account-name gitcitoolstore -c tools -n microsoft.esrpclient.1.2.47.nupkg -f esrp.zip + Expand-Archive -Path esrp.zip -DestinationPath .\esrp + - name: Install ESRP certificates + run: | + az keyvault secret download --subscription "${{ secrets.AZURE_SUBSCRIPTION }}" --vault-name "git-client-ci-kv" --name "microsoft-git-publisher-ssl-cert" -f ssl_cert.pfx + Import-PfxCertificate ssl_cert.pfx -CertStoreLocation Cert:\LocalMachine\My + az keyvault secret download --subscription "${{ secrets.AZURE_SUBSCRIPTION }}" --vault-name "git-client-ci-kv" --name "microsoft-git-publisher-esrp-payload-cert" -f payload_cert.pfx + Import-PfxCertificate payload_cert.pfx -CertStoreLocation Cert:\LocalMachine\My + - uses: actions/setup-python@v2 + - name: Run ESRP client + run: python .github/scripts/sign-debian-packages.py + - name: Upload signed artifact + uses: actions/upload-artifact@v2 + with: + name: deb-package-signed + path: ${{ env.ARTIFACTS_DIR }}/signed + # End build & sign Ubuntu package + + create-github-release: + runs-on: ubuntu-latest + needs: [prereqs, windows_artifacts, mac_artifacts, ubuntu_sign-artifacts] + if: | + success() || + (needs.ubuntu_sign-artifacts.result == 'skipped' && + needs.mac_artifacts.result == 'success' && + needs.windows_artifacts.result == 'success') + steps: + - name: Download Windows portable installer + uses: actions/download-artifact@v2 + with: + name: win-portable-x86_64 + path: win-portable-x86_64 + - name: Download Windows x86_64 installer + uses: actions/download-artifact@v2 + with: + name: win-installer-x86_64 + path: win-installer-x86_64 + - name: Download Mac installer + uses: actions/download-artifact@v2 + with: + name: osx-installer + path: osx-installer + - name: Download Ubuntu package (signed) + if: needs.prereqs.outputs.deb_signable == 'true' + uses: actions/download-artifact@v2 + with: + name: deb-package-signed + path: deb-package + - name: Download Ubuntu package (unsigned) + if: needs.prereqs.outputs.deb_signable != 'true' + uses: actions/download-artifact@v2 + with: + name: deb-package-unsigned + path: deb-package + - uses: actions/github-script@v4 + with: + script: | + const fs = require('fs'); + const path = require('path'); + + var releaseMetadata = { + owner: context.repo.owner, + repo: context.repo.repo + }; + + // Create the release + var tagName = "${{ needs.prereqs.outputs.tag_name }}"; + var createdRelease = await github.repos.createRelease({ + ...releaseMetadata, + draft: true, + tag_name: tagName, + name: tagName + }); + releaseMetadata.release_id = createdRelease.data.id; + + // Uploads contents of directory to the release created above + async function uploadDirectoryToRelease(directory, includeExtensions=[]) { + return fs.promises.readdir(directory) + .then(async(files) => Promise.all( + files.filter(file => { + return includeExtensions.length==0 || includeExtensions.includes(path.extname(file).toLowerCase()); + }) + .map(async (file) => { + var filePath = path.join(directory, file); + github.repos.uploadReleaseAsset({ + ...releaseMetadata, + name: file, + headers: { + "content-length": (await fs.promises.stat(filePath)).size + }, + data: fs.createReadStream(filePath) + }); + })) + ); + } + + await Promise.all([ + // Upload Windows artifacts + uploadDirectoryToRelease('win-installer-x86_64', ['.exe']), + uploadDirectoryToRelease('win-portable-x86_64', ['.exe']), + + // Upload Mac artifacts + uploadDirectoryToRelease('osx-installer'), + + // Upload Ubuntu artifacts + uploadDirectoryToRelease('deb-package') + ]); diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 94b4729807bf5e..94279aa6593687 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -4,6 +4,7 @@ on: [push, pull_request] env: DEVELOPER: 1 + INCLUDE_SCALAR: YesPlease jobs: ci-config: diff --git a/.github/workflows/release-apt-get.yml b/.github/workflows/release-apt-get.yml new file mode 100644 index 00000000000000..115ddc1101a93c --- /dev/null +++ b/.github/workflows/release-apt-get.yml @@ -0,0 +1,95 @@ +name: "release-apt-get" +on: + release: + types: [released] + + workflow_dispatch: + inputs: + release: + description: 'Release Id' + required: true + default: 'latest' + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - uses: azure/login@v1 + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} + + - name: "Download Repo Client" + env: + AZ_SUB: ${{ secrets.AZURE_SUBSCRIPTION }} + run: | + az storage blob download --subscription "$AZ_SUB" --account-name gitcitoolstore -c tools -n azure-repoapi-client_2.0.1_amd64.deb -f repoclient.deb --auth-mode login + + - name: "Install Repo Client" + run: | + sudo apt-get install python3-adal --yes + sudo dpkg -i repoclient.deb + rm repoclient.deb + + - name: "Configure Repo Client" + uses: actions/github-script@v3 + env: + AZURE_AAD_ID: ${{ secrets.AZURE_AAD_ID }} + AAD_CLIENT_SECRET: ${{ secrets.AAD_CLIENT_SECRET }} + with: + script: | + for (const key of ['AZURE_AAD_ID', 'AAD_CLIENT_SECRET']) { + if (!process.env[key]) throw new Error(`Required env var ${key} is missing!`) + } + const config = { + AADResource: 'https://microsoft.onmicrosoft.com/945999e9-da09-4b5b-878f-b66c414602c0', + AADTenant: '72f988bf-86f1-41af-91ab-2d7cd011db47', + AADAuthorityUrl: 'https://login.microsoftonline.com', + server: 'azure-apt-cat.cloudapp.net', + port: '443', + AADClientId: process.env.AZURE_AAD_ID, + AADClientSecret: process.env.AAD_CLIENT_SECRET, + repositoryId: '' + } + const fs = require('fs') + fs.writeFileSync('config.json', JSON.stringify(config, null, 2)) + + - name: "Get Release Asset" + id: get-asset + env: + RELEASE: ${{ github.event.inputs.release }} + uses: actions/github-script@v3 + with: + github-token: ${{secrets.GITHUB_TOKEN}} + script: | + const { data } = await github.repos.getRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + release_id: process.env.RELEASE || 'latest' + }) + const assets = data.assets.filter(asset => asset.name.endsWith('.deb')) + if (assets.length !== 1) { + throw new Error(`Unexpected number of .deb assets: ${assets.length}`) + } + const fs = require('fs') + const buffer = await github.repos.getReleaseAsset({ + headers: { + accept: 'application/octet-stream' + }, + owner: context.repo.owner, + repo: context.repo.repo, + asset_id: assets[0].id + }) + console.log(buffer) + fs.writeFileSync(assets[0].name, Buffer.from(buffer.data)) + core.setOutput('name', assets[0].name) + + - name: "Publish to apt feed" + env: + RELEASE: ${{ github.event.inputs.release }} + run: | + for id in ${{ secrets.BIONIC_REPO_ID }} ${{ secrets.HIRSUTE_REPO_ID }} + do + repoclient -v v3 -c config.json package add --check --wait 300 "${{steps.get-asset.outputs.name}}" -r $id + done diff --git a/.github/workflows/release-homebrew.yml b/.github/workflows/release-homebrew.yml new file mode 100644 index 00000000000000..8ea835b3d59986 --- /dev/null +++ b/.github/workflows/release-homebrew.yml @@ -0,0 +1,30 @@ +name: Update Homebrew Tap +on: + release: + types: [released] + +jobs: + release: + runs-on: ubuntu-latest + steps: + - id: version + name: Compute version number + run: | + echo "::set-output name=result::$(echo $GITHUB_REF | sed -e "s/^refs\/tags\/v//")" + - id: hash + name: Compute release asset hash + uses: mjcheetham/asset-hash@v1 + with: + asset: /git-(.*)\.pkg/ + hash: sha256 + token: ${{ secrets.GITHUB_TOKEN }} + - name: Update scalar Cask + uses: mjcheetham/update-homebrew@v1.1 + with: + token: ${{ secrets.HOMEBREW_TOKEN }} + tap: microsoft/git + name: microsoft-git + type: cask + version: ${{ steps.version.outputs.result }} + sha256: ${{ steps.hash.outputs.result }} + alwaysUsePullRequest: true diff --git a/.github/workflows/release-winget.yml b/.github/workflows/release-winget.yml new file mode 100644 index 00000000000000..17840be214933a --- /dev/null +++ b/.github/workflows/release-winget.yml @@ -0,0 +1,39 @@ +name: "release-winget" +on: + release: + types: [released] + +jobs: + release: + runs-on: ubuntu-latest + steps: + - id: update-winget + name: Update winget repository + uses: mjcheetham/update-winget@v1.3.2 + with: + id: Microsoft.Git + token: ${{ secrets.WINGET_TOKEN }} + releaseAsset: Git-([0-9.vfs]*)\-64-bit.exe + manifestText: | + PackageIdentifier: {{id}} + PackageVersion: {{version:s/\.[A-Za-z]+\././}} + PackageName: Microsoft Git + Publisher: The Git Client Team at GitHub + Moniker: microsoft-git + PackageUrl: https://aka.ms/ms-git + Tags: + - microsoft-git + License: GPLv2 + ShortDescription: | + Git distribution to support monorepo scenarios. + Note: This is not Git for Windows. Unless you are working in a monorepo and require + specific Git modifications, please run `winget install git` to start using Git for Windows. + Installers: + - Architecture: x64 + InstallerUrl: {{url}} + InstallerType: inno + InstallerSha256: {{sha256}} + PackageLocale: en-US + ManifestType: singleton + ManifestVersion: 1.0.0 + alwaysUsePullRequest: true diff --git a/.github/workflows/scalar-functional-tests.yml b/.github/workflows/scalar-functional-tests.yml new file mode 100644 index 00000000000000..438933d6aed2a3 --- /dev/null +++ b/.github/workflows/scalar-functional-tests.yml @@ -0,0 +1,221 @@ +name: Scalar Functional Tests + +env: + SCALAR_REPOSITORY: microsoft/scalar + SCALAR_REF: main + DEBUG_WITH_TMATE: false + SCALAR_TEST_SKIP_VSTS_INFO: true + +on: + push: + branches: [ vfs-* ] + pull_request: + branches: [ vfs-*, features/* ] + +jobs: + scalar: + name: "Scalar Functional Tests" + + strategy: + fail-fast: false + matrix: + # Order by runtime (in descending order) + os: [windows-2019, macos-10.15, ubuntu-16.04, ubuntu-18.04, ubuntu-20.04] + # Scalar.NET used to be tested using `features: [false, experimental]` + # But currently, Scalar/C ignores `feature.scalar` altogether, so let's + # save some electrons and run only one of them... + features: [ignored] + exclude: + # The built-in FSMonitor is not (yet) supported on Linux + - os: ubuntu-16.04 + features: experimental + - os: ubuntu-18.04 + features: experimental + - os: ubuntu-20.04 + features: experimental + runs-on: ${{ matrix.os }} + + env: + BUILD_FRAGMENT: bin/Release/netcoreapp3.1 + + steps: + - name: Check out Git's source code + uses: actions/checkout@v2 + + - name: Setup build tools on Windows + if: runner.os == 'Windows' + uses: git-for-windows/setup-git-for-windows-sdk@v1 + + - name: Provide a minimal `install` on Windows + if: runner.os == 'Windows' + shell: bash + run: | + test -x /usr/bin/install || + tr % '\t' >/usr/bin/install <<-\EOF + #!/bin/sh + + cmd=cp + while test $# != 0 + do + %case "$1" in + %-d) cmd="mkdir -p";; + %-m) shift;; # ignore mode + %*) break;; + %esac + %shift + done + + exec $cmd "$@" + EOF + + - name: Install build dependencies for Git (Linux) + if: runner.os == 'Linux' + run: | + sudo apt-get update + sudo apt-get -q -y install libssl-dev libcurl4-openssl-dev gettext + + - name: Build and install Git + shell: bash + env: + NO_TCLTK: Yup + run: | + # We do require a VFS version + def_ver="$(sed -n 's/DEF_VER=\(.*vfs.*\)/\1/p' GIT-VERSION-GEN)" + test -n "$def_ver" + + # Ensure that `git version` reflects DEF_VER + case "$(git describe --match "v[0-9]*vfs*" HEAD)" in + ${def_ver%%.vfs.*}.vfs.*) ;; # okay, we can use this + *) git -c user.name=ci -c user.email=ci@github tag -m for-testing ${def_ver}.NNN.g$(git rev-parse --short HEAD);; + esac + + SUDO= + extra= + case "${{ runner.os }}" in + Windows) + extra=DESTDIR=/c/Progra~1/Git + cygpath -aw "/c/Program Files/Git/cmd" >>$GITHUB_PATH + ;; + Linux) + SUDO=sudo + extra=prefix=/usr + ;; + macOS) + SUDO=sudo + extra=prefix=/usr/local + ;; + esac + + $SUDO make -j5 INCLUDE_SCALAR=AbsolutelyYes $extra install + + - name: Ensure that we use the built Git and Scalar + shell: bash + run: | + type -p git + git version + case "$(git version)" in *.vfs.*) echo Good;; *) exit 1;; esac + type -p scalar + scalar version + case "$(scalar version 2>&1)" in *.vfs.*) echo Good;; *) exit 1;; esac + + - name: Check out Scalar's source code + uses: actions/checkout@v2 + with: + fetch-depth: 0 # Indicate full history so Nerdbank.GitVersioning works. + path: scalar + repository: ${{ env.SCALAR_REPOSITORY }} + ref: ${{ env.SCALAR_REF }} + + - name: Setup .NET Core + uses: actions/setup-dotnet@v1 + with: + dotnet-version: 3.1.302 + + - name: Install dependencies + run: dotnet restore + working-directory: scalar + env: + DOTNET_NOLOGO: 1 + + - name: Build + working-directory: scalar + run: dotnet build --configuration Release --no-restore -p:UseAppHost=true # Force generation of executable on macOS. + + - name: Setup platform (Linux) + if: runner.os == 'Linux' + run: | + echo "BUILD_PLATFORM=${{ runner.os }}" >>$GITHUB_ENV + echo "TRACE2_BASENAME=Trace2.${{ github.run_id }}__${{ github.run_number }}__${{ matrix.os }}__${{ matrix.features }}" >>$GITHUB_ENV + + - name: Setup platform (Mac) + if: runner.os == 'macOS' + run: | + echo 'BUILD_PLATFORM=Mac' >>$GITHUB_ENV + echo "TRACE2_BASENAME=Trace2.${{ github.run_id }}__${{ github.run_number }}__${{ matrix.os }}__${{ matrix.features }}" >>$GITHUB_ENV + + - name: Setup platform (Windows) + if: runner.os == 'Windows' + run: | + echo "BUILD_PLATFORM=${{ runner.os }}" >>$env:GITHUB_ENV + echo 'BUILD_FILE_EXT=.exe' >>$env:GITHUB_ENV + echo "TRACE2_BASENAME=Trace2.${{ github.run_id }}__${{ github.run_number }}__${{ matrix.os }}__${{ matrix.features }}" >>$env:GITHUB_ENV + + - name: Configure feature.scalar + run: git config --global feature.scalar ${{ matrix.features }} + + - id: functional_test + name: Functional test + timeout-minutes: 60 + working-directory: scalar + shell: bash + run: | + export GIT_TRACE2_EVENT="$PWD/$TRACE2_BASENAME/Event" + export GIT_TRACE2_PERF="$PWD/$TRACE2_BASENAME/Perf" + export GIT_TRACE2_EVENT_BRIEF=true + export GIT_TRACE2_PERF_BRIEF=true + mkdir -p "$TRACE2_BASENAME" + mkdir -p "$TRACE2_BASENAME/Event" + mkdir -p "$TRACE2_BASENAME/Perf" + git version --build-options + cd ../out + Scalar.FunctionalTests/$BUILD_FRAGMENT/Scalar.FunctionalTests$BUILD_FILE_EXT --test-scalar-on-path --test-git-on-path --timeout=300000 --full-suite + + - name: Force-stop FSMonitor daemons and Git processes (Windows) + if: runner.os == 'Windows' && (success() || failure()) + shell: bash + run: | + set -x + wmic process get CommandLine,ExecutablePath,HandleCount,Name,ParentProcessID,ProcessID + wmic process where "CommandLine Like '%fsmonitor--daemon %run'" delete + wmic process where "ExecutablePath Like '%git.exe'" delete + + - id: trace2_zip_unix + if: runner.os != 'Windows' && ( success() || failure() ) && ( steps.functional_test.conclusion == 'success' || steps.functional_test.conclusion == 'failure' ) + name: Zip Trace2 Logs (Unix) + shell: bash + working-directory: scalar + run: zip -q -r $TRACE2_BASENAME.zip $TRACE2_BASENAME/ + + - id: trace2_zip_windows + if: runner.os == 'Windows' && ( success() || failure() ) && ( steps.functional_test.conclusion == 'success' || steps.functional_test.conclusion == 'failure' ) + name: Zip Trace2 Logs (Windows) + working-directory: scalar + run: Compress-Archive -DestinationPath ${{ env.TRACE2_BASENAME }}.zip -Path ${{ env.TRACE2_BASENAME }} + + - name: Archive Trace2 Logs + if: ( success() || failure() ) && ( steps.trace2_zip_unix.conclusion == 'success' || steps.trace2_zip_windows.conclusion == 'success' ) + uses: actions/upload-artifact@v2 + with: + name: ${{ env.TRACE2_BASENAME }}.zip + path: scalar/${{ env.TRACE2_BASENAME }}.zip + retention-days: 3 + + # The GitHub Action `action-tmate` allows developers to connect to the running agent + # using SSH (it will be a `tmux` session; on Windows agents it will be inside the MSYS2 + # environment in `C:\msys64`, therefore it can be slightly tricky to interact with + # Git for Windows, which runs a slightly incompatible MSYS2 runtime). + - name: action-tmate + if: env.DEBUG_WITH_TMATE == 'true' && failure() + uses: mxschmitt/action-tmate@v3 + with: + limit-access-to-actor: true diff --git a/.gitignore b/.gitignore index 4baba472aa8261..d5c886dab572c4 100644 --- a/.gitignore +++ b/.gitignore @@ -76,6 +76,7 @@ /git-gc /git-get-tar-commit-id /git-grep +/git-gvfs-helper /git-hash-object /git-help /git-http-backend @@ -172,6 +173,7 @@ /git-unpack-file /git-unpack-objects /git-update-index +/git-update-microsoft-git /git-update-ref /git-update-server-info /git-upload-archive diff --git a/BRANCHES.md b/BRANCHES.md new file mode 100644 index 00000000000000..364158375e7d55 --- /dev/null +++ b/BRANCHES.md @@ -0,0 +1,59 @@ +Branches used in this repo +========================== + +The document explains the branching structure that we are using in the VFSForGit repository as well as the forking strategy that we have adopted for contributing. + +Repo Branches +------------- + +1. `vfs-#` + + These branches are used to track the specific version that match Git for Windows with the VFSForGit specific patches on top. When a new version of Git for Windows is released, the VFSForGit patches will be rebased on that windows version and a new gvfs-# branch created to create pull requests against. + + #### Examples + + ``` + vfs-2.27.0 + vfs-2.30.0 + ``` + + The versions of git for VFSForGit are based on the Git for Windows versions. v2.20.0.vfs.1 will correspond with the v2.20.0.windows.1 with the VFSForGit specific patches applied to the windows version. + +2. `vfs-#-exp` + + These branches are for releasing experimental features to early adopters. They + should contain everything within the corresponding `vfs-#` branch; if the base + branch updates, then merge into the `vfs-#-exp` branch as well. + +Tags +---- + +We are using annotated tags to build the version number for git. The build will look back through the commit history to find the first tag matching `v[0-9]*vfs*` and build the git version number using that tag. + +Full releases are of the form `v2.XX.Y.vfs.Z.W` where `v2.XX.Y` comes from the +upstream version and `Z.W` are custom updates within our fork. Specifically, +the `.Z` value represents the "compatibility level" with VFS for Git. Only +increase this version when making a breaking change with a released version +of VFS for Git. The `.W` version is used for minor updates between major +versions. + +Experimental releases are of the form `v2.XX.Y.vfs.Z.W.exp`. The `.exp` +suffix indicates that experimental features are available. The rest of the +version string comes from the full release tag. These versions will only +be made available as pre-releases on the releases page, never a full release. + +Forking +------- + +A personal fork of this repository and a branch in that repository should be used for development. + +These branches should be based on the latest vfs-# branch. If there are work in progress pull requests that you have based on a previous version branch when a new version branch is created, you will need to move your patches to the new branch to get them in that latest version. + +#### Example + +``` +git clone +git remote add ms https://github.com/Microsoft/git.git +git checkout -b my-changes ms/vfs-2.20.0 --no-track +git push -fu origin HEAD +``` diff --git a/Documentation/config.txt b/Documentation/config.txt index 3f158803ef6fba..70040121165c2e 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -380,6 +380,8 @@ include::config/gui.txt[] include::config/guitool.txt[] +include::config/gvfs.txt[] + include::config/help.txt[] include::config/http.txt[] diff --git a/Documentation/config/core.txt b/Documentation/config/core.txt index 2db16334252271..d3a499f7ae5579 100644 --- a/Documentation/config/core.txt +++ b/Documentation/config/core.txt @@ -107,6 +107,14 @@ and MacOS. Note: if this config setting is set to `true`, the values of `core.fsmonitor` and `core.fsmonitorHookVersion` are ignored. +core.virtualFilesystem:: + If set, the value of this variable is used as a command which + will identify all files and directories that are present in + the working directory. Git will only track and update files + listed in the virtual file system. Using the virtual file system + will supersede the sparse-checkout settings which will be ignored. + See the "virtual file system" section of linkgit:githooks[5]. + core.trustctime:: If false, the ctime differences between the index and the working tree are ignored; useful when the inode change time @@ -650,6 +658,55 @@ core.multiPackIndex:: single index. See linkgit:git-multi-pack-index[1] for more information. Defaults to true. +core.gvfs:: + Enable the features needed for GVFS. This value can be set to true + to indicate all features should be turned on or the bit values listed + below can be used to turn on specific features. ++ +-- + GVFS_SKIP_SHA_ON_INDEX:: + Bit value 1 + Disables the calculation of the sha when writing the index + GVFS_MISSING_OK:: + Bit value 4 + Normally git write-tree ensures that the objects referenced by the + directory exist in the object database. This option disables this check. + GVFS_NO_DELETE_OUTSIDE_SPARSECHECKOUT:: + Bit value 8 + When marking entries to remove from the index and the working + directory this option will take into account what the + skip-worktree bit was set to so that if the entry has the + skip-worktree bit set it will not be removed from the working + directory. This will allow virtualized working directories to + detect the change to HEAD and use the new commit tree to show + the files that are in the working directory. + GVFS_FETCH_SKIP_REACHABILITY_AND_UPLOADPACK:: + Bit value 16 + While performing a fetch with a virtual file system we know + that there will be missing objects and we don't want to download + them just because of the reachability of the commits. We also + don't want to download a pack file with commits, trees, and blobs + since these will be downloaded on demand. This flag will skip the + checks on the reachability of objects during a fetch as well as + the upload pack so that extraneous objects don't get downloaded. + GVFS_BLOCK_FILTERS_AND_EOL_CONVERSIONS:: + Bit value 64 + With a virtual file system we only know the file size before any + CRLF or smudge/clean filters processing is done on the client. + To prevent file corruption due to truncation or expansion with + garbage at the end, these filters must not run when the file + is first accessed and brought down to the client. Git.exe can't + currently tell the first access vs subsequent accesses so this + flag just blocks them from occurring at all. + GVFS_PREFETCH_DURING_FETCH:: + Bit value 128 + While performing a `git fetch` command, use the gvfs-helper to + perform a "prefetch" of commits and trees. +-- + +core.useGvfsHelper:: + TODO + core.sparseCheckout:: Enable "sparse checkout" feature. See linkgit:git-sparse-checkout[1] for more information. @@ -669,3 +726,12 @@ core.abbrev:: If set to "no", no abbreviation is made and the object names are shown in their full length. The minimum length is 4. + +core.configWriteLockTimeoutMS:: + When processes try to write to the config concurrently, it is likely + that one process "wins" and the other process(es) fail to lock the + config file. By configuring a timeout larger than zero, Git can be + told to try to lock the config again a couple times within the + specified timeout. If the timeout is configure to zero (which is the + default), Git will fail immediately when the config is already + locked. diff --git a/Documentation/config/gvfs.txt b/Documentation/config/gvfs.txt new file mode 100644 index 00000000000000..6ab221ded36c91 --- /dev/null +++ b/Documentation/config/gvfs.txt @@ -0,0 +1,5 @@ +gvfs.cache-server:: + TODO + +gvfs.sharedcache:: + TODO diff --git a/Documentation/config/status.txt b/Documentation/config/status.txt index 0fc704ab80b223..af043d7e26f269 100644 --- a/Documentation/config/status.txt +++ b/Documentation/config/status.txt @@ -75,3 +75,25 @@ status.submoduleSummary:: the --ignore-submodules=dirty command-line option or the 'git submodule summary' command, which shows a similar output but does not honor these settings. + +status.deserializePath:: + EXPERIMENTAL, Pathname to a file containing cached status results + generated by `--serialize`. This will be overridden by + `--deserialize=` on the command line. If the cache file is + invalid or stale, git will fall-back and compute status normally. + +status.deserializeWait:: + EXPERIMENTAL, Specifies what `git status --deserialize` should do + if the serialization cache file is stale and whether it should + fall-back and compute status normally. This will be overridden by + `--deserialize-wait=` on the command line. ++ +-- +* `fail` - cause git to exit with an error when the status cache file +is stale; this is intended for testing and debugging. +* `block` - cause git to spin and periodically retry the cache file +every 100 ms; this is intended to help coordinate with another git +instance concurrently computing the cache file. +* `no` - to immediately fall-back if cache file is stale. This is the default. +* `` - time (in tenths of a second) to spin and retry. +-- diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt index 55af6fd24e27cd..3f1030df70e566 100644 --- a/Documentation/git-rebase.txt +++ b/Documentation/git-rebase.txt @@ -340,9 +340,7 @@ See also INCOMPATIBLE OPTIONS below. -m:: --merge:: - Use merging strategies to rebase. When the recursive (default) merge - strategy is used, this allows rebase to be aware of renames on the - upstream side. This is the default. + Using merging strategies to rebase (default). + Note that a rebase merge works by replaying each commit from the working branch on top of the branch. Because of this, when a merge @@ -354,9 +352,8 @@ See also INCOMPATIBLE OPTIONS below. -s :: --strategy=:: - Use the given merge strategy. - If there is no `-s` option 'git merge-recursive' is used - instead. This implies --merge. + Use the given merge strategy, instead of the default `ort`. + This implies `--merge`. + Because 'git rebase' replays each commit from the working branch on top of the branch using the given strategy, using @@ -369,7 +366,7 @@ See also INCOMPATIBLE OPTIONS below. --strategy-option=:: Pass the through to the merge strategy. This implies `--merge` and, if no strategy has been - specified, `-s recursive`. Note the reversal of 'ours' and + specified, `-s ort`. Note the reversal of 'ours' and 'theirs' as noted above for the `-m` option. + See also INCOMPATIBLE OPTIONS below. @@ -530,7 +527,7 @@ The `--rebase-merges` mode is similar in spirit to the deprecated where commits can be reordered, inserted and dropped at will. + It is currently only possible to recreate the merge commits using the -`recursive` merge strategy; Different merge strategies can be used only via +`ort` merge strategy; different merge strategies can be used only via explicit `exec git merge -s [...]` commands. + See also REBASING MERGES and INCOMPATIBLE OPTIONS below. @@ -1219,12 +1216,16 @@ successful merge so that the user can edit the message. If a `merge` command fails for any reason other than merge conflicts (i.e. when the merge operation did not even start), it is rescheduled immediately. -At this time, the `merge` command will *always* use the `recursive` -merge strategy for regular merges, and `octopus` for octopus merges, -with no way to choose a different one. To work around -this, an `exec` command can be used to call `git merge` explicitly, -using the fact that the labels are worktree-local refs (the ref -`refs/rewritten/onto` would correspond to the label `onto`, for example). +By default, the `merge` command will use the `ort` merge strategy for +regular merges, and `octopus` for octopus merges. One can specify a +default strategy for all merges using the `--strategy` argument when +invoking rebase, or can override specific merges in the interactive +list of commands by using an `exec` command to call `git merge` +explicitly with a `--strategy` argument. Note that when calling `git +merge` explicitly like this, you can make use of the fact that the +labels are worktree-local refs (the ref `refs/rewritten/onto` would +correspond to the label `onto`, for example) in order to refer to the +branches you want to merge. Note: the first command (`label onto`) labels the revision onto which the commits are rebased; The name `onto` is just a convention, as a nod diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt index b31716bd607748..1b6ea8bb21a884 100644 --- a/Documentation/git-status.txt +++ b/Documentation/git-status.txt @@ -156,6 +156,21 @@ ignored, then the directory is not shown, but all contents are shown. update it afterwards if any changes were detected. Defaults to `--lock-index`. +--serialize[=]:: + (EXPERIMENTAL) Serialize raw status results to a file or stdout + in a format suitable for use by `--deserialize`. If a path is + given, serialize data will be written to that path *and* normal + status output will be written to stdout. If path is omitted, + only binary serialization data will be written to stdout. + +--deserialize[=]:: + (EXPERIMENTAL) Deserialize raw status results from a file or + stdin rather than scanning the worktree. If `` is omitted + and `status.deserializePath` is unset, input is read from stdin. +--no-deserialize:: + (EXPERIMENTAL) Disable implicit deserialization of status results + from the value of `status.deserializePath`. + ...:: See the 'pathspec' entry in linkgit:gitglossary[7]. @@ -417,6 +432,26 @@ quoted as explained for the configuration variable `core.quotePath` (see linkgit:git-config[1]). +SERIALIZATION and DESERIALIZATION (EXPERIMENTAL) +------------------------------------------------ + +The `--serialize` option allows git to cache the result of a +possibly time-consuming status scan to a binary file. A local +service/daemon watching file system events could use this to +periodically pre-compute a fresh status result. + +Interactive users could then use `--deserialize` to simply +(and immediately) print the last-known-good result without +waiting for the status scan. + +The binary serialization file format includes some worktree state +information allowing `--deserialize` to reject the cached data +and force a normal status scan if, for example, the commit, branch, +or status modes/options change. The format cannot, however, indicate +when the cached data is otherwise stale -- that coordination belongs +to the task driving the serializations. + + CONFIGURATION ------------- diff --git a/Documentation/git-update-microsoft-git.txt b/Documentation/git-update-microsoft-git.txt new file mode 100644 index 00000000000000..724bfc172f8ab7 --- /dev/null +++ b/Documentation/git-update-microsoft-git.txt @@ -0,0 +1,24 @@ +git-update-microsoft-git(1) +=========================== + +NAME +---- +git-update-microsoft-git - Update the installed version of Git + + +SYNOPSIS +-------- +[verse] +'git update-microsoft-git' + +DESCRIPTION +----------- +This version of Git is based on the Microsoft fork of Git, which +has custom capabilities focused on supporting monorepos. This +command checks for the latest release of that fork and installs +it on your machine. + + +GIT +--- +Part of the linkgit:git[1] suite diff --git a/Documentation/gitfaq.txt b/Documentation/gitfaq.txt index afdaeab8503c30..8c1f2d56751dce 100644 --- a/Documentation/gitfaq.txt +++ b/Documentation/gitfaq.txt @@ -275,7 +275,7 @@ best to always use a regular merge commit. [[merge-two-revert-one]] If I make a change on two branches but revert it on one, why does the merge of those branches include the change?:: - By default, when Git does a merge, it uses a strategy called the recursive + By default, when Git does a merge, it uses a strategy called the `ort` strategy, which does a fancy three-way merge. In such a case, when Git performs the merge, it considers exactly three points: the two heads and a third point, called the _merge base_, which is usually the common ancestor of diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt index b7d5e926f7b042..810d281ca985b4 100644 --- a/Documentation/githooks.txt +++ b/Documentation/githooks.txt @@ -699,6 +699,26 @@ and "0" meaning they were not. Only one parameter should be set to "1" when the hook runs. The hook running passing "1", "1" should not be possible. +virtualFilesystem +~~~~~~~~~~~~~~~~~~ + +"Virtual File System" allows populating the working directory sparsely. +The projection data is typically automatically generated by an external +process. Git will limit what files it checks for changes as well as which +directories are checked for untracked files based on the path names given. +Git will also only update those files listed in the projection. + +The hook is invoked when the configuration option core.virtualFilesystem +is set. It takes one argument, a version (currently 1). + +The hook should output to stdout the list of all files in the working +directory that git should track. The paths are relative to the root +of the working directory and are separated by a single NUL. Full paths +('dir1/a.txt') as well as directories are supported (ie 'dir1/'). + +The exit status determines whether git will use the data from the +hook. On error, git will abort the command with an error message. + GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt index 52565014c15a51..18649171e48b25 100644 --- a/Documentation/merge-options.txt +++ b/Documentation/merge-options.txt @@ -112,8 +112,8 @@ With --squash, --commit is not allowed, and will fail. Use the given merge strategy; can be supplied more than once to specify them in the order they should be tried. If there is no `-s` option, a built-in list of strategies - is used instead ('git merge-recursive' when merging a single - head, 'git merge-octopus' otherwise). + is used instead (`ort` when merging a single head, + `octopus` otherwise). -X