Skip to content

Extend git CLI interface based on agent usage - #141

Open
aron-cf wants to merge 2 commits into
mainfrom
git-fixes
Open

Extend git CLI interface based on agent usage#141
aron-cf wants to merge 2 commits into
mainfrom
git-fixes

Conversation

@aron-cf

@aron-cf aron-cf commented Sep 11, 2026

Copy link
Copy Markdown
Collaborator

The git clone command defaulted to a depth of 1, so a clone then push ended up wiping the remote history.

git clone "$URL" repo && cd repo
git log --oneline | wc -l    # 1, from a repository with hundreds
git push "$OTHER" HEAD:refs/heads/copy
# exits 0, prints a normal ref update, and the copy has one commit

Clone now fetches full history, and a shallow clone is something the caller asks for:

git clone "$URL" repo              # full history
git clone --depth 1 "$URL" repo    # shallow, knowingly
await ws.git.clone({ url });             // full history
await ws.git.clone({ url, depth: 1 });   // shallow

Speed was the reason for the old default and it is still available. It is just no longer the silent choice, because the caller who wanted speed and the caller who wanted their history had no way to tell them apart.

Three smaller gaps in the same command set go with it. cat-file read an object's bytes but could not report its type or size, which readObject already returned:

git cat-file -p <oid>   # bytes, as before
git cat-file -t <oid>   # commit
git cat-file -s <oid>   # 245

Exactly one of the three is required, matching real git. The typed surface carries the type alongside the bytes:

const { bytes, type } = await ws.git.catFile({ oid });

log had --oneline and nothing else, so any other shape meant post-processing the default output. It now takes --format and its alias --pretty:

git log --format='%h %s (%an)'
# 2bc75d1 let the caller choose the exec shell (A. Name)

The placeholders are %H, %h, %s, %b, %an, %ae, %ad, %cn, %ce, %cd, and %%, plus the named format oneline. Anything outside that set is left as written, so an unsupported placeholder appears in the output rather than disappearing from it.

git help <command> ignored its argument and reprinted the full command list, leaving no way to find a command's flags except guessing and reading the exit code. It now answers the question asked, listing only the flags this wrapper accepts:

git help log
# usage: git log [-n <count>] [-<count>] [--oneline] [<ref>]

To check the clone change, clone any repository with history and count the commits: the number should match the source rather than be 1. The other three are visible directly from the examples above.

Tests cover each one: that clone requests full history by default and still honors an explicit depth, that cat-file reports type and size and rejects combining the modes, that the log placeholders expand and an unknown one survives untouched, and that help answers for one command, still lists everything when asked for nothing, and reports a command it does not have.

The git interface documentation covers the new clone default, the cat-file modes, the log placeholders, and the per-command help.


Devin Review

@changeset-bot

changeset-bot Bot commented Sep 11, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: ba8591b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 4 packages
Name Type
@cloudflare/computer Minor
@cloudflare/dofs Minor
@cloudflare/computer-rpc Minor
@cloudflare/computerd Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

This report is out of date. Scroll down for Devin Review's latest report on this PR.

Devin Review found 2 potential issues.

2 flags not posted on this PR by your GitHub settings — view them in Devin Review. (Configure)

Devin Review

Comment on lines +161 to +193
const COMMAND_USAGE: Record<string, string> = {
add: "git add [-A] <path>...",
branch: "git branch [-d|-D <name>] [--show-current] [<name>]",
"cat-file": "git cat-file (-p|-t|-s) <oid>[:<path>]",
checkout: "git checkout [-b <name>] [-f] <ref> [--] [<path>...]",
clean: "git clean [-f] [-d] [-n] [<path>...]",
clone:
"git clone [--depth <n>] [--branch <ref>] [--single-branch|--no-single-branch] <url> [<dir>]",
commit: "git commit -m <message> [-a]",
config: "git config [--get] <key> [<value>]",
diff: "git diff [--stat] [--name-only] [<ref>] [--] [<path>...]",
fetch: "git fetch [<remote>] [<ref>]",
"hash-object": "git hash-object [-w] [-t <type>] <path>",
init: "git init [<dir>]",
log: "git log [-n <count>] [-<count>] [--oneline] [<ref>]",
"ls-files": "git ls-files [<ref>]",
"ls-tree": "git ls-tree <ref> [<path>]",
merge: "git merge [--ff-only] [--no-ff] <ref>",
pull: "git pull [<remote>] [<ref>]",
push: "git push [-f|--force] [--delete] [<remote>] [<refspec>]",
remote: "git remote [-v] [add <name> <url>] [remove <name>]",
reset: "git reset [--hard|--soft|--mixed] [<ref>] [--] [<path>...]",
"rev-parse": "git rev-parse <rev>",
rm: "git rm [--cached] [-r] <path>...",
show: "git show [<ref>]",
stash: "git stash [push|pop|apply|list|drop]",
status: "git status [-s|--short|--porcelain]",
switch: "git switch [-c <name>] <ref>",
"symbolic-ref": "git symbolic-ref <name> [<ref>]",
tag: "git tag [-d <name>] [<name> [<ref>]]",
"update-ref": "git update-ref <ref> <oid>",
help: "git help [<command>]",
version: "git version",

@devin-ai-integration devin-ai-integration Bot Sep 11, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Help advertises rejected operations

When git help stash or git help symbolic-ref runs, COMMAND_USAGE lists unsupported apply, drop, and ref-writing forms. Following this help exits 129 instead of running the listed operation.

Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread packages/computer/src/git/cli.ts Outdated
clone defaulted to depth 1. That made it fast, but it quietly cost
the caller their history: pushing such a clone somewhere else sent
only the single commit it had fetched, reported success, and left a
remote whose tip hash matched while every earlier commit was
missing. A content diff against that remote passes, so nothing
surfaces the loss until someone looks for a parent that is not
there. Default to full history and leave the shallow case to an
explicit --depth, where the caller is choosing speed knowingly.

Three smaller gaps go with it. cat-file grew -t and -s, which
readObject already had the type and size for. log grew --format and
its --pretty alias over the commonly scripted placeholders, leaving
an unrecognized one as written so it shows up in the output rather
than vanishing. help grew a per-command form; it previously ignored
its argument and reprinted the list, which left no way to discover
a command's flags except guessing and reading the exit code.
The usage lines went in by hand and several described a command
that does not exist. hash-object advertised a positional path when
it only reads --stdin, reset offered --soft and --mixed when both
are explicitly refused, and log omitted the --format it had just
gained. A caller following that help got exit 129 for doing what
it said.

Correct every line against the flags its parser actually declares,
including the short spellings that were missing, and add a test
that walks each advertised long flag back through the command it
belongs to. Drift now fails a test rather than reaching a caller.

Normalize --pretty to --format while parsing, rather than reading
whichever key happened to be set. They are one option in real git,
so the last one written should win; before this, --format always
did regardless of order.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 new potential issues.

4 flags not posted on this PR by your GitHub settings — view them in Devin Review. (Configure)

Devin Review

Comment on lines +1945 to +1949
if (mode === "t") {
return { stdout: `${result.type ?? "blob"}\n`, stderr: "", exitCode: 0 };
}
if (mode === "s") {
return { stdout: `${result.bytes.byteLength}\n`, stderr: "", exitCode: 0 };

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Tree subpath metadata always fails

When <oid>:<path> names a directory, -t and -s use the blob-only filepath path. The command fails instead of returning the tree type or size.

Learn more

The CLI accepts <oid>:<path> for every new mode, but GitClient.catFile receives no mode. With filepath set, catFileWith always calls readBlob, which only resolves blob targets. A directory target therefore fails before the CLI can inspect result.type or result.bytes.

Example: git cat-file -t HEAD:src must print tree. The current call asks readBlob for src, which rejects the tree and makes the command exit with an error.

Recommended fix: Pass the requested mode through the cat-file API, or add a generic object-resolution path for filepath. Resolve the target object first, then use readObject({ format: "content" }) so tree subpaths expose both their type and raw byte size. Preserve the existing blob fast path for -p where applicable.

Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

// full list, which left no way to discover a command's flags short of
// guessing and reading the exit code.
if (topic !== undefined) {
const usage = COMMAND_USAGE[topic];

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Prototype names receive false help

When topic is constructor or another inherited name, COMMAND_USAGE[topic] returns an Object prototype member. git help exits zero and prints function source for an unsupported command.

Suggested change
const usage = COMMAND_USAGE[topic];
const usage = Object.hasOwn(COMMAND_USAGE, topic) ? COMMAND_USAGE[topic] : undefined;
Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@pkg-pr-new

pkg-pr-new Bot commented Sep 11, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@cloudflare/computer@141

commit: ba8591b

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant