mirror of
https://github.com/tiktok/sparo.git
synced 2025-03-27 05:11:42 -04:00
commit
9d3d49a2ea
36 changed files with 1494 additions and 5 deletions
apps/website
README.md
docs
docusaurus.config.jsi18n/zh-cn
code.json
package.jsondocusaurus-plugin-content-docs
current.json
current
docusaurus-theme-classic
common/config/rush
|
@ -29,6 +29,24 @@ Notes:
|
|||
- `@algolia/client-search` is included in **package.json** dependencies only because `@docusaurus/preset-classic` includes it as a peer dependency.
|
||||
|
||||
|
||||
## Managing translations
|
||||
|
||||
Instructions for internationalization with Docusaurus: https://docusaurus.io/docs/i18n/introduction
|
||||
|
||||
The supported locales for this project can be found in the `"i18n"` section of
|
||||
[docusaurus.config.js](./docusaurus.config.js).
|
||||
|
||||
> **NOTE:** Each locale is built as a distinct standalone single-page application. The localhost
|
||||
> dev server builds only one locale at a time. To view multiple locales together, you must deploy
|
||||
> the site.
|
||||
|
||||
Common commands:
|
||||
|
||||
- `rushx start --locale zh-cn` - launch the localhost dev server in the specified language.
|
||||
|
||||
- `rushx write-translations --locale zh-cn` - Update the `i18n/*.json` files with any new strings.
|
||||
|
||||
|
||||
## Deployment
|
||||
|
||||
1. If you will manually copy the files to a server, you can build the **apps/sparo/build** folder like this:
|
||||
|
|
|
@ -49,6 +49,10 @@ Try out Sparo in 5 easy steps:
|
|||
2. For this demo, we'll use the Azure SDK which is a large public [RushJS](https://rushjs.io/) monorepo from GitHub. The following command will check out the [skeleton folders](./pages/reference/skeleton_folders.md) but not the source code:
|
||||
|
||||
```shell
|
||||
# Globally install the Sparo CLI from NPM
|
||||
npm install -g sparo
|
||||
|
||||
# Use Sparo to clone your repository
|
||||
sparo clone https://github.com/Azure/azure-sdk-for-js.git
|
||||
|
||||
cd azure-sdk-for-js
|
||||
|
|
|
@ -15,6 +15,10 @@ For macOS, we recommend to use [brew install git](https://git-scm.com/download/m
|
|||
Clone your [RushJS](https://rushjs.io/) monorepo:
|
||||
|
||||
```shell
|
||||
# Globally install the Sparo CLI from NPM
|
||||
npm install -g sparo
|
||||
|
||||
# Use Sparo to clone your repository
|
||||
sparo clone https://github.com/my-company/my-monorepo.git
|
||||
|
||||
cd my-monorepo
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
title: Skeleton folders
|
||||
---
|
||||
|
||||
By default `sparo clones` initializes a sparse checkout that does not include any Sparo profile selections, but does include folders containing essential config files such as **package-lock.yaml** and **package.json**. We call this starting point the checkout **"skeleton"** because it shows the full tree of all project folders in your monorepo, but without their source code subfolders. In other words, although the source files for each project are excluded, the skeleton nonetheless allows engineers to remain aware of other team's projects, and how their own project relates to those other projects. This discourages "tunnel vision" (where engineers pretend their project is the only project in the repository), while still ensuring fast Git performance.
|
||||
By default `sparo clone` initializes a sparse checkout that does not include any Sparo profile selections, but does include folders containing essential config files such as **package-lock.yaml** and **package.json**. We call this starting point the checkout **"skeleton"** because it shows the full tree of all project folders in your monorepo, but without their source code subfolders. In other words, although the source files for each project are excluded, the skeleton nonetheless allows engineers to remain aware of other team's projects, and how their own project relates to those other projects. This discourages "tunnel vision" (where engineers pretend their project is the only project in the repository), while still ensuring fast Git performance.
|
||||
|
||||
Because Sparo enables the "cone mode" optimization for Git sparse checkout, the skeleton uses globs to match entire folders, not individual files.
|
||||
Because Sparo enables the "cone mode" optimization for Git sparse checkout, the skeleton uses globs to match entire folders, not individual files.
|
||||
|
||||
## Skeleton spec
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ const config = {
|
|||
// may want to replace "en" with "zh-Hans".
|
||||
i18n: {
|
||||
defaultLocale: 'en',
|
||||
locales: ['en']
|
||||
locales: ['en', 'zh-cn']
|
||||
},
|
||||
|
||||
plugins: [
|
||||
|
@ -40,7 +40,7 @@ const config = {
|
|||
require.resolve('docusaurus-lunr-search'),
|
||||
{
|
||||
// language codes
|
||||
languages: ['en']
|
||||
languages: ['en', 'zh']
|
||||
}
|
||||
]
|
||||
],
|
||||
|
|
289
apps/website/i18n/zh-cn/code.json
Normal file
289
apps/website/i18n/zh-cn/code.json
Normal file
|
@ -0,0 +1,289 @@
|
|||
{
|
||||
"theme.ErrorPageContent.title": {
|
||||
"message": "页面已崩溃。",
|
||||
"description": "The title of the fallback page when the page crashed"
|
||||
},
|
||||
"theme.BackToTopButton.buttonAriaLabel": {
|
||||
"message": "回到顶部",
|
||||
"description": "The ARIA label for the back to top button"
|
||||
},
|
||||
"theme.blog.archive.title": {
|
||||
"message": "历史博文",
|
||||
"description": "The page & hero title of the blog archive page"
|
||||
},
|
||||
"theme.blog.archive.description": {
|
||||
"message": "历史博文",
|
||||
"description": "The page & hero description of the blog archive page"
|
||||
},
|
||||
"theme.blog.paginator.navAriaLabel": {
|
||||
"message": "博文列表分页导航",
|
||||
"description": "The ARIA label for the blog pagination"
|
||||
},
|
||||
"theme.blog.paginator.newerEntries": {
|
||||
"message": "较新的博文",
|
||||
"description": "The label used to navigate to the newer blog posts page (previous page)"
|
||||
},
|
||||
"theme.blog.paginator.olderEntries": {
|
||||
"message": "较旧的博文",
|
||||
"description": "The label used to navigate to the older blog posts page (next page)"
|
||||
},
|
||||
"theme.blog.post.paginator.navAriaLabel": {
|
||||
"message": "博文分页导航",
|
||||
"description": "The ARIA label for the blog posts pagination"
|
||||
},
|
||||
"theme.blog.post.paginator.newerPost": {
|
||||
"message": "较新一篇",
|
||||
"description": "The blog post button label to navigate to the newer/previous post"
|
||||
},
|
||||
"theme.blog.post.paginator.olderPost": {
|
||||
"message": "较旧一篇",
|
||||
"description": "The blog post button label to navigate to the older/next post"
|
||||
},
|
||||
"theme.blog.post.plurals": {
|
||||
"message": "{count} 篇博文",
|
||||
"description": "Pluralized label for \"{count} posts\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)"
|
||||
},
|
||||
"theme.blog.tagTitle": {
|
||||
"message": "{nPosts} 含有标签「{tagName}」",
|
||||
"description": "The title of the page for a blog tag"
|
||||
},
|
||||
"theme.tags.tagsPageLink": {
|
||||
"message": "查看所有标签",
|
||||
"description": "The label of the link targeting the tag list page"
|
||||
},
|
||||
"theme.colorToggle.ariaLabel": {
|
||||
"message": "切换浅色/暗黑模式(当前为{mode})",
|
||||
"description": "The ARIA label for the navbar color mode toggle"
|
||||
},
|
||||
"theme.colorToggle.ariaLabel.mode.dark": {
|
||||
"message": "暗黑模式",
|
||||
"description": "The name for the dark color mode"
|
||||
},
|
||||
"theme.colorToggle.ariaLabel.mode.light": {
|
||||
"message": "浅色模式",
|
||||
"description": "The name for the light color mode"
|
||||
},
|
||||
"theme.docs.breadcrumbs.navAriaLabel": {
|
||||
"message": "页面路径",
|
||||
"description": "The ARIA label for the breadcrumbs"
|
||||
},
|
||||
"theme.docs.DocCard.categoryDescription": {
|
||||
"message": "{count} 个项目",
|
||||
"description": "The default description for a category card in the generated index about how many items this category includes"
|
||||
},
|
||||
"theme.docs.paginator.navAriaLabel": {
|
||||
"message": "文件选项卡",
|
||||
"description": "The ARIA label for the docs pagination"
|
||||
},
|
||||
"theme.docs.paginator.previous": {
|
||||
"message": "上一页",
|
||||
"description": "The label used to navigate to the previous doc"
|
||||
},
|
||||
"theme.docs.paginator.next": {
|
||||
"message": "下一页",
|
||||
"description": "The label used to navigate to the next doc"
|
||||
},
|
||||
"theme.docs.tagDocListPageTitle.nDocsTagged": {
|
||||
"message": "{count} 篇文档带有标签",
|
||||
"description": "Pluralized label for \"{count} docs tagged\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)"
|
||||
},
|
||||
"theme.docs.tagDocListPageTitle": {
|
||||
"message": "{nDocsTagged}「{tagName}」",
|
||||
"description": "The title of the page for a docs tag"
|
||||
},
|
||||
"theme.docs.versionBadge.label": {
|
||||
"message": "版本:{versionLabel}"
|
||||
},
|
||||
"theme.docs.versions.unreleasedVersionLabel": {
|
||||
"message": "此为 {siteTitle} {versionLabel} 版尚未发行的文档。",
|
||||
"description": "The label used to tell the user that he's browsing an unreleased doc version"
|
||||
},
|
||||
"theme.docs.versions.unmaintainedVersionLabel": {
|
||||
"message": "此为 {siteTitle} {versionLabel} 版的文档,现已不再积极维护。",
|
||||
"description": "The label used to tell the user that he's browsing an unmaintained doc version"
|
||||
},
|
||||
"theme.docs.versions.latestVersionSuggestionLabel": {
|
||||
"message": "最新的文档请参阅 {latestVersionLink} ({versionLabel})。",
|
||||
"description": "The label used to tell the user to check the latest version"
|
||||
},
|
||||
"theme.docs.versions.latestVersionLinkLabel": {
|
||||
"message": "最新版本",
|
||||
"description": "The label used for the latest version suggestion link label"
|
||||
},
|
||||
"theme.common.editThisPage": {
|
||||
"message": "编辑此页",
|
||||
"description": "The link label to edit the current page"
|
||||
},
|
||||
"theme.common.headingLinkTitle": {
|
||||
"message": "{heading}的直接链接",
|
||||
"description": "Title for link to heading"
|
||||
},
|
||||
"theme.lastUpdated.atDate": {
|
||||
"message": "于 {date} ",
|
||||
"description": "The words used to describe on which date a page has been last updated"
|
||||
},
|
||||
"theme.lastUpdated.byUser": {
|
||||
"message": "由 {user} ",
|
||||
"description": "The words used to describe by who the page has been last updated"
|
||||
},
|
||||
"theme.lastUpdated.lastUpdatedAtBy": {
|
||||
"message": "最后{byUser}{atDate}更新",
|
||||
"description": "The sentence used to display when a page has been last updated, and by who"
|
||||
},
|
||||
"theme.navbar.mobileVersionsDropdown.label": {
|
||||
"message": "选择版本",
|
||||
"description": "The label for the navbar versions dropdown on mobile view"
|
||||
},
|
||||
"theme.NotFound.title": {
|
||||
"message": "找不到页面",
|
||||
"description": "The title of the 404 page"
|
||||
},
|
||||
"theme.tags.tagsListLabel": {
|
||||
"message": "标签:",
|
||||
"description": "The label alongside a tag list"
|
||||
},
|
||||
"theme.admonition.caution": {
|
||||
"message": "警告",
|
||||
"description": "The default label used for the Caution admonition (:::caution)"
|
||||
},
|
||||
"theme.admonition.danger": {
|
||||
"message": "危险",
|
||||
"description": "The default label used for the Danger admonition (:::danger)"
|
||||
},
|
||||
"theme.admonition.info": {
|
||||
"message": "信息",
|
||||
"description": "The default label used for the Info admonition (:::info)"
|
||||
},
|
||||
"theme.admonition.note": {
|
||||
"message": "备注",
|
||||
"description": "The default label used for the Note admonition (:::note)"
|
||||
},
|
||||
"theme.admonition.tip": {
|
||||
"message": "提示",
|
||||
"description": "The default label used for the Tip admonition (:::tip)"
|
||||
},
|
||||
"theme.admonition.warning": {
|
||||
"message": "注意",
|
||||
"description": "The default label used for the Warning admonition (:::warning)"
|
||||
},
|
||||
"theme.AnnouncementBar.closeButtonAriaLabel": {
|
||||
"message": "关闭",
|
||||
"description": "The ARIA label for close button of announcement bar"
|
||||
},
|
||||
"theme.blog.sidebar.navAriaLabel": {
|
||||
"message": "最近博文导航",
|
||||
"description": "The ARIA label for recent posts in the blog sidebar"
|
||||
},
|
||||
"theme.CodeBlock.copied": {
|
||||
"message": "复制成功",
|
||||
"description": "The copied button label on code blocks"
|
||||
},
|
||||
"theme.CodeBlock.copyButtonAriaLabel": {
|
||||
"message": "复制代码到剪贴板",
|
||||
"description": "The ARIA label for copy code blocks button"
|
||||
},
|
||||
"theme.CodeBlock.copy": {
|
||||
"message": "复制",
|
||||
"description": "The copy button label on code blocks"
|
||||
},
|
||||
"theme.CodeBlock.wordWrapToggle": {
|
||||
"message": "切换自动换行",
|
||||
"description": "The title attribute for toggle word wrapping button of code block lines"
|
||||
},
|
||||
"theme.DocSidebarItem.expandCategoryAriaLabel": {
|
||||
"message": "展开侧边栏分类 '{label}'",
|
||||
"description": "The ARIA label to expand the sidebar category"
|
||||
},
|
||||
"theme.DocSidebarItem.collapseCategoryAriaLabel": {
|
||||
"message": "折叠侧边栏分类 '{label}'",
|
||||
"description": "The ARIA label to collapse the sidebar category"
|
||||
},
|
||||
"theme.NavBar.navAriaLabel": {
|
||||
"message": "主导航",
|
||||
"description": "The ARIA label for the main navigation"
|
||||
},
|
||||
"theme.navbar.mobileLanguageDropdown.label": {
|
||||
"message": "选择语言",
|
||||
"description": "The label for the mobile language switcher dropdown"
|
||||
},
|
||||
"theme.NotFound.p1": {
|
||||
"message": "我们找不到您要找的页面。",
|
||||
"description": "The first paragraph of the 404 page"
|
||||
},
|
||||
"theme.NotFound.p2": {
|
||||
"message": "请联系原始链接来源网站的所有者,并告知他们链接已损坏。",
|
||||
"description": "The 2nd paragraph of the 404 page"
|
||||
},
|
||||
"theme.TOCCollapsible.toggleButtonLabel": {
|
||||
"message": "本页总览",
|
||||
"description": "The label used by the button on the collapsible TOC component"
|
||||
},
|
||||
"theme.blog.post.readMore": {
|
||||
"message": "阅读更多",
|
||||
"description": "The label used in blog post item excerpts to link to full blog posts"
|
||||
},
|
||||
"theme.blog.post.readMoreLabel": {
|
||||
"message": "阅读 {title} 的全文",
|
||||
"description": "The ARIA label for the link to full blog posts from excerpts"
|
||||
},
|
||||
"theme.blog.post.readingTime.plurals": {
|
||||
"message": "阅读需 {readingTime} 分钟",
|
||||
"description": "Pluralized label for \"{readingTime} min read\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)"
|
||||
},
|
||||
"theme.docs.breadcrumbs.home": {
|
||||
"message": "主页面",
|
||||
"description": "The ARIA label for the home page in the breadcrumbs"
|
||||
},
|
||||
"theme.docs.sidebar.collapseButtonTitle": {
|
||||
"message": "收起侧边栏",
|
||||
"description": "The title attribute for collapse button of doc sidebar"
|
||||
},
|
||||
"theme.docs.sidebar.collapseButtonAriaLabel": {
|
||||
"message": "收起侧边栏",
|
||||
"description": "The title attribute for collapse button of doc sidebar"
|
||||
},
|
||||
"theme.docs.sidebar.navAriaLabel": {
|
||||
"message": "文档侧边栏",
|
||||
"description": "The ARIA label for the sidebar navigation"
|
||||
},
|
||||
"theme.docs.sidebar.closeSidebarButtonAriaLabel": {
|
||||
"message": "关闭导航栏",
|
||||
"description": "The ARIA label for close button of mobile sidebar"
|
||||
},
|
||||
"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": {
|
||||
"message": "← 回到主菜单",
|
||||
"description": "The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)"
|
||||
},
|
||||
"theme.docs.sidebar.toggleSidebarButtonAriaLabel": {
|
||||
"message": "切换导航栏",
|
||||
"description": "The ARIA label for hamburger menu button of mobile navigation"
|
||||
},
|
||||
"theme.docs.sidebar.expandButtonTitle": {
|
||||
"message": "展开侧边栏",
|
||||
"description": "The ARIA label and title attribute for expand button of doc sidebar"
|
||||
},
|
||||
"theme.docs.sidebar.expandButtonAriaLabel": {
|
||||
"message": "展开侧边栏",
|
||||
"description": "The ARIA label and title attribute for expand button of doc sidebar"
|
||||
},
|
||||
"theme.ErrorPageContent.tryAgain": {
|
||||
"message": "重试",
|
||||
"description": "The label of the button to try again rendering when the React error boundary captures an error"
|
||||
},
|
||||
"theme.common.skipToMainContent": {
|
||||
"message": "跳到主要内容",
|
||||
"description": "The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation"
|
||||
},
|
||||
"theme.tags.tagsPageTitle": {
|
||||
"message": "标签",
|
||||
"description": "The title of the tag list page"
|
||||
},
|
||||
"theme.unlistedContent.title": {
|
||||
"message": "未列出页",
|
||||
"description": "The unlisted content banner title"
|
||||
},
|
||||
"theme.unlistedContent.message": {
|
||||
"message": "此页面未列出。搜索引擎不会对其索引,只有拥有直接链接的用户才能访问。",
|
||||
"description": "The unlisted content banner message"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"version.label": {
|
||||
"message": "下一个",
|
||||
"description": "The label for version current"
|
||||
},
|
||||
"sidebar.docsSidebar.category.Introduction": {
|
||||
"message": "介绍",
|
||||
"description": "The label for category Introduction in sidebar docsSidebar"
|
||||
},
|
||||
"sidebar.docsSidebar.category.Reference": {
|
||||
"message": "参考",
|
||||
"description": "The label for category Reference in sidebar docsSidebar"
|
||||
},
|
||||
"sidebar.docsSidebar.category.Config files": {
|
||||
"message": "配置文件",
|
||||
"description": "The label for category Config files in sidebar docsSidebar"
|
||||
},
|
||||
"sidebar.docsSidebar.category.Commands": {
|
||||
"message": "命令",
|
||||
"description": "The label for category Commands in sidebar docsSidebar"
|
||||
},
|
||||
"sidebar.docsSidebar.category.CI Commands": {
|
||||
"message": "CI 命令",
|
||||
"description": "The label for category CI Commands in sidebar docsSidebar"
|
||||
},
|
||||
"sidebar.docsSidebar.category.Support": {
|
||||
"message": "支持",
|
||||
"description": "The label for category Support in sidebar docsSidebar"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
---
|
||||
title: 概述
|
||||
hide_title: true
|
||||
custom_edit_url: null
|
||||
---
|
||||
|
||||
import { ThemedImage } from '@site/src/components/ThemedImage';
|
||||
|
||||
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
|
||||
<ThemedImage
|
||||
srcLight="images/site/sparo-logo.svg"
|
||||
srcDark="images/site/sparo-logo-dark.svg"
|
||||
alt="Sparo"
|
||||
title="Sparo"
|
||||
style={{ width: '380px', paddingTop: '30px' }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
## 更快的克隆!
|
||||
|
||||
Sparo 优化了 Git 操作在大型前端 monorepo 中的性能。
|
||||
|
||||
<!-- ---------------------------------------------------------------------------- -->
|
||||
|
||||
## 主要特点
|
||||
|
||||
- **熟悉的界面:** `sparo` 命令行工具 (CLI) 提供了 **更好的默认设置** 和 **性能建议**,而无需更改熟悉的 `git` 语法。(本地 `git` CLI 也受支持。)
|
||||
- **经过验证的解决方案:** Git 提供了[许多优化大型仓库的基础能力](https://tiktok.github.io/sparo/pages/reference/git_optimization/); Sparo 基于这些能力提供上层的解决方案。
|
||||
- **简化的稀疏签出:** 使用稀疏签出[配置文件](https://tiktok.github.io/sparo/pages/guide/sparo_profiles/) 来定义文件签出范围,而不是复杂的 "cones" 和 globs。
|
||||
- **前端集成:** Sparo 利用了 [Rush](https://rushjs.io/) 和 [PNPM](https://pnpm.io/) 的工作区配置,甚至可以自动签出项目依赖项。
|
||||
- **双重工作流程:** `sparo-ci` 工具实现了一个专门为持续集成 (CI) 流水线优化的签出模型。
|
||||
- **额外的安全措施:** 避免常见的 Git 错误,例如在活动视图之外的暂存文件签出。
|
||||
- **超越 Git hooks:** 可选地收集您的 monorepo 中的匿名化 Git 计时数据,使您的构建团队能够为_本地_开发者体验(不仅仅是 CI)设定数据驱动的目标。
|
||||
|
||||
_(这些指标会传输到您自己的服务,其他任何方都无法访问。)_
|
||||
|
||||
<!-- ---------------------------------------------------------------------------- -->
|
||||
|
||||
|
||||
## 快速演示
|
||||
|
||||
只需五个简单步骤即可试用 Sparo:
|
||||
|
||||
1. _**升级到最新的 Git 版本!**_ 对于 macOS,我们推荐使用 [brew install git](https://git-scm.com/download/mac)。对于其他操作系统,请参阅 [Git 文档](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) 了解安装说明。
|
||||
|
||||
2. 在此演示中,我们将使用 Azure SDK,这是 GitHub 上一个大型的公共 [RushJS](https://rushjs.io/) monorepo。以下命令将签出[骨架文件夹](./pages/reference/skeleton_folders.md),但不会签出源代码:
|
||||
|
||||
```shell
|
||||
# 从 NPM 全局安装 Sparo CLI
|
||||
npm install -g sparo
|
||||
|
||||
# 使用 Sparo 克隆你的仓库
|
||||
sparo clone https://github.com/Azure/azure-sdk-for-js.git
|
||||
|
||||
cd azure-sdk-for-js
|
||||
```
|
||||
|
||||
> 💡 目前支持 PNPM 和 Yarn 工作区的功能计划中,但尚未实现。欢迎贡献!
|
||||
|
||||
3. 定义一个 [Sparo 配置文件](./pages/configs/profile_json.md),描述 Git 稀疏签出的仓库文件夹子集。
|
||||
|
||||
```shell
|
||||
# 将模板写入 common/sparo-profiles/my-team.json
|
||||
sparo init-profile --profile my-team
|
||||
```
|
||||
|
||||
编辑创建的 **my-team.json** 文件并添加以下选择器:
|
||||
|
||||
**common/sparo-profiles/my-team.json**
|
||||
```json
|
||||
{
|
||||
"selections": [
|
||||
{
|
||||
// 此演示配置文件将签出 "@azure/arm-commerce" 项目及其所有依赖项:
|
||||
"selector": "--to",
|
||||
"argument": "@azure/arm-commerce"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
`--to` [项目选择器](https://rushjs.io/pages/developer/selecting_subsets/#--to) 指示 Sparo 签出工作区中构建 `my-rush-project` 所需的所有依赖项。
|
||||
|
||||
|
||||
|
||||
4. 在保存 **my-team.json** 的更改后,现在是应用它的时候了:
|
||||
|
||||
```shell
|
||||
sparo checkout --profile my-team
|
||||
```
|
||||
|
||||
尝试一下!例如:
|
||||
|
||||
```shell
|
||||
rush install
|
||||
|
||||
# 构建应该成功,因为 Sparo 确保依赖项目被包含在稀疏签出中:
|
||||
rush build --to @azure/arm-commerce
|
||||
```
|
||||
|
||||
5. 在日常工作中,考虑选择 [mirrored子命令](./pages/commands/overview.md),例如 `sparo revert` 而不是 `git revert`。Sparo 包装器提供 (1) 更好的默认设置,(2) 更好的性能建议,以及 (3) 可选的匿名化性能指标。
|
||||
|
||||
示例:
|
||||
|
||||
```shell
|
||||
sparo pull
|
||||
|
||||
sparo commit -m "Example command"
|
||||
```
|
||||
|
||||
👍👍 这就是 **快速演示** 的全部内容。有关更详细的教程,请继续阅读 [入门指南](./pages/guide/getting_started.md)。
|
|
@ -0,0 +1,18 @@
|
|||
---
|
||||
title: 概述
|
||||
---
|
||||
|
||||
虽然日常开发涉及多种复杂的 Git 操作,例如在分支之间切换、从服务器获取增量更改以及浏览历史记录。但是相比之下,当持续集成 (CI) 流水线签出一个 Git 分支时,通常是一个更简单的操作。CI 执行任务过程中所用到的文件夹或整个虚拟机可能在作业完成后立即被丢弃。因此,这两种用例需要不同的 Git 优化方法。
|
||||
|
||||
Sparo 提供了一个单独的命令行工具 `sparo-ci`,专门针对 CI 流水线进行了优化。当前实现采用以下方法:
|
||||
|
||||
- 使用 [treeless clone](https://github.blog/2020-12-21-get-up-to-speed-with-partial-clone-and-shallow-clone/) 而非 **blobless clone**,因为在 CI 环境会很少需要使用完整的 Git 历史记录。
|
||||
|
||||
_Shallow clone 是一种常见的替代方案,但在支持需要与基准分支进行比较的增量构建或发布操作时会遇到困难。_
|
||||
|
||||
- 配置了稀疏签出,并包含了[骨架文件夹](../reference/skeleton_folders.md)。
|
||||
|
||||
目前,`sparo-ci` 支持两个子命令用于 CI:
|
||||
|
||||
- `sparo-ci checkout`
|
||||
- `sparo-ci clone`
|
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
title: sparo-ci checkout
|
||||
---
|
||||
|
||||
```
|
||||
sparo-ci checkout
|
||||
|
||||
用于 CI 场景的签出命令。它目前只接受项目选择器,例如 --to 和 --from。
|
||||
|
||||
选项:
|
||||
--help 显示帮助 [boolean]
|
||||
-t, --to 查看 https://rushjs.io/pages/developer/selecting_subsets/#--to
|
||||
了解更多详情。 [array]
|
||||
-f, --from 查看 https://rushjs.io/pages/developer/selecting_subsets/#--from
|
||||
了解更多详情。 [array]
|
||||
```
|
|
@ -0,0 +1,18 @@
|
|||
---
|
||||
title: sparo-ci clone
|
||||
---
|
||||
|
||||
```
|
||||
sparo-ci clone <repository> [directory]
|
||||
|
||||
位置参数:
|
||||
repository 要克隆的远程仓库地址。 [string] [required]
|
||||
directory 要克隆到的新目录名称。如果未显式指定目录,
|
||||
将使用源仓库的“humanish”部分
|
||||
(对于 /path/to/repo.gitService 使用 repo,对于
|
||||
host.xz:foo/.gitService 使用 foo)。
|
||||
仅当目录为空时才允许克隆到现有目录。 [string]
|
||||
|
||||
选项:
|
||||
--help 显示帮助 [boolean]
|
||||
```
|
|
@ -0,0 +1,80 @@
|
|||
---
|
||||
title: 概述
|
||||
---
|
||||
|
||||
`git` 命令行工具支持各种子命令,例如 `git clone`、`git checkout` 等。`sparo` 命令行旨在完全替代 `git`。
|
||||
|
||||
Sparo 有四种类型的子命令:
|
||||
|
||||
1. **mirrored子命令**,例如 `sparo branch` 和 `sparo revert`,直接调用相应的 `git` 子命令。使用mirrored子命令的目的是让 Sparo 能够提供有关可能导致性能问题的参数的建议。此外,您还可以选择在 Sparo 中配置埋点数据收集,帮助您衡量在您的代码库中的使用体验。(收集的数据会发送到您自己的服务,其他任何人无法访问。)
|
||||
|
||||
2. **增强子命令**,其基本设计与对应的 `git` 子命令相同,但针对稀疏签出配置文件和更高效的默认设置进行了调整。共有四个增强命令:
|
||||
- `sparo checkout`
|
||||
- `sparo clone`
|
||||
- `sparo fetch`
|
||||
- `sparo pull`
|
||||
|
||||
3. **重命名子命令** 是四个增强子命令的mirrored版本,它们被重命名为添加了 `git-` 前缀:
|
||||
- `sparo git-checkout`
|
||||
- `sparo git-clone`
|
||||
- `sparo git-fetch`
|
||||
- `sparo git-pull`
|
||||
|
||||
4. **辅助子命令** 是提供 Sparo 特定功能的新子命令。它们包括:
|
||||
- `sparo auto-config`
|
||||
- `sparo init-profile`
|
||||
- `sparo list-profiles`
|
||||
- `sparo inspect` _(尚未实现,将报告工作目录状态和诊断信息)_
|
||||
- `sparo reclone` _(尚未实现,将有效地恢复到干净的克隆状态)_
|
||||
|
||||
## mirrored命令
|
||||
|
||||
每个子命令在本文档中都有自己的页面,mirrored命令除外,它们已经在 Git 文档中进行了介绍。为了方便起见,下面的表格列出了最重要的["porcelain"](https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain)子命令,然而每个 Git 子命令都受支持。
|
||||
|
||||
| 子命令 | 概述 |
|
||||
| --- | --- |
|
||||
| [git add](https://git-scm.com/docs/git-add) | 将文件内容添加到索引 |
|
||||
| [git am](https://git-scm.com/docs/git-am) | 从邮箱中应用一系列补丁 |
|
||||
| [git archive](https://git-scm.com/docs/git-archive) | 从指定树创建文件归档 |
|
||||
| [git bisect](https://git-scm.com/docs/git-bisect) | 使用二分查找找到引入错误的提交 |
|
||||
| [git branch](https://git-scm.com/docs/git-branch) | 列出、创建或删除分支 |
|
||||
| [git bundle](https://git-scm.com/docs/git-bundle) | 通过归档移动对象和引用 |
|
||||
| [git checkout](https://git-scm.com/docs/git-checkout) | 切换分支或还原工作树文件 |
|
||||
| [git cherry-pick](https://git-scm.com/docs/git-cherry-pick) | 应用某些现有提交引入的更改 |
|
||||
| [git citool](https://git-scm.com/docs/git-citool) | 图形化替代 git-commit |
|
||||
| [git clean](https://git-scm.com/docs/git-clean) | 从工作树中删除未跟踪的文件 |
|
||||
| [git clone](https://git-scm.com/docs/git-clone) | 将仓库克隆到一个新目录中 |
|
||||
| [git commit](https://git-scm.com/docs/git-commit) | 将更改记录到仓库 |
|
||||
| [git describe](https://git-scm.com/docs/git-describe) | 基于可用引用为对象赋予一个可读名称 |
|
||||
| [git diff](https://git-scm.com/docs/git-diff) | 显示提交之间的更改、提交与工作树之间的更改等 |
|
||||
| [git fetch](https://git-scm.com/docs/git-fetch) | 从另一个仓库下载对象和引用 |
|
||||
| [git format-patch](https://git-scm.com/docs/git-format-patch) | 为电子邮件提交准备补丁 |
|
||||
| [git gc](https://git-scm.com/docs/git-gc) | 清理不必要的文件并优化本地仓库 |
|
||||
| [git gitk](https://git-scm.com/docs/git-gitk) | Git 仓库浏览器 |
|
||||
| [git grep](https://git-scm.com/docs/git-grep) | 打印匹配模式的行 |
|
||||
| [git gui](https://git-scm.com/docs/git-gui) | Git 的可移植图形界面 |
|
||||
| [git init](https://git-scm.com/docs/git-init) | 创建一个空的 Git 仓库或重新初始化现有的仓库 |
|
||||
| [git log](https://git-scm.com/docs/git-log) | 显示提交日志 |
|
||||
| [git maintenance](https://git-scm.com/docs/git-maintenance) | 运行任务以优化 Git 仓库数据 |
|
||||
| [git merge](https://git-scm.com/docs/git-merge) | 将两个或多个开发历史合并在一起 |
|
||||
| [git mv](https://git-scm.com/docs/git-mv) | 移动或重命名文件、目录或符号链接 |
|
||||
| [git notes](https://git-scm.com/docs/git-notes) | 添加或查看对象注释 |
|
||||
| [git pull](https://git-scm.com/docs/git-pull) | 从另一个仓库或本地分支获取并集成 |
|
||||
| [git push](https://git-scm.com/docs/git-push) | 更新远程引用及其关联对象 |
|
||||
| [git range-diff](https://git-scm.com/docs/git-range-diff) | 比较两个提交范围(例如分支的两个版本) |
|
||||
| [git rebase](https://git-scm.com/docs/git-rebase) | 在另一个基底上重新应用提交 |
|
||||
| [git reset](https://git-scm.com/docs/git-reset) | 将当前 HEAD 重置为指定状态 |
|
||||
| [git restore](https://git-scm.com/docs/git-restore) | 恢复工作树文件 |
|
||||
| [git revert](https://git-scm.com/docs/git-revert) | 撤销某些现有的提交 |
|
||||
| [git rm](https://git-scm.com/docs/git-rm) | 从工作树和索引中删除文件 |
|
||||
| [git shortlog](https://git-scm.com/docs/git-shortlog) | 总结 'git log' 输出 |
|
||||
| [git show](https://git-scm.com/docs/git-show) | 显示各种类型的对象 |
|
||||
| [git sparse-checkout](https://git-scm.com/docs/git-sparse-checkout) | 将工作树减少到跟踪文件的子集 |
|
||||
| [git stash](https://git-scm.com/docs/git-stash) | 将脏的工作目录中的更改暂存 |
|
||||
| [git status](https://git-scm.com/docs/git-status) | 显示工作树状态 |
|
||||
| [git submodule](https://git-scm.com/docs/git-submodule) | 初始化、更新或查看子模块 |
|
||||
| [git switch](https://git-scm.com/docs/git-switch) | 切换分支 |
|
||||
| [git tag](https://git-scm.com/docs/git-tag) | 创建、列出、删除或验证使用 GPG 签名的标签对象 |
|
||||
| [git worktree](https://git-scm.com/docs/git-worktree) | 管理多个工作树 |
|
||||
| . . . | _...以及许多其他子命令,包括 shell `PATH` 中找到的任何自定义命令_ |
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
---
|
||||
title: sparo auto-config
|
||||
---
|
||||
|
||||
```
|
||||
sparo auto-config
|
||||
|
||||
自动设置推荐的 Git 配置
|
||||
|
||||
选项:
|
||||
-h, --help 显示帮助 [boolean]
|
||||
--overwrite [boolean] [default: false]
|
||||
```
|
||||
|
||||
通常,您不需要手动调用 `sparo auto-config`。顾名思义,它由 `sparo clone` 自动应用。该命令提供用于在用户可能手动更改了 Sparo 配置的情况下重新应用配置。当调查问题时,这是一个不错的第一步。
|
||||
|
||||
## 自动配置设置
|
||||
|
||||
实现可以在 [GitService.ts](https://github.com/tiktok/sparo/blob/main/apps/sparo-lib/src/services/GitService.ts) 中找到。以下是当前应用设置的摘要:
|
||||
|
||||
```
|
||||
pull.rebase=true
|
||||
fetch.prune=true
|
||||
fetch.showForcedUpdates=false
|
||||
feature.manyFiles=true
|
||||
core.fsmonitor=true
|
||||
core.fscache=true
|
||||
core.untrackedcache=true
|
||||
oh-my-zsh.hide-status=1
|
||||
oh-my-zsh.hide-dirty=1
|
||||
lfs.allowincompletepush=true
|
||||
lfs.concurrenttransfers=32
|
||||
push.autoSetupRemote=true
|
||||
```
|
|
@ -0,0 +1,33 @@
|
|||
---
|
||||
title: sparo checkout
|
||||
---
|
||||
|
||||
```
|
||||
sparo checkout [branch] [start-point]
|
||||
|
||||
更新工作树中的文件,以匹配索引或指定树中的版本。如果未提供路径规范,
|
||||
git checkout 还将更新 HEAD,将指定分支设置为当前分支。
|
||||
|
||||
位置参数:
|
||||
branch [string]
|
||||
start-point [string]
|
||||
|
||||
选项:
|
||||
--help 显示帮助 [boolean]
|
||||
-b 创建一个新分支,并在 <start-point> 处启动 [boolean]
|
||||
-B 创建一个新分支,并在 <start-point> 处启动;如果已存在,
|
||||
将其重置到 <start-point> [boolean]
|
||||
--profile 根据指定的配置文件签出项目。这些配置文件将被记录,
|
||||
并被其他 sparo 命令重用。例如,在运行 "sparo checkout <branch>"
|
||||
后,会基于重用的配置文件进行稀疏签出 [array] [default: []]
|
||||
--add-profile 使用记录的配置文件和指定的附加配置文件签出项目。
|
||||
将指定的附加配置文件添加到 sparo 记录的配置文件中 [array] [default: []]
|
||||
--no-profile 签出项目时不使用任何配置文件,并清除所有记录的配置文件 [boolean]
|
||||
--to 签出项目直到(并包括)项目 <to..>,可以与选项 --profile/--add-profile
|
||||
一起使用,以形成两个选项的并集选择。此处的项目选择器将
|
||||
永远不会取代配置文件已签出的内容 [array] [default: []]
|
||||
--from 签出项目从(包括其自身及其所有依赖项)项目 <from..> 下游开始,
|
||||
可以与选项 --profile/--add-profile 一起使用,
|
||||
以形成两个选项的并集选择。此处的项目选择器将
|
||||
永远不会取代配置文件已签出的内容 [array] [default: []]
|
||||
```
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
title: sparo clone
|
||||
---
|
||||
|
||||
```
|
||||
sparo clone <repository> [directory]
|
||||
|
||||
位置参数:
|
||||
repository 要克隆的远程仓库。 [string] [required]
|
||||
directory 要克隆到的新目录名称。如果未明确指定目录名称,则使用源仓库的
|
||||
名字部分(对于 /path/to/repo.gitService 使用 repo,对于
|
||||
host.xz:foo/.gitService 使用 foo)。仅当目录为空时,才允许克隆
|
||||
到现有目录中。 [string]
|
||||
|
||||
选项:
|
||||
-h, --help 显示帮助 [boolean]
|
||||
-s, --skip-git-config 默认情况下,Sparo 会自动配置您即将克隆的仓库的推荐
|
||||
git 设置。如果您不希望包含此步骤,可以使用输入参数
|
||||
--skip-git-config [boolean] [default: false]
|
||||
-b, --branch 指定要克隆的分支 [string]
|
||||
--profile [array] [default: []]
|
||||
```
|
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
title: sparo fetch
|
||||
---
|
||||
|
||||
```
|
||||
sparo fetch [remote] [branch]
|
||||
|
||||
将远程分支获取到本地
|
||||
|
||||
位置参数:
|
||||
remote [string]
|
||||
branch [string]
|
||||
|
||||
选项:
|
||||
-h, --help 显示帮助 [boolean]
|
||||
```
|
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
title: sparo git-checkout
|
||||
---
|
||||
|
||||
这是 `git checkout` 的[mirrored子命令](./overview.md)。它具有与相应 Git 子命令相同的功能,但支持 Sparo 可选的匿名计时数据收集。
|
||||
|
||||
```
|
||||
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>…]
|
||||
```
|
||||
|
||||
详情请参阅 Git 文档中的 [git checkout](https://git-scm.com/docs/git-checkout)。
|
|
@ -0,0 +1,19 @@
|
|||
---
|
||||
title: sparo git-clone
|
||||
---
|
||||
|
||||
这是 `git clone` 的[mirrored子命令](./overview.md)。它具有与相应 Git 子命令相同的功能,但支持 Sparo 可选的匿名计时数据收集。
|
||||
|
||||
```
|
||||
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>]
|
||||
```
|
||||
|
||||
详情请参阅 Git 文档中的 [git clone](https://git-scm.com/docs/git-clone)。
|
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
title: sparo git-fetch
|
||||
---
|
||||
|
||||
这是 `git fetch` 的[mirrored子命令](./overview.md)。它具有与相应 Git 子命令相同的功能,但支持 Sparo 可选的匿名计时数据收集。
|
||||
|
||||
```
|
||||
sparo git-fetch [<options>] [<repository> [<refspec>…]]
|
||||
sparo git-fetch [<options>] <group>
|
||||
sparo git-fetch --multiple [<options>] [(<repository> | <group>)…]
|
||||
sparo git-fetch --all [<options>]
|
||||
```
|
||||
|
||||
详情请参阅 Git 文档中的 [git fetch](https://git-scm.com/docs/git-fetch)。
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
title: sparo git-pull
|
||||
---
|
||||
|
||||
这是 `git pull` 的[mirrored子命令](./overview.md)。它具有与相应 Git 子命令相同的功能,但支持 Sparo 可选的匿名计时数据收集。
|
||||
|
||||
```
|
||||
sparo git-pull [<options>] [<repository> [<refspec>…]]
|
||||
```
|
||||
|
||||
详情请参阅 Git 文档中的 [git pull](https://git-scm.com/docs/git-pull)。
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
title: sparo init-profile
|
||||
---
|
||||
|
||||
```
|
||||
用法: sparo init-profile --profile <profile>
|
||||
|
||||
选项:
|
||||
-h, --help 显示帮助 [boolean]
|
||||
--profile 要初始化的配置文件名称。 [string] [required]
|
||||
```
|
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
title: sparo list-profiles
|
||||
---
|
||||
|
||||
```
|
||||
sparo list-profiles
|
||||
|
||||
列出所有可用的配置文件或查询包含指定项目名称的配置文件
|
||||
|
||||
选项:
|
||||
-h, --help 显示帮助 [boolean]
|
||||
--project 列出所有包含此指定项目名称的配置文件 [string]
|
||||
```
|
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
title: sparo pull
|
||||
---
|
||||
|
||||
```
|
||||
sparo pull [options] [repository] [refspec...] [--profile <profile_name> | --no-profile]
|
||||
|
||||
将远程仓库的更改合并到当前分支。
|
||||
|
||||
选项:
|
||||
--help 显示帮助 [boolean]
|
||||
--profile [array] [default: []]
|
||||
```
|
|
@ -0,0 +1,66 @@
|
|||
---
|
||||
title: <profile-name>.json
|
||||
---
|
||||
|
||||
要初始化一个新的 Sparo 配置文件,您可以复制并粘贴此模板的内容。
|
||||
|
||||
**common/sparo-profiles/<profile-name>.json**
|
||||
```js
|
||||
/**
|
||||
* 所有者: <您的团队名称>
|
||||
* 目的: <您使用此配置文件的目的>
|
||||
*/
|
||||
{
|
||||
"$schema": "https://tiktok.github.io/sparo/schemas/sparo-profile.schema.json",
|
||||
|
||||
/**
|
||||
* 一个 Rush 项目选择器列表,指示要包含在稀疏签出中的项目文件夹。
|
||||
* 选择器将组合以构成项目的并集。详情请参阅 Rush 选择器文档:
|
||||
* https://rushjs.io/pages/developer/selecting_subsets/
|
||||
*/
|
||||
"selections": [
|
||||
/**
|
||||
* 例如,包含所有标记为 "tag:my-team" 的 Rush 项目
|
||||
* 以及构建它们所需的依赖工作区项目。
|
||||
* 要了解有关 Rush 项目标签的信息,请参阅此文档:
|
||||
* https://rushjs.io/pages/developer/project_tags/
|
||||
*/
|
||||
// {
|
||||
// "selector": "--to",
|
||||
// "argument": "tag:my-team"
|
||||
// },
|
||||
/**
|
||||
* 例如,包含名为 "my-library" 的项目,以及所有
|
||||
* 受其更改影响的项目,以及构建所有项目所需的依赖项目。
|
||||
*/
|
||||
// {
|
||||
// "selector": "--from",
|
||||
// "argument": "my-library"
|
||||
// }
|
||||
],
|
||||
|
||||
/**
|
||||
* 要包含在签出中的任意其他文件夹列表,
|
||||
* 不一定对应于任何工作区项目。
|
||||
* 路径应使用正斜杠,不带前导斜杠,并且应指向 monorepo 的根文件夹。
|
||||
* 出于性能原因,不支持通配符和 glob 模式。
|
||||
*/
|
||||
"includeFolders": [
|
||||
// "path/to/include"
|
||||
],
|
||||
|
||||
/**
|
||||
* 要从签出中排除的文件夹列表。此字段优先于
|
||||
* "includeFolders" 和 "selections" 字段,确保指定的路径绝对不会被包含。
|
||||
* 路径应使用正斜杠,不带前导斜杠,并且应指向 monorepo 的根文件夹。
|
||||
* 出于性能原因,不支持通配符和 glob 模式。
|
||||
*/
|
||||
"excludeFolders": [
|
||||
// "path/to/exclude"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 另见
|
||||
|
||||
- [Sparo 配置文件](../guide/sparo_profiles.md)
|
|
@ -0,0 +1,110 @@
|
|||
---
|
||||
title: 入门指南
|
||||
---
|
||||
|
||||
在本教程中,我们将重温[快速演示](../../index.md#quick-demo)的步骤,但这次我们将更详细地探讨 Sparo 的工作流程。
|
||||
|
||||
## 第 1 步:升级 Git
|
||||
|
||||
请记住将 Git 升级到最新版本!许多 Git 优化功能相对较新,在旧版本的软件中不可用。
|
||||
|
||||
对于 macOS,我们推荐使用 [brew install git](https://git-scm.com/download/mac)。对于其他操作系统,请参阅 [Git 文档](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) 了解安装说明。
|
||||
|
||||
## 第 2 步:克隆您的 Rush monorepo
|
||||
|
||||
克隆您的 [RushJS](https://rushjs.io/) monorepo:
|
||||
|
||||
```shell
|
||||
# 从 NPM 全局安装 Sparo CLI
|
||||
npm install -g sparo
|
||||
|
||||
# 使用 Sparo 克隆你的仓库
|
||||
sparo clone https://github.com/my-company/my-monorepo.git
|
||||
|
||||
cd my-monorepo
|
||||
```
|
||||
|
||||
👉 _对于真实世界的演示,尝试克隆这个仓库:_
|
||||
[https://github.com/Azure/azure-sdk-for-js.git](https://github.com/Azure/azure-sdk-for-js.git)
|
||||
|
||||
|
||||
**"sparo clone" 的优化方式:**
|
||||
|
||||
- 仅获取默认分支(通常是 `main` 分支)。这显著减少了下载大小。
|
||||
|
||||
- 启用了 Git 无 Blob 的[部分克隆](../reference/git_optimization.md)以延迟下载文件内容。
|
||||
|
||||
- 使用 Git [稀疏签出](https://git-scm.com/docs/git-sparse-checkout) 仅克隆["骨架"文件夹](../reference/skeleton_folders.md),其中包括所有工作区的 **package.json** 文件,但不包括源代码子文件夹。
|
||||
|
||||
- 稀疏签出已配置为更高效的["锥形模式"](https://git-scm.com/docs/git-sparse-checkout#_internalsnon_cone_problems)。
|
||||
|
||||
**提示:** 如果想查看执行的操作和 Git 操作,使用 `sparo --debug clone` 代替 `sparo clone`。
|
||||
|
||||
> 💡 目前支持 PNPM 和 Yarn 工作区的功能计划中,但尚未实现。欢迎贡献!
|
||||
|
||||
## 第 3 步:创建稀疏配置文件
|
||||
|
||||
定义一个 [Sparo 配置文件](../configs/profile_json.md),描述 Git 稀疏签出的仓库文件夹子集。
|
||||
|
||||
```shell
|
||||
# 将模板写入 common/sparo-profiles/my-team.json
|
||||
sparo init-profile --profile my-team
|
||||
```
|
||||
|
||||
编辑创建的 **my-team.json** 文件并添加一个选择器。例如:
|
||||
|
||||
**common/sparo-profiles/my-team.json**
|
||||
```json
|
||||
{
|
||||
"selections": [
|
||||
{
|
||||
"selector": "--to",
|
||||
"argument": "my-rush-project"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
👉 _如果您正在演示 **azure-sdk-for-js**,请将 `my-rush-project` 替换为 `@azure/arm-commerce`。_
|
||||
|
||||
在上面的例子中,`--to` [项目选择器](https://rushjs.io/pages/developer/selecting_subsets/#--to) 指示 Sparo 签出工作区中构建 `my-rush-project` 所需的所有依赖项。
|
||||
|
||||
```shell
|
||||
# 将您的配置文件提交到 Git。(此步骤在快速演示中已跳过。)
|
||||
# Sparo 配置文件通常应存储在 Git 中,因为这可以使您在分支之间移动时无需担心
|
||||
# 某个分支中存在哪些项目。
|
||||
sparo add .
|
||||
sparo commit -m "Created a new Sparo profile"
|
||||
```
|
||||
|
||||
## 第 4 步:签出您的 Sparo 配置文件
|
||||
|
||||
`--profile` 参数可以与 `sparo checkout` 一起使用(未来也可以与 `sparo clone` 和 `sparo pull` 一起使用)。此参数指定要选择的 JSON 文件的名称。您还可以组合多个配置文件(`sparo checkout --profile p1 --profile p2`),在这种情况下,将使用它们选择的集合的并集。组合配置文件是一个高级场景,但在例如您的拉取请求将影响属于多个团队的项目集时非常有用。
|
||||
|
||||
**基于 common/sparo-profiles/my-team.json 的稀疏签出**
|
||||
```shell
|
||||
sparo checkout --profile my-team
|
||||
```
|
||||
|
||||
**关于 "sparo checkout" 的更多信息:**
|
||||
|
||||
- Sparo 根据您的配置文件选择自动生成 Git 的 `$GIT_DIR/info/sparse-checkout` [配置文件](https://git-scm.com/docs/git-sparse-checkout#_internalssparse_checkout)。为避免冲突,请不要直接编辑此文件或使用其他工具(如 `git sparse-checkout`)重写它。(这样做不会破坏任何东西,但可能会干扰 Sparo 的操作。)
|
||||
|
||||
- 要仅签出骨架(返回到第 1 步尚未选择任何配置文件的初始状态),请指定 `--no-profile` 代替 `--profile NAME`。
|
||||
|
||||
- 要添加更多配置文件,并与现有选择组合,请使用 `--add-profile NAME` 代替 `--profile NAME`。例如,以下两个命令与 `sparo checkout --profile p1 --profile p2` 产生相同的结果:
|
||||
```shell
|
||||
sparo checkout --profile p1
|
||||
sparo checkout --add-profile p2
|
||||
```
|
||||
|
||||
## 第 5 步:使用mirrored子命令
|
||||
|
||||
在日常工作中,考虑选择 [mirrored子命令](../commands/overview.md),例如 `sparo revert` 而不是 `git revert`。Sparo 包装器提供 (1) 更好的默认设置,(2) 更好的性能建议,以及 (3) 可选的匿名化性能指标。
|
||||
|
||||
示例:
|
||||
|
||||
```shell
|
||||
sparo pull
|
||||
|
||||
sparo commit -m "Example command"
|
||||
```
|
|
@ -0,0 +1,115 @@
|
|||
---
|
||||
title: Sparo 配置文件
|
||||
---
|
||||
|
||||
## 背景
|
||||
|
||||
Git 的稀疏签出功能通常依赖于存储在 `.git/info/sparse-checkout` 配置文件中的一组 glob 模式。Git 维护者发现常规的 glob 语法效率太低,因此他们引入了一种["锥形模式"](https://git-scm.com/docs/git-sparse-checkout#_internalsnon_cone_problems)的 glob 解释,这种模式忽略文件匹配模式,只匹配目录。
|
||||
|
||||
语法类似于以下内容:
|
||||
|
||||
**.git/info/sparse-checkout 示例**
|
||||
```
|
||||
/*
|
||||
!/*/
|
||||
/apps/
|
||||
!/apps/*/
|
||||
/apps/my-app/
|
||||
!/apps/my-app/*/
|
||||
/apps/my-app/_/
|
||||
```
|
||||
|
||||
为了简化管理,Git 还提供了 `git sparse-checkout` 命令,用于简化从该文件中添加/删除模式的语法。然而,在一个包含数百个项目的大型 monorepo 中,管理这些 globs 仍然会令人困惑且容易出错。
|
||||
|
||||
## Sparo 改进了稀疏签出
|
||||
|
||||
Sparo 通过从称为 **配置文件** 的配置文件自动生成 `.git/info/sparse-checkout` 配置,使生活变得更简单。这带来了许多好处:
|
||||
|
||||
- Sparo 配置文件使用 [项目选择器](https://rushjs.io/pages/developer/selecting_subsets/#--to) 定义,例如:_"给我 **app1**、**app2**,以及所有构建它们所需的项目。"_ 这比指定 globs 更简洁且更易维护。
|
||||
|
||||
- 配置文件存储在配置文件中并提交到 Git。这使得与团队成员共享它们变得容易。
|
||||
|
||||
- 在分支切换时,配置文件会自动更新,确保确定性结果。例如,在签出一个非常旧的分支时,您希望获得旧的配置文件定义,而不是今天的版本。
|
||||
|
||||
- 您可以将多个配置文件组合在一起(`sparo checkout --profile team1 --profile team2`),选择它们项目的并集。这在修改一个被多个其他团队的项目使用的库项目时非常有用。当然,您可以使用 `--from the-library` 签出这些项目,但其他团队可能已经在他们的配置文件中包括了其他相关项目。
|
||||
|
||||
- Sparo 通过施加 `git sparse-checkout` 之外的额外限制来避免常见错误。这可以避免诸如尝试切换到缺少包含本地修改文件的项目文件夹的配置文件等错误。用户最好先暂存或提交此类修改。
|
||||
|
||||
## 配置文件的最佳实践
|
||||
|
||||
您可以向配置文件中添加 JSON 注释。在大型共享代码库中,我们建议在文件顶部添加一个标准化的标题,指示它们的所有权和用途。类似于以下内容:
|
||||
|
||||
**common/sparo-profiles/example-profile.json**
|
||||
```js
|
||||
/**
|
||||
* 所有者: 客户服务团队
|
||||
* 目的: 在处理客户服务应用程序时使用此配置文件。
|
||||
*/
|
||||
{
|
||||
"$schema": "https://tiktok.github.io/sparo/schemas/sparo-profile.schema.json",
|
||||
|
||||
/**
|
||||
* 一个 Rush 项目选择器列表,指示要包含在稀疏签出中的项目文件夹。
|
||||
* 选择器将组合以构成项目的并集。详情请参阅 Rush 选择器文档:
|
||||
* https://rushjs.io/pages/developer/selecting_subsets/
|
||||
*/
|
||||
"selections": [
|
||||
{
|
||||
"selector": "--to",
|
||||
"argument": "tag:cs-dashboard"
|
||||
},
|
||||
{
|
||||
"selector": "--to",
|
||||
"argument": "tag:cs-tools"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 组合配置文件
|
||||
|
||||
组合配置文件的简单方法是多次指定 `--profile`。例如:
|
||||
|
||||
```sh
|
||||
# 签出 team-a.json、team-b.json、team-c.json 配置文件的并集
|
||||
# 注意: 这将替换已签出的任何配置文件选择。
|
||||
sparo checkout --profile team-a --profile team-b --profile team-c
|
||||
```
|
||||
|
||||
您还可以使用 `--add-profile` 来逐步组合它们。例如:
|
||||
|
||||
```shell
|
||||
# 这三个命令等同于上述命令。
|
||||
sparo checkout --profile team-a
|
||||
sparo checkout --add-profile team-b
|
||||
sparo checkout --add-profile team-c
|
||||
```
|
||||
|
||||
如何完全不签出任何配置文件?也就是说,如何返回到仅包含[骨架](../reference/skeleton_folders.md)文件夹的干净 `sparo clone` 的初始状态?答案是使用 `--no-profile` 参数:
|
||||
|
||||
```shell
|
||||
# 尚未实现 - 仅签出骨架文件夹
|
||||
# 而不应用任何配置文件
|
||||
sparo checkout --no-profile
|
||||
```
|
||||
|
||||
如果 `sparo checkout` 不带 `--profile` 或 `--add-profile` 或 `--no-profile`,则保留现有的配置文件选择。换句话说,您的配置文件选择通常在命令之间是“粘性的”。
|
||||
|
||||
## 查询配置文件
|
||||
|
||||
用户可以通过调用 [sparo list-profiles](../commands/sparo_list-profiles.md) 命令发现当前分支中的可用配置文件。`--project` 参数使您可以查询给定项目的相关配置文件。例如:
|
||||
|
||||
```shell
|
||||
# 假设您需要为 "example-app" 项目进行修复。
|
||||
|
||||
# 哪些稀疏签出配置文件包含 "example-app" 项目?
|
||||
sparo list-profiles --project example-app
|
||||
|
||||
# 很好,让我们将 "example-profile" 结果添加到我们当前的签出中
|
||||
# (与现有配置文件组合)。
|
||||
sparo checkout --add-profile example-profile
|
||||
```
|
||||
|
||||
## 另见
|
||||
|
||||
- [<profile-name>.json](../configs/profile_json.md) 配置文件
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
title: Git 优化
|
||||
---
|
||||
|
||||
默认情况下,`git clone` 将下载 Git 仓库中的每个文件,以及每个文件的完整历史记录。对于小型仓库来说,这不是什么大问题。但随着您的 monorepo 累积项目和多年的历史记录,Git 操作会变得越来越慢,直到有一天 `git status` 需要 10 秒或更长时间。该怎么办?
|
||||
|
||||
Git 提供了这些基本解决方案,适用于中型仓库并且易于使用:
|
||||
|
||||
- **浅克隆 (Shallow clone)** 允许只克隆几个提交,但通常仅适用于一次性克隆,例如 CI 任务。
|
||||
|
||||
- **部分克隆 (Partial clone)** 允许在不包含文件内容(**无 Blob** 克隆)甚至提交详细信息(**无树** 克隆)的情况下进行克隆,大大加快了 `git clone` 的时间,并允许在 `git checkout` 期间获取这些详细信息。
|
||||
|
||||
- **大文件存储 (LFS)** 可以将二进制文件移动到单独的服务器,在签出时按需下载。然而,LFS 的配置非常复杂,如果配置不当,可能会导致更差的性能。
|
||||
|
||||
然而,要在大型仓库中实现良好的性能,需要使用更复杂的 Git 功能,例如:
|
||||
|
||||
- Git **文件系统监视器** 和 **后台维护** 是监视更改并定期预取服务器数据的后台进程。用户必须手动注册/注销工作目录,并记得在不需要时“暂停”服务。
|
||||
|
||||
- **Git 工作树 (worktrees)** 允许在您的计算机上使用多个工作目录共享一个 `.git` 文件夹,避免了多次克隆的成本。然而,这一功能也有一些尴尬的限制,例如同一个分支不能在两个工作树中签出,并且 Git 钩子也是共享的。
|
||||
|
||||
- **稀疏签出 (Sparse checkout)** 允许 `git checkout` 提取文件的子集,而不是整个目录结构。结合部分克隆,稀疏签出是 Git 优化的“战斧”:尽管无关的项目和历史会积累,但您的等待时间将与您实际需要的文件成正比。
|
|
@ -0,0 +1,82 @@
|
|||
---
|
||||
title: 安全性
|
||||
---
|
||||
|
||||
由于 Sparo 工具作为 Git 的包装器,我们的目标是提供与 `git` 命令相当的安全性预期。
|
||||
|
||||
> ⚠️ **这是一个目标,而不是保证。** ⚠️
|
||||
>
|
||||
> 该软件仍处于开发的早期阶段,并非所有的安全需求都已被识别或实现。任何改进 Sparo 安全性的努力都不应被解释为与 MIT 许可证的条款相矛盾:
|
||||
>
|
||||
> ```
|
||||
> 该软件按“原样”提供,不附带任何形式的明示或暗示担保,
|
||||
> 包括但不限于适销性、特定用途适用性和非侵权的担保。
|
||||
> 在任何情况下,作者或版权持有者都不对因软件或软件的使用或其他交易
|
||||
> 引起的任何索赔、损害或其他责任负责,无论是在合同诉讼、侵权行为或其他情况下。
|
||||
> ```
|
||||
|
||||
## 安全场景
|
||||
|
||||
Git 没有提供正式的安全规范,因此为了便于分析 Sparo 贡献,我们确定了一些暗示安全需求的使用场景。我们欢迎您的反馈——如果我们忽略了重要的用例,或者 Git 的行为与描述不符,请[告知我们](../support/contributing.md)。
|
||||
|
||||
### SS1: 安全地克隆不受信任的仓库
|
||||
|
||||
假设一个不熟悉的远程 Git 仓库包含恶意文件,其中包括恶意配置文件,如 `.gitattributes`、`.gitignore` 和 Git 钩子脚本。以下操作应被认为是安全的:
|
||||
|
||||
- 使用 `git clone` 克隆远程仓库。
|
||||
- 使用 `git checkout` 签出文件。
|
||||
- 使用 `git commit` 提交本地文件的修改。
|
||||
|
||||
Git 通过默认忽略 Git 钩子和 `.gitattributes` 过滤器来确保安全。用户必须显式运行命令以“选择加入”,表示他们相信该仓库没有恶意代码。例如,调用 `rush install` 将注册预定义的 Git 钩子,因为 NPM 安装涉及执行不受信任的脚本,因此表示信任克隆的仓库。另一个例子是,如果 `.gitattributes` 引用了 LFS 过滤器,用户必须先通过运行 `git lfs install` 选择加入,这表明他们相信过滤器的作者已实施安全保护措施以防止恶意输入。
|
||||
|
||||
Sparo 引入了额外的配置文件,例如 [<profile-name>.json](../configs/profile_json.md)。这些配置文件的解析也必须将输入视为潜在的恶意,并提供相同的安全保证。
|
||||
|
||||
### SS2: 安全地克隆不受信任的仓库参数
|
||||
|
||||
诸如 `git clone https://github.com/example/project.git` 之类的命令会写入一个名为 `project` 的子文件夹。Git 文档将此称为 URL 的["humanish"](https://git-scm.com/docs/git-clone#Documentation/git-clone.txt-ltdirectorygt)部分。
|
||||
|
||||
考虑一个接收 `REPOSITORY` 参数作为文本字符串并随后正确进行 shell 转义后调用 `git clone REPOSITORY` 的远程服务。在计算 humanish 文件夹名称时,Git 不应包含诸如 `..` 或 `/` 之类的特殊字符,这些字符会导致操作将克隆的文件写入预期文件夹之外。
|
||||
|
||||
当然,如果使用 `git clone https://github.com/example/project.git my-folder` 指定了显式目标文件夹,则不应将任何文件克隆到 `my-folder` 文件夹之外。
|
||||
|
||||
### SS3: Git 参数可能包含特殊字符
|
||||
|
||||
Shell 解释器通常会转换涉及特殊字符的表达式,例如 `$`、`%`、`(` 等。例如:
|
||||
|
||||
```shell
|
||||
# 问题:Bash 会将 "$project" 替换为
|
||||
# 名为 "project" 的环境变量的值。
|
||||
git clone https://github.com/example/project.git $project
|
||||
```
|
||||
|
||||
这需要进行转义:
|
||||
|
||||
```shell
|
||||
# 这个反斜杠转义确保在创建的文件夹名称中包含一个字面上的美元符号:
|
||||
git clone https://github.com/example/project.git \$project
|
||||
```
|
||||
|
||||
当 `sparo` 命令行调用子进程(如 `git`)时,它必须仔细确保进程参数被正确转义,以避免被 shell 转换。例如,如果 `\$project` 在子进程调用期间被 shell 扩展,转义将失效,这可能被利用来规避 Sparo 的其他安全保证。如果某些字符[无法通过 Node.js 安全转义](https://github.com/microsoft/rushstack/blob/e2a17c81731cadc6b39b8e75c08dfccb9bc5ce9c/libraries/node-core-library/src/Executable.ts#L689),则应通过错误消息将其拒绝。
|
||||
|
||||
|
||||
## 安全假设
|
||||
|
||||
同时指出一些不期望是安全的方面也很有用。
|
||||
|
||||
## 假设:Shell 环境变量是受信任的
|
||||
|
||||
在大多数情况下,`git` CLI 假设 shell 环境变量是受信任的。例如,它依赖 `PATH` 变量来发现 `ssh` 二进制文件的位置,并且大多数父进程的变量会传递给子进程。
|
||||
|
||||
由于 Sparo 工具是由 Node.js 运行时调用的,通过环境变量(如 [NODE_OPTIONS](https://nodejs.org/api/cli.html#node_optionsoptions))执行任意代码是可能的。
|
||||
|
||||
## 假设:命令行通常是受信任的
|
||||
|
||||
`git` 命令行接受诸如 [-c](https://git-scm.com/docs/git#Documentation/git.txt--cltnamegtltvaluegt) 之类的参数,这些参数可以触发任意代码的执行。因此,通常情况下,我们假设命令行参数是受信任的。然而,某些参数可以提供更严格的保证,例如 **SS3** 中提到的 `git clone` 的 `<repository>` 参数。
|
||||
|
||||
## 假设:命令可能会消耗过多资源
|
||||
|
||||
诸如 `git clone` 之类的命令可能会消耗任意数量的磁盘空间或需要任意长的时间才能完成。一般来说,拒绝服务攻击对于这种开发工具来说不被认为是重要的风险。
|
||||
|
||||
## 假设:STDOUT 和 STDERR 可能包含任意字符
|
||||
|
||||
在调用 `git` CLI 时,控制台输出可能包含由钩子脚本或其他 shell 命令打印的字符串。这些字符串可能包含不安全的特殊字符,不适合嵌入到其他上下文中,如 HTML 文档或 SQL 字符串文字中。调用进程有责任正确转义 `git` 或 `sparo` 进程产生的任何 STDOUT 或 STDERR 输出。
|
|
@ -0,0 +1,28 @@
|
|||
---
|
||||
title: 骨架文件夹
|
||||
---
|
||||
|
||||
默认情况下,`sparo clone` 会初始化一个稀疏签出,不包含任何 Sparo 配置文件选择,但会包含包含基本配置文件的文件夹,如 **package-lock.yaml** 和 **package.json**。我们将这个起点称为签出的 **"骨架"**,因为它显示了 monorepo 中所有项目文件夹的完整树结构,但没有它们的源代码子文件夹。换句话说,尽管每个项目的源文件被排除在外,但骨架仍然允许工程师了解其他团队的项目,以及他们自己的项目与这些其他项目的关系。这有助于避免“隧道视野”(工程师假装他们的项目是仓库中唯一的项目),同时仍然确保 Git 的高效性能。
|
||||
|
||||
由于 Sparo 启用了 Git 稀疏签出的“锥形模式”优化,骨架使用 glob 模式来匹配整个文件夹,而不是单个文件。
|
||||
|
||||
## 骨架规范
|
||||
|
||||
包含的文件夹如下:
|
||||
|
||||
- 整个 `common/**` 文件夹,通常包括所有重要的配置文件和 Rush 操作的自动安装程序。
|
||||
- 对于 **rush.json** 中定义的每个项目,顶级项目文件夹的内容。例如,**packages/my-app/package.json** 和 **packages/my-app/README.md** 将被包含,但 **packages/my-app/src/index.ts** 不会被包含。
|
||||
- 顶级文件夹 `scripts/**` 和 `plugins/**`,因为这些名称通常用于其他重要项目。
|
||||
|
||||
当选择了一个 Sparo 配置文件(例如使用 `sparo checkout --profile my-team`)时,它将引入所选工作区项目下的所有源代码子文件夹。
|
||||
|
||||
## 嵌套项目的处理
|
||||
|
||||
在另一个工作区项目下嵌套一个工作区项目并不是最佳实践。例如,应避免以下文件夹组织方式:
|
||||
|
||||
- **packages/x/package.json**
|
||||
- **packages/x/src/index.ts**
|
||||
- **packages/x/y/package.json** (项目 `y` 嵌套在项目 `x` 内——请避免这样做)
|
||||
- **packages/x/y/src/index.ts**
|
||||
|
||||
然而,Sparo 可以正确支持这种场景。例如,如果您的配置文件选择了 `x` 而未选择 `y`,那么签出将包含 **x/src/index.ts**,但不包含 **x/y/src/index.ts**。
|
|
@ -0,0 +1,37 @@
|
|||
---
|
||||
title: 贡献指南
|
||||
---
|
||||
|
||||
在这个 monorepo 中构建项目:
|
||||
|
||||
1. 安装 [RushJS](https://rushjs.io/) 工具:
|
||||
|
||||
```shell
|
||||
npm install -g @microsoft/rush
|
||||
```
|
||||
|
||||
2. 克隆仓库:
|
||||
|
||||
```shell
|
||||
git clone https://github.com/tiktok/sparo.git
|
||||
```
|
||||
|
||||
3. 安装依赖项
|
||||
|
||||
```shell
|
||||
cd sparo
|
||||
rush install
|
||||
```
|
||||
|
||||
4. 构建所有项目
|
||||
|
||||
```shell
|
||||
rush build
|
||||
```
|
||||
|
||||
如何调用您本地构建的 `sparo` 命令:
|
||||
|
||||
```shell
|
||||
cd apps/sparo
|
||||
node lib/start.js
|
||||
```
|
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
title: 获取帮助
|
||||
---
|
||||
|
||||
请[创建 GitHub issue](https://github.com/tiktok/sparo/issues/new/choose) 来报告任何问题或功能请求。
|
||||
|
||||
对于一般性问题,请使用我们的 [GitHub Discussions](https://github.com/tiktok/sparo/discussions) 论坛。
|
||||
|
||||
## 故障排除提示
|
||||
|
||||
- 升级到最新的 GIT。 如果您的 Git 版本过旧,Sparo 通常会报告错误。如果最低 Git 版本不够高,请告诉我们!
|
||||
|
||||
- 如果操作失败,请使用 `--debug` 进行调查。例如,使用 `sparo --debug clone http://my-repo` 代替 `sparo clone http://my-repo`。
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
title: 更新内容
|
||||
---
|
||||
|
||||
要了解最新版本的更改,请查阅变更日志:
|
||||
|
||||
[CHANGELOG.md](https://github.com/tiktok/sparo/blob/main/apps/sparo/CHANGELOG.md)
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"copyright": {
|
||||
"message": "Copyright © 2024 TikTok Pte. Ltd.",
|
||||
"description": "The footer copyright -- do not translate"
|
||||
}
|
||||
}
|
22
apps/website/i18n/zh-cn/docusaurus-theme-classic/navbar.json
Normal file
22
apps/website/i18n/zh-cn/docusaurus-theme-classic/navbar.json
Normal file
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"logo.alt": {
|
||||
"message": "Sparo",
|
||||
"description": "The alt text of navbar logo"
|
||||
},
|
||||
"item.label.Docs": {
|
||||
"message": "文档",
|
||||
"description": "Navbar item with label Docs"
|
||||
},
|
||||
"item.label.GitHub": {
|
||||
"message": "GitHub",
|
||||
"description": "Navbar item with label GitHub"
|
||||
},
|
||||
"item.label.News": {
|
||||
"message": "新闻",
|
||||
"description": "Navbar item with label News"
|
||||
},
|
||||
"item.label.Help": {
|
||||
"message": "帮助",
|
||||
"description": "Navbar item with label Help"
|
||||
}
|
||||
}
|
|
@ -26,6 +26,7 @@
|
|||
"prism-react-renderer": "^2.3.1",
|
||||
"docusaurus-lunr-search": "^3.3.2",
|
||||
"lunr": "^2.3.9",
|
||||
"lunr-languages": "^1.14.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"search-insights": "^2.13.0"
|
||||
|
@ -33,6 +34,7 @@
|
|||
"devDependencies": {
|
||||
"@docusaurus/module-type-aliases": "3.1.1",
|
||||
"@docusaurus/types": "3.1.1",
|
||||
"@node-rs/jieba": "^1.10.3",
|
||||
"@types/react": "~18.2.59",
|
||||
"@types/react-dom": "~18.2.19",
|
||||
"typescript": "~5.3.3",
|
||||
|
|
190
common/config/rush/pnpm-lock.yaml
generated
190
common/config/rush/pnpm-lock.yaml
generated
|
@ -117,6 +117,9 @@ importers:
|
|||
lunr:
|
||||
specifier: ^2.3.9
|
||||
version: 2.3.9
|
||||
lunr-languages:
|
||||
specifier: ^1.14.0
|
||||
version: 1.14.0
|
||||
prism-react-renderer:
|
||||
specifier: ^2.3.1
|
||||
version: 2.3.1(react@18.2.0)
|
||||
|
@ -136,6 +139,9 @@ importers:
|
|||
'@docusaurus/types':
|
||||
specifier: 3.1.1
|
||||
version: 3.1.1(react-dom@18.2.0)(react@18.2.0)
|
||||
'@node-rs/jieba':
|
||||
specifier: ^1.10.3
|
||||
version: 1.10.3
|
||||
'@types/react':
|
||||
specifier: ~18.2.59
|
||||
version: 18.2.59
|
||||
|
@ -2519,6 +2525,22 @@ packages:
|
|||
- webpack-cli
|
||||
dev: false
|
||||
|
||||
/@emnapi/core@1.1.1:
|
||||
resolution: {integrity: sha512-eu4KjHfXg3I+UUR7vSuwZXpRo4c8h4Rtb5Lu2F7Z4JqJFl/eidquONEBiRs6viXKpWBC3BaJBy68xGJ2j56idw==}
|
||||
requiresBuild: true
|
||||
dependencies:
|
||||
tslib: 2.6.2
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@emnapi/runtime@1.1.1:
|
||||
resolution: {integrity: sha512-3bfqkzuR1KLx57nZfjr2NLnFOobvyS0aTszaEGCGqmYMVDRaGvgIZbjGSV/MHSSmLgQ/b9JFHQ5xm5WRZYd+XQ==}
|
||||
requiresBuild: true
|
||||
dependencies:
|
||||
tslib: 2.6.2
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@eslint-community/eslint-utils@4.4.0(eslint@8.56.0):
|
||||
resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
|
@ -2995,6 +3017,163 @@ packages:
|
|||
resolution: {integrity: sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==}
|
||||
dev: true
|
||||
|
||||
/@napi-rs/wasm-runtime@0.2.3:
|
||||
resolution: {integrity: sha512-e4qmGDzXu2MYjj/XiKSgJ7XS7Z83MYVRN1yYaYXeQNVEO56zmshqmzFaELfdb612sLq/GmiPfRIwSji+bIlyCw==}
|
||||
requiresBuild: true
|
||||
dependencies:
|
||||
'@emnapi/core': 1.1.1
|
||||
'@emnapi/runtime': 1.1.1
|
||||
'@tybys/wasm-util': 0.8.3
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@node-rs/jieba-android-arm-eabi@1.10.3:
|
||||
resolution: {integrity: sha512-fuqVtaYlUKZg3cqagYFxj1DSa7ZHKXLle4iGH2kbQWg7Kw6cf7aCYBHIUZuH5sliK10M/CWccZ+SGRUwcSGfbg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@node-rs/jieba-android-arm64@1.10.3:
|
||||
resolution: {integrity: sha512-iuZZZq5yD9lT+AgaXpFe19gtAsIecUODRLLaBFbavjgjLk5cumv38ytWjS36s/eqptwI15MQfysSYOlWtMEG5g==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@node-rs/jieba-darwin-arm64@1.10.3:
|
||||
resolution: {integrity: sha512-dwPhkav1tEARskwPz91UUXL2NXy4h0lJYTuJzpGgwXxm552zBM2JJ41kjah1364j+EOq5At3NQvf5r5rH89phQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@node-rs/jieba-darwin-x64@1.10.3:
|
||||
resolution: {integrity: sha512-kjxvV6G1baQo/2I3mELv5qGv4Q0rhd5srwXhypSxMWZFtSpNwCDsLcIOR5bvMBci6QVFfZOs6WD6DKiWVz0SlA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@node-rs/jieba-freebsd-x64@1.10.3:
|
||||
resolution: {integrity: sha512-QYTsn+zlWRil+MuBeLfTK5Md4GluOf2lHnFqjrOZW2oMgNOvxB3qoLV4TUf70S/E2XHeP6PUdjCKItX8C7GQPg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@node-rs/jieba-linux-arm-gnueabihf@1.10.3:
|
||||
resolution: {integrity: sha512-UFB43kDOvqmbRl99e3GPwaTuwJZaAvgLaMTvBkmxww4MpQH6G1k31RLzMW/S21uSQso2lj6W/Mm59gaJk2FiyA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@node-rs/jieba-linux-arm64-gnu@1.10.3:
|
||||
resolution: {integrity: sha512-bu++yWi10wZtnS5uLcwxzxKmHVT77NgQMK8JiQr1TWCl3Y1Th7CnEHQtxfVB489edDK8l644h1/4zSTe5fRnOQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@node-rs/jieba-linux-arm64-musl@1.10.3:
|
||||
resolution: {integrity: sha512-pJh+SzrK1HaKakhdFM+ew9vXwpZqMxy9u0U7J4GT+3GvOwnAZ+KjeaHebIfgOz7ZHvp/T4YBNf8oWW4zwj3AJw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@node-rs/jieba-linux-x64-gnu@1.10.3:
|
||||
resolution: {integrity: sha512-GF5cfvu/0wXO2fVX/XV3WYH/xEGWzMBvfqLhGiA1OA1xHIufnA1T7uU3ZXkyoNi5Bzf6dmxnwtE4CJL0nvhwjQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@node-rs/jieba-linux-x64-musl@1.10.3:
|
||||
resolution: {integrity: sha512-h45HMVU/hgzQ0saXNsK9fKlGdah1i1cXZULpB5vQRlRL2ZIaGp+ULtWTogS7vkoo2K8s2l4tqakWMg9eUjIJ2A==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@node-rs/jieba-wasm32-wasi@1.10.3:
|
||||
resolution: {integrity: sha512-vuoQ62vVoedNGcBmIi4UWdtNBOZG8B+vDYfjx3FD6rNg6g/RgwbVjYXbOVMOQwX06Ob9CfrutICXdUGHgoxzEQ==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
cpu: [wasm32]
|
||||
requiresBuild: true
|
||||
dependencies:
|
||||
'@napi-rs/wasm-runtime': 0.2.3
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@node-rs/jieba-win32-arm64-msvc@1.10.3:
|
||||
resolution: {integrity: sha512-B8t4dh56TZnMLBoYWDkopf1ed37Ru/iU1qiIeBkbZWXGmNBChNZUOd//eaPOFjx8m9Sfc8bkj3FBRWt/kTAhmw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@node-rs/jieba-win32-ia32-msvc@1.10.3:
|
||||
resolution: {integrity: sha512-SKuPGZJ5T+X4jOn1S8LklOSZ6HC7UBiw0hwi2z9uqX6WgElquLjGi/xfZ2gPqffeR/5K/PUu7aqYUUPL1XonVQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@node-rs/jieba-win32-x64-msvc@1.10.3:
|
||||
resolution: {integrity: sha512-j9I4+a/tf2hsLu8Sr0NhcLBVNBBQctO2mzcjemMpRa1SlEeODyic9RIyP8Ljz3YTN6MYqKh1KA9iR1xvxjxYFg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@node-rs/jieba@1.10.3:
|
||||
resolution: {integrity: sha512-SG0CWHmhIveH6upJURgymDKLertEPYbOc5NSFIpbZWW1W2MpqgumVteQO+5YBlkmpR6jMNDPWNQyQwkB6HoeNg==}
|
||||
engines: {node: '>= 10'}
|
||||
optionalDependencies:
|
||||
'@node-rs/jieba-android-arm-eabi': 1.10.3
|
||||
'@node-rs/jieba-android-arm64': 1.10.3
|
||||
'@node-rs/jieba-darwin-arm64': 1.10.3
|
||||
'@node-rs/jieba-darwin-x64': 1.10.3
|
||||
'@node-rs/jieba-freebsd-x64': 1.10.3
|
||||
'@node-rs/jieba-linux-arm-gnueabihf': 1.10.3
|
||||
'@node-rs/jieba-linux-arm64-gnu': 1.10.3
|
||||
'@node-rs/jieba-linux-arm64-musl': 1.10.3
|
||||
'@node-rs/jieba-linux-x64-gnu': 1.10.3
|
||||
'@node-rs/jieba-linux-x64-musl': 1.10.3
|
||||
'@node-rs/jieba-wasm32-wasi': 1.10.3
|
||||
'@node-rs/jieba-win32-arm64-msvc': 1.10.3
|
||||
'@node-rs/jieba-win32-ia32-msvc': 1.10.3
|
||||
'@node-rs/jieba-win32-x64-msvc': 1.10.3
|
||||
dev: true
|
||||
|
||||
/@nodelib/fs.scandir@2.1.5:
|
||||
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
|
||||
engines: {node: '>= 8'}
|
||||
|
@ -3542,6 +3721,14 @@ packages:
|
|||
engines: {node: '>=10.13.0'}
|
||||
dev: false
|
||||
|
||||
/@tybys/wasm-util@0.8.3:
|
||||
resolution: {integrity: sha512-Z96T/L6dUFFxgFJ+pQtkPpne9q7i6kIPYCFnQBHSgSPV9idTsKfIhCss0h5iM9irweZCatkrdeP8yi5uM1eX6Q==}
|
||||
requiresBuild: true
|
||||
dependencies:
|
||||
tslib: 2.6.2
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@types/acorn@4.0.6:
|
||||
resolution: {integrity: sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==}
|
||||
dependencies:
|
||||
|
@ -11518,7 +11705,6 @@ packages:
|
|||
|
||||
/tslib@2.6.2:
|
||||
resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
|
||||
dev: false
|
||||
|
||||
/type-check@0.4.0:
|
||||
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
|
||||
|
@ -12371,6 +12557,7 @@ time:
|
|||
/@docusaurus/theme-common@3.1.1: '2024-01-26T12:52:31.593Z'
|
||||
/@docusaurus/types@3.1.1: '2024-01-26T12:51:42.114Z'
|
||||
/@mdx-js/react@3.0.1: '2024-02-12T10:50:27.073Z'
|
||||
/@node-rs/jieba@1.10.3: '2024-04-23T07:06:16.446Z'
|
||||
/@rushstack/heft-node-rig@2.4.5: '2024-01-25T23:04:47.299Z'
|
||||
/@rushstack/heft@0.64.3: '2024-01-25T01:10:38.111Z'
|
||||
/@rushstack/node-core-library@3.64.2: '2024-01-25T01:11:45.156Z'
|
||||
|
@ -12388,6 +12575,7 @@ time:
|
|||
/git-repo-info@2.1.1: '2019-10-18T15:12:09.674Z'
|
||||
/inversify@6.0.2: '2023-10-20T23:35:39.918Z'
|
||||
/jest-diff@29.7.0: '2023-09-12T06:43:43.883Z'
|
||||
/lunr-languages@1.14.0: '2023-10-09T20:33:09.608Z'
|
||||
/lunr@2.3.9: '2020-08-19T20:30:07.948Z'
|
||||
/prism-react-renderer@2.3.1: '2023-12-18T14:23:38.265Z'
|
||||
/prismjs@1.29.0: '2022-08-23T10:42:14.395Z'
|
||||
|
|
Loading…
Add table
Reference in a new issue