git0 0.2.98 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/benchmark/README.md +104 -0
- package/benchmark/report.ts +142 -0
- package/benchmark/tarball-vs-clone.bench.ts +173 -0
- package/dist/cli.js +264 -25
- package/dist/cli.js.map +9 -7
- package/package.json +3 -2
- package/readme.md +120 -1
- package/src/args.ts +58 -0
- package/src/cli.ts +104 -20
- package/src/download.ts +214 -12
- package/src/github-api.ts +108 -2
- package/src/history.ts +225 -0
- package/src/utils.ts +29 -9
- package/test/args.test.ts +44 -0
- package/test/benchmark-report.test.ts +102 -0
- package/test/download-repo.test.ts +178 -0
- package/test/history.test.ts +157 -0
- package/test/parse-target.test.ts +73 -0
- package/test/subpath.test.ts +178 -0
- package/test/utils.test.ts +37 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "git0",
|
|
3
3
|
"description": "CLI tool to search GitHub repositories, download source & releases for your system, and instantly set up, then install dependencies and open code editor.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.3.0",
|
|
5
5
|
"author": "vtempest",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"build": "bun build src/cli.ts --outdir dist --target node --format esm --sourcemap",
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"test:ci": "bun test --reporter=junit --reporter-outfile=./junit.xml --coverage --coverage-reporter=lcov --coverage-dir=./coverage",
|
|
10
10
|
"docs": "cd docs-config && bun run build:docs",
|
|
11
11
|
"demo": "bun src/cli.ts react template",
|
|
12
|
+
"bench": "bun benchmark/tarball-vs-clone.bench.ts",
|
|
12
13
|
"publish:npm": "npm version patch && npm publish --access public",
|
|
13
14
|
"test:watch": "vitest",
|
|
14
15
|
"coverage": "vitest run --coverage"
|
|
@@ -45,7 +46,7 @@
|
|
|
45
46
|
"url": "git+https://github.com/OpenSourceAGI/dev-tools-starter-agent.git",
|
|
46
47
|
"directory": "packages/git0-repo-downloader"
|
|
47
48
|
},
|
|
48
|
-
"homepage": "https://
|
|
49
|
+
"homepage": "https://git0.js.org",
|
|
49
50
|
"devDependencies": {
|
|
50
51
|
"@vitest/coverage-v8": "^4.1.0",
|
|
51
52
|
"vitest": "^4.1.0"
|
package/readme.md
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
<!-- template-git-repo:badges:start -->
|
|
6
6
|
<p align="center">
|
|
7
|
+
<a href="https://git0.js.org"><img height="20px" src="https://img.shields.io/badge/App-blueviolet?style=for-the-badge&logo=googlechrome&logoColor=white" alt="Website" /></a>
|
|
7
8
|
<a href="https://starterdocs.vtempest.workers.dev/docs/packages/git0-repo-downloader"><img src="https://img.shields.io/badge/Docs-blue?logo=ReadTheDocs&logoColor=white" alt="Documentation" /></a>
|
|
8
9
|
<br />
|
|
9
10
|
<a href="https://github.com/OpenSourceAGI/dev-tools-starter-agent/stargazers"><img src="https://img.shields.io/github/stars/OpenSourceAGI/dev-tools-starter-agent" alt="GitHub Stars" /></a>
|
|
@@ -33,6 +34,8 @@
|
|
|
33
34
|
|
|
34
35
|
CLI tool to search GitHub repositories, download source & releases for your system, and instantly set up, then install dependencies and open code editor.
|
|
35
36
|
|
|
37
|
+
**🌐 [git0.js.org](https://git0.js.org)**
|
|
38
|
+
|
|
36
39
|
## 🚀 Installation
|
|
37
40
|
|
|
38
41
|
```bash
|
|
@@ -55,6 +58,8 @@ bun install -g git0
|
|
|
55
58
|
- **Smart IDE integration** - automatically opens projects in your preferred editor
|
|
56
59
|
- **Cross-platform support** - works on Windows, macOS, and Linux
|
|
57
60
|
- **Conflict resolution** - handles directory naming conflicts automatically
|
|
61
|
+
- **Partial paths** - paste a `/tree/` or `/blob/` link and download just that folder or file
|
|
62
|
+
- **Optional `.git` history** - `--history` attaches the full history *after* the source is already on disk
|
|
58
63
|
- **Faster than git** - skips `.git` history and uncompresses while downloading
|
|
59
64
|
|
|
60
65
|
## 🎯 Usage
|
|
@@ -74,6 +79,119 @@ git0 facebook/react
|
|
|
74
79
|
# Use git0 without installing, (only node needed)
|
|
75
80
|
# (copy this line into your project's readme to help others setup)
|
|
76
81
|
npx git0 facebook/react
|
|
82
|
+
|
|
83
|
+
# Download only one folder — paste the GitHub link as you copied it
|
|
84
|
+
g https://github.com/facebook/react/tree/main/packages/react-dom
|
|
85
|
+
|
|
86
|
+
# ...or one file
|
|
87
|
+
g https://github.com/debate/debate-ai.com/blob/master/.continue/agents/new-config.yaml
|
|
88
|
+
|
|
89
|
+
# Same thing, without a URL
|
|
90
|
+
git0 facebook/react/packages/react-dom
|
|
91
|
+
git0 facebook/react --path=packages/react-dom
|
|
92
|
+
|
|
93
|
+
# A specific branch, tag or commit
|
|
94
|
+
git0 facebook/react --branch=v18.2.0
|
|
95
|
+
|
|
96
|
+
# With the full .git history attached after the download
|
|
97
|
+
git0 facebook/react --history
|
|
98
|
+
|
|
99
|
+
# History only — no working files at all
|
|
100
|
+
git0 facebook/react --history-only
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Options
|
|
104
|
+
|
|
105
|
+
| Flag | What it does |
|
|
106
|
+
| --- | --- |
|
|
107
|
+
| `--path=<path>` | Download only that folder or file of the repository |
|
|
108
|
+
| `--branch=<ref>` | Download a branch, tag or commit instead of the default branch |
|
|
109
|
+
| `--history` | Also fetch the full `.git` history, in the background |
|
|
110
|
+
| `--history-only` | Clone only the history — no working files |
|
|
111
|
+
| `--mirror` | Keep every ref (notes, remote-tracking) when cloning history |
|
|
112
|
+
|
|
113
|
+
## 📁 Partial Paths
|
|
114
|
+
|
|
115
|
+
Copy a link out of the GitHub UI and git0 downloads exactly what the link points
|
|
116
|
+
at, not the repository around it:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
g https://github.com/facebook/react/tree/main/packages/react-dom
|
|
120
|
+
# → ./react-dom/ — the contents of that folder, at the root
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
The branch and the path are both read off the URL. Entries outside the path are
|
|
124
|
+
discarded as the tarball streams, so they are never written to disk, and what is
|
|
125
|
+
kept is lifted to the root of the target folder — you get `react-dom/`, not
|
|
126
|
+
`react/packages/react-dom/`.
|
|
127
|
+
|
|
128
|
+
The folder is named after the path rather than the repository, because that is
|
|
129
|
+
what you asked for. A `/blob/` link to a single file downloads that one file into
|
|
130
|
+
its enclosing folder's name. Pass a second argument, or `--path` with any repo
|
|
131
|
+
reference, if you'd rather name it yourself:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
git0 facebook/react --path=packages/react-dom my-copy
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## 🕐 Downloading With `.git` History
|
|
138
|
+
|
|
139
|
+
By default git0 downloads a tarball — the source at one commit, no history. That
|
|
140
|
+
is what makes it quick. When you *do* want the history, `--history` gets you both
|
|
141
|
+
without giving up the speed:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
git0 facebook/react --history
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
The source tarball lands first. The history is fetched **after** the archive has
|
|
148
|
+
finished unzipping, in the background, while the IDE opens and dependencies
|
|
149
|
+
install. You end up in exactly the state `git clone` would have left you in — a
|
|
150
|
+
working tree with a full `.git` beside it, `git log` and `git blame` working,
|
|
151
|
+
`git status` clean — except you started working several seconds earlier.
|
|
152
|
+
|
|
153
|
+
**Why the lazy order is faster.** `git clone` is one serial operation: the remote
|
|
154
|
+
counts and packs every object in the project's history, sends the pack, and only
|
|
155
|
+
then writes files you can run. Nothing can start until all of it finishes. A
|
|
156
|
+
GitHub tarball is a pre-made, cached, already-compressed snapshot of one commit,
|
|
157
|
+
so git0 pipes it straight into a `tar` extractor — files are being written while
|
|
158
|
+
the rest is still downloading. And history is the one part of a clone that
|
|
159
|
+
nothing on the critical path is waiting for: `bun install` does not need `git
|
|
160
|
+
log`. So it is fetched last, overlapping the install rather than blocking it.
|
|
161
|
+
|
|
162
|
+
There is a benchmark for this in [`benchmark/`](./benchmark) — it measures
|
|
163
|
+
*time until the project can run*, separately from *time until history is
|
|
164
|
+
available*, for `git clone`, `git clone --depth=1`, git0, and `git0 --history`:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
bun run bench facebook/react
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### History Only
|
|
171
|
+
|
|
172
|
+
To take the history and none of the working files — for a backup, a mirror, or
|
|
173
|
+
to move a repository between hosts:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
git0 facebook/react --history-only
|
|
177
|
+
# → ./react.git/ — HEAD, config, objects/, refs/, packed-refs
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
That directory holds what normally lives inside `.git`, placed at its root: all
|
|
181
|
+
the commits, branches and tags, no editable files. Read it without checking
|
|
182
|
+
anything out, or restore a normal working copy from it:
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
git --git-dir=react.git log --all --oneline
|
|
186
|
+
git clone react.git react
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
`--history-only` uses a bare clone (branches and tags). Add `--mirror` for every
|
|
190
|
+
ref Git can fetch — notes, remote-tracking refs and the rest — which is what you
|
|
191
|
+
want when the point is a complete backup:
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
git0 facebook/react --history-only --mirror
|
|
77
195
|
```
|
|
78
196
|
|
|
79
197
|
### Supported Project Types
|
|
@@ -104,11 +222,12 @@ git0 automatically detects and opens projects in your preferred IDE:
|
|
|
104
222
|
|
|
105
223
|
### What Happens After Download
|
|
106
224
|
|
|
107
|
-
1. **Repository is downloaded** to your current directory
|
|
225
|
+
1. **Repository is downloaded** to your current directory — only the requested path, if you named one
|
|
108
226
|
2. **Project type is detected** automatically
|
|
109
227
|
3. **Dependencies are installed** based on project type
|
|
110
228
|
4. **IDE is launched** automatically (if available)
|
|
111
229
|
5. **Development server starts** (for Node.js projects)
|
|
230
|
+
6. **`.git` history is attached** in the background, if you passed `--history`
|
|
112
231
|
|
|
113
232
|
If a directory with the same name exists, git0 automatically appends a number (e.g., `react-2`, `react-3`).
|
|
114
233
|
|
package/src/args.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The flags git0 accepts, and what they mean.
|
|
5
|
+
*
|
|
6
|
+
* Kept to a handful on purpose — the common case is one argument and no flags.
|
|
7
|
+
*/
|
|
8
|
+
export interface Flags {
|
|
9
|
+
/** `--path=<p>` — limit the download to one folder or file of the repo. */
|
|
10
|
+
path?: string;
|
|
11
|
+
/** `--branch=<ref>` — download a branch, tag or commit other than the default. */
|
|
12
|
+
branch?: string;
|
|
13
|
+
/** `--history` — also attach the full `.git` history, in the background. */
|
|
14
|
+
history: boolean;
|
|
15
|
+
/** `--history-only` — clone only the history, no working files. */
|
|
16
|
+
historyOnly: boolean;
|
|
17
|
+
/** `--mirror` — use `--mirror` rather than `--bare` when cloning history. */
|
|
18
|
+
mirror: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Splits `process.argv` into positional arguments and flags.
|
|
23
|
+
*
|
|
24
|
+
* Deliberately hand-rolled rather than pulled in: git0's surface is one
|
|
25
|
+
* positional argument and five flags, and the argument itself is frequently a
|
|
26
|
+
* URL, which most parsers are keen to mangle.
|
|
27
|
+
*
|
|
28
|
+
* @param argv - Arguments after the node binary and script name.
|
|
29
|
+
* @returns The positional arguments and the parsed flags.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* parseArgs(['facebook/react', '--history', '--path=packages/react-dom']);
|
|
33
|
+
* // → { positional: ['facebook/react'],
|
|
34
|
+
* // flags: { history: true, path: 'packages/react-dom', … } }
|
|
35
|
+
*/
|
|
36
|
+
export function parseArgs(argv: string[]): { positional: string[]; flags: Flags } {
|
|
37
|
+
const positional: string[] = [];
|
|
38
|
+
const flags: Flags = { history: false, historyOnly: false, mirror: false };
|
|
39
|
+
|
|
40
|
+
for (const arg of argv) {
|
|
41
|
+
if (!arg.startsWith('--')) {
|
|
42
|
+
positional.push(arg);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const [name, ...rest] = arg.slice(2).split('=');
|
|
47
|
+
const value = rest.join('=');
|
|
48
|
+
|
|
49
|
+
if (name === 'path') flags.path = value;
|
|
50
|
+
else if (name === 'branch' || name === 'ref') flags.branch = value;
|
|
51
|
+
else if (name === 'history' || name === 'git') flags.history = true;
|
|
52
|
+
else if (name === 'history-only' || name === 'git-only') flags.historyOnly = true;
|
|
53
|
+
else if (name === 'mirror') flags.mirror = true;
|
|
54
|
+
else console.log(chalk.yellow(`Ignoring unknown flag: ${arg}`));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return { positional, flags };
|
|
58
|
+
}
|
package/src/cli.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import inquirer from 'inquirer';
|
|
3
3
|
import chalk from 'chalk';
|
|
4
|
-
import
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import GithubAPI, { type RepoTarget } from './github-api.js';
|
|
5
6
|
import { openInIDE } from './ide.js';
|
|
6
7
|
import { installDependencies } from './install.js';
|
|
7
8
|
import { showPackageMenu } from './package-menu.js';
|
|
9
|
+
import { attachGitHistoryLazily, cloneHistoryOnly } from './history.js';
|
|
10
|
+
import { parseArgs, type Flags } from './args.js';
|
|
11
|
+
import { getAvailableDirectoryName } from './download.js';
|
|
8
12
|
import { printLogo } from './utils.js';
|
|
9
13
|
import type { SearchResult } from './types.js';
|
|
10
14
|
|
|
@@ -17,19 +21,71 @@ const Github = new GithubAPI({ debug: false });
|
|
|
17
21
|
* The IDE launch is deferred 500 ms so the extraction can finish writing files
|
|
18
22
|
* before the editor tries to index them.
|
|
19
23
|
*
|
|
20
|
-
*
|
|
24
|
+
* With `--history`, the `.git` directory is fetched *after* extraction and runs
|
|
25
|
+
* alongside the IDE launch and the dependency install rather than in front of
|
|
26
|
+
* them — see {@link attachGitHistoryLazily} for why that ordering is the whole
|
|
27
|
+
* point.
|
|
28
|
+
*
|
|
29
|
+
* @param target - Parsed repository reference, including any sub-path.
|
|
21
30
|
* @param folderPath - Optional name for the extraction directory; defaults to
|
|
22
|
-
* the repository name.
|
|
31
|
+
* the repository name, or the sub-path's name when one is given.
|
|
32
|
+
* @param flags - Parsed CLI flags.
|
|
23
33
|
*
|
|
24
34
|
* @example
|
|
25
|
-
* await downloadRepoAndSetup('
|
|
35
|
+
* await downloadRepoAndSetup(parseTarget('vitejs/vite') as RepoTarget);
|
|
26
36
|
* // Downloads vite/, opens it in the first available IDE, runs bun install
|
|
27
37
|
*/
|
|
28
|
-
async function downloadRepoAndSetup(
|
|
38
|
+
async function downloadRepoAndSetup(
|
|
39
|
+
target: RepoTarget,
|
|
40
|
+
folderPath: string | null = null,
|
|
41
|
+
flags: Flags = { history: false, historyOnly: false, mirror: false }
|
|
42
|
+
): Promise<void> {
|
|
29
43
|
printLogo();
|
|
30
|
-
|
|
44
|
+
|
|
45
|
+
const ref = flags.branch || target.ref;
|
|
46
|
+
const extractPath = await Github.downloadRepo(target.href, folderPath, {
|
|
47
|
+
subPath: flags.path ?? target.subPath,
|
|
48
|
+
subPathType: flags.path ? '' : target.subPathType,
|
|
49
|
+
ref,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// Started here, not awaited here: the files are on disk, so everything below
|
|
53
|
+
// can proceed while the history downloads.
|
|
54
|
+
const history = flags.history
|
|
55
|
+
? attachGitHistoryLazily(extractPath, target.href, { mirror: flags.mirror, ref })
|
|
56
|
+
: Promise.resolve();
|
|
57
|
+
|
|
31
58
|
setTimeout(() => openInIDE(extractPath), 500);
|
|
32
59
|
await installDependencies(extractPath);
|
|
60
|
+
await history;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Handles `--history-only`: clones the repository's history into `<name>.git`
|
|
65
|
+
* and downloads no working files at all.
|
|
66
|
+
*
|
|
67
|
+
* @param target - Parsed repository reference.
|
|
68
|
+
* @param flags - Parsed CLI flags.
|
|
69
|
+
*
|
|
70
|
+
* @internal
|
|
71
|
+
*/
|
|
72
|
+
async function downloadHistoryOnly(target: RepoTarget, flags: Flags): Promise<void> {
|
|
73
|
+
printLogo();
|
|
74
|
+
|
|
75
|
+
const targetDir = getAvailableDirectoryName(path.resolve(process.cwd(), `${target.name}.git`));
|
|
76
|
+
console.log(chalk.blue(`📦 Cloning ${target.name} history into ${path.basename(targetDir)}...`));
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
await cloneHistoryOnly(target.href, targetDir, { bare: !flags.mirror });
|
|
80
|
+
console.log(chalk.green(`✅ History-only clone at ${targetDir}`));
|
|
81
|
+
console.log(chalk.white(' Read the log without checking anything out:'));
|
|
82
|
+
console.log(chalk.gray(` git --git-dir="${targetDir}" log --all --oneline`));
|
|
83
|
+
console.log(chalk.white(' Or restore a working copy from it:'));
|
|
84
|
+
console.log(chalk.gray(` git clone "${targetDir}" ${target.name}`));
|
|
85
|
+
} catch (error: any) {
|
|
86
|
+
console.error(chalk.red('❌ History clone failed:'), error.message);
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
33
89
|
}
|
|
34
90
|
|
|
35
91
|
/**
|
|
@@ -61,12 +117,19 @@ function formatRepoChoice(repo: SearchResult): string {
|
|
|
61
117
|
* source code, or both when a repository has release assets.
|
|
62
118
|
*
|
|
63
119
|
* @param selectedRepo - The repository the user chose in the search results.
|
|
120
|
+
* @param flags - Parsed CLI flags, forwarded to the source download.
|
|
64
121
|
*
|
|
65
122
|
* @internal
|
|
66
123
|
*/
|
|
67
|
-
async function handleRepoDownload(selectedRepo: SearchResult): Promise<void> {
|
|
124
|
+
async function handleRepoDownload(selectedRepo: SearchResult, flags: Flags): Promise<void> {
|
|
125
|
+
const target = Github.parseTarget(selectedRepo.url);
|
|
126
|
+
if (!target) {
|
|
127
|
+
console.log(chalk.yellow(`Could not parse repository URL: ${selectedRepo.url}`));
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
68
131
|
if (!selectedRepo.hasReleases && !selectedRepo.hasCompatibleReleases) {
|
|
69
|
-
await downloadRepoAndSetup(
|
|
132
|
+
await downloadRepoAndSetup(target, null, flags);
|
|
70
133
|
return;
|
|
71
134
|
}
|
|
72
135
|
|
|
@@ -89,7 +152,7 @@ async function handleRepoDownload(selectedRepo: SearchResult): Promise<void> {
|
|
|
89
152
|
);
|
|
90
153
|
}
|
|
91
154
|
if (downloadChoice === 'source' || downloadChoice === 'both') {
|
|
92
|
-
await downloadRepoAndSetup(
|
|
155
|
+
await downloadRepoAndSetup(target, null, flags);
|
|
93
156
|
}
|
|
94
157
|
}
|
|
95
158
|
|
|
@@ -97,9 +160,10 @@ async function handleRepoDownload(selectedRepo: SearchResult): Promise<void> {
|
|
|
97
160
|
* CLI entry point for the `git0` / `g` / `gg` commands.
|
|
98
161
|
*
|
|
99
162
|
* **Flow:**
|
|
100
|
-
* 1. Parse `process.argv`
|
|
163
|
+
* 1. Parse `process.argv` into flags and a search query or direct repo URL.
|
|
101
164
|
* 2. If the argument looks like a GitHub URL or `owner/repo`, download it
|
|
102
|
-
* directly — optionally into a custom folder (second
|
|
165
|
+
* directly — optionally into a custom folder (second positional argument),
|
|
166
|
+
* limited to a sub-path, and optionally with `.git` history.
|
|
103
167
|
* 3. Otherwise, search GitHub and present an interactive list.
|
|
104
168
|
* 4. After the user picks a repo, offer package vs. source download when
|
|
105
169
|
* releases are available.
|
|
@@ -111,23 +175,40 @@ async function handleRepoDownload(selectedRepo: SearchResult): Promise<void> {
|
|
|
111
175
|
* // git0 facebook/react
|
|
112
176
|
* // git0 https://github.com/vitejs/vite my-vite-copy
|
|
113
177
|
*
|
|
178
|
+
* // Just one folder of it:
|
|
179
|
+
* // git0 https://github.com/facebook/react/tree/main/packages/react-dom
|
|
180
|
+
* // git0 facebook/react --path=packages/react-dom
|
|
181
|
+
*
|
|
182
|
+
* // With git history, fetched after the source is already on disk:
|
|
183
|
+
* // git0 facebook/react --history
|
|
184
|
+
* // git0 facebook/react --history-only
|
|
185
|
+
*
|
|
114
186
|
* // Search:
|
|
115
187
|
* // git0 react template starter
|
|
116
188
|
*/
|
|
117
189
|
async function main(): Promise<void> {
|
|
118
190
|
printLogo();
|
|
119
191
|
|
|
120
|
-
const
|
|
121
|
-
if (!
|
|
122
|
-
console.log(chalk.yellow('Usage: git0 <github-url | owner/repo | search-query>'));
|
|
192
|
+
const { positional, flags } = parseArgs(process.argv.slice(2));
|
|
193
|
+
if (!positional.length) {
|
|
194
|
+
console.log(chalk.yellow('Usage: git0 <github-url | owner/repo[/path] | search-query>'));
|
|
195
|
+
console.log(chalk.gray(' --path=<path> download only that folder or file'));
|
|
196
|
+
console.log(chalk.gray(' --branch=<ref> download a branch, tag or commit'));
|
|
197
|
+
console.log(chalk.gray(' --history also fetch .git history, in the background'));
|
|
198
|
+
console.log(chalk.gray(' --history-only clone only the history, no working files'));
|
|
199
|
+
console.log(chalk.gray(' --mirror keep every ref when cloning history'));
|
|
123
200
|
process.exit(1);
|
|
124
201
|
}
|
|
125
202
|
|
|
126
|
-
const query =
|
|
127
|
-
const
|
|
203
|
+
const query = positional.join(' ');
|
|
204
|
+
const target = Github.parseTarget(query);
|
|
128
205
|
|
|
129
|
-
if (
|
|
130
|
-
|
|
206
|
+
if (target) {
|
|
207
|
+
if (flags.historyOnly) {
|
|
208
|
+
await downloadHistoryOnly(target, flags);
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
await downloadRepoAndSetup(target, positional[1] ?? null, flags);
|
|
131
212
|
return;
|
|
132
213
|
}
|
|
133
214
|
|
|
@@ -144,7 +225,10 @@ async function main(): Promise<void> {
|
|
|
144
225
|
choices: results.map(repo => ({ name: formatRepoChoice(repo), value: repo })),
|
|
145
226
|
});
|
|
146
227
|
|
|
147
|
-
await handleRepoDownload(selectedRepo);
|
|
228
|
+
await handleRepoDownload(selectedRepo, flags);
|
|
148
229
|
}
|
|
149
230
|
|
|
150
|
-
main()
|
|
231
|
+
main().catch((error: any) => {
|
|
232
|
+
console.error(chalk.red(`❌ ${error.message}`));
|
|
233
|
+
process.exit(1);
|
|
234
|
+
});
|