Skip to content

Fetch, push and clone

Transfer commands move objects and references between repositories. They speak to local paths, file:// URLs, smart HTTP(S) and, on macOS and Linux, system OpenSSH. The examples publish the demo repository as a bare repository next to it, clone that, and move commits between the three. The remotes they use come from configuration. The library side is in Fetch, push and clone and Credentials and transports.

girt clone <url> [directory] copies a repository and checks out its HEAD. The directory defaults to the URL’s last component without .git. --bare makes a bare clone and --no-checkout leaves the index and working tree empty for a later girt checkout HEAD.

$ git clone -q --bare . ../demo.git
$ cd ..
$ girt clone demo.git copy
cloned into /home/me/copy
HEAD -> refs/heads/main 7ed7a0cc68995713f52d973e6adfd3d9e667324f

If the transfer succeeds and the checkout fails, the clone is kept and girt says so, so you can fix the cause and run girt -C <dir> checkout HEAD instead of downloading again.

girt fetch [remote] downloads from a configured remote, origin by default, using its fetch refspecs, and prints each reference it changed as <old>..<new> <name>. Here demo publishes a new commit and the copy fetches it.

$ git -C demo commit -q --allow-empty -m "Upstream change"
$ git -C demo push -q ../demo.git main
$ cd copy
$ girt fetch
7ed7a0cc68995713f52d973e6adfd3d9e667324f..47faceec37e8ce5e789f39ed43a4233d71202051 refs/remotes/origin/main

Unlike Git, fetch doesn’t follow tags automatically. A non-fast-forward update is refused unless the refspec allows it with a leading +. Interactive password and SSH prompts aren’t available, and neither is job control: use a credential helper, an SSH agent or SSH_ASKPASS. SSH URL forms and command selection are on Configuration and remotes. For all three transfer commands, --git only hides progress: results keep girt’s format, so they can’t be byte-compared with Git’s.

girt push <remote> <refspec>… publishes references. Every update is conditional on the remote-tracking value you last fetched, like git push --force-with-lease: if the remote has moved since, the push is rejected as stale and you fetch first. A leading + permits a non-fast-forward update. Here the copy commits on top of the old main, so pushing it to main would discard the upstream commit it just fetched.

$ git commit -q --allow-empty -m "From the copy"
$ girt push origin main:refs/heads/review
ok refs/heads/review
$ girt push origin main
Error:
0: pushing to origin
1: push not sent
2: replacement requires explicit force for RefName([114, 101, 102, 115, 47, 104, 101, 97, 100, 115, 47, 109, 97, 105, 110])
$ girt push origin +main
ok refs/heads/main

A destination without refs/ is taken as a branch under refs/heads/. girt exits 1 unless every reference was accepted.