[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-71452":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":17,"stars7d":18,"stars30d":19,"stars90d":16,"forks30d":16,"starsTrendScore":20,"compositeScore":21,"rankGlobal":10,"rankLanguage":10,"license":22,"archived":23,"fork":23,"defaultBranch":24,"hasWiki":25,"hasPages":23,"topics":26,"createdAt":10,"pushedAt":10,"updatedAt":30,"readmeContent":31,"aiSummary":32,"trendingCount":16,"starSnapshotCount":16,"syncStatus":33,"lastSyncTime":34,"discoverSource":35},71452,"soft-serve","charmbracelet\u002Fsoft-serve","charmbracelet","The mighty, self-hostable Git server for the command line🍦","",null,"Go",7027,229,37,76,0,6,49,129,18,38.09,"MIT License",false,"main",true,[27,28,29],"git","golang","ssh","2026-06-12 02:02:52","# Soft Serve\n\n\u003Cp>\n    \u003Cimg style=\"width: 451px\" src=\"https:\u002F\u002Fstuff.charm.sh\u002Fsoft-serve\u002Fsoft-serve-header.png?0\" alt=\"A nice rendering of some melting ice cream with the words ‘Charm Soft Serve’ next to it\">\u003Cbr>\n    \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fcharmbracelet\u002Fsoft-serve\u002Freleases\">\u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Frelease\u002Fcharmbracelet\u002Fsoft-serve.svg\" alt=\"Latest Release\">\u003C\u002Fa>\n    \u003Ca href=\"https:\u002F\u002Fpkg.go.dev\u002Fgithub.com\u002Fcharmbracelet\u002Fsoft-serve?tab=doc\">\u003Cimg src=\"https:\u002F\u002Fgodoc.org\u002Fgithub.com\u002Fgolang\u002Fgddo?status.svg\" alt=\"GoDoc\">\u003C\u002Fa>\n    \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fcharmbracelet\u002Fsoft-serve\u002Factions\">\u003Cimg src=\"https:\u002F\u002Fgithub.com\u002Fcharmbracelet\u002Fsoft-serve\u002Fworkflows\u002Fbuild\u002Fbadge.svg\" alt=\"Build Status\">\u003C\u002Fa>\n    \u003Ca href=\"https:\u002F\u002Fnightly.link\u002Fcharmbracelet\u002Fsoft-serve\u002Fworkflows\u002Fnightly\u002Fmain\">\u003Cimg src=\"https:\u002F\u002Fshields.io\u002Fbadge\u002F-Nightly%20Builds-orange?logo=hackthebox&logoColor=fff&style=appveyor\"\u002F>\u003C\u002Fa>\n\u003C\u002Fp>\n\nA tasty, self-hostable Git server for the command line. 🍦\n\n\u003Cpicture>\n  \u003Csource media=\"(max-width: 750px)\" srcset=\"https:\u002F\u002Fgithub.com\u002Fcharmbracelet\u002Fsoft-serve\u002Fassets\u002F42545625\u002Fc754c746-dc4c-44a6-9c39-28649264cbf2\">\n  \u003Csource media=\"(min-width: 750px)\" width=\"750\" srcset=\"https:\u002F\u002Fgithub.com\u002Fcharmbracelet\u002Fsoft-serve\u002Fassets\u002F42545625\u002Fc754c746-dc4c-44a6-9c39-28649264cbf2\">\n  \u003Cimg src=\"https:\u002F\u002Fgithub.com\u002Fcharmbracelet\u002Fsoft-serve\u002Fassets\u002F42545625\u002Fc754c746-dc4c-44a6-9c39-28649264cbf2\" alt=\"Soft Serve screencast\">\n\u003C\u002Fpicture>\n\n- Easy to navigate TUI available over SSH\n- Clone repos over SSH, HTTP, or Git protocol\n- Git LFS support with both HTTP and SSH backends\n- Manage repos with SSH\n- Create repos on demand with SSH or `git push`\n- Browse repos, files and commits with SSH-accessible UI\n- Print files over SSH with or without syntax highlighting and line numbers\n- Easy access control\n  - SSH authentication using public keys\n  - Allow\u002Fdisallow anonymous access\n  - Add collaborators with SSH public keys\n  - Repos can be public or private\n  - User access tokens\n\n## Where can I see it?\n\nJust run `ssh git.charm.sh` for an example. You can also try some of the following commands:\n\n```bash\n# Jump directly to a repo in the TUI\nssh git.charm.sh -t soft-serve\n\n# Print out a directory tree for a repo\nssh git.charm.sh repo tree soft-serve\n\n# Print a specific file\nssh git.charm.sh repo blob soft-serve cmd\u002Fsoft\u002Fmain.go\n\n# Print a file with syntax highlighting and line numbers\nssh git.charm.sh repo blob soft-serve cmd\u002Fsoft\u002Fmain.go -c -l\n```\n\nOr you can use Soft Serve to browse local repositories using `soft browse\n[directory]` or running `soft` within a Git repository.\n\n## Installation\n\nSoft Serve is a single binary called `soft`. You can get it from a package\nmanager:\n\n```bash\n# macOS or Linux\nbrew install charmbracelet\u002Ftap\u002Fsoft-serve\n\n# Windows (with Winget)\nwinget install charmbracelet.soft-serve\n\n# Arch Linux\npacman -S soft-serve\n\n# Nix\nnix-env -iA nixpkgs.soft-serve\n\n# Debian\u002FUbuntu\nsudo mkdir -p \u002Fetc\u002Fapt\u002Fkeyrings\ncurl -fsSL https:\u002F\u002Frepo.charm.sh\u002Fapt\u002Fgpg.key | sudo gpg --dearmor -o \u002Fetc\u002Fapt\u002Fkeyrings\u002Fcharm.gpg\necho \"deb [signed-by=\u002Fetc\u002Fapt\u002Fkeyrings\u002Fcharm.gpg] https:\u002F\u002Frepo.charm.sh\u002Fapt\u002F * *\" | sudo tee \u002Fetc\u002Fapt\u002Fsources.list.d\u002Fcharm.list\nsudo apt update && sudo apt install soft-serve\n\n# Fedora\u002FRHEL\necho '[charm]\nname=Charm\nbaseurl=https:\u002F\u002Frepo.charm.sh\u002Fyum\u002F\nenabled=1\ngpgcheck=1\ngpgkey=https:\u002F\u002Frepo.charm.sh\u002Fyum\u002Fgpg.key' | sudo tee \u002Fetc\u002Fyum.repos.d\u002Fcharm.repo\nsudo yum install soft-serve\n```\n\nYou can also download a binary from the [releases][releases] page. Packages are\navailable in Alpine, Debian, and RPM formats. Binaries are available for Linux,\nmacOS, and Windows.\n\n[releases]: https:\u002F\u002Fgithub.com\u002Fcharmbracelet\u002Fsoft-serve\u002Freleases\n\nOr just install it with `go`:\n\n```bash\ngo install github.com\u002Fcharmbracelet\u002Fsoft-serve\u002Fcmd\u002Fsoft@latest\n```\n\nA [Docker image][docker] is also available.\n\n[docker]: https:\u002F\u002Fgithub.com\u002Fcharmbracelet\u002Fsoft-serve\u002Fblob\u002Fmain\u002Fdocker.md\n\n## Setting up a server\n\nMake sure `git` is installed, then run `soft serve`. That’s it.\n\nThis will create a `data` directory that will store all the repos, ssh keys,\nand database.\n\nBy default, program configuration is stored within the `data` directory. But,\nthis can be overridden by setting a custom path to a config file with `SOFT_SERVE_CONFIG_LOCATION`\nthat is pre-created. If a config file pointed to by `SOFT_SERVE_CONFIG_LOCATION`,\nthe default location within the `data` dir is used for generating a default config.\n\nTo change the default data path use `SOFT_SERVE_DATA_PATH` environment variable.\n\n```sh\nSOFT_SERVE_DATA_PATH=\u002Fvar\u002Flib\u002Fsoft-serve soft serve\n```\n\nWhen you run Soft Serve for the first time, make sure you have the\n`SOFT_SERVE_INITIAL_ADMIN_KEYS` environment variable is set to your ssh\nauthorized key. Any added key to this variable will be treated as admin with\nfull privileges.\n\nUsing this environment variable, Soft Serve will create a new `admin` user that\nhas full privileges. You can rename and change the user settings later.\n\nCheck out [Systemd][systemd] on how to run Soft Serve as a service using\nSystemd. Soft Serve packages in our Apt\u002FYum repositories come with Systemd\nservice units.\n\n[systemd]: https:\u002F\u002Fgithub.com\u002Fcharmbracelet\u002Fsoft-serve\u002Fblob\u002Fmain\u002Fsystemd.md\n\n### Server Configuration\n\nOnce you start the server for the first time, the settings will be in\n`config.yaml` under your data directory. The default `config.yaml` is\nself-explanatory and will look like this:\n\n```yaml\n# Soft Serve Server configurations\n\n# The name of the server.\n# This is the name that will be displayed in the UI.\nname: \"Soft Serve\"\n\n# Log format to use. Valid values are \"json\", \"logfmt\", and \"text\".\nlog_format: \"text\"\n\n# The SSH server configuration.\nssh:\n  # The address on which the SSH server will listen.\n  listen_addr: \":23231\"\n\n  # The public URL of the SSH server.\n  # This is the address that will be used to clone repositories.\n  public_url: \"ssh:\u002F\u002Flocalhost:23231\"\n\n  # The path to the SSH server's private key.\n  key_path: \"ssh\u002Fsoft_serve_host\"\n\n  # The path to the SSH server's client private key.\n  # This key will be used to authenticate the server to make git requests to\n  # ssh remotes.\n  client_key_path: \"ssh\u002Fsoft_serve_client\"\n\n  # The maximum number of seconds a connection can take.\n  # A value of 0 means no timeout.\n  max_timeout: 0\n\n  # The number of seconds a connection can be idle before it is closed.\n  idle_timeout: 120\n\n# The Git daemon configuration.\ngit:\n  # The address on which the Git daemon will listen.\n  listen_addr: \":9418\"\n\n  # The maximum number of seconds a connection can take.\n  # A value of 0 means no timeout.\n  max_timeout: 0\n\n  # The number of seconds a connection can be idle before it is closed.\n  idle_timeout: 3\n\n  # The maximum number of concurrent connections.\n  max_connections: 32\n\n# The HTTP server configuration.\nhttp:\n  # The address on which the HTTP server will listen.\n  listen_addr: \":23232\"\n\n  # The path to the TLS private key.\n  tls_key_path: \"\"\n\n  # The path to the TLS certificate.\n  tls_cert_path: \"\"\n\n  # The public URL of the HTTP server.\n  # This is the address that will be used to clone repositories.\n  # Make sure to use https:\u002F\u002F if you are using TLS.\n  public_url: \"http:\u002F\u002Flocalhost:23232\"\n\n  # The cross-origin request security options\n  cors:\n    # The allowed cross-origin headers\n    allowed_headers:\n      - \"Accept\"\n      - \"Accept-Language\"\n      - \"Content-Language\"\n      - \"Content-Type\"\n      - \"Origin\"\n      - \"X-Requested-With\"\n      - \"User-Agent\"\n      - \"Authorization\"\n      - \"Access-Control-Request-Method\"\n      - \"Access-Control-Allow-Origin\"\n\n    # The allowed cross-origin URLs\n    allowed_origins:\n      - \"http:\u002F\u002Flocalhost:23232\" # always allowed\n      # - \"https:\u002F\u002Fexample.com\"\n\n    # The allowed cross-origin methods\n    allowed_methods:\n      - \"GET\"\n      - \"HEAD\"\n      - \"POST\"\n      - \"PUT\"\n      - \"OPTIONS\"\n\n# The database configuration.\ndb:\n  # The database driver to use.\n  # Valid values are \"sqlite\" and \"postgres\".\n  driver: \"sqlite\"\n  # The database data source name.\n  # This is driver specific and can be a file path or connection string.\n  # Make sure foreign key support is enabled when using SQLite.\n  data_source: \"soft-serve.db?_pragma=busy_timeout(5000)&_pragma=foreign_keys(1)\"\n\n# Git LFS configuration.\nlfs:\n  # Enable Git LFS.\n  enabled: true\n  # Enable Git SSH transfer.\n  ssh_enabled: false\n\n# Cron job configuration\njobs:\n  mirror_pull: \"@every 10m\"\n\n# The stats server configuration.\nstats:\n  # The address on which the stats server will listen.\n  listen_addr: \":23233\"\n# Additional admin keys.\n#initial_admin_keys:\n#  - \"ssh-rsa AAAAB3NzaC1yc2...\"\n```\n\nYou can also use environment variables, to override these settings. All server\nsettings environment variables start with `SOFT_SERVE_` followed by the setting\nname all in uppercase. Here are some examples:\n\n- `SOFT_SERVE_NAME`: The name of the server that will appear in the TUI\n- `SOFT_SERVE_SSH_LISTEN_ADDR`: SSH listen address\n- `SOFT_SERVE_SSH_KEY_PATH`: SSH host key-pair path\n- `SOFT_SERVE_HTTP_LISTEN_ADDR`: HTTP listen address\n- `SOFT_SERVE_HTTP_PUBLIC_URL`: HTTP public URL used for cloning\n- `SOFT_SERVE_GIT_MAX_CONNECTIONS`: The number of simultaneous connections to git daemon\n\n#### Database Configuration\n\nSoft Serve supports both SQLite and Postgres for its database. Like all other Soft Serve settings, you can change the database _driver_ and _data source_ using either `config.yaml` or environment variables. The default config uses SQLite as the default database driver.\n\nTo use Postgres as your database, first create a Soft Serve database:\n\n```sh\npsql -h\u003Chostname> -p\u003Cport> -U\u003Cuser> -c 'CREATE DATABASE soft_serve'\n```\n\nThen set the database _data source_ to point to your Postgres database. For instance, if you're running Postgres locally, using the default user `postgres` and using a database name `soft_serve`, you would have this config in your config file or environment variable:\n\n```\ndb:\n  driver: \"postgres\"\n  data_source: \"postgres:\u002F\u002Fpostgres@localhost:5432\u002Fsoft_serve?sslmode=disable\"\n```\n\nEnvironment variables equivalent:\n\n```sh\nSOFT_SERVE_DB_DRIVER=postgres \\\nSOFT_SERVE_DB_DATA_SOURCE=\"postgres:\u002F\u002Fpostgres@localhost:5432\u002Fsoft_serve?sslmode=disable\" \\\nsoft serve\n```\n\nYou can specify a database connection password in the _data source_ url. For example, `postgres:\u002F\u002Fmyuser:dbpass@localhost:5432\u002Fmy_soft_serve_db`.\n\n#### LFS Configuration\n\nSoft Serve supports both Git LFS [HTTP](https:\u002F\u002Fgithub.com\u002Fgit-lfs\u002Fgit-lfs\u002Fblob\u002Fmain\u002Fdocs\u002Fapi\u002FREADME.md) and [SSH](https:\u002F\u002Fgithub.com\u002Fgit-lfs\u002Fgit-lfs\u002Fblob\u002Fmain\u002Fdocs\u002Fproposals\u002Fssh_adapter.md) protocols out of the box, there is no need to do any extra set up.\n\nUse the `lfs` config section to customize your Git LFS server.\n\n> **Note**: The pure-SSH transfer is disabled by default.\n\n## Server Access\n\nSoft Serve at its core manages your server authentication and authorization. Authentication verifies the identity of a user, while authorization determines their access rights to a repository.\n\nTo manage the server users, access, and repos, you can use the SSH command line interface.\n\nTry `ssh localhost -i ~\u002F.ssh\u002Fid_ed25519 -o IdentitiesOnly=yes -p 23231 help` for more info. Make sure\nyou use your key here.\n\n> **Note** The `IdentitiesOnly` option is used to prevent SSH from using any\n> other keys in your `~\u002F.ssh` directory. This is useful when you have multiple\n> keys, and you want to use a specific key for Soft Serve.\n\nFor ease of use, instead of specifying the key, port, and hostname every time\nyou SSH into Soft Serve, add your own Soft Serve instance entry to your SSH\nconfig. For instance, to use `ssh soft` instead of typing `ssh localhost -i\n~\u002F.ssh\u002Fid_ed25519 -o IdentitiesOnly=yes -p 23231`, we can define a `soft` entry in our SSH config\nfile `~\u002F.ssh\u002Fconfig`.\n\n```conf\nHost soft\n  HostName localhost\n  Port 23231\n  IdentityFile ~\u002F.ssh\u002Fid_ed25519\n  IdentitiesOnly yes\n```\n\nNow, we can do `ssh soft` to SSH into Soft Serve. Since `git` is also aware of\nthis config, you can use `soft` as the hostname for your clone commands.\n\n```sh\ngit clone ssh:\u002F\u002Fsoft\u002Fdotfiles\n# make changes\n# add & commit\ngit push origin main\n```\n\n> **Note** The `-i` and `-o` parts will be omitted in the examples below for brevity. You\n> can add your server settings to your sshconfig for quicker access.\n\n### Authentication\n\nEverything that needs authentication is done using SSH. Make sure you have\nadded an entry for your Soft Serve instance in your `~\u002F.ssh\u002Fconfig` file.\n\nBy default, Soft Serve gives read-only permission to anonymous connections to\nany of the above protocols. This is controlled by two settings `anon-access`\nand `allow-keyless`.\n\n- `anon-access`: Defines the access level for anonymous users. Available\n  options are `no-access`, `read-only`, `read-write`, and `admin-access`.\n  Default is `read-only`.\n- `allow-keyless`: Whether to allow connections that doesn't use keys to pass.\n  Setting this to `false` would disable access to SSH keyboard-interactive,\n  HTTP, and Git protocol connections. Default is `true`.\n\n```sh\n$ ssh -p 23231 localhost settings\nManage server settings\n\nUsage:\n  ssh -p 23231 localhost settings [command]\n\nAvailable Commands:\n  allow-keyless Set or get allow keyless access to repositories\n  anon-access   Set or get the default access level for anonymous users\n\nFlags:\n  -h, --help   help for settings\n\nUse \"ssh -p 23231 localhost settings [command] --help\" for more information about a command.\n```\n\n> **Note** These settings can only be changed by admins.\n\nWhen `allow-keyless` is disabled, connections that don't use SSH Public Key\nauthentication will get denied. This means cloning repos over HTTP(s) or git:\u002F\u002F\nwill get denied.\n\nMeanwhile, `anon-access` controls the access level granted to connections that\nuse SSH Public Key authentication but are not registered users. The default\nsetting for this is `read-only`. This will grant anonymous connections that use\nSSH Public Key authentication `read-only` access to public repos.\n\n`anon-access` is also used in combination with `allow-keyless` to determine the\naccess level for HTTP(s) and git:\u002F\u002F clone requests.\n\n#### SSH\n\nSoft Serve doesn't allow duplicate SSH public keys for users. A public key can be associated with one user only. This makes SSH authentication simple and straight forward, add your public key to your Soft Serve user to be able to access Soft Serve.\n\n#### HTTP\n\nYou can generate user access tokens through the SSH command line interface. Access tokens can have an optional expiration date. Use your access token as the basic auth user to access your Soft Serve repos through HTTP.\n\n```sh\n# Create a user token\nssh -p 23231 localhost token create 'my new token'\nss_1234abc56789012345678901234de246d798fghi\n\n# Or with an expiry date\nssh -p 23231 localhost token create --expires-in 1y 'my other token'\nss_98fghi1234abc56789012345678901234de246d7\n```\n\nNow you can access to repos that require `read-write` access.\n\n```sh\ngit clone http:\u002F\u002Fss_98fghi1234abc56789012345678901234de246d7@localhost:23232\u002Fmy-private-repo.git my-private-repo\n# Make changes and push\n```\n\n### Authorization\n\nSoft Serve offers a simple access control. There are four access levels,\nno-access, read-only, read-write, and admin-access.\n\n`admin-access` has full control of the server and can make changes to users and repos.\n\n`read-write` access gets full control of repos.\n\n`read-only` can read public repos.\n\n`no-access` denies access to all repos.\n\n## User Management\n\nAdmins can manage users and their keys using the `user` command. Once a user is\ncreated and has access to the server, they can manage their own keys and\nsettings.\n\nTo create a new user simply use `user create`:\n\n```sh\n# Create a new user\nssh -p 23231 localhost user create beatrice\n\n# Add user keys\nssh -p 23231 localhost user add-pubkey beatrice ssh-rsa AAAAB3Nz...\nssh -p 23231 localhost user add-pubkey beatrice ssh-ed25519 AAAA...\n\n# Create another user with public key\nssh -p 23231 localhost user create frankie '-k \"ssh-ed25519 AAAATzN...\"'\n\n# Need help?\nssh -p 23231 localhost user help\n```\n\nOnce a user is created, they get `read-only` access to public repositories.\nThey can also create new repositories on the server.\n\nUsers can manage their keys using the `pubkey` command:\n\n```sh\n# List user keys\nssh -p 23231 localhost pubkey list\n\n# Add key\nssh -p 23231 localhost pubkey add ssh-ed25519 AAAA...\n\n# Wanna change your username?\nssh -p 23231 localhost set-username yolo\n\n# To display user info\nssh -p 23231 localhost info\n```\n\n## Repositories\n\nYou can manage repositories using the `repo` command.\n\n```sh\n# Run repo help\n$ ssh -p 23231 localhost repo help\nManage repositories\n\nUsage:\n  ssh -p 23231 localhost repo [command]\n\nAliases:\n  repo, repos, repository, repositories\n\nAvailable Commands:\n  blob         Print out the contents of file at path\n  branch       Manage repository branches\n  collab       Manage collaborators\n  create       Create a new repository\n  delete       Delete a repository\n  description  Set or get the description for a repository\n  hide         Hide or unhide a repository\n  import       Import a new repository from remote\n  info         Get information about a repository\n  list         List repositories\n  mirror       Set or get a repository mirror property\n  private      Set or get a repository private property\n  project-name Set or get the project name for a repository\n  rename       Rename an existing repository\n  tag          Manage repository tags\n  tree         Print repository tree at path\n\nFlags:\n  -h, --help   help for repo\n\nUse \"ssh -p 23231 localhost repo [command] --help\" for more information about a command.\n```\n\nTo use any of the above `repo` commands, a user must be a collaborator in the repository. More on this below.\n\n### Creating Repositories\n\nTo create a repository, first make sure you are a registered user. Use the\n`repo create \u003Crepo>` command to create a new repository:\n\n```sh\n# Create a new repository\nssh -p 23231 localhost repo create icecream\n\n# Create a repo with description\nssh -p 23231 localhost repo create icecream '-d \"This is an Ice Cream description\"'\n\n# ... and project name\nssh -p 23231 localhost repo create icecream '-d \"This is an Ice Cream description\"' '-n \"Ice Cream\"'\n\n# I need my repository private!\nssh -p 23231 localhost repo create icecream -p '-d \"This is an Ice Cream description\"' '-n \"Ice Cream\"'\n\n# Help?\nssh -p 23231 localhost repo create -h\n```\n\nOr you can add your Soft Serve server as a remote to any existing repo, given\nyou have write access, and push to remote:\n\n```\ngit remote add origin ssh:\u002F\u002Flocalhost:23231\u002Ficecream\n```\n\nAfter you’ve added the remote just go ahead and push. If the repo doesn’t exist\non the server it’ll be created.\n\n```\ngit push origin main\n```\n\n### Nested Repositories\n\nRepositories can be nested too:\n\n```sh\n# Create a new nested repository\nssh -p 23231 localhost repo create charmbracelet\u002Ficecream\n\n# Or ...\ngit remote add charm ssh:\u002F\u002Flocalhost:23231\u002Fcharmbracelet\u002Ficecream\ngit push charm main\n```\n\n### Mirrors\n\nYou can also *import* repositories from any public remote. Use the `repo import` command.\n\n```sh\nssh -p 23231 localhost repo import soft-serve https:\u002F\u002Fgithub.com\u002Fcharmbracelet\u002Fsoft-serve\n```\n\nUse `--mirror` or `-m` to mark the repository as a *pull* mirror.\n\n### Deleting Repositories\n\nYou can delete repositories using the `repo delete \u003Crepo>` command.\n\n```sh\nssh -p 23231 localhost repo delete icecream\n```\n\n### Renaming Repositories\n\nUse the `repo rename \u003Cold> \u003Cnew>` command to rename existing repositories.\n\n```sh\nssh -p 23231 localhost repo rename icecream vanilla\n```\n\n### Repository Collaborators\n\nSometimes you want to restrict write access to certain repositories. This can\nbe achieved by adding a collaborator to your repository.\n\nUse the `repo collab \u003Ccommand> \u003Crepo>` command to manage repo collaborators.\n\n```sh\n# Add collaborator to soft-serve\nssh -p 23231 localhost repo collab add soft-serve frankie\n\n# Add collaborator with a specific access level\nssh -p 23231 localhost repo collab add soft-serve beatrice read-only\n\n# Remove collaborator\nssh -p 23231 localhost repo collab remove soft-serve beatrice\n\n# List collaborators\nssh -p 23231 localhost repo collab list soft-serve\n```\n\n### Repository Metadata\n\nYou can also change the repo's description, project name, whether it's private,\netc using the `repo \u003Ccommand>` command.\n\n```sh\n# Set description for repo\nssh -p 23231 localhost repo description icecream \"This is a new description\"\n\n# Hide repo from listing\nssh -p 23231 localhost repo hidden icecream true\n\n# List repository info (branches, tags, description, etc)\nssh -p 23231 localhost repo icecream info\n```\n\nTo make a repository private, use `repo private \u003Crepo> [true|false]`. Private\nrepos can only be accessed by admins and collaborators.\n\n```sh\nssh -p 23231 localhost repo private icecream true\n```\n\n### Repository Branches & Tags\n\nUse `repo branch` and `repo tag` to list, and delete branches or tags. You can\nalso use `repo branch default` to set or get the repository default branch.\n\n### Repository Tree\n\nTo print a file tree for the project, just use the `repo tree` command along with\nthe repo name as the SSH command to your Soft Serve server:\n\n```sh\nssh -p 23231 localhost repo tree soft-serve\n```\n\nYou can also specify the sub-path and a specific reference or branch.\n\n```sh\nssh -p 23231 localhost repo tree soft-serve server\u002Fconfig\nssh -p 23231 localhost repo tree soft-serve main server\u002Fconfig\n```\n\nFrom there, you can print individual files using the `repo blob` command:\n\n```sh\nssh -p 23231 localhost repo blob soft-serve cmd\u002Fsoft\u002Fmain.go\n```\n\nYou can add the `-c` flag to enable syntax coloring and `-l` to print line\nnumbers:\n\n```sh\nssh -p 23231 localhost repo blob soft-serve cmd\u002Fsoft\u002Fmain.go -c -l\n\n```\n\nUse `--raw` to print raw file contents. This is useful for dumping binary data.\n\n### Repository webhooks\n\nSoft Serve supports repository webhooks using the `repo webhook` command. You\ncan create and manage webhooks for different repository events such as _push_,\n_collaborators_, and _branch_tag_create_ events.\n\n```\nManage repository webhooks\n\nUsage:\n  ssh -p 23231 localhost repo webhook [command]\n\nAliases:\n  webhook, webhooks\n\nAvailable Commands:\n  create      Create a repository webhook\n  delete      Delete a repository webhook\n  deliveries  Manage webhook deliveries\n  list        List repository webhooks\n  update      Update a repository webhook\n\nFlags:\n  -h, --help   help for webhook\n```\n\n## The Soft Serve TUI\n\n\u003Cimg src=\"https:\u002F\u002Fstuff.charm.sh\u002Fsoft-serve\u002Fsoft-serve-demo-commit.png\" width=\"750\" alt=\"TUI example showing a diff\">\n\nSoft Serve TUI is mainly used to browse repos over SSH. You can also use it to\nbrowse local repositories with `soft browse` or running `soft` within a Git\nrepository.\n\n```sh\nssh localhost -p 23231\n```\n\nIt's also possible to “link” to a specific repo:\n\n```sh\nssh -p 23231 localhost -t soft-serve\n```\n\nYou can copy text to your clipboard over SSH. For instance, you can press\n\u003Ckbd>c\u003C\u002Fkbd> on the highlighted repo in the menu to copy the clone command\n[^osc52].\n\n[^osc52]:\n    Copying over SSH depends on your terminal support of OSC52. Refer to\n    [go-osc52](https:\u002F\u002Fgithub.com\u002Faymanbagabas\u002Fgo-osc52) for more information.\n\n## Hooks\n\nSoft Serve supports git server-side hooks `pre-receive`, `update`,\n`post-update`, and `post-receive`. This means you can define your own hooks to\nrun on repository push events. Hooks can be defined as a per-repository hook,\nand\u002For global hooks that run for all repositories.\n\nYou can find per-repository hooks under the repository `hooks` directory.\n\nGlobs hooks can be found in your `SOFT_SERVE_DATA_PATH` directory under\n`hooks`. Defining global hooks is useful if you want to run CI\u002FCD for example.\n\nHere's an example of sending a message after receiving a push event. Create an\nexecutable file `\u003Cdata path>\u002Fhooks\u002Fupdate`:\n\n```sh\n#!\u002Fbin\u002Fsh\n#\n# An example hook script to echo information about the push\n# and send it to the client.\n\nrefname=\"$1\"\noldrev=\"$2\"\nnewrev=\"$3\"\n\n# Safety check\nif [ -z \"$GIT_DIR\" ]; then\n        echo \"Don't run this script from the command line.\" >&2\n        echo \" (if you want, you could supply GIT_DIR then run\" >&2\n        echo \"  $0 \u003Cref> \u003Coldrev> \u003Cnewrev>)\" >&2\n        exit 1\nfi\n\nif [ -z \"$refname\" -o -z \"$oldrev\" -o -z \"$newrev\" ]; then\n        echo \"usage: $0 \u003Cref> \u003Coldrev> \u003Cnewrev>\" >&2\n        exit 1\nfi\n\n# Check types\n# if $newrev is 0000...0000, it's a commit to delete a ref.\nzero=$(git hash-object --stdin \u003C\u002Fdev\u002Fnull | tr '[0-9a-f]' '0')\nif [ \"$newrev\" = \"$zero\" ]; then\n        newrev_type=delete\nelse\n        newrev_type=$(git cat-file -t $newrev)\nfi\n\necho \"Hi from Soft Serve update hook!\"\necho\necho \"RefName: $refname\"\necho \"Change Type: $newrev_type\"\necho \"Old SHA1: $oldrev\"\necho \"New SHA1: $newrev\"\n\nexit 0\n```\n\nNow, you should get a message after pushing changes to any repository.\n\n## A note about RSA keys\n\nUnfortunately, due to a shortcoming in Go’s `x\u002Fcrypto\u002Fssh` package, Soft Serve\ndoes not currently support access via new SSH RSA keys: only the old SHA-1\nones will work.\n\nUntil we sort this out you’ll either need an SHA-1 RSA key or a key with\nanother algorithm, e.g. Ed25519. Not sure what type of keys you have?\nYou can check with the following:\n\n```sh\n$ find ~\u002F.ssh\u002Fid_*.pub -exec ssh-keygen -l -f {} \\;\n```\n\nIf you’re curious about the inner workings of this problem have a look at:\n\n- https:\u002F\u002Fgithub.com\u002Fgolang\u002Fgo\u002Fissues\u002F37278\n- https:\u002F\u002Fgo-review.googlesource.com\u002Fc\u002Fcrypto\u002F+\u002F220037\n- https:\u002F\u002Fgithub.com\u002Fgolang\u002Fcrypto\u002Fpull\u002F197\n\n## Contributing\n\nSee [contributing][contribute].\n\n[contribute]: https:\u002F\u002Fgithub.com\u002Fcharmbracelet\u002Fsoft-serve\u002Fcontribute\n\n## Feedback\n\nWe’d love to hear your thoughts on this project. Feel free to drop us a note!\n\n- [Twitter](https:\u002F\u002Ftwitter.com\u002Fcharmcli)\n- [The Fediverse](https:\u002F\u002Fmastodon.social\u002F@charmcli)\n- [Discord](https:\u002F\u002Fcharm.sh\u002Fchat)\n\n## License\n\n[MIT](https:\u002F\u002Fgithub.com\u002Fcharmbracelet\u002Fsoft-serve\u002Fraw\u002Fmain\u002FLICENSE)\n\n---\n\nPart of [Charm](https:\u002F\u002Fcharm.sh).\n\n\u003Ca href=\"https:\u002F\u002Fcharm.sh\u002F\">\u003Cimg alt=\"The Charm logo\" src=\"https:\u002F\u002Fstuff.charm.sh\u002Fcharm-badge.jpg\" width=\"400\">\u003C\u002Fa>\n\nCharm热爱开源 • Charm loves open source\n","Soft Serve 是一个适用于命令行的自托管 Git 服务器。它采用 Go 语言编写，提供了通过 SSH 访问的易于导航的 TUI 界面，支持通过 SSH、HTTP 或 Git 协议克隆仓库，并且集成了 Git LFS 支持。此外，用户可以使用 SSH 进行仓库管理，包括创建新仓库、浏览文件和提交记录以及打印带有或不带语法高亮显示的文件内容。该项目还具备灵活的访问控制功能，比如基于 SSH 公钥的身份验证、允许或禁止匿名访问等。Soft Serve 非常适合需要在本地环境中快速搭建 Git 服务并偏好使用命令行工具进行操作的小团队或个人开发者。",2,"2026-06-11 03:37:48","high_star"]