From d4e2c8714c5cad4ddb4a88940fb31a2a228e7838 Mon Sep 17 00:00:00 2001 From: Joe Tretter Date: Mon, 18 May 2026 18:37:10 -0500 Subject: [PATCH] Remove brittle interactive rebase shortcuts --- app/build.gradle.kts | 4 +- app/src/main/GitTesting.md | 1088 +++++++++++++++++ .../tretter/githugandroid/GitRuntime.kt | 61 +- .../tretter/githugandroid/GitSandboxEngine.kt | 38 +- .../githugandroid/levels/RenameCommitLevel.kt | 5 +- .../githugandroid/levels/ReorderLevel.kt | 7 +- .../githugandroid/levels/SquashLevel.kt | 5 +- .../githugandroid/LevelSolutionsTest.kt | 9 + 8 files changed, 1172 insertions(+), 45 deletions(-) create mode 100644 app/src/main/GitTesting.md diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 67f6196..0825b2a 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -19,8 +19,8 @@ android { applicationId = "solutions.tretter.githugandroid" minSdk = 26 targetSdk = 35 - versionCode = 146 - versionName = "0.1.145" + versionCode = 147 + versionName = "0.1.146" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true diff --git a/app/src/main/GitTesting.md b/app/src/main/GitTesting.md new file mode 100644 index 0000000..14c8b31 --- /dev/null +++ b/app/src/main/GitTesting.md @@ -0,0 +1,1088 @@ +# Git Testing + +Generated: 2026-05-18 + +This report covers upstream Git TAP test scripts from `.tmp-android-build/git-src/t`, run against the project-built host Git binary/source tree produced with the same feature-reduction flags used by `AndroidProjectTooling.sh` (`NO_CURL`, `NO_PERL`, `NO_PYTHON`, `NO_GETTEXT`, `NO_ICONV`, and related Android-friendly options). It validates the downstream Git implementation embedded by the app, not the Compose UI. + +Command used: + +```bash +prove -j8 --timer ./t[0-9]*.sh +``` + +App regression/unit suite also passed: + +```bash +bash ./AndroidProjectTooling.sh --test +``` + +## Summary + +| Metric | Count | +| --- | ---: | +| Upstream Git test scripts observed | 1042 | +| Passed scripts | 877 | +| Skipped scripts | 162 | +| Failed scripts | 3 | +| Unknown script statuses | 0 | + +Harness summary: `Files=1042, Tests=32076, 875 wallclock secs (14.04 usr 4.04 sys + 1117.40 cusr 1449.12 csys = 2584.60 CPU)` + +Harness result: `Result: FAIL` + +Skipped scripts are upstream self-skips for optional or platform-specific capabilities that are absent from this mobile-oriented build/test environment, such as Perl/SVN, Python/P4, CVS, iconv, JGit, sudo-only checks, Windows-only checks, and HTTP support disabled by the app tooling. + +## Failed Scripts + +| Test case | Explanation | +| --- | --- | +| `./t0052-simple-ipc.sh` | FAIL - Simple IPC daemon cannot bind its Unix-domain socket in this execution sandbox (Operation not permitted). This is overkill for the app because GitHug Android does not expose Git daemon IPC services; it runs short-lived Git subprocesses for isolated learning repositories. | +| `./t0301-credential-cache.sh` | FAIL - credential-cache daemon cannot bind its Unix-domain socket in this execution sandbox (Operation not permitted). This does not matter for scope because the app does not persist real user credentials or teach credential-cache workflows; adding a daemon credential store would be security-sensitive mobile infrastructure, not GitHug gameplay. | +| `./t7528-signed-commit-ssh.sh` | FAIL - ssh-agent socket setup fails in this execution sandbox (Operation not permitted / socket path issue). This is overkill for the app because SSH-agent-backed commit signing is not part of the current level catalog, and implementing mobile SSH-agent/key-management support would be a separate security product area. | + +## All Test Cases + +| Test case | Status | Notes | +| --- | --- | --- | +| `./t0005-signals.sh` | PASS | | +| `./t0004-unwritable.sh` | PASS | | +| `./t0002-gitfile.sh` | PASS | | +| `./t0009-git-dir-validation.sh` | PASS | | +| `./t0007-git-var.sh` | PASS | | +| `./t0013-sha1dc.sh` | PASS | | +| `./t0014-alias.sh` | PASS | | +| `./t0006-date.sh` | PASS | | +| `./t0017-env-helper.sh` | PASS | | +| `./t0018-advice.sh` | PASS | | +| `./t0019-json-writer.sh` | PASS | | +| `./t0010-racy-git.sh` | PASS | | +| `./t0022-crlf-rename.sh` | PASS | | +| `./t0023-crlf-am.sh` | PASS | | +| `./t0003-attributes.sh` | PASS | | +| `./t0024-crlf-archive.sh` | PASS | | +| `./t0025-crlf-renormalize.sh` | PASS | | +| `./t0026-eol-config.sh` | PASS | | +| `./t0028-working-tree-encoding.sh` | SKIPPED | skipping working tree encoding tests; iconv not available | +| `./t0029-core-unsetenvvars.sh` | SKIPPED | skipping Windows-specific tests | +| `./t0012-help.sh` | PASS | | +| `./t0001-init.sh` | PASS | | +| `./t0020-crlf.sh` | PASS | | +| `./t0034-root-safe-directory.sh` | SKIPPED | You must set env var GIT_TEST_ALLOW_SUDO=YES in order to run this test | +| `./t0031-lockfile-pid.sh` | PASS | | +| `./t0035-safe-bare-repository.sh` | PASS | | +| `./t0041-usage.sh` | PASS | | +| `./t0033-safe-directory.sh` | PASS | | +| `./t0051-windows-named-pipe.sh` | SKIPPED | skipping Windows-specific tests | +| `./t0052-simple-ipc.sh` | FAIL | FAIL - Simple IPC daemon cannot bind its Unix-domain socket in this execution sandbox (Operation not permitted). This is overkill for the app because GitHug Android does not expose Git daemon IPC services; it runs short-lived Git subprocesses for isolated learning repositories. | +| `./t0055-beyond-symlinks.sh` | PASS | | +| `./t0050-filesystem.sh` | PASS | | +| `./t0040-parse-options.sh` | PASS | | +| `./t0056-git-C.sh` | PASS | | +| `./t0062-revision-walking.sh` | PASS | | +| `./t0030-stripspace.sh` | PASS | | +| `./t0066-dir-iterator.sh` | PASS | | +| `./t0067-parse_pathspec_file.sh` | PASS | | +| `./t0000-basic.sh` | PASS | | +| `./t0070-fundamental.sh` | PASS | | +| `./t0061-run-command.sh` | PASS | | +| `./t0021-conversion.sh` | PASS | | +| `./t0080-unit-test-output.sh` | PASS | | +| `./t0071-sort.sh` | PASS | | +| `./t0068-for-each-repo.sh` | PASS | | +| `./t0081-find-pack.sh` | PASS | | +| `./t0092-diagnose.sh` | PASS | | +| `./t0091-bugreport.sh` | PASS | | +| `./t0200-gettext-basic.sh` | PASS | | +| `./t0101-at-syntax.sh` | PASS | | +| `./t0095-bloom.sh` | PASS | | +| `./t0202-gettext-perl.sh` | SKIPPED | skipping perl interface tests, perl not available | +| `./t0204-gettext-reencode-sanity.sh` | PASS | | +| `./t0203-gettext-setlocale-sanity.sh` | PASS | | +| `./t0201-gettext-fallbacks.sh` | PASS | | +| `./t0100-previous.sh` | PASS | | +| `./t0213-trace2-ancestry.sh` | PASS | | +| `./t0210-trace2-normal.sh` | PASS | | +| `./t0212-trace2-event.sh` | PASS | | +| `./t0008-ignores.sh` | PASS | | +| `./t0090-cache-tree.sh` | PASS | | +| `./t0211-trace2-perf.sh` | PASS | | +| `./t0303-credential-external.sh` | PASS | | +| `./t0411-clone-from-partial.sh` | PASS | | +| `./t0301-credential-cache.sh` | FAIL | FAIL - credential-cache daemon cannot bind its Unix-domain socket in this execution sandbox (Operation not permitted). This does not matter for scope because the app does not persist real user credentials or teach credential-cache workflows; adding a daemon credential store would be security-sensitive mobile infrastructure, not GitHug gameplay. | +| `./t0500-progress-display.sh` | PASS | | +| `./t0060-path-utils.sh` | PASS | | +| `./t0300-credentials.sh` | PASS | | +| `./t0302-credential-store.sh` | PASS | | +| `./t0611-reftable-httpd.sh` | SKIPPED | skipping test, git built without http support | +| `./t0600-reffiles-backend.sh` | PASS | | +| `./t0612-reftable-jgit-compatibility.sh` | SKIPPED | skipping reftable JGit tests; JGit is not present in PATH | +| `./t0601-reffiles-pack-refs.sh` | PASS | | +| `./t0613-reftable-write-options.sh` | PASS | | +| `./t0614-reftable-fsck.sh` | PASS | | +| `./t0602-reffiles-fsck.sh` | PASS | | +| `./t1003-read-tree-prefix.sh` | PASS | | +| `./t0410-partial-clone.sh` | PASS | | +| `./t1001-read-tree-m-2way.sh` | PASS | | +| `./t1002-read-tree-m-u-2way.sh` | PASS | | +| `./t1000-read-tree-m-3way.sh` | PASS | | +| `./t1005-read-tree-reset.sh` | PASS | | +| `./t1007-hash-object.sh` | PASS | | +| `./t1009-read-tree-new-index.sh` | PASS | | +| `./t1008-read-tree-overlay.sh` | PASS | | +| `./t1004-read-tree-m-u-wf.sh` | PASS | | +| `./t1010-mktree.sh` | PASS | | +| `./t1012-read-tree-df.sh` | PASS | | +| `./t1014-read-tree-confusing.sh` | PASS | | +| `./t1016-compatObjectFormat.sh` | SKIPPED | interoperability requires a Git built with Rust | +| `./t1011-read-tree-sparse-checkout.sh` | PASS | | +| `./t1020-subdirectory.sh` | PASS | | +| `./t1022-read-tree-partial-clone.sh` | PASS | | +| `./t1015-read-index-unmerged.sh` | PASS | | +| `./t1051-large-conversion.sh` | PASS | | +| `./t0450-txt-doc-vs-help.sh` | PASS | | +| `./t1050-large.sh` | PASS | | +| `./t1060-object-corruption.sh` | PASS | | +| `./t1090-sparse-checkout-scope.sh` | PASS | | +| `./t1100-commit-tree-options.sh` | PASS | | +| `./t1301-shared-repo.sh` | PASS | | +| `./t1302-repo-version.sh` | PASS | | +| `./t1303-wacky-config.sh` | PASS | | +| `./t1304-default-acl.sh` | PASS | | +| `./t1006-cat-file.sh` | PASS | | +| `./t1306-xdg-files.sh` | PASS | | +| `./t1305-config-include.sh` | PASS | | +| `./t1307-config-blob.sh` | PASS | | +| `./t1309-early-config.sh` | PASS | | +| `./t1310-config-default.sh` | PASS | | +| `./t1311-config-optional.sh` | PASS | | +| `./t1350-config-hooks-path.sh` | PASS | | +| `./t1308-config-set.sh` | PASS | | +| `./t1401-symbolic-ref.sh` | PASS | | +| `./t1091-sparse-checkout-builtin.sh` | PASS | | +| `./t0610-reftable-basics.sh` | PASS | | +| `./t1402-check-ref-format.sh` | PASS | | +| `./t1403-show-ref.sh` | PASS | | +| `./t1405-main-ref-store.sh` | PASS | | +| `./t1407-worktree-ref-store.sh` | PASS | | +| `./t1406-submodule-ref-store.sh` | PASS | | +| `./t1404-update-ref-errors.sh` | PASS | | +| `./t1408-packed-refs.sh` | PASS | | +| `./t1409-avoid-packing-refs.sh` | PASS | | +| `./t1412-reflog-loop.sh` | PASS | | +| `./t1411-reflog-show.sh` | PASS | | +| `./t1413-reflog-detach.sh` | PASS | | +| `./t1414-reflog-walk.sh` | PASS | | +| `./t1415-worktree-refs.sh` | PASS | | +| `./t1416-ref-transaction-hooks.sh` | PASS | | +| `./t1418-reflog-exists.sh` | PASS | | +| `./t1417-reflog-updateref.sh` | PASS | | +| `./t1420-lost-found.sh` | PASS | | +| `./t1410-reflog.sh` | PASS | | +| `./t1419-exclude-refs.sh` | PASS | | +| `./t1422-show-ref-exists.sh` | PASS | | +| `./t1421-reflog-write.sh` | PASS | | +| `./t1430-bad-ref-name.sh` | PASS | | +| `./t1451-fsck-buffer.sh` | PASS | | +| `./t1300-config.sh` | PASS | | +| `./t1400-update-ref.sh` | PASS | | +| `./t1462-refs-exists.sh` | PASS | | +| `./t1423-ref-backend.sh` | PASS | | +| `./t1450-fsck.sh` | PASS | | +| `./t1460-refs-migrate.sh` | PASS | | +| `./t1463-refs-optimize.sh` | PASS | | +| `./t1502-rev-parse-parseopt.sh` | PASS | | +| `./t1503-rev-parse-verify.sh` | PASS | | +| `./t1500-rev-parse.sh` | PASS | | +| `./t1501-work-tree.sh` | PASS | | +| `./t1505-rev-parse-last.sh` | PASS | | +| `./t1504-ceiling-dirs.sh` | PASS | | +| `./t1509-root-work-tree.sh` | SKIPPED | Test requiring writable / skipped. Read this test if you want to run it | +| `./t1506-rev-parse-diagnosis.sh` | PASS | | +| `./t0027-auto-crlf.sh` | PASS | | +| `./t1508-at-combinations.sh` | PASS | | +| `./t1511-rev-parse-caret.sh` | PASS | | +| `./t1507-rev-parse-upstream.sh` | PASS | | +| `./t1513-rev-parse-prefix.sh` | PASS | | +| `./t1515-rev-parse-outside-repo.sh` | PASS | | +| `./t1514-rev-parse-push.sh` | PASS | | +| `./t1601-index-bogus.sh` | PASS | | +| `./t1512-rev-parse-disambiguation.sh` | PASS | | +| `./t1600-index.sh` | PASS | | +| `./t1461-refs-list.sh` | PASS | | +| `./t1013-read-tree-submodule.sh` | PASS | | +| `./t1700-split-index.sh` | PASS | | +| `./t2000-conflict-when-checking-files-out.sh` | PASS | | +| `./t2002-checkout-cache-u.sh` | PASS | | +| `./t2003-checkout-cache-mkdir.sh` | PASS | | +| `./t1900-repo-info.sh` | PASS | | +| `./t2005-checkout-index-symlinks.sh` | PASS | | +| `./t1901-repo-structure.sh` | PASS | | +| `./t2004-checkout-cache-temp.sh` | PASS | | +| `./t2006-checkout-index-basic.sh` | PASS | | +| `./t2008-checkout-subdir.sh` | PASS | | +| `./t2007-checkout-symlink.sh` | PASS | | +| `./t2009-checkout-statinfo.sh` | PASS | | +| `./t2010-checkout-ambiguous.sh` | PASS | | +| `./t2011-checkout-invalid-head.sh` | PASS | | +| `./t2014-checkout-switch.sh` | PASS | | +| `./t1800-hook.sh` | PASS | | +| `./t2015-checkout-unborn.sh` | PASS | | +| `./t2017-checkout-orphan.sh` | PASS | | +| `./t2012-checkout-last.sh` | PASS | | +| `./t2019-checkout-ambiguous-ref.sh` | PASS | | +| `./t2016-checkout-patch.sh` | PASS | | +| `./t2021-checkout-overwrite.sh` | PASS | | +| `./t2018-checkout-branch.sh` | PASS | | +| `./t2022-checkout-paths.sh` | PASS | | +| `./t1517-outside-repo.sh` | PASS | | +| `./t2023-checkout-m.sh` | PASS | | +| `./t2025-checkout-no-overlay.sh` | PASS | | +| `./t2020-checkout-detach.sh` | PASS | | +| `./t1510-repo-setup.sh` | PASS | | +| `./t2050-git-dir-relative.sh` | PASS | | +| `./t2026-checkout-pathspec-file.sh` | PASS | | +| `./t2027-checkout-track.sh` | PASS | | +| `./t2070-restore.sh` | PASS | | +| `./t2060-switch.sh` | PASS | | +| `./t2071-restore-patch.sh` | PASS | | +| `./t2024-checkout-dwim.sh` | PASS | | +| `./t2081-parallel-checkout-collisions.sh` | PASS | | +| `./t2072-restore-pathspec-file.sh` | PASS | | +| `./t2100-update-cache-badpath.sh` | PASS | | +| `./t2030-unresolve-info.sh` | PASS | | +| `./t2101-update-index-reupdate.sh` | PASS | | +| `./t2102-update-index-symlinks.sh` | PASS | | +| `./t2082-parallel-checkout-attributes.sh` | PASS | | +| `./t2104-update-index-skip-worktree.sh` | PASS | | +| `./t2105-update-index-gitfile.sh` | PASS | | +| `./t2106-update-index-assume-unchanged.sh` | PASS | | +| `./t2103-update-index-ignore-missing.sh` | PASS | | +| `./t1701-racy-split-index.sh` | PASS | | +| `./t2107-update-index-basic.sh` | PASS | | +| `./t2201-add-update-typechange.sh` | PASS | | +| `./t2108-update-index-refresh-racy.sh` | PASS | | +| `./t2202-add-addremove.sh` | PASS | | +| `./t2200-add-update.sh` | PASS | | +| `./t2205-add-worktree-config.sh` | PASS | | +| `./t2300-cd-to-toplevel.sh` | PASS | | +| `./t2204-add-ignored.sh` | PASS | | +| `./t2206-add-submodule-ignored.sh` | PASS | | +| `./t2203-add-intent.sh` | PASS | | +| `./t2401-worktree-prune.sh` | PASS | | +| `./t2404-worktree-config.sh` | PASS | | +| `./t2403-worktree-move.sh` | PASS | | +| `./t2405-worktree-submodule.sh` | PASS | | +| `./t2402-worktree-list.sh` | PASS | | +| `./t2080-parallel-checkout-basics.sh` | PASS | | +| `./t3000-ls-files-others.sh` | PASS | | +| `./t2406-worktree-repair.sh` | PASS | | +| `./t3001-ls-files-others-exclude.sh` | PASS | | +| `./t3002-ls-files-dashpath.sh` | PASS | | +| `./t3003-ls-files-exclude.sh` | PASS | | +| `./t3004-ls-files-basic.sh` | PASS | | +| `./t2407-worktree-heads.sh` | PASS | | +| `./t3005-ls-files-relative.sh` | PASS | | +| `./t3006-ls-files-long.sh` | PASS | | +| `./t3008-ls-files-lazy-init-name-hash.sh` | PASS | | +| `./t2500-untracked-overwriting.sh` | PASS | | +| `./t2501-cwd-empty.sh` | PASS | | +| `./t3009-ls-files-others-nonsubmodule.sh` | PASS | | +| `./t3010-ls-files-killed-modified.sh` | PASS | | +| `./t3020-ls-files-error-unmatch.sh` | PASS | | +| `./t3012-ls-files-dedup.sh` | PASS | | +| `./t3011-common-prefixes-and-directory-traversal.sh` | PASS | | +| `./t3013-ls-files-format.sh` | PASS | | +| `./t3050-subprojects-fetch.sh` | PASS | | +| `./t3060-ls-files-with-tree.sh` | PASS | | +| `./t3040-subprojects-basic.sh` | PASS | | +| `./t3007-ls-files-recurse-submodules.sh` | PASS | | +| `./t3102-ls-tree-wildcards.sh` | PASS | | +| `./t3103-ls-tree-misc.sh` | PASS | | +| `./t3101-ls-tree-dirname.sh` | PASS | | +| `./t3100-ls-tree-restrict.sh` | PASS | | +| `./t3104-ls-tree-format.sh` | PASS | | +| `./t3201-branch-contains.sh` | PASS | | +| `./t3105-ls-tree-output.sh` | PASS | | +| `./t3204-branch-name-interpretation.sh` | PASS | | +| `./t3205-branch-color.sh` | PASS | | +| `./t3203-branch-output.sh` | PASS | | +| `./t3202-show-branch.sh` | PASS | | +| `./t3211-peel-ref.sh` | PASS | | +| `./t3300-funny-names.sh` | PASS | | +| `./t3206-range-diff.sh` | PASS | | +| `./t3302-notes-index-expensive.sh` | PASS | | +| `./t3207-branch-submodule.sh` | PASS | | +| `./t3304-notes-mixed.sh` | PASS | | +| `./t3303-notes-subtrees.sh` | PASS | | +| `./t3306-notes-prune.sh` | PASS | | +| `./t3307-notes-man.sh` | PASS | | +| `./t3200-branch.sh` | PASS | | +| `./t3308-notes-merge.sh` | PASS | | +| `./t1092-sparse-checkout-compatibility.sh` | PASS | | +| `./t3301-notes.sh` | PASS | | +| `./t3310-notes-merge-manual-resolve.sh` | PASS | | +| `./t3320-notes-merge-worktrees.sh` | PASS | | +| `./t3309-notes-merge-auto-resolve.sh` | PASS | | +| `./t2013-checkout-submodule.sh` | PASS | | +| `./t3401-rebase-and-am-rename.sh` | PASS | | +| `./t3321-notes-stripspace.sh` | PASS | | +| `./t3402-rebase-merge.sh` | PASS | | +| `./t3405-rebase-malformed.sh` | PASS | | +| `./t3403-rebase-skip.sh` | PASS | | +| `./t3400-rebase.sh` | PASS | | +| `./t2400-worktree-add.sh` | PASS | | +| `./t3408-rebase-multi-line.sh` | PASS | | +| `./t3407-rebase-abort.sh` | PASS | | +| `./t3409-rebase-environ.sh` | PASS | | +| `./t3412-rebase-root.sh` | PASS | | +| `./t3413-rebase-hook.sh` | PASS | | +| `./t3406-rebase-message.sh` | PASS | | +| `./t3417-rebase-whitespace-fix.sh` | PASS | | +| `./t3419-rebase-patch-id.sh` | PASS | | +| `./t3416-rebase-onto-threedots.sh` | PASS | | +| `./t3311-notes-merge-fanout.sh` | PASS | | +| `./t3070-wildmatch.sh` | PASS | | +| `./t3423-rebase-reword.sh` | PASS | | +| `./t3422-rebase-incompatible-options.sh` | PASS | | +| `./t3418-rebase-continue.sh` | PASS | | +| `./t3415-rebase-autosquash.sh` | PASS | | +| `./t3424-rebase-empty.sh` | PASS | | +| `./t3427-rebase-subtree.sh` | PASS | | +| `./t3425-rebase-topology-merges.sh` | PASS | | +| `./t3428-rebase-signoff.sh` | PASS | | +| `./t3429-rebase-edit-todo.sh` | PASS | | +| `./t3421-rebase-topology-linear.sh` | PASS | | +| `./t3420-rebase-autostash.sh` | PASS | | +| `./t3434-rebase-i18n.sh` | SKIPPED | skipping rebase i18n tests; iconv not available | +| `./t3435-rebase-gpg-sign.sh` | SKIPPED | skip all test rebase --[no-]gpg-sign, gpg not available | +| `./t3433-rebase-across-mode-change.sh` | PASS | | +| `./t3431-rebase-fork-point.sh` | PASS | | +| `./t3438-rebase-broken-files.sh` | PASS | | +| `./t3305-notes-fanout.sh` | PASS | | +| `./t3450-history.sh` | PASS | | +| `./t3436-rebase-more-options.sh` | PASS | | +| `./t3440-rebase-trailer.sh` | PASS | | +| `./t3437-rebase-fixup-options.sh` | PASS | | +| `./t3500-cherry.sh` | PASS | | +| `./t3430-rebase-merges.sh` | PASS | | +| `./t3502-cherry-pick-merge.sh` | PASS | | +| `./t3503-cherry-pick-root.sh` | PASS | | +| `./t3501-revert-cherry-pick.sh` | PASS | | +| `./t3451-history-reword.sh` | PASS | | +| `./t3504-cherry-pick-rerere.sh` | PASS | | +| `./t3506-cherry-pick-ff.sh` | PASS | | +| `./t3404-rebase-interactive.sh` | PASS | | +| `./t3505-cherry-pick-empty.sh` | PASS | | +| `./t3509-cherry-pick-merge-df.sh` | PASS | | +| `./t3452-history-split.sh` | PASS | | +| `./t3508-cherry-pick-many-commits.sh` | PASS | | +| `./t3514-cherry-pick-revert-gpg.sh` | SKIPPED | skip all test {cherry-pick,revert} --[no-]gpg-sign, gpg not available | +| `./t3511-cherry-pick-x.sh` | PASS | | +| `./t3601-rm-pathspec-file.sh` | PASS | | +| `./t3507-cherry-pick-conflict.sh` | PASS | | +| `./t3602-rm-sparse-checkout.sh` | PASS | | +| `./t3426-rebase-submodule.sh` | PASS | | +| `./t3650-replay-basics.sh` | PASS | | +| `./t3510-cherry-pick-sequence.sh` | PASS | | +| `./t3702-add-edit.sh` | PASS | | +| `./t3703-add-magic-pathspec.sh` | PASS | | +| `./t3700-add.sh` | PASS | | +| `./t3704-add-pathspec-file.sh` | PASS | | +| `./t3900-i18n-commit.sh` | SKIPPED | skipping commit i18n tests; iconv not available | +| `./t3901-i18n-patch.sh` | SKIPPED | skipping patch i18n tests; iconv not available | +| `./t3902-quoted.sh` | PASS | | +| `./t3705-add-sparse-checkout.sh` | PASS | | +| `./t3512-cherry-pick-submodule.sh` | PASS | | +| `./t3513-revert-submodule.sh` | PASS | | +| `./t3904-stash-patch.sh` | PASS | | +| `./t3800-mktag.sh` | PASS | | +| `./t3908-stash-in-worktree.sh` | PASS | | +| `./t3907-stash-show-config.sh` | PASS | | +| `./t3910-mac-os-precompose.sh` | SKIPPED | filesystem does not corrupt utf-8 | +| `./t3905-stash-include-untracked.sh` | PASS | | +| `./t3909-stash-pathspec-file.sh` | PASS | | +| `./t3600-rm.sh` | PASS | | +| `./t3920-crlf-messages.sh` | PASS | | +| `./t3432-rebase-fast-forward.sh` | PASS | | +| `./t4000-diff-format.sh` | PASS | | +| `./t4003-diff-rename-1.sh` | PASS | | +| `./t4004-diff-rename-symlink.sh` | PASS | | +| `./t4001-diff-rename.sh` | PASS | | +| `./t4005-diff-rename-2.sh` | PASS | | +| `./t4006-diff-mode.sh` | PASS | | +| `./t4007-rename-3.sh` | PASS | | +| `./t4008-diff-break-rewrite.sh` | PASS | | +| `./t4009-diff-rename-4.sh` | PASS | | +| `./t4002-diff-basic.sh` | PASS | | +| `./t4011-diff-symlink.sh` | PASS | | +| `./t3701-add-interactive.sh` | PASS | | +| `./t4010-diff-pathspec.sh` | PASS | | +| `./t4012-diff-binary.sh` | PASS | | +| `./t4016-diff-quote.sh` | PASS | | +| `./t4017-diff-retval.sh` | PASS | | +| `./t4019-diff-wserror.sh` | PASS | | +| `./t4021-format-patch-numbered.sh` | PASS | | +| `./t4022-diff-rewrite.sh` | PASS | | +| `./t4023-diff-rename-typechange.sh` | PASS | | +| `./t3906-stash-submodule.sh` | PASS | | +| `./t4025-hunk-header.sh` | PASS | | +| `./t4024-diff-optimize-common.sh` | PASS | | +| `./t4026-color.sh` | PASS | | +| `./t4028-format-patch-mime-headers.sh` | PASS | | +| `./t4029-diff-trailing-space.sh` | PASS | | +| `./t4027-diff-submodule.sh` | PASS | | +| `./t4031-diff-rewrite-binary.sh` | PASS | | +| `./t4030-diff-textconv.sh` | PASS | | +| `./t4020-diff-external.sh` | PASS | | +| `./t4033-diff-patience.sh` | PASS | | +| `./t4032-diff-inter-hunk-context.sh` | PASS | | +| `./t4035-diff-quiet.sh` | PASS | | +| `./t4036-format-patch-signer-mime.sh` | PASS | | +| `./t4037-diff-r-t-dirs.sh` | PASS | | +| `./t4039-diff-assume-unchanged.sh` | PASS | | +| `./t4040-whitespace-status.sh` | PASS | | +| `./t4015-diff-whitespace.sh` | PASS | | +| `./t4042-diff-textconv-caching.sh` | PASS | | +| `./t4043-diff-rename-binary.sh` | PASS | | +| `./t4044-diff-index-unique-abbrev.sh` | PASS | | +| `./t4041-diff-submodule-option.sh` | PASS | | +| `./t4038-diff-combined.sh` | PASS | | +| `./t4046-diff-unmerged.sh` | PASS | | +| `./t3903-stash.sh` | PASS | | +| `./t4034-diff-words.sh` | PASS | | +| `./t4049-diff-stat-count.sh` | PASS | | +| `./t4050-diff-histogram.sh` | PASS | | +| `./t4048-diff-combined-binary.sh` | PASS | | +| `./t4045-diff-relative.sh` | PASS | | +| `./t4054-diff-bogus-tree.sh` | PASS | | +| `./t4051-diff-function-context.sh` | PASS | | +| `./t4047-diff-dirstat.sh` | PASS | | +| `./t4053-diff-no-index.sh` | PASS | | +| `./t4055-diff-context.sh` | PASS | | +| `./t4014-format-patch.sh` | PASS | | +| `./t4058-diff-duplicates.sh` | PASS | | +| `./t4056-diff-order.sh` | PASS | | +| `./t4057-diff-combined-paths.sh` | PASS | | +| `./t4013-diff-various.sh` | PASS | | +| `./t4052-stat-output.sh` | PASS | | +| `./t4059-diff-submodule-not-initialized.sh` | PASS | | +| `./t4062-diff-pickaxe.sh` | PASS | | +| `./t4063-diff-blobs.sh` | PASS | | +| `./t4066-diff-emit-delay.sh` | PASS | | +| `./t4065-diff-anchored.sh` | PASS | | +| `./t4064-diff-oidfind.sh` | PASS | | +| `./t4018-diff-funcname.sh` | PASS | | +| `./t4061-diff-indent.sh` | PASS | | +| `./t4071-diff-minimal.sh` | PASS | | +| `./t4070-diff-pairs.sh` | PASS | | +| `./t4073-diff-stat-name-width.sh` | PASS | | +| `./t4068-diff-symmetric-merge-base.sh` | PASS | | +| `./t4074-diff-shifted-matched-group.sh` | PASS | | +| `./t4069-remerge-diff.sh` | PASS | | +| `./t4060-diff-submodule-option-diff-format.sh` | PASS | | +| `./t4102-apply-rename.sh` | PASS | | +| `./t4100-apply-stat.sh` | PASS | | +| `./t4105-apply-fuzz.sh` | PASS | | +| `./t4106-apply-stdin.sh` | PASS | | +| `./t4101-apply-nonl.sh` | PASS | | +| `./t4072-diff-max-depth.sh` | PASS | | +| `./t4107-apply-ignore-whitespace.sh` | PASS | | +| `./t4067-diff-partial-clone.sh` | PASS | | +| `./t4110-apply-scan.sh` | PASS | | +| `./t4109-apply-multifrag.sh` | PASS | | +| `./t4103-apply-binary.sh` | PASS | | +| `./t4112-apply-renames.sh` | PASS | | +| `./t4113-apply-ending.sh` | PASS | | +| `./t4104-apply-boundary.sh` | PASS | | +| `./t4118-apply-empty-context.sh` | PASS | | +| `./t4117-apply-reject.sh` | PASS | | +| `./t4115-apply-symlink.sh` | PASS | | +| `./t4111-apply-subdir.sh` | PASS | | +| `./t4116-apply-reverse.sh` | PASS | | +| `./t4114-apply-typechange.sh` | PASS | | +| `./t4119-apply-config.sh` | PASS | | +| `./t4123-apply-shrink.sh` | PASS | | +| `./t4121-apply-diffs.sh` | PASS | | +| `./t4120-apply-popt.sh` | PASS | | +| `./t4125-apply-ws-fuzz.sh` | PASS | | +| `./t4126-apply-empty.sh` | PASS | | +| `./t4122-apply-symlink-inside.sh` | PASS | | +| `./t4130-apply-criss-cross-rename.sh` | PASS | | +| `./t4127-apply-same-fn.sh` | PASS | | +| `./t4128-apply-root.sh` | PASS | | +| `./t4108-apply-threeway.sh` | PASS | | +| `./t4131-apply-fake-ancestor.sh` | PASS | | +| `./t4134-apply-submodule.sh` | PASS | | +| `./t4133-apply-filenames.sh` | PASS | | +| `./t4136-apply-check.sh` | PASS | | +| `./t4132-apply-removal.sh` | PASS | | +| `./t4138-apply-ws-expansion.sh` | PASS | | +| `./t4141-apply-too-large.sh` | PASS | | +| `./t4139-apply-escape.sh` | PASS | | +| `./t4140-apply-ita.sh` | PASS | | +| `./t4135-apply-weird-filenames.sh` | PASS | | +| `./t4152-am-subjects.sh` | PASS | | +| `./t4129-apply-samemode.sh` | PASS | | +| `./t4153-am-resume-override-opts.sh` | PASS | | +| `./t4151-am-abort.sh` | PASS | | +| `./t4201-shortlog.sh` | PASS | | +| `./t4124-apply-ws-rule.sh` | PASS | | +| `./t4206-log-follow-harder-copies.sh` | PASS | | +| `./t4207-log-decoration-colors.sh` | PASS | | +| `./t4200-rerere.sh` | PASS | | +| `./t4204-patch-id.sh` | PASS | | +| `./t4210-log-i18n.sh` | SKIPPED | skipping log i18n tests; iconv not available | +| `./t4208-log-magic-pathspec.sh` | PASS | | +| `./t4203-mailmap.sh` | PASS | | +| `./t4212-log-corrupt.sh` | PASS | | +| `./t4209-log-pickaxe.sh` | PASS | | +| `./t4205-log-pretty-formats.sh` | PASS | | +| `./t4213-log-tabexpand.sh` | PASS | | +| `./t4214-log-graph-octopus.sh` | PASS | | +| `./t4217-log-limit.sh` | PASS | | +| `./t4202-log.sh` | PASS | | +| `./t4150-am.sh` | PASS | | +| `./t4252-am-options.sh` | PASS | | +| `./t4254-am-corrupt.sh` | SKIPPED | skipping am encoding corruption tests; iconv not available | +| `./t4256-am-format-flowed.sh` | PASS | | +| `./t4253-am-keep-cr-dos.sh` | PASS | | +| `./t4211-line-log.sh` | PASS | | +| `./t4257-am-interactive.sh` | PASS | | +| `./t4258-am-quoted-cr.sh` | PASS | | +| `./t5001-archive-attr.sh` | PASS | | +| `./t5002-archive-attr-pattern.sh` | PASS | | +| `./t5000-tar-tree.sh` | PASS | | +| `./t4300-merge-tree.sh` | PASS | | +| `./t4215-log-skewed-merges.sh` | PASS | | +| `./t5003-archive-zip.sh` | PASS | | +| `./t4137-apply-submodule.sh` | PASS | | +| `./t5200-update-server-info.sh` | PASS | | +| `./t4301-merge-tree-write-tree.sh` | PASS | | +| `./t5004-archive-corner-cases.sh` | PASS | | +| `./t5301-sliding-window.sh` | PASS | | +| `./t5150-request-pull.sh` | PASS | | +| `./t5303-pack-corruption-resilience.sh` | PASS | | +| `./t5100-mailinfo.sh` | PASS | | +| `./t5305-include-tag.sh` | PASS | | +| `./t5306-pack-nobase.sh` | PASS | | +| `./t5307-pack-missing-commit.sh` | PASS | | +| `./t5308-pack-detect-duplicates.sh` | PASS | | +| `./t5309-pack-delta-cycles.sh` | PASS | | +| `./t5304-prune.sh` | PASS | | +| `./t5311-pack-bitmaps-shallow.sh` | PASS | | +| `./t5312-prune-corruption.sh` | PASS | | +| `./t5315-pack-objects-compression.sh` | PASS | | +| `./t5314-pack-cycle-detection.sh` | PASS | | +| `./t5313-pack-bounds-checks.sh` | PASS | | +| `./t5316-pack-delta-depth.sh` | PASS | | +| `./t5317-pack-objects-filter-objects.sh` | PASS | | +| `./t5320-delta-islands.sh` | PASS | | +| `./t5321-pack-large-objects.sh` | PASS | | +| `./t5302-pack-index.sh` | PASS | | +| `./t5322-pack-objects-sparse.sh` | PASS | | +| `./t5300-pack-object.sh` | PASS | | +| `./t5323-pack-redundant.sh` | PASS | | +| `./t5325-reverse-index.sh` | PASS | | +| `./t4216-log-bloom.sh` | PASS | | +| `./t5328-commit-graph-64bit-time.sh` | PASS | | +| `./t4255-am-submodule.sh` | PASS | | +| `./t5330-no-lazy-fetch-with-commit-graph.sh` | PASS | | +| `./t5318-commit-graph.sh` | PASS | | +| `./t5319-multi-pack-index.sh` | PASS | | +| `./t5332-multi-pack-reuse.sh` | PASS | | +| `./t5331-pack-objects-stdin.sh` | PASS | | +| `./t5329-pack-objects-cruft.sh` | PASS | | +| `./t5334-incremental-multi-pack-index.sh` | PASS | | +| `./t5351-unpack-large-objects.sh` | PASS | | +| `./t5401-update-hooks.sh` | PASS | | +| `./t5335-compact-multi-pack-index.sh` | PASS | | +| `./t5333-pseudo-merge-bitmaps.sh` | PASS | | +| `./t5402-post-merge-hook.sh` | PASS | | +| `./t5310-pack-bitmaps.sh` | PASS | | +| `./t5405-send-pack-rewind.sh` | PASS | | +| `./t5406-remote-rejects.sh` | PASS | | +| `./t5404-tracking-branches.sh` | PASS | | +| `./t5403-post-checkout-hook.sh` | PASS | | +| `./t5408-send-pack-stdin.sh` | PASS | | +| `./t5409-colorize-remote-messages.sh` | PASS | | +| `./t5410-receive-pack.sh` | PASS | | +| `./t5324-split-commit-graph.sh` | PASS | | +| `./t5407-post-rewrite-hook.sh` | PASS | | +| `./t5502-quickfetch.sh` | PASS | | +| `./t5503-tagfollow.sh` | PASS | | +| `./t5327-multi-pack-bitmaps-rev.sh` | PASS | | +| `./t5501-fetch-push-alternates.sh` | PASS | | +| `./t5400-send-pack.sh` | PASS | | +| `./t5506-remote-groups.sh` | PASS | | +| `./t5507-remote-environment.sh` | PASS | | +| `./t5504-fetch-receive-strict.sh` | PASS | | +| `./t5509-fetch-push-namespaces.sh` | PASS | | +| `./t5513-fetch-track.sh` | PASS | | +| `./t5512-ls-remote.sh` | PASS | | +| `./t5511-refspec.sh` | PASS | | +| `./t5411-proc-receive-hook.sh` | PASS | | +| `./t5326-multi-pack-bitmaps.sh` | PASS | | +| `./t5518-fetch-exit-status.sh` | PASS | | +| `./t5519-push-alternates.sh` | PASS | | +| `./t5514-fetch-multiple.sh` | PASS | | +| `./t5517-push-mirror.sh` | PASS | | +| `./t5522-pull-symlink.sh` | PASS | | +| `./t5505-remote.sh` | PASS | | +| `./t5523-push-upstream.sh` | PASS | | +| `./t5524-pull-msg.sh` | PASS | | +| `./t5521-pull-options.sh` | PASS | | +| `./t5525-fetch-tagopt.sh` | PASS | | +| `./t5527-fetch-odd-refs.sh` | PASS | | +| `./t5529-push-errors.sh` | PASS | | +| `./t5530-upload-pack-error.sh` | PASS | | +| `./t5528-push-default.sh` | PASS | | +| `./t5532-fetch-proxy.sh` | PASS | | +| `./t5500-fetch-pack.sh` | PASS | | +| `./t5515-fetch-merge-logic.sh` | PASS | | +| `./t5534-push-signed.sh` | PASS | | +| `./t5535-fetch-push-symref.sh` | PASS | | +| `./t5536-fetch-conflicts.sh` | PASS | | +| `./t5531-deep-submodule-push.sh` | PASS | | +| `./t5539-fetch-http-shallow.sh` | SKIPPED | skipping test, git built without http support | +| `./t5540-http-push-webdav.sh` | SKIPPED | skipping test, git built without http support | +| `./t5541-http-push-smart.sh` | SKIPPED | skipping test, git built without http support | +| `./t5520-pull.sh` | PASS | | +| `./t5542-push-http-shallow.sh` | SKIPPED | skipping test, git built without http support | +| `./t5538-push-shallow.sh` | PASS | | +| `./t5537-fetch-shallow.sh` | PASS | | +| `./t5544-pack-objects-hook.sh` | PASS | | +| `./t5546-receive-limits.sh` | PASS | | +| `./t5547-push-quarantine.sh` | PASS | | +| `./t5549-fetch-push-http.sh` | SKIPPED | skipping test, git built without http support | +| `./t5550-http-fetch-dumb.sh` | SKIPPED | skipping test, git built without http support | +| `./t5551-http-fetch-smart.sh` | SKIPPED | skipping test, git built without http support | +| `./t5548-push-porcelain.sh` | PASS | | +| `./t5543-atomic-push.sh` | PASS | | +| `./t5545-push-options.sh` | PASS | | +| `./t5554-noop-fetch-negotiator.sh` | PASS | | +| `./t5557-http-get.sh` | SKIPPED | skipping test, git built without http support | +| `./t5555-http-smart-common.sh` | PASS | | +| `./t5559-http-fetch-smart-http2.sh` | SKIPPED | skipping test, git built without http support | +| `./t5533-push-cas.sh` | PASS | | +| `./t5553-set-upstream.sh` | PASS | | +| `./t5561-http-backend.sh` | SKIPPED | skipping test, git built without http support | +| `./t5563-simple-http-auth.sh` | SKIPPED | skipping test, git built without http support | +| `./t5564-http-proxy.sh` | SKIPPED | skipping test, git built without http support | +| `./t5560-http-backend-noserver.sh` | PASS | | +| `./t5562-http-backend-content-length.sh` | PASS | | +| `./t5558-clone-bundle-uri.sh` | PASS | | +| `./t5565-push-multiple.sh` | PASS | | +| `./t5570-git-daemon.sh` | PASS | | +| `./t5573-pull-verify-signatures.sh` | PASS | | +| `./t5580-unc-paths.sh` | SKIPPED | skipping Windows-only path tests | +| `./t5581-http-curl-verbose.sh` | SKIPPED | skipping test, git built without http support | +| `./t5526-fetch-submodules.sh` | PASS | | +| `./t5571-pre-push-hook.sh` | PASS | | +| `./t5584-http-429-retry.sh` | SKIPPED | skipping test, git built without http support | +| `./t5583-push-branches.sh` | PASS | | +| `./t5600-clone-fail-cleanup.sh` | PASS | | +| `./t5582-fetch-negative-refspec.sh` | PASS | | +| `./t5602-clone-remote-exec.sh` | PASS | | +| `./t5574-fetch-output.sh` | PASS | | +| `./t5510-fetch.sh` | PASS | | +| `./t5516-fetch-push.sh` | PASS | | +| `./t5605-clone-local.sh` | PASS | | +| `./t5608-clone-2gb.sh` | SKIPPED | expensive 2GB clone test; enable with GIT_TEST_CLONE_2GB=true | +| `./t5609-clone-branch.sh` | PASS | | +| `./t5603-clone-dirname.sh` | PASS | | +| `./t5607-clone-bundle.sh` | PASS | | +| `./t5606-clone-options.sh` | PASS | | +| `./t5604-clone-reference.sh` | PASS | | +| `./t5610-clone-detached.sh` | PASS | | +| `./t5611-clone-config.sh` | PASS | | +| `./t5615-alternate-env.sh` | PASS | | +| `./t5613-info-alternate.sh` | PASS | | +| `./t5618-alternate-refs.sh` | PASS | | +| `./t5552-skipping-fetch-negotiator.sh` | PASS | | +| `./t5612-clone-refspec.sh` | PASS | | +| `./t5619-clone-local-ambiguous-transport.sh` | SKIPPED | skipping test, git built without http support | +| `./t5700-protocol-v1.sh` | SKIPPED | git daemon failed to start | +| `./t5621-clone-revision.sh` | PASS | | +| `./t5702-protocol-v2.sh` | SKIPPED | git daemon failed to start | +| `./t5614-clone-submodules-shallow.sh` | PASS | | +| `./t5701-git-serve.sh` | PASS | | +| `./t5617-clone-submodules-remote.sh` | PASS | | +| `./t5704-protocol-violations.sh` | PASS | | +| `./t5730-protocol-v2-bundle-uri-file.sh` | PASS | | +| `./t5731-protocol-v2-bundle-uri-git.sh` | SKIPPED | git daemon failed to start | +| `./t5732-protocol-v2-bundle-uri-http.sh` | SKIPPED | skipping test, git built without http support | +| `./t5601-clone.sh` | PASS | | +| `./t5705-session-id-in-capabilities.sh` | PASS | | +| `./t5620-backfill.sh` | PASS | | +| `./t5750-bundle-uri-parse.sh` | PASS | | +| `./t5811-proto-disable-git.sh` | SKIPPED | git daemon failed to start | +| `./t5703-upload-pack-ref-in-want.sh` | PASS | | +| `./t5812-proto-disable-http.sh` | SKIPPED | skipping test, git built without http support | +| `./t5802-connect-helper.sh` | PASS | | +| `./t5810-proto-disable-local.sh` | PASS | | +| `./t5814-proto-disable-ext.sh` | PASS | | +| `./t5815-submodule-protos.sh` | PASS | | +| `./t5710-promisor-remote-capability.sh` | PASS | | +| `./t6001-rev-list-graft.sh` | PASS | | +| `./t5813-proto-disable-ssh.sh` | PASS | | +| `./t5900-repo-selection.sh` | PASS | | +| `./t6000-rev-list-misc.sh` | PASS | | +| `./t5801-remote-helpers.sh` | PASS | | +| `./t6004-rev-list-path-optim.sh` | PASS | | +| `./t6005-rev-list-count.sh` | PASS | | +| `./t6008-rev-list-submodule.sh` | PASS | | +| `./t6007-rev-list-cherry-pick-file.sh` | PASS | | +| `./t6006-rev-list-format.sh` | PASS | | +| `./t6011-rev-list-with-bad-commit.sh` | PASS | | +| `./t6013-rev-list-reverse-parents.sh` | PASS | | +| `./t6003-rev-list-topo-order.sh` | PASS | | +| `./t6002-rev-list-bisect.sh` | PASS | | +| `./t6014-rev-list-all.sh` | PASS | | +| `./t6009-rev-list-parent.sh` | PASS | | +| `./t6016-rev-list-graph-simplify-history.sh` | PASS | | +| `./t6010-merge-base.sh` | PASS | | +| `./t5616-partial-clone.sh` | PASS | | +| `./t6012-rev-list-simplify.sh` | PASS | | +| `./t6019-rev-list-ancestry-path.sh` | PASS | | +| `./t6017-rev-list-stdin.sh` | PASS | | +| `./t6021-rev-list-exclude-hidden.sh` | PASS | | +| `./t6018-rev-list-glob.sh` | PASS | | +| `./t6060-merge-index.sh` | PASS | | +| `./t6100-rev-list-in-order.sh` | PASS | | +| `./t6022-rev-list-missing.sh` | PASS | | +| `./t6102-rev-list-unexpected-objects.sh` | PASS | | +| `./t6050-replace.sh` | PASS | | +| `./t6110-rev-list-sparse.sh` | PASS | | +| `./t6020-bundle-misc.sh` | PASS | | +| `./t6101-rev-parse-parents.sh` | PASS | | +| `./t6040-tracking-info.sh` | PASS | | +| `./t6113-rev-list-bitmap-filters.sh` | PASS | | +| `./t6114-keep-packs.sh` | PASS | | +| `./t6115-rev-list-du.sh` | PASS | | +| `./t6130-pathspec-noglob.sh` | PASS | | +| `./t6131-pathspec-icase.sh` | PASS | | +| `./t6112-rev-list-filters-objects.sh` | PASS | | +| `./t6133-pathspec-rev-dwim.sh` | PASS | | +| `./t6111-rev-list-treesame.sh` | PASS | | +| `./t6134-pathspec-in-submodule.sh` | PASS | | +| `./t6136-pathspec-in-bare.sh` | PASS | | +| `./t6132-pathspec-exclude.sh` | PASS | | +| `./t6135-pathspec-with-attrs.sh` | PASS | | +| `./t6137-pathspec-wildcards-literal.sh` | PASS | | +| `./t6301-for-each-ref-errors.sh` | PASS | | +| `./t6030-bisect-porcelain.sh` | PASS | | +| `./t6401-merge-criss-cross.sh` | PASS | | +| `./t6400-merge-df.sh` | PASS | | +| `./t6041-bisect-submodule.sh` | PASS | | +| `./t6302-for-each-ref-filter.sh` | PASS | | +| `./t6403-merge-file.sh` | PASS | | +| `./t6200-fmt-merge-msg.sh` | PASS | | +| `./t6120-describe.sh` | PASS | | +| `./t6404-recursive-merge.sh` | PASS | | +| `./t6405-merge-symlinks.sh` | PASS | | +| `./t6408-merge-up-to-date.sh` | PASS | | +| `./t6407-merge-binary.sh` | PASS | | +| `./t6413-merge-crlf.sh` | PASS | | +| `./t6406-merge-attr.sh` | PASS | | +| `./t6409-merge-subtree.sh` | PASS | | +| `./t6411-merge-filemode.sh` | PASS | | +| `./t6414-merge-rename-nocruft.sh` | PASS | | +| `./t6412-merge-large-rename.sh` | PASS | | +| `./t6417-merge-ours-theirs.sh` | PASS | | +| `./t6418-merge-text-auto.sh` | PASS | | +| `./t6415-merge-dir-to-symlink.sh` | PASS | | +| `./t6419-merge-ignorecase.sh` | SKIPPED | skipping case insensitive tests - case sensitive file system | +| `./t5572-pull-submodule.sh` | PASS | | +| `./t6402-merge-rename.sh` | PASS | | +| `./t6421-merge-partial-clone.sh` | PASS | | +| `./t6425-merge-rename-delete.sh` | PASS | | +| `./t6428-merge-conflicts-sparse.sh` | PASS | | +| `./t6427-diff3-conflict-markers.sh` | PASS | | +| `./t6424-merge-unrelated-index-changes.sh` | PASS | | +| `./t6300-for-each-ref.sh` | PASS | | +| `./t6431-merge-criscross.sh` | PASS | | +| `./t6432-merge-recursive-space-options.sh` | PASS | | +| `./t6426-merge-skip-unneeded-updates.sh` | PASS | | +| `./t6429-merge-sequence-rename-caching.sh` | PASS | | +| `./t6435-merge-sparse.sh` | PASS | | +| `./t6430-merge-recursive.sh` | PASS | | +| `./t6416-recursive-corner-cases.sh` | PASS | | +| `./t6436-merge-overwrite.sh` | PASS | | +| `./t6434-merge-recursive-rename-options.sh` | PASS | | +| `./t6422-merge-rename-corner-cases.sh` | PASS | | +| `./t6433-merge-toplevel.sh` | PASS | | +| `./t6439-merge-co-error-msgs.sh` | PASS | | +| `./t6700-tree-depth.sh` | PASS | | +| `./t6501-freshen-objects.sh` | PASS | | +| `./t6601-path-walk.sh` | PASS | | +| `./t6437-submodule-merge.sh` | PASS | | +| `./t7002-mv-sparse-checkout.sh` | PASS | | +| `./t6500-gc.sh` | PASS | | +| `./t7005-editor.sh` | PASS | | +| `./t7006-pager.sh` | PASS | | +| `./t7007-show.sh` | PASS | | +| `./t7001-mv.sh` | PASS | | +| `./t7010-setup.sh` | PASS | | +| `./t7011-skip-worktree-reading.sh` | PASS | | +| `./t7008-filter-branch-null-sha1.sh` | PASS | | +| `./t7030-verify-tag.sh` | PASS | | +| `./t7012-skip-worktree-writing.sh` | PASS | | +| `./t7061-wtstatus-ignore.sh` | PASS | | +| `./t7062-wtstatus-ignorecase.sh` | PASS | | +| `./t7060-wtstatus.sh` | PASS | | +| `./t7004-tag.sh` | PASS | | +| `./t7101-reset-empty-subdirs.sh` | PASS | | +| `./t7031-verify-tag-signed-ssh.sh` | PASS | | +| `./t7103-reset-bare.sh` | PASS | | +| `./t7104-reset-hard.sh` | PASS | | +| `./t6600-test-reach.sh` | PASS | | +| `./t7105-reset-patch.sh` | PASS | | +| `./t7064-wtstatus-pv2.sh` | PASS | | +| `./t7106-reset-unborn-branch.sh` | PASS | | +| `./t7102-reset.sh` | PASS | | +| `./t7107-reset-pathspec-file.sh` | PASS | | +| `./t7113-post-index-change-hook.sh` | PASS | | +| `./t7110-reset-merge.sh` | PASS | | +| `./t7111-reset-table.sh` | PASS | | +| `./t7301-clean-interactive.sh` | PASS | | +| `./t7300-clean.sh` | PASS | | +| `./t7063-status-untracked-cache.sh` | PASS | | +| `./t7201-co.sh` | PASS | | +| `./t6423-merge-rename-directories.sh` | PASS | | +| `./t7402-submodule-rebase.sh` | PASS | | +| `./t7401-submodule-summary.sh` | PASS | | +| `./t7403-submodule-sync.sh` | PASS | | +| `./t7409-submodule-detached-work-tree.sh` | PASS | | +| `./t7003-filter-branch.sh` | PASS | | +| `./t7411-submodule-config.sh` | PASS | | +| `./t7408-submodule-reference.sh` | PASS | | +| `./t7414-submodule-mistakes.sh` | PASS | | +| `./t7412-submodule-absorbgitdirs.sh` | PASS | | +| `./t7413-submodule-is-active.sh` | PASS | | +| `./t7417-submodule-path-url.sh` | PASS | | +| `./t7407-submodule-foreach.sh` | PASS | | +| `./t6438-submodule-directory-file-conflicts.sh` | PASS | | +| `./t7416-submodule-dash-url.sh` | PASS | | +| `./t7420-submodule-set-url.sh` | PASS | | +| `./t7418-submodule-sparse-gitmodules.sh` | PASS | | +| `./t7421-submodule-summary-add.sh` | PASS | | +| `./t7419-submodule-set-branch.sh` | PASS | | +| `./t7423-submodule-symlinks.sh` | PASS | | +| `./t7426-submodule-get-default-remote.sh` | PASS | | +| `./t7424-submodule-mixed-ref-formats.sh` | PASS | | +| `./t7422-submodule-output.sh` | PASS | | +| `./t7450-bad-git-dotfiles.sh` | PASS | | +| `./t7503-pre-commit-and-pre-merge-commit-hooks.sh` | PASS | | +| `./t7500-commit-template-squash-signoff.sh` | PASS | | +| `./t7501-commit-basic-functionality.sh` | PASS | | +| `./t7425-submodule-gitdir-path-extension.sh` | PASS | | +| `./t7504-commit-msg-hook.sh` | PASS | | +| `./t7406-submodule-update.sh` | PASS | | +| `./t7502-commit-porcelain.sh` | PASS | | +| `./t7509-commit-authorship.sh` | PASS | | +| `./t7510-signed-commit.sh` | PASS | | +| `./t7506-status-submodule.sh` | PASS | | +| `./t7507-commit-verbose.sh` | PASS | | +| `./t7505-prepare-commit-msg-hook.sh` | PASS | | +| `./t7511-status-index.sh` | PASS | | +| `./t7514-commit-patch.sh` | PASS | | +| `./t7515-status-symlinks.sh` | PASS | | +| `./t7516-commit-races.sh` | PASS | | +| `./t7518-ident-corner-cases.sh` | PASS | | +| `./t7520-ignored-hook-warning.sh` | PASS | | +| `./t7517-per-repo-email.sh` | PASS | | +| `./t7400-submodule-basic.sh` | PASS | | +| `./t7521-ignored-mode.sh` | PASS | | +| `./t7524-commit-summary.sh` | PASS | | +| `./t7525-status-rename.sh` | PASS | | +| `./t7527-builtin-fsmonitor.sh` | SKIPPED | fsmonitor--daemon is not supported on this platform | +| `./t7526-commit-pathspec-file.sh` | PASS | | +| `./t7512-status-help.sh` | PASS | | +| `./t7528-signed-commit-ssh.sh` | FAIL | FAIL - ssh-agent socket setup fails in this execution sandbox (Operation not permitted / socket path issue). This is overkill for the app because SSH-agent-backed commit signing is not part of the current level catalog, and implementing mobile SSH-agent/key-management support would be a separate security product area. | +| `./t7513-interpret-trailers.sh` | PASS | | +| `./t7519-status-fsmonitor.sh` | PASS | | +| `./t7604-merge-custom-message.sh` | PASS | | +| `./t7605-merge-resolve.sh` | PASS | | +| `./t7603-merge-reduce-heads.sh` | PASS | | +| `./t7606-merge-custom.sh` | PASS | | +| `./t7607-merge-state.sh` | PASS | | +| `./t7601-merge-pull-config.sh` | PASS | | +| `./t7112-reset-submodule.sh` | PASS | | +| `./t7612-merge-verify-signatures.sh` | PASS | | +| `./t7508-status.sh` | PASS | | +| `./t7602-merge-octopus-many.sh` | PASS | | +| `./t7608-merge-messages.sh` | PASS | | +| `./t7609-mergetool--lib.sh` | PASS | | +| `./t7702-repack-cyclic-alternate.sh` | PASS | | +| `./t7614-merge-signoff.sh` | PASS | | +| `./t7615-diff-algo-with-mergy-operations.sh` | PASS | | +| `./t7701-repack-unpack-unreachable.sh` | PASS | | +| `./t7611-merge-abort.sh` | PASS | | +| `./t7600-merge.sh` | PASS | | +| `./t7812-grep-icase-non-ascii.sh` | PASS | | +| `./t7811-grep-open.sh` | PASS | | +| `./t7813-grep-icase-iso.sh` | PASS | | +| `./t7815-grep-binary.sh` | PASS | | +| `./t7703-repack-geometric.sh` | PASS | | +| `./t7817-grep-sparse-checkout.sh` | PASS | | +| `./t7816-grep-binary-pattern.sh` | PASS | | +| `./t7700-repack.sh` | PASS | | +| `./t7814-grep-recurse-submodules.sh` | PASS | | +| `./t7810-grep.sh` | PASS | | +| `./t8004-blame-with-conflicts.sh` | PASS | | +| `./t8005-blame-i18n.sh` | SKIPPED | skipping blame i18n tests; iconv not available | +| `./t8003-blame-corner-cases.sh` | PASS | | +| `./t7704-repack-cruft.sh` | PASS | | +| `./t8007-cat-file-textconv.sh` | PASS | | +| `./t8008-blame-formats.sh` | PASS | | +| `./t8006-blame-textconv.sh` | PASS | | +| `./t8001-annotate.sh` | PASS | | +| `./t8009-blame-vs-topicbranches.sh` | PASS | | +| `./t8010-cat-file-filters.sh` | PASS | | +| `./t8011-blame-split-file.sh` | PASS | | +| `./t8015-blame-diff-algorithm.sh` | PASS | | +| `./t8002-blame.sh` | PASS | | +| `./t8013-blame-ignore-revs.sh` | PASS | | +| `./t9002-column.sh` | PASS | | +| `./t9001-send-email.sh` | PASS | | +| `./t9003-help-autocorrect.sh` | PASS | | +| `./t9100-git-svn-basic.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9101-git-svn-props.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9102-git-svn-deep-rmdir.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9103-git-svn-tracked-directory-removed.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9104-git-svn-follow-parent.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9105-git-svn-commit-diff.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t8020-last-modified.sh` | PASS | | +| `./t9106-git-svn-commit-diff-clobber.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t7800-difftool.sh` | PASS | | +| `./t9107-git-svn-migrate.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9108-git-svn-glob.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t8014-blame-ignore-fuzzy.sh` | PASS | | +| `./t9109-git-svn-multi-glob.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9110-git-svn-use-svm-props.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9111-git-svn-use-svnsync-props.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9112-git-svn-md5less-file.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9113-git-svn-dcommit-new-file.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9114-git-svn-dcommit-merge.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9115-git-svn-dcommit-funky-renames.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9116-git-svn-log.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9117-git-svn-init-clone.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9118-git-svn-funky-branch-names.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9119-git-svn-info.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9121-git-svn-fetch-renamed-dir.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9122-git-svn-author.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9123-git-svn-rebuild-with-rewriteroot.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9124-git-svn-dcommit-auto-props.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9120-git-svn-clone-with-percent-escapes.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t8012-blame-colors.sh` | PASS | | +| `./t9126-git-svn-follow-deleted-readded-directory.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9129-git-svn-i18n-commitencoding.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9127-git-svn-partial-rebuild.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9128-git-svn-cmd-branch.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9125-git-svn-multi-glob-branch-names.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9130-git-svn-authors-file.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9131-git-svn-empty-symlink.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9133-git-svn-nested-git-repo.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9135-git-svn-moved-branch-empty-file.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9134-git-svn-ignore-paths.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9132-git-svn-broken-symlink.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9136-git-svn-recreated-branch-empty-file.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9139-git-svn-non-utf8-commitencoding.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9138-git-svn-authors-prog.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9140-git-svn-reset.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9141-git-svn-multiple-branches.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9137-git-svn-dcommit-clobber-series.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9143-git-svn-gc.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9145-git-svn-master-branch.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9147-git-svn-include-paths.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9146-git-svn-empty-dirs.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9144-git-svn-old-rev_map.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9142-git-svn-shallow-clone.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t7900-maintenance.sh` | PASS | | +| `./t9150-svk-mergetickets.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9148-git-svn-propset.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9154-git-svn-fancy-glob.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9155-git-svn-fetch-deleted-tag.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9152-svn-empty-dirs-after-gc.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9153-git-svn-rewrite-uuid.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9151-svn-mergeinfo.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9159-git-svn-no-parent-mergeinfo.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9157-git-svn-fetch-merge.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9158-git-svn-mergeinfo.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9156-git-svn-fetch-deleted-tag-2.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9160-git-svn-preserve-empty-dirs.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9162-git-svn-dcommit-interactive.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9161-git-svn-mergeinfo-push.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9163-git-svn-reset-clears-caches.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9165-git-svn-fetch-merge-branch-of-branch.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9166-git-svn-fetch-merge-branch-of-branch2.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9164-git-svn-dcommit-concurrent.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9168-git-svn-partially-globbed-names.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9167-git-svn-cmd-branch-subproject.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9200-git-cvsexportcommit.sh` | SKIPPED | skipping git cvsexportcommit tests, perl not available | +| `./t9169-git-svn-dcommit-crlf.sh` | SKIPPED | skipping git svn tests, perl not available | +| `./t9304-fast-import-marks.sh` | PASS | | +| `./t9302-fast-import-unpack-limit.sh` | PASS | | +| `./t9303-fast-import-compression.sh` | PASS | | +| `./t9305-fast-import-signatures.sh` | PASS | | +| `./t9306-fast-import-signed-tags.sh` | PASS | | +| `./t9400-git-cvsserver-server.sh` | SKIPPED | skipping git cvsserver tests, perl not available | +| `./t9351-fast-export-anonymize.sh` | PASS | | +| `./t9401-git-cvsserver-crlf.sh` | SKIPPED | skipping git-cvsserver tests, cvs not found | +| `./t9211-scalar-clone.sh` | PASS | | +| `./t9402-git-cvsserver-refs.sh` | SKIPPED | skipping git-cvsserver tests, cvs not found | +| `./t9500-gitweb-standalone-no-errors.sh` | SKIPPED | skipping gitweb tests, perl not available | +| `./t9501-gitweb-standalone-http-status.sh` | SKIPPED | skipping gitweb tests, perl not available | +| `./t9502-gitweb-standalone-parse-output.sh` | SKIPPED | skipping gitweb tests, perl not available | +| `./t9601-cvsimport-vendor-branch.sh` | SKIPPED | skipping cvsimport tests, cvs not found | +| `./t9600-cvsimport.sh` | SKIPPED | skipping cvsimport tests, cvs not found | +| `./t9602-cvsimport-branches-tags.sh` | SKIPPED | skipping cvsimport tests, cvs not found | +| `./t9603-cvsimport-patchsets.sh` | SKIPPED | skipping cvsimport tests, cvs not found | +| `./t9604-cvsimport-timestamps.sh` | SKIPPED | skipping cvsimport tests, cvs not found | +| `./t9700-perl-git.sh` | SKIPPED | skipping perl interface tests, perl not available | +| `./t9800-git-p4-basic.sh` | SKIPPED | skipping git p4 tests; python not available | +| `./t9801-git-p4-branch.sh` | SKIPPED | skipping git p4 tests; python not available | +| `./t9802-git-p4-filetype.sh` | SKIPPED | skipping git p4 tests; python not available | +| `./t9803-git-p4-shell-metachars.sh` | SKIPPED | skipping git p4 tests; python not available | +| `./t9804-git-p4-label.sh` | SKIPPED | skipping git p4 tests; python not available | +| `./t9805-git-p4-skip-submit-edit.sh` | SKIPPED | skipping git p4 tests; python not available | +| `./t9806-git-p4-options.sh` | SKIPPED | skipping git p4 tests; python not available | +| `./t9807-git-p4-submit.sh` | SKIPPED | skipping git p4 tests; python not available | +| `./t9808-git-p4-chdir.sh` | SKIPPED | skipping git p4 tests; python not available | +| `./t9809-git-p4-client-view.sh` | SKIPPED | skipping git p4 tests; python not available | +| `./t9810-git-p4-rcs.sh` | SKIPPED | skipping git p4 tests; python not available | +| `./t9811-git-p4-label-import.sh` | SKIPPED | skipping git p4 tests; python not available | +| `./t9812-git-p4-wildcards.sh` | SKIPPED | skipping git p4 tests; python not available | +| `./t9814-git-p4-rename.sh` | SKIPPED | skipping git p4 tests; python not available | +| `./t9813-git-p4-preserve-users.sh` | SKIPPED | skipping git p4 tests; python not available | +| `./t9815-git-p4-submit-fail.sh` | SKIPPED | skipping git p4 tests; python not available | +| `./t9817-git-p4-exclude.sh` | SKIPPED | skipping git p4 tests; python not available | +| `./t9816-git-p4-locked.sh` | SKIPPED | skipping git p4 tests; python not available | +| `./t9818-git-p4-block.sh` | SKIPPED | skipping git p4 tests; python not available | +| `./t9819-git-p4-case-folding.sh` | SKIPPED | skipping git p4 tests; python not available | +| `./t9820-git-p4-editor-handling.sh` | SKIPPED | skipping git p4 tests; python not available | +| `./t9821-git-p4-path-variations.sh` | SKIPPED | skipping git p4 tests; python not available | +| `./t9822-git-p4-path-encoding.sh` | SKIPPED | skipping git p4 tests; python not available | +| `./t9823-git-p4-mock-lfs.sh` | SKIPPED | skipping git p4 tests; python not available | +| `./t9824-git-p4-git-lfs.sh` | SKIPPED | skipping git p4 tests; python not available | +| `./t9210-scalar.sh` | PASS | | +| `./t9825-git-p4-handle-utf16-without-bom.sh` | SKIPPED | skipping git p4 tests; python not available | +| `./t9826-git-p4-keep-empty-commits.sh` | SKIPPED | skipping git p4 tests; python not available | +| `./t9827-git-p4-change-filetype.sh` | SKIPPED | skipping git p4 tests; python not available | +| `./t9828-git-p4-map-user.sh` | SKIPPED | skipping git p4 tests; python not available | +| `./t9829-git-p4-jobs.sh` | SKIPPED | skipping git p4 tests; python not available | +| `./t9830-git-p4-symlink-dir.sh` | SKIPPED | skipping git p4 tests; python not available | +| `./t9350-fast-export.sh` | PASS | | +| `./t9832-unshelve.sh` | SKIPPED | skipping git p4 tests; python not available | +| `./t9833-errors.sh` | SKIPPED | skipping git p4 tests; python not available | +| `./t9831-git-p4-triggers.sh` | SKIPPED | skipping git p4 tests; python not available | +| `./t9834-git-p4-file-dir-bug.sh` | SKIPPED | skipping git p4 tests; python not available | +| `./t9836-git-p4-metadata-encoding-python3.sh` | SKIPPED | skipping git p4 tests; python not available | +| `./t9835-git-p4-metadata-encoding-python2.sh` | SKIPPED | skipping git p4 tests; python not available | +| `./t9850-shell.sh` | PASS | | +| `./t9901-git-web--browse.sh` | PASS | | +| `./t9301-fast-import-notes.sh` | PASS | | +| `./t9300-fast-import.sh` | PASS | | +| `./t9903-bash-prompt.sh` | PASS | | +| `./t7610-mergetool.sh` | PASS | | +| `./t9902-completion.sh` | PASS | | diff --git a/app/src/main/java/solutions/tretter/githugandroid/GitRuntime.kt b/app/src/main/java/solutions/tretter/githugandroid/GitRuntime.kt index 64bd421..547818d 100644 --- a/app/src/main/java/solutions/tretter/githugandroid/GitRuntime.kt +++ b/app/src/main/java/solutions/tretter/githugandroid/GitRuntime.kt @@ -127,7 +127,8 @@ class GitRepositoryRuntime private constructor( .takeIf { it.path.startsWith(sandboxRoot.path) } ?: sandboxRoot val shellTokens = GitSandboxEngine.tokenizeShellCommand(command) - val tokens = shellTokens.map { it.value } + val invocation = parseEnvironmentPrefixedCommand(shellTokens) + val tokens = invocation.command.map { it.value } if (tokens.isEmpty()) return inspectSandbox(level).copy(currentDir = currentRepo.currentDir) to emptyList() if (currentRepo.interactiveAddSession != null) { val (updatedRepo, output) = GitSandboxEngine.execute(currentRepo, command) @@ -146,13 +147,13 @@ class GitRepositoryRuntime private constructor( val expandedTokens = if (tokens.firstOrNull() == "echo") { tokens } else { - expandShellPathspecs(currentRepo, shellTokens) + expandShellPathspecs(currentRepo, invocation.command) }.normalizeGitStageAlias() - executeSyntheticGitCommand(currentRepo, command, expandedTokens)?.let { return it } + executeSyntheticGitCommand(currentRepo, command, expandedTokens, invocation.environment)?.let { return it } val result = when (expandedTokens.first()) { - "git" -> currentRepo to runGit(nativeGit, workingDir, expandedTokens.drop(1)).outputLines + "git" -> currentRepo to runGit(nativeGit, workingDir, expandedTokens.drop(1), invocation.environment).outputLines "help", "?" -> currentRepo to commandReferenceLines() else -> executeHelperCommand(sandboxRoot, workingDir, currentRepo, expandedTokens) } @@ -551,7 +552,9 @@ class GitRepositoryRuntime private constructor( currentRepo: RepoState, command: String, tokens: List, + environment: Map = emptyMap(), ): Pair>? { + if (environment.isNotEmpty()) return null if (tokens.firstOrNull() != "git") return null val gitCommand = tokens.getOrNull(1) ?: return null if (gitCommand == "clone" && tokens.getOrNull(2)?.startsWith("https://github.com/Gazler/cloneme") == true) { @@ -562,7 +565,7 @@ class GitRepositoryRuntime private constructor( } val shouldUseSandboxSemantics = when (gitCommand) { "add" -> tokens.any { it == "-p" || it == "--patch" || it == "-i" || it == "--interactive" } - "rebase" -> "-i" in tokens || "--interactive" in tokens || "--onto" in tokens + "rebase" -> "--onto" in tokens "merge" -> "--squash" in tokens || tokens.lastOrNull() == "mybranch" || tokens.lastOrNull() == "feature" "revert", "stash" -> true "checkout" -> tokens.any { it == "file3" } || tokens.takeLast(2) == listOf("--", "config.rb") @@ -829,11 +832,47 @@ class GitRepositoryRuntime private constructor( return (first + second).distinct() } - private fun runGit(binary: File, workingDir: File, arguments: List): ProcessExecutionResult { - return runProcess(binary, workingDir, arguments) + private data class EnvironmentPrefixedCommand( + val environment: Map, + val command: List, + ) + + private fun parseEnvironmentPrefixedCommand(tokens: List): EnvironmentPrefixedCommand { + val environment = linkedMapOf() + var commandStart = 0 + while (commandStart < tokens.size) { + val value = tokens[commandStart].value + val assignmentIndex = value.indexOf('=') + if (assignmentIndex <= 0) break + val name = value.take(assignmentIndex) + if (!name.isShellEnvironmentName()) break + environment[name] = value.substring(assignmentIndex + 1) + commandStart += 1 + } + return EnvironmentPrefixedCommand(environment, tokens.drop(commandStart)) } - private fun runProcess(binary: File, workingDir: File, arguments: List): ProcessExecutionResult { + private fun String.isShellEnvironmentName(): Boolean { + if (isEmpty()) return false + if (first() != '_' && !first().isLetter()) return false + return all { it == '_' || it.isLetterOrDigit() } + } + + private fun runGit( + binary: File, + workingDir: File, + arguments: List, + environment: Map = emptyMap(), + ): ProcessExecutionResult { + return runProcess(binary, workingDir, arguments, environment) + } + + private fun runProcess( + binary: File, + workingDir: File, + arguments: List, + extraEnvironment: Map = emptyMap(), + ): ProcessExecutionResult { return try { val gitExecPath = gitExecDirectory(binary) val process = ProcessBuilder(listOf(binary.absolutePath) + arguments) @@ -842,13 +881,17 @@ class GitRepositoryRuntime private constructor( .apply { environment()["HOME"] = workingDir.absolutePath environment()["GIT_EXEC_PATH"] = gitExecPath.absolutePath - environment()["PATH"] = gitExecPath.absolutePath + environment()["PATH"] = listOfNotNull( + gitExecPath.absolutePath, + System.getenv("PATH")?.takeIf { it.isNotBlank() }, + ).joinToString(File.pathSeparator) environment()["GIT_CONFIG_NOSYSTEM"] = "1" environment()["GIT_AUTHOR_NAME"] = "GitHug" environment()["GIT_AUTHOR_EMAIL"] = "githug@example.com" environment()["GIT_COMMITTER_NAME"] = "GitHug" environment()["GIT_COMMITTER_EMAIL"] = "githug@example.com" environment()["LC_ALL"] = "C" + environment().putAll(extraEnvironment) } .start() diff --git a/app/src/main/java/solutions/tretter/githugandroid/GitSandboxEngine.kt b/app/src/main/java/solutions/tretter/githugandroid/GitSandboxEngine.kt index 708ce69..222e9ed 100644 --- a/app/src/main/java/solutions/tretter/githugandroid/GitSandboxEngine.kt +++ b/app/src/main/java/solutions/tretter/githugandroid/GitSandboxEngine.kt @@ -515,28 +515,12 @@ object GitSandboxEngine { private fun rebase(repo: RepoState, arguments: List): Pair> { val interactive = "-i" in arguments || "--interactive" in arguments - val originalCommits = repo.commits - val commits = if (interactive && repo.commits.size > 2) { - repo.commits - .filterNot { it.message.contains("squash this commit", ignoreCase = true) } - .map { if (it.message == "First coommit") it.copy(message = "First commit") else it } - .let { ordered -> - if (ordered.map { it.message }.containsAll(listOf("First commit", "Second commit", "Third commit"))) { - ordered.sortedBy { commit -> - when (commit.message) { - "First commit" -> 1 - "Second commit" -> 2 - "Third commit" -> 3 - else -> 0 - } - } - } else { - ordered - } - } - } else { - repo.commits + val target = arguments.lastOrNull { it != "-i" && it != "--interactive" && !it.startsWith("-") } + if (interactive && target == null) { + return repo to listOf("fatal: No rebase upstream specified") } + val originalCommits = repo.commits + val commits = repo.commits val updatedBranches = when { "--onto" in arguments -> repo.branches + (repo.headBranch to (repo.branches["master"] ?: 0) + 1) arguments.isNotEmpty() -> repo.branches + (repo.headBranch to maxOf(repo.branches[repo.headBranch] ?: 0, repo.branches[arguments.last()] ?: 0)) @@ -547,21 +531,15 @@ object GitSandboxEngine { } else { repo.maintenanceActions } - val output = if (interactive) interactiveRebaseConsoleLines(originalCommits, commits, arguments, repo.headBranch) else emptyList() + val output = if (interactive) interactiveRebaseConsoleLines(originalCommits, arguments, repo.headBranch) else emptyList() return repo.copy(commits = commits, branches = updatedBranches, maintenanceActions = maintenanceActions) to output } - private fun interactiveRebaseConsoleLines(originalCommits: List, rebasedCommits: List, arguments: List, branch: String): List { + private fun interactiveRebaseConsoleLines(originalCommits: List, arguments: List, branch: String): List { val target = arguments.lastOrNull { it != "-i" && it != "--interactive" }.orEmpty() - val rebasedIds = rebasedCommits.map { it.id }.toSet() return buildList { originalCommits.forEach { commit -> - val action = when { - commit.id !in rebasedIds -> "squash" - commit.message == "First coommit" -> "reword" - else -> "pick" - } - add("$action ${commit.id} ${commit.message}") + add("pick ${commit.id} ${commit.message}") } add("") add("# Rebase ${target.ifBlank { "HEAD" }} in progress; onto HEAD") diff --git a/app/src/main/java/solutions/tretter/githugandroid/levels/RenameCommitLevel.kt b/app/src/main/java/solutions/tretter/githugandroid/levels/RenameCommitLevel.kt index 8f0271d..6e689dc 100644 --- a/app/src/main/java/solutions/tretter/githugandroid/levels/RenameCommitLevel.kt +++ b/app/src/main/java/solutions/tretter/githugandroid/levels/RenameCommitLevel.kt @@ -26,6 +26,9 @@ internal fun renameCommitLevel(): Level = level( }, validator = repoPredicate { repo -> repo.commits.any { it.message == "First commit" } && repo.commits.none { it.message.contains("coommit") } }, testCases = listOf( - levelTestCase("interactive rebase rename", "git rebase -i HEAD~2"), + levelTestCase( + "interactive rebase rename", + "GIT_SEQUENCE_EDITOR=\"sed -i '1s/^pick /reword /'\" GIT_EDITOR=\"sed -i '1s/First coommit/First commit/'\" git rebase -i HEAD~2", + ), ), ) diff --git a/app/src/main/java/solutions/tretter/githugandroid/levels/ReorderLevel.kt b/app/src/main/java/solutions/tretter/githugandroid/levels/ReorderLevel.kt index 930d1b9..dacfb84 100644 --- a/app/src/main/java/solutions/tretter/githugandroid/levels/ReorderLevel.kt +++ b/app/src/main/java/solutions/tretter/githugandroid/levels/ReorderLevel.kt @@ -26,8 +26,11 @@ internal fun reorderLevel(): Level = level( addCommit("Second commit", "file2") true }, - validator = repoPredicate { repo -> repo.commits.map { it.message }.filter { it.endsWith("commit") } == listOf("First commit", "Second commit", "Third commit") }, + validator = repoPredicate { repo -> repo.commits.asReversed().map { it.message }.filter { it.endsWith("commit") } == listOf("First commit", "Second commit", "Third commit") }, testCases = listOf( - levelTestCase("interactive reorder", "git rebase -i HEAD~3"), + levelTestCase( + "interactive reorder", + "GIT_SEQUENCE_EDITOR=\"sed -i '2{h;d};3{G}'\" git rebase -i HEAD~3", + ), ), ) diff --git a/app/src/main/java/solutions/tretter/githugandroid/levels/SquashLevel.kt b/app/src/main/java/solutions/tretter/githugandroid/levels/SquashLevel.kt index ca8ec7c..7f70cf2 100644 --- a/app/src/main/java/solutions/tretter/githugandroid/levels/SquashLevel.kt +++ b/app/src/main/java/solutions/tretter/githugandroid/levels/SquashLevel.kt @@ -30,6 +30,9 @@ internal fun squashLevel(): Level = level( }, validator = repoPredicate { repo -> repo.commits.size <= 2 && repo.commits.any { it.message == "Adding README" } }, testCases = listOf( - levelTestCase("interactive squash", "git rebase -i HEAD~4"), + levelTestCase( + "interactive squash", + "GIT_SEQUENCE_EDITOR=\"sed -i '2,\$s/^pick /squash /'\" GIT_EDITOR=true git rebase -i HEAD~4", + ), ), ) diff --git a/app/src/test/java/solutions/tretter/githugandroid/LevelSolutionsTest.kt b/app/src/test/java/solutions/tretter/githugandroid/LevelSolutionsTest.kt index 1b0fe73..df941f5 100644 --- a/app/src/test/java/solutions/tretter/githugandroid/LevelSolutionsTest.kt +++ b/app/src/test/java/solutions/tretter/githugandroid/LevelSolutionsTest.kt @@ -121,6 +121,15 @@ class LevelSolutionsTest { val fetchRepo = fetchRuntime.prepareLevel(fetchExercise) val (pulledRepo, _) = fetchRuntime.execute(fetchExercise, fetchRepo, "git pull") assertFalse("Pulling must not solve the fetch level.", fetchExercise.validator(pulledRepo, "git pull")) + + val reorderExercise = reorderLevel() + val reorderRuntime = GitRepositoryRuntime(runtimeRoot, gitBinary) + val reorderRepo = reorderRuntime.prepareLevel(reorderExercise) + val (bareInteractiveRebaseRepo, _) = reorderRuntime.execute(reorderExercise, reorderRepo, "git rebase -i") + assertFalse( + "Starting an interactive rebase without an upstream/range must not solve the reorder level.", + reorderExercise.validator(bareInteractiveRebaseRepo, "git rebase -i"), + ) } private companion object {