{"searchDocs":[{"title":"Overview","type":0,"sectionRef":"#","url":"/sparo/pages/ci_commands/overview/","content":"Overview Everyday development involves a variety of Git operations such as switching between branches, fetching incremental changes from the server, and browsing history. By contrast, when a continuous integration (CI) pipeline checks out a Git branch, it is typically a much simpler operation. The folder or entire virtual machine image may be discarded as soon as the job completes. Therefore, different approaches for optimizing Git require required for these two use cases. Sparo provides a separate command line sparo-ci that is specifically optimized for CI pipelines. The current implementation takes this approach: It uses treeless clone instead of blobless clone, under the assumption that Git history will be rarely needed. Shallow clone is a common alternative, however it has trouble supporting operations such as incremental build or publishing that require comparison with a base branch. Sparse checkout is configured, and the skeleton folders are included. Currently two subcommands are supported for CI: sparo-ci checkoutsparo-ci clone","keywords":"","version":"Next"},{"title":"sparo-ci checkout","type":0,"sectionRef":"#","url":"/sparo/pages/ci_commands/sparo-ci_checkout/","content":"sparo-ci checkout sparo-ci checkout Special checkout command for CI. It only accepts project selector such as --to and --from now. Options: --help Show help [boolean] -t, --to See https://rushjs.io/pages/developer/selecting_subsets/#--to for more details. [array] -f, --from See https://rushjs.io/pages/developer/selecting_subsets/#--from for more details. [array] ","keywords":"","version":"Next"},{"title":"sparo fetch","type":0,"sectionRef":"#","url":"/sparo/pages/commands/sparo_fetch/","content":"sparo fetch sparo fetch [remote] [branch] fetch remote branch to local Positionals: remote [string] branch [string] Options: --help Show help [boolean] ","keywords":"","version":"Next"},{"title":"sparo clone","type":0,"sectionRef":"#","url":"/sparo/pages/commands/sparo_clone/","content":"sparo clone sparo clone <repository> [directory] Positionals: repository The remote repository to clone from. [string] [required] directory The name of a new directory to clone into. The "humanish" part of the source repository is used if no directory is explicitly given (repo for /path/to/repo.gitService and foo for host.xz:foo/.gitService). Cloning into an existing directory is only allowed if the directory is empty [string] Options: --help Show help [boolean] -s, --skip-git-config By default, Sparo automatically configures the recommended git settings for the repository you are about to clone. If you prefer not to include this step, you can use the input parameter --skip-git-config [boolean] [default: false] -b, --branch Specify a branch to clone [string] ","keywords":"","version":"Next"},{"title":"sparo-ci clone","type":0,"sectionRef":"#","url":"/sparo/pages/ci_commands/sparo-ci_clone/","content":"sparo-ci clone sparo-ci clone <repository> [directory] Positionals: repository The remote repository to clone from. [string] [required] directory The name of a new directory to clone into. The "humanish" part of the source repository is used if no directory is explicitly given (repo for /path/to/repo.gitService and foo for host.xz:foo/.gitService). Cloning into an existing directory is only allowed if the directory is empty [string] Options: --help Show help [boolean] ","keywords":"","version":"Next"},{"title":"sparo checkout","type":0,"sectionRef":"#","url":"/sparo/pages/commands/sparo_checkout/","content":"sparo checkout sparo checkout [branch] [start-point] Updates files in the working tree to match the version in the index or the specified tree. If no pathspec was given, git checkout will also update HEAD to set the specified branch as the current branch. Positionals: branch [string] start-point [string] Options: --help Show help [boolean] -b Create a new branch and start it at <start-point> [boolean] -B Create a new branch and start it at <start-point>; if it already exists, reset it to <start-point> [boolean] --profile [array] [default: []] --add-profile [array] [default: []] ","keywords":"","version":"Next"},{"title":"sparo git-checkout","type":0,"sectionRef":"#","url":"/sparo/pages/commands/sparo_git-checkout/","content":"sparo git-checkout This is the mirrored subcommand for git checkout. It has the same functionality as the corresponding Git subcommand, but supports Sparo's optional anonymous timing metrics collection. sparo git-checkout [-q] [-f] [-m] [<branch>] sparo git-checkout [-q] [-f] [-m] --detach [<branch>] sparo git-checkout [-q] [-f] [-m] [--detach] <commit> sparo git-checkout [-q] [-f] [-m] [[-b|-B|--orphan] <new-branch>] [<start-point>] sparo git-checkout [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <pathspec>…​ sparo git-checkout [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] --pathspec-from-file=<file> [--pathspec-file-nul] sparo git-checkout (-p|--patch) [<tree-ish>] [--] [<pathspec>…​] See git checkout in the Git documentation for details.","keywords":"","version":"Next"},{"title":"sparo git-fetch","type":0,"sectionRef":"#","url":"/sparo/pages/commands/sparo_git-fetch/","content":"sparo git-fetch This is the mirrored subcommand for git fetch. It has the same functionality as the corresponding Git subcommand, but supports Sparo's optional anonymous timing metrics collection. sparo git-fetch [<options>] [<repository> [<refspec>…​]] sparo git-fetch [<options>] <group> sparo git-fetch --multiple [<options>] [(<repository> | <group>)…​] sparo git-fetch --all [<options>] See git fetch in the Git documentation for details.","keywords":"","version":"Next"},{"title":"Getting Started","type":0,"sectionRef":"#","url":"/sparo/pages/guide/getting_started/","content":"","keywords":"","version":"Next"},{"title":"Everyday workflow​","type":1,"pageTitle":"Getting Started","url":"/sparo/pages/guide/getting_started/#everyday-workflow","content":" ","version":"Next","tagName":"h2"},{"title":"Step 1: Upgrade Git​","type":1,"pageTitle":"Getting Started","url":"/sparo/pages/guide/getting_started/#step-1-upgrade-git","content":" Many Git optimizations are relatively new and not available in older versions of the software. For macOS, we recommend to use brew install git. For other operating systems, see the Git documentation for instructions. ","version":"Next","tagName":"h3"},{"title":"Step 2: Clone your Rush monorepo​","type":1,"pageTitle":"Getting Started","url":"/sparo/pages/guide/getting_started/#step-2-clone-your-rush-monorepo","content":" Clone your RushJS monorepo: sparo clone https://github.com/my-company/my-monorepo.git 👉 For a real world demo, try this repo:https://github.com/Azure/azure-sdk-for-js.git 💡 Support for PNPM and Yarn workspaces is planned but not implemented yet. Contributions welcome! Behind the scenes: Only the default branch (usually main) is fetched. Git blobless partial clone is enabled to postpone downloading file contents. Git sparse checkout is used to clone only the "skeleton" folders, which includes all workspace package.json files, but excludes the source code subfolders. Sparse checkout is configured for the more efficient "cone mode". To understand exactly what actions and Git operations are being performed, invoke sparo --debug clone instead of sparo clone. ","version":"Next","tagName":"h3"},{"title":"Step 3: Create a sparse profile​","type":1,"pageTitle":"Getting Started","url":"/sparo/pages/guide/getting_started/#step-3-create-a-sparse-profile","content":" Define a Sparo profile describing the subset of repository folders for Git sparse checkout. Here is a basic example: common/sparo-profiles/my-team.json { "selections": [ { "selector": "--to", "argument": "my-rush-project" } ] } The --to project selector instructs Sparo to checkout all dependencies in the workspace that are required to build my-rush-project. 👉 If you're demoing azure-sdk-for-js, replace my-rush-project with @azure/arm-commerce. ","version":"Next","tagName":"h3"},{"title":"Step 4: Check out your Sparo profile​","type":1,"pageTitle":"Getting Started","url":"/sparo/pages/guide/getting_started/#step-4-check-out-your-sparo-profile","content":" The --profile parameter can be included with sparo checkout (and in the future also sparo clone and sparo pull). This parameter specifies the name of the JSON file to be selected. You can also combine multiple profiles (sparo checkout --profile p1 --profile p2), in which case the union of their selections will be used. (Combining profiles is an advanced scenario, but useful for example if your pull request will impact sets of projects belonging to multiple teams.) Sparse checkout based on common/sparo-profiles/my-team.json sparo checkout --profile my-team Behind the scenes: Sparo automatically generates the $GIT_DIR/info/sparse-checkout configuration automatically based on your profile selections. To avoid conflicts, while using Sparo do not edit this file directly or rewrite it using other tools such as git sparse-checkout. To checkout just the skeleton (returning to the initial state from Step 1 where no profile is chosen yet), specify --no-profile instead of --profile NAME. To add more profiles, combining with your existing selection, use --add-profile NAME instead of --profile NAME. For example, these two commands produce the same result as sparo checkout --profile p1 --profile p2: sparo checkout --profile p1 sparo checkout --add-profile p2 ","version":"Next","tagName":"h3"},{"title":"Step 5: Use the mirrored subcommands​","type":1,"pageTitle":"Getting Started","url":"/sparo/pages/guide/getting_started/#step-5-use-the-mirrored-subcommands","content":" For everyday work, consider choosing mirrored subcommands such as sparo revert instead of git revert. The Sparo wrapper provides (1) better defaults, (2) suggestions for better performance, and (3) optional anonymized performance metrics. Examples: sparo pull sparo commit -m "Example command" ","version":"Next","tagName":"h3"},{"title":"sparo auto-config","type":0,"sectionRef":"#","url":"/sparo/pages/commands/sparo_auto-config/","content":"","keywords":"","version":"Next"},{"title":"Auto-config settings​","type":1,"pageTitle":"sparo auto-config","url":"/sparo/pages/commands/sparo_auto-config/#auto-config-settings","content":" The implementation can be found in GitService.ts. Below is a summary of the currently applied settings: pull.rebase=true fetch.prune=true fetch.showForcedUpdates=false feature.manyFiles=true core.fsmonitor=true core.fscache=true core.untrackedcache=true om-my-zsh.hide-status=1 on-my-zsh.hide-dirty=1 lfs.allowincompletepush=true lfs.concurrenttransfers=32 push.autoSetupRemote=true ","version":"Next","tagName":"h2"},{"title":"sparo init-profile","type":0,"sectionRef":"#","url":"/sparo/pages/commands/sparo_init-profile/","content":"sparo init-profile sparo init-profile Initialize a new profile. Options: --help Show help [boolean] --profile The name of the profile to initialize. [string] [required] ","keywords":"","version":"Next"},{"title":"sparo git-clone","type":0,"sectionRef":"#","url":"/sparo/pages/commands/sparo_git-clone/","content":"sparo git-clone This is the mirrored subcommand for git clone. It has the same functionality as the corresponding Git subcommand, but supports Sparo's optional anonymous timing metrics collection. sparo git-clone [--template=<template-directory>] [-l] [-s] [--no-hardlinks] [-q] [-n] [--bare] [--mirror] [-o <name>] [-b <name>] [-u <upload-pack>] [--reference <repository>] [--dissociate] [--separate-git-dir <git-dir>] [--depth <depth>] [--[no-]single-branch] [--no-tags] [--recurse-submodules[=<pathspec>]] [--[no-]shallow-submodules] [--[no-]remote-submodules] [--jobs <n>] [--sparse] [--[no-]reject-shallow] [--filter=<filter> [--also-filter-submodules]] [--] <repository> [<directory>] See git clone in the Git documentation for details.","keywords":"","version":"Next"},{"title":"sparo list-profiles","type":0,"sectionRef":"#","url":"/sparo/pages/commands/sparo_list-profiles/","content":"sparo list-profiles sparo list-profiles List all available profiles or query profiles that contain the specified project name Options: --help Show help [boolean] --project List all profiles contains this specified project name [string] ","keywords":"","version":"Next"},{"title":"Git optimization","type":0,"sectionRef":"#","url":"/sparo/pages/reference/git_optimization/","content":"Git optimization By default git clone will download every file in your Git repository, as well as the complete history of every file. For small repositories, that's no big deal. But as your monorepo accumulates projects and years of history, Git operations become slower and slower, until one day git status is taking 10 seconds or more. What to do? Git provides these basic solutions that are easy to use in a medium sized repository: Shallow clone allows cloning only a few commits, but is generally only suitable for throwaway clones such as a CI job. Partial clone allows cloning without file contents (blobless clone) or even commit details (treeless clone), greatly accelerating your git clone time and allowing such details to be fetched during git checkout. Large file storage (LFS) can move binary files to a separate server, downloading them on demand during checkout. Configuration of LFS is tricky however and if done incorrectly may cause worse performance. However, achieving good performance in a large repository requires more complex Git features such as: Git filesystem monitor and background maintenance are background processes that watch for changes and periodically prefetch server data. The user must manually register/unregister working directories and remember to "pause" the service when not needed. Git worktrees allow multiple working directories on your computer to share a single .git folder, avoiding the cost of multiple clones. However this feature comes with awkward limitations, for example the same branch can't be checked out in two worktrees, and Git hooks are also shared. Sparse checkout allows git checkout to extract a subset of files instead of the entire directory structure. Combined with partial clone, sparse checkout is the "battle axe" of Git optimization: although irrelevant projects and history will accumulate, your wait time will be proportional to the files you actually need.","keywords":"","version":"Next"},{"title":".json","type":0,"sectionRef":"#","url":"/sparo/pages/configs/profile_json/","content":"","keywords":"","version":"Next"},{"title":"See also​","type":1,"pageTitle":".json","url":"/sparo/pages/configs/profile_json/#see-also","content":" Sparo profiles ","version":"Next","tagName":"h2"},{"title":"Overview","type":0,"sectionRef":"#","url":"/sparo/pages/commands/overview/","content":"","keywords":"","version":"Next"},{"title":"Mirrored commands​","type":1,"pageTitle":"Overview","url":"/sparo/pages/commands/overview/#mirrored-commands","content":" Each subcommand has its own page in this documentation, except for the mirrored commands which are already covered by the Git documentation. For convenience, the most essential "porcelain" subcommands are listed in the table below, however every Git subcommand is supported. Subcommand\tSummarygit add\tAdd file contents to the index git am\tApply a series of patches from a mailbox git archive\tCreate an archive of files from a named tree git bisect\tUse binary search to find the commit that introduced a bug git branch\tList, create, or delete branches git bundle\tMove objects and refs by archive git checkout\tSwitch branches or restore working tree files git cherry-pick\tApply the changes introduced by some existing commits git citool\tGraphical alternative to git-commit git clean\tRemove untracked files from the working tree git clone\tClone a repository into a new directory git commit\tRecord changes to the repository git describe\tGive an object a human readable name based on an available ref git diff\tShow changes between commits, commit and working tree, etc git fetch\tDownload objects and refs from another repository git format-patch\tPrepare patches for e-mail submission git gc\tCleanup unnecessary files and optimize the local repository git gitk\tThe Git repository browser git grep\tPrint lines matching a pattern git gui\tA portable graphical interface to Git git init\tCreate an empty Git repository or reinitialize an existing one git log\tShow commit logs git maintenance\tRun tasks to optimize Git repository data git merge\tJoin two or more development histories together git mv\tMove or rename a file, a directory, or a symlink git notes\tAdd or inspect object notes git pull\tFetch from and integrate with another repository or a local branch git push\tUpdate remote refs along with associated objects git range-diff\tCompare two commit ranges (e.g. two versions of a branch) git rebase\tReapply commits on top of another base tip git reset\tReset current HEAD to the specified state git restore\tRestore working tree files git revert\tRevert some existing commits git rm\tRemove files from the working tree and from the index git shortlog\tSummarize 'git log' output git show\tShow various types of objects git sparse-checkout\tReduce your working tree to a subset of tracked files git stash\tStash the changes in a dirty working directory away git status\tShow the working tree status git submodule\tInitialize, update or inspect submodules git switch\tSwitch branches git tag\tCreate, list, delete or verify a tag object signed with GPG git worktree\tManage multiple working trees . . .\t...and many other subcommands including any custom commands found in the shell PATH ","version":"Next","tagName":"h2"},{"title":"Contributing","type":0,"sectionRef":"#","url":"/sparo/pages/support/contributing/","content":"Contributing Building the projects in this monorepo: Install the RushJS tool: npm install -g @microsoft/rush Clone the repo: git clone https://github.com/tiktok/sparo.git Install the dependencies cd sparo rush install Build all projects rush build How to invoke your locally build sparo command: cd apps/sparo node lib/start.js ","keywords":"","version":"Next"},{"title":"Security","type":0,"sectionRef":"#","url":"/sparo/pages/reference/security/","content":"","keywords":"","version":"Next"},{"title":"Security scenarios​","type":1,"pageTitle":"Security","url":"/sparo/pages/reference/security/#security-scenarios","content":" Git doesn't provide a formal security specification, so to facilitate analysis of Sparo contributions, we've identified usage scenarios that imply security requirements. We welcome your feedback -- please let us know if we've overlooked an important use case or if Git does not behave as described. ","version":"Next","tagName":"h2"},{"title":"SS1: Safely clone an untrusted repo​","type":1,"pageTitle":"Security","url":"/sparo/pages/reference/security/#ss1-safely-clone-an-untrusted-repo","content":" Suppose that an unfamiliar remote Git repository contains malicious files, which includes malicious config files such as .gitattributes, .gitignore, and Git hook scripts. The following operations are expected to be safe: Using git clone to clone the remote repo.Using git checkout to checkout files.Using git commit to commit modifications of local files. Git ensures safety by ignoring Git hooks and .gitattributes filters by default. The user must explicitly run a command to "opt-in", signifying their trust that the repository is free from malicious code. For example, invoking rush install will register predefined Git hooks, because NPM installation involves executing untrusted scripts and therefore signifies trust in the cloned repository. As another example, if .gitattributes references the LFS filter, the user must first opt-in by running git lfs install, signifying their trust that the filter author has implemented security protections against malicious inputs for that filter. Sparo introduces additional config files such as <profile-name>.json. Parsing of these config files must also treat the inputs as potentially malicious, and provide the same guarantees. ","version":"Next","tagName":"h3"},{"title":"SS2: Safely clone an untrusted repository parameter​","type":1,"pageTitle":"Security","url":"/sparo/pages/reference/security/#ss2-safely-clone-an-untrusted-repository-parameter","content":" A command such as git clone https://github.com/example/project.git will write into a subfolder called project. The Git documentation calls this the "humanish" portion of the URL. Consider a remote service that receives the REPOSITORY parameter as a text string and then invokes git clone REPOSITORY with correct shell-escaping of the parameter. In calculating the humanish folder name, Git should not incorporate special characters such as .. or / that would cause the operation to write cloned files outside of the intended folder. And of course, if an explicit target folder is specified using git clone https://github.com/example/project.git my-folder, then no files should be cloned outside of the my-folder folder. ","version":"Next","tagName":"h3"},{"title":"SS3: Git parameters may include special characters​","type":1,"pageTitle":"Security","url":"/sparo/pages/reference/security/#ss3-git-parameters-may-include-special-characters","content":" Shell interpreters commonly transform expressions involving special characters such as $, %, (, etc. For example: # Problem: Bash would replace "$project" with the value of # the environment variable whose name is "project". git clone https://github.com/example/project.git $project This requires escaping: # This backslash escape ensures that a literal dollar sign # is included in the created folder name: git clone https://github.com/example/project.git \\$project When the sparo command-line invokes subprocesses such as git, it must carefully ensure that process arguments are correctly escaped to avoid being transformed by the shell. For example, if \\$project gets expanded by the shell during subprocess invocation, the escaping will be defeated, which could be exploited to circumvent the other Sparo security guarantees. If certain characters cannot be safely escaped by Node.js, they should be rejected with an error message. ","version":"Next","tagName":"h3"},{"title":"Security assumptions​","type":1,"pageTitle":"Security","url":"/sparo/pages/reference/security/#security-assumptions","content":" It's also useful to point out aspects that are NOT expected to be secure. ","version":"Next","tagName":"h2"},{"title":"Assumption: Shell environment variables are trusted​","type":1,"pageTitle":"Security","url":"/sparo/pages/reference/security/#assumption-shell-environment-variables-are-trusted","content":" For the most part, the git CLI assumes that the shell environment variables are trusted. For example, it relies on the PATH variable to discover the location of the ssh binary, and most of the parent process's variables are passed through to child processes. Because Sparo the tool is invoked by the Node.js runtime, arbitrary code execution is possible via environment variables such as NODE_OPTIONS. ","version":"Next","tagName":"h2"},{"title":"Assumption: Command line is generally trusted​","type":1,"pageTitle":"Security","url":"/sparo/pages/reference/security/#assumption-command-line-is-generally-trusted","content":" The git command-line accepts parameters such as -c which can trigger execution of arbitrary code. Therefore in general, we assume that the command-line parameters are trusted. However, certain parameters can provide stricter guarantees, for example the <repository> argument for git clone mentioned in SS3. ","version":"Next","tagName":"h2"},{"title":"Assumption: Commands may consume excessive resources​","type":1,"pageTitle":"Security","url":"/sparo/pages/reference/security/#assumption-commands-may-consume-excessive-resources","content":" Commands such as git clone may consume an arbitrary amount of disk space or take arbitrarily long to complete. In general, denial-of-service attacks are not considered an important risk for this type of development tool. ","version":"Next","tagName":"h2"},{"title":"Assumption: STDOUT and STDERR may contain arbitrary characters​","type":1,"pageTitle":"Security","url":"/sparo/pages/reference/security/#assumption-stdout-and-stderr-may-contain-arbitrary-characters","content":" When invoking the git CLI, the console output may include strings printed by hook scripts or other shell commands. These strings may contain special characters that are unsafe to embed in other contexts such as an HTML document or SQL string literal. It is the responsibility of the calling processes to correctly escape any STDOUT or STDERR output produced by the git or sparo process. ","version":"Next","tagName":"h2"},{"title":"Getting help","type":0,"sectionRef":"#","url":"/sparo/pages/support/help/","content":"Getting help Please create a GitHub issue to report any problems or feature requests. For general questions, please use our GitHub Discussions forum.","keywords":"","version":"Next"},{"title":"Skeleton folders","type":0,"sectionRef":"#","url":"/sparo/pages/reference/skeleton_folders/","content":"","keywords":"","version":"Next"},{"title":"Skeleton spec​","type":1,"pageTitle":"Skeleton folders","url":"/sparo/pages/reference/skeleton_folders/#skeleton-spec","content":" The included folders are as follows: The entire common/** folder, which generally includes all the important config files and autoinstallers for Rush operationsFor every project defined in rush.json, the top-level project folder contents. For example, packages/my-app/package.json and packages/my-app/README.md will be included, but not packages/my-app/src/index.ts.The scripts/** and plugins/** top-level folders, because these names are commonly used for other essential projects. When a Sparo profile is chosen (for example using sparo checkout --profile my-team), it will bring in all the source code subfolders under the selected workspace projects. ","version":"Next","tagName":"h2"},{"title":"Handling of nested projects​","type":1,"pageTitle":"Skeleton folders","url":"/sparo/pages/reference/skeleton_folders/#handling-of-nested-projects","content":" It is not a best practice for a workspace project to be nested under another workspace project. For example, this folder organization should be avoided: packages/x/package.jsonpackages/x/src/index.tspackages/x/y/package.json (project y is nested inside project x -- don't do this)packages/x/y/src/index.ts Sparo correctly supports this scenario, however. For example, if your profile selects x but not y, then the checkout will include x/src/index.ts but exclude x/y/src/index.ts. ","version":"Next","tagName":"h2"},{"title":"What's new","type":0,"sectionRef":"#","url":"/sparo/pages/support/news/","content":"What's new To find out what's changed in the latest release, please consult the CHANGELOG.md notes.","keywords":"","version":"Next"},{"title":"Sparo profiles","type":0,"sectionRef":"#","url":"/sparo/pages/guide/sparo_profiles/","content":"","keywords":"","version":"Next"},{"title":"Best practices for profiles​","type":1,"pageTitle":"Sparo profiles","url":"/sparo/pages/guide/sparo_profiles/#best-practices-for-profiles","content":" You an add JSON comments to your profile config files. In a large shared codebase, we recommend adding a standardized header to the top of your files indicating their ownership and purpose. Something like this: common/sparo-profiles/example-profile.json /** * OWNER: Customer service team * PURPOSE: Use this profile when working on the customer service apps. */ { "$schema": "https://tiktok.github.io/sparo/schemas/sparo-profile.schema.json", /** * A list of Rush project selectors indicating the project folders to be * included for sparse checkout. The selectors will be combined to make * the union superset of projects. See the Rush selector docs for details: * https://rushjs.io/pages/developer/selecting_subsets/ */ "selections": [ { "selector": "--to", "argument": "tag:cs-dashboard" }, { "selector": "--to", "argument": "tag:cs-tools" } ] } ","version":"Next","tagName":"h2"},{"title":"Combining profiles​","type":1,"pageTitle":"Sparo profiles","url":"/sparo/pages/guide/sparo_profiles/#combining-profiles","content":" The simple way to combine profiles is to specify --profile multiple times. For example: # Check out the union of profiles team-a.json, team-b.json, team-c.json # NOTE: This will replace whatever profile selection was already checked out. sparo checkout --profile team-a --profile team-b --profile team-c You can also use --add-profile to incrementally combine them. For example: # These three commands are equivalent to the above command. sparo checkout --profile team-a sparo checkout --add-profile team-b sparo checkout --add-profile team-c How to checkout no profile at all? That is, how to return to the initial state of a clean sparo clone that only includes the skeleton folders? If --profile is entirely omitted, then sparo checkout will preserve the existing profile selection. Instead, the --no-profile parameter is needed: # NOT IMPLEMENTED YET - check out just the skeleton folders # without applying any profiles sparo checkout --no-profile ","version":"Next","tagName":"h2"},{"title":"Querying profiles​","type":1,"pageTitle":"Sparo profiles","url":"/sparo/pages/guide/sparo_profiles/#querying-profiles","content":" Users can discover available profiles in the current branch by invoking the sparo list-profiles command. The --project parameter enables you to query relevant profiles for a given project. For example: # Suppose you need to make a fix for the "example-app" project. # Which sparse checkout profiles include the "example-app" project? sparo list-profiles --project example-app # Great, let's add the "example-profile" result to our current checkout # (combining it with the existing profile). sparo checkout --add-profile example-profile ","version":"Next","tagName":"h2"}],"options":{"languages":["en"],"id":"default"}}