### Start the Server with Various Configurations Source: https://github.com/wjqserver/gitserver/blob/main/docs/en/usage.md Examples for launching the server with custom network settings, logging formats, and directory scan depths. ```sh # With default settings gitserver ./repos # Custom address and port gitserver -b 0.0.0.0 -p 8080 ./repos # JSON log format gitserver --log-format json ./repos # Limit scan depth to 1 gitserver --max-depth 1 ./repos ``` -------------------------------- ### Install Gitserver from Source Source: https://github.com/wjqserver/gitserver/blob/main/docs/en/installation.md Clone the repository and install the gitserver binary using Cargo. The binary will be placed in Cargo's bin directory. ```sh git clone https://github.com/WJQSERVER/gitserver.git gitserver cd gitserver cargo install --path crates/gitserver ``` -------------------------------- ### Run gitserver CLI Source: https://context7.com/wjqserver/gitserver/llms.txt Commands for starting the server, configuring authentication, and performing standard Git operations. ```bash # Start server with default settings (bind 127.0.0.1:3000) gitserver ./repos # Custom address and port with JSON logging gitserver -b 0.0.0.0 -p 8080 --log-format json ./repos # Enable authentication and push support gitserver \ --auth-basic-username admin \ --auth-basic-password secret \ --enable-receive-pack \ ./repos # Clone from the server git clone http://127.0.0.1:3000/my-project.git # Clone with authentication git clone http://admin:secret@127.0.0.1:3000/my-project.git # Fetch updates cd my-project && git fetch # Push changes (requires --enable-receive-pack) git push origin main ``` -------------------------------- ### Library Quick Start - Discovery Mode Source: https://context7.com/wjqserver/gitserver/llms.txt Embed Git Smart HTTP serving into an existing Axum application by scanning a directory for bare repositories. ```APIDOC ## Library Quick Start - Discovery Mode Embed Git Smart HTTP serving into an existing Axum application by scanning a directory for bare repositories. ### Rust Code Example ```rust use gitserver_core::discovery::RepoStore; use gitserver_http::{SharedState, router}; #[tokio::main] async fn main() -> anyhow::Result<()> { // Scan ./repos directory for bare git repositories, max depth 3 let store = RepoStore::discover("./repos".into(), 3)?; // Create shared state and build Axum routes let state = SharedState::new(store); let app = router(state); // Start serving with graceful shutdown let listener = tokio::net::TcpListener::bind("127.0.0.1:3000").await?; axum::serve(listener, app) .with_graceful_shutdown(async { tokio::signal::ctrl_c().await.expect("install Ctrl+C handler"); }) .await?; Ok(()) } ``` ``` -------------------------------- ### Gitserver CLI Usage Source: https://context7.com/wjqserver/gitserver/llms.txt Demonstrates how to start the gitserver binary with various configurations, including custom addresses, ports, logging, authentication, and push support. Also shows how to clone, fetch, and push using git commands. ```APIDOC ## CLI Usage The `gitserver` binary serves bare Git repositories over HTTP with configurable authentication, push support, and graceful shutdown handling. ### Start Server ```bash # Start server with default settings (bind 127.0.0.1:3000) gitserver ./repos # Custom address and port with JSON logging gitserver -b 0.0.0.0 -p 8080 --log-format json ./repos # Enable authentication and push support gitserver \ --auth-basic-username admin \ --auth-basic-password secret \ --enable-receive-pack \ ./repos ``` ### Git Operations ```bash # Clone from the server git clone http://127.0.0.1:3000/my-project.git # Clone with authentication git clone http://admin:secret@127.0.0.1:3000/my-project.git # Fetch updates cd my-project && git fetch # Push changes (requires --enable-receive-pack) git push origin main ``` ``` -------------------------------- ### Repository listing response format Source: https://github.com/wjqserver/gitserver/blob/main/README.md Example JSON response returned by the root endpoint. ```json [ { "name": "my-project.git", "relative_path": "my-project.git", "description": "My project" } ] ``` -------------------------------- ### Run gitserver via CLI Source: https://github.com/wjqserver/gitserver/blob/main/docs/en/usage.md Basic command to start the server by specifying the root directory containing bare Git repositories. ```sh gitserver [OPTIONS] ``` -------------------------------- ### Serve Repositories with gitserver CLI Source: https://github.com/wjqserver/gitserver/blob/main/README.md Serve all bare Git repositories found under the specified directory using the gitserver CLI. This command starts the HTTP server. ```sh # Serve all bare repos under ./repos gitserver ./repos ``` -------------------------------- ### Convenience Method for Dynamic Registry with SharedState::with_dynamic_registry Source: https://context7.com/wjqserver/gitserver/llms.txt A simplified way to create dynamic registry mode with state-based registration methods. This method simplifies the setup for dynamic repository management. ```rust use gitserver_core::discovery::RepoInfo; use gitserver_http::{SharedState, router, ServicePolicy, AuthConfig}; #[tokio::main] async fn main() -> anyhow::Result<()> { // Create state with built-in dynamic registry let state = SharedState::with_dynamic_registry( AuthConfig::default(), ServicePolicy::default(), ); // Register via state directly state.register_repo(RepoInfo { name: "project.git".into(), relative_path: "project.git".into(), absolute_path: "/data/repos/project.git".into(), description: None, })?; // Unregister via state // state.unregister_repo("project.git")?; let app = router(state); let listener = tokio::net::TcpListener::bind("127.0.0.1:3000").await?; axum::serve(listener, app).await?; Ok(()) } ``` -------------------------------- ### Handle Error Responses via CLI Source: https://context7.com/wjqserver/gitserver/llms.txt Examples of curl commands and expected error responses for common API scenarios. ```bash # Repository not found curl -s http://127.0.0.1:3000/nonexistent.git/info/refs?service=git-upload-pack # Response (404): # {"error":"not_found","message":"Repository not found: nonexistent.git"} # Missing service parameter curl -s http://127.0.0.1:3000/my-project.git/info/refs # Response (400): Missing required query parameter # Authentication required curl -s http://127.0.0.1:3000/ # Response (401): # {"error":"unauthorized","message":"Authentication required"} ``` -------------------------------- ### Embed gitserver in Axum Source: https://github.com/wjqserver/gitserver/blob/main/docs/en/usage.md Integration example for using gitserver-http components within an existing Axum application. ```rust use gitserver_core::discovery::RepoStore; use gitserver_http::{SharedState, router}; let store = RepoStore::discover("./repos".into(), 3)?; let state = SharedState::new(store); let app = router(state); // Mount `app` into your Axum service ``` -------------------------------- ### Embed gitserver Server into Axum Application Source: https://github.com/wjqserver/gitserver/blob/main/README.md Embed the gitserver HTTP server into an Axum application. This example discovers repositories from a local directory and serves them. ```rust use gitserver_core::discovery::RepoStore; use gitserver_http::{SharedState, router}; #[tokio::main] async fn main() -> anyhow::Result<()> { let store = RepoStore::discover("./repos".into(), 3)?; let state = SharedState::new(store); let app = router(state); let listener = tokio::net::TcpListener::bind("127.0.0.1:3000").await?; axum::serve(listener, app) .with_graceful_shutdown(async { tokio::signal::ctrl_c().await.expect("install Ctrl+C handler"); }) .await?; Ok(()) } ``` -------------------------------- ### Initialize discovery mode server Source: https://github.com/wjqserver/gitserver/blob/main/docs/en/library.md Automatically discover bare repositories in a directory and serve them via an Axum-based HTTP server. ```rust use gitserver_core::discovery::RepoStore; use gitserver_http::{SharedState, router}; #[tokio::main] async fn main() -> anyhow::Result<()> { // Scan ./repos directory, max depth 3 let store = RepoStore::discover("./repos".into(), 3)?; // Create shared state and build routes let state = SharedState::new(store); let app = router(state); // Start serving let listener = tokio::net::TcpListener::bind("127.0.0.1:3000").await?; axum::serve(listener, app) .with_graceful_shutdown(async { tokio::signal::ctrl_c().await.expect("install Ctrl+C handler"); }) .await?; Ok(()) } ``` -------------------------------- ### Discover and Manage Repositories with RepoStore Source: https://context7.com/wjqserver/gitserver/llms.txt Demonstrates filesystem-based repository discovery, listing, and manual refreshing. ```rust use gitserver_core::discovery::RepoStore; fn main() -> anyhow::Result<()> { // Discover bare repositories up to 3 levels deep let store = RepoStore::discover("./repos".into(), 3)?; // List all discovered repositories for repo in store.list() { println!("Name: {}", repo.name); println!("Path: {}", repo.relative_path); if let Some(desc) = &repo.description { println!("Description: {}", desc); } println!("---"); } // Resolve a specific repository by relative path let repo = store.resolve("my-project.git")?; println!("Absolute path: {:?}", repo.absolute_path); // Refresh to pick up new repositories let mut store = store; store.refresh()?; Ok(()) } ``` -------------------------------- ### Build gitserver from source Source: https://github.com/wjqserver/gitserver/blob/main/README.md Commands to clone the repository and compile the binary in release mode. ```sh git clone https://github.com/WJQSERVER/gitserver.git gitserver cd gitserver cargo build --release ``` -------------------------------- ### gitserver CLI Usage Help Source: https://github.com/wjqserver/gitserver/blob/main/README.md Display the help message for the gitserver CLI, showing available options and arguments for running the standalone server. ```sh gitserver [OPTIONS] Arguments: Root directory containing bare Git repositories Options: -b, --bind Bind address [default: 127.0.0.1] -p, --port Port number [default: 3000] -l, --log-level Log level [default: info] --log-format Log format: text or json [default: text] -w, --workers Number of Tokio worker threads --max-depth Max directory depth for repo discovery [default: 3] --rescan-interval-secs Periodic rescan interval in seconds [default: 30] --auth-basic-username Require HTTP Basic auth username --auth-basic-password Require HTTP Basic auth password --auth-bearer-token Require Bearer auth token --enable-receive-pack Enable push support over git-receive-pack ``` -------------------------------- ### 配置服务策略 Source: https://github.com/wjqserver/gitserver/blob/main/docs/zh/library.md 配置 Git 服务策略,包括 clone/fetch 和 push 操作。 ```rust use gitserver_http::{SharedState, ServicePolicy, AuthConfig}; let state = SharedState::with_store_and_auth_policy( store, AuthConfig::default(), ServicePolicy { upload_pack: true, // clone/fetch upload_pack_v2: true, // 协议 v2 receive_pack: true, // push (默认关闭) }, ); ``` -------------------------------- ### 添加 gitserver 依赖 Source: https://github.com/wjqserver/gitserver/blob/main/docs/zh/library.md 在 Cargo.toml 文件中添加 gitserver-core 和 gitserver-http 的依赖项。 ```toml [dependencies] gitserver-core = { git = "https://github.com/WJQSERVER/gitserver" } gitserver-http = { git = "https://github.com/WJQSERVER/gitserver" } axum = "0.8" tokio = { version = "1", features = ["full"] } anyhow = "1" ``` -------------------------------- ### Register repositories dynamically Source: https://github.com/wjqserver/gitserver/blob/main/docs/en/library.md Manually manage repository registration instead of relying on directory scanning. ```rust use std::sync::Arc; use gitserver_core::discovery::{DynamicRepoRegistry, MutableRepoRegistry, RepoInfo}; use gitserver_http::{SharedState, router, ServicePolicy, AuthConfig}; // Create empty registry let registry = Arc::new(DynamicRepoRegistry::new()); let state = SharedState::with_registry( registry.clone(), AuthConfig::default(), ServicePolicy::default(), ); // Register a repository (validates that the path is a bare repo) registry.register(RepoInfo { name: "my-project.git".into(), relative_path: "tenant-a/my-project.git".into(), absolute_path: "/data/repos/tenant-a/my-project.git".into(), description: Some("My project".into()), })?; // Unregister a repository registry.unregister("tenant-a/my-project.git")?; let app = router(state); ``` ```rust let state = SharedState::with_dynamic_registry( AuthConfig::default(), ServicePolicy::default(), ); // Register via state state.register_repo(RepoInfo { name: "project.git".into(), relative_path: "project.git".into(), absolute_path: "/data/repos/project.git".into(), description: None, })?; ``` -------------------------------- ### Configure Authentication with SharedState::with_auth Source: https://context7.com/wjqserver/gitserver/llms.txt Enable HTTP Basic and/or Bearer token authentication for Git endpoints. Both Basic and Bearer tokens can be configured simultaneously. ```rust use gitserver_core::discovery::RepoStore; use gitserver_http::{SharedState, router, AuthConfig, BasicAuthConfig}; #[tokio::main] async fn main() -> anyhow::Result<()> { let store = RepoStore::discover("./repos".into(), 3)?; // Configure authentication (Basic and Bearer can be used together) let state = SharedState::with_auth(store, AuthConfig { basic: Some(BasicAuthConfig { username: "admin".into(), password: "secret".into(), }), bearer_token: Some("my-api-token".into()), }); let app = router(state); let listener = tokio::net::TcpListener::bind("127.0.0.1:3000").await?; axum::serve(listener, app).await?; Ok(()) } ``` -------------------------------- ### Perform Direct Git Protocol Operations Source: https://github.com/wjqserver/gitserver/blob/main/docs/en/library.md Demonstrates repository discovery, reference advertisement, and pack generation using gitserver-core without the HTTP layer. ```rust use gitserver_core::{ discovery::RepoStore, backend::GitBackend, pack::{UploadPackRequest, UploadPackCapabilities, ShallowRequest}, }; // Repository discovery let store = RepoStore::discover("./repos".into(), 3)?; let repo = store.resolve("my-project.git")?; // Ref advertisement let backend = GitBackend::new(repo.absolute_path.clone()); let refs = backend.advertise_refs()?; // Generate a pack let request = UploadPackRequest { wants: vec![/* object ids */], haves: vec![], done: true, capabilities: UploadPackCapabilities::default(), shallow: ShallowRequest::default(), object_ids: None, }; let pack_stream = backend.upload_pack(&request).await?; ``` -------------------------------- ### 嵌入到现有 Axum 路由 Source: https://github.com/wjqserver/gitserver/blob/main/docs/zh/library.md 将 gitserver 的 Axum Router 嵌套到更大的应用路由中。 ```rust use axum::Router; use gitserver_core::discovery::RepoStore; use gitserver_http::{SharedState, router}; let store = RepoStore::discover("./repos".into(), 3)?; let git_state = SharedState::new(store); let git_app = router(git_state); // 挂载到 /git 路径下 let app = Router::new() .nest("/git", git_app) // ... 其他路由 ; ``` -------------------------------- ### List Repositories Source: https://github.com/wjqserver/gitserver/blob/main/docs/en/api.md Retrieves a list of exposed bare Git repositories. Requires authentication if configured. ```http GET / ``` ```json [ { "name": "my-project.git", "relative_path": "my-project.git", "description": "My project" }, { "name": "nested.git", "relative_path": "org/nested.git" } ] ``` -------------------------------- ### Configure Service Policy with SharedState::with_store_and_auth_policy Source: https://context7.com/wjqserver/gitserver/llms.txt Configure specific Git services, including push support via git-receive-pack. This allows fine-grained control over which Git operations are permitted. ```rust use gitserver_core::discovery::RepoStore; use gitserver_http::{SharedState, router, ServicePolicy, AuthConfig}; #[tokio::main] async fn main() -> anyhow::Result<()> { let store = RepoStore::discover("./repos".into(), 3)?; // Configure service policy let state = SharedState::with_store_and_auth_policy( store, AuthConfig::default(), ServicePolicy { upload_pack: true, // Enable clone/fetch (default: true) upload_pack_v2: true, // Enable protocol v2 (default: true) receive_pack: true, // Enable push (default: false) }, ); let app = router(state); let listener = tokio::net::TcpListener::bind("127.0.0.1:3000").await?; axum::serve(listener, app).await?; Ok(()) } ``` -------------------------------- ### Perform Git Ref Advertisement Source: https://context7.com/wjqserver/gitserver/llms.txt Execute the initial Git handshake for clone, fetch, or push operations using the info/refs endpoint. ```bash # Protocol v1 ref advertisement for git-upload-pack (clone/fetch) curl -s "http://127.0.0.1:3000/my-project.git/info/refs?service=git-upload-pack" # Protocol v2 ref advertisement (used by modern Git clients) curl -s \ -H "git-protocol: version=2" \ "http://127.0.0.1:3000/my-project.git/info/refs?service=git-upload-pack" # Ref advertisement for git-receive-pack (push, requires --enable-receive-pack) curl -s "http://127.0.0.1:3000/my-project.git/info/refs?service=git-receive-pack" # With gzip compression curl -s \ -H "Accept-Encoding: gzip" \ "http://127.0.0.1:3000/my-project.git/info/refs?service=git-upload-pack" ``` -------------------------------- ### Enable Authentication Source: https://github.com/wjqserver/gitserver/blob/main/docs/en/usage.md Commands to secure the server using either HTTP Basic authentication or a Bearer token. ```sh # Basic auth gitserver --auth-basic-username admin --auth-basic-password secret ./repos # Bearer token auth gitserver --auth-bearer-token my-secret-token ./repos ``` -------------------------------- ### Build a Release Binary Source: https://github.com/wjqserver/gitserver/blob/main/docs/en/installation.md Compile the project in release mode to generate an optimized binary. The executable will be located in the target/release directory. ```sh cargo build --release ``` -------------------------------- ### Manual Repository Registration with Dynamic Mode Source: https://context7.com/wjqserver/gitserver/llms.txt Use dynamic mode for manual repository management when your application dictates which repositories exist. This involves creating and managing a registry. ```rust use std::sync::Arc; use gitserver_core::discovery::{DynamicRepoRegistry, MutableRepoRegistry, RepoInfo}; use gitserver_http::{SharedState, router, ServicePolicy, AuthConfig}; #[tokio::main] async fn main() -> anyhow::Result<()> { // Create empty registry for manual management let registry = Arc::new(DynamicRepoRegistry::new()); let state = SharedState::with_registry( registry.clone(), AuthConfig::default(), ServicePolicy::default(), ); // Register a repository (validates path is a bare repo) registry.register(RepoInfo { name: "my-project.git".into(), relative_path: "tenant-a/my-project.git".into(), absolute_path: "/data/repos/tenant-a/my-project.git".into(), description: Some("My project".into()), })?; // Unregister when no longer needed // registry.unregister("tenant-a/my-project.git")?; let app = router(state); let listener = tokio::net::TcpListener::bind("127.0.0.1:3000").await?; axum::serve(listener, app).await?; Ok(()) } ``` -------------------------------- ### Git Ref Advertisement Source: https://github.com/wjqserver/gitserver/blob/main/docs/en/api.md Initial handshake for git clone and fetch operations. ```http GET /{repo}/info/refs?service=git-upload-pack GET /{repo}/info/refs?service=git-receive-pack ``` -------------------------------- ### Run All Code Quality Checks with Make Source: https://github.com/wjqserver/gitserver/blob/main/docs/en/installation.md Execute a comprehensive check that includes code formatting, Clippy linting, and running tests. This is typically managed by a Makefile. ```sh make check ``` -------------------------------- ### Git Ref Advertisement (info/refs) Source: https://context7.com/wjqserver/gitserver/llms.txt The ref advertisement endpoint handles the initial Git handshake for clone and fetch operations, supporting both protocol v1 and v2 with optional compression. ```APIDOC ## Git Ref Advertisement (info/refs) The ref advertisement endpoint handles the initial Git handshake for clone and fetch operations, supporting both protocol v1 and v2 with optional compression. ### Request Example ```bash # Protocol v1 ref advertisement for git-upload-pack (clone/fetch) curl -s "http://127.0.0.1:3000/my-project.git/info/refs?service=git-upload-pack" # Protocol v2 ref advertisement (used by modern Git clients) curl -s \ -H "git-protocol: version=2" \ "http://127.0.0.1:3000/my-project.git/info/refs?service=git-upload-pack" # Ref advertisement for git-receive-pack (push, requires --enable-receive-pack) curl -s "http://127.0.0.1:3000/my-project.git/info/refs?service=git-receive-pack" # With gzip compression curl -s \ -H "Accept-Encoding: gzip" \ "http://127.0.0.1:3000/my-project.git/info/refs?service=git-upload-pack" ``` ``` -------------------------------- ### 配置认证 Source: https://github.com/wjqserver/gitserver/blob/main/docs/zh/library.md 配置 Basic 和 Bearer 认证,两者任一通过即可。 ```rust use gitserver_core::discovery::RepoStore; use gitserver_http::{SharedState, router, AuthConfig, BasicAuthConfig}; let store = RepoStore::discover("./repos".into(), 3)?; let state = SharedState::with_auth(store, AuthConfig { basic: Some(BasicAuthConfig { username: "admin".into(), password: "secret".into(), }), bearer_token: Some("my-token".into()), }); let app = router(state); ``` -------------------------------- ### Query Repository Listing API Source: https://context7.com/wjqserver/gitserver/llms.txt Retrieve a list of available repositories in JSON format, supporting authentication and tokens. ```bash # List all repositories curl -s http://127.0.0.1:3000/ | jq # Response: # [ # { # "name": "my-project.git", # "relative_path": "my-project.git", # "description": "My project" # }, # { # "name": "nested.git", # "relative_path": "org/nested.git" # } # ] # With authentication curl -s -u admin:secret http://127.0.0.1:3000/ # Using Bearer token curl -s -H "Authorization: Bearer my-token" http://127.0.0.1:3000/ ``` -------------------------------- ### List Repositories Source: https://github.com/wjqserver/gitserver/blob/main/README.md Retrieves a JSON array of all available repositories. ```APIDOC ## GET / ### Description JSON array of available repositories. ### Method GET ### Endpoint / ### Response #### Success Response (200) - **name** (string) - The name of the repository. - **relative_path** (string) - The relative path to the repository. - **description** (string) - A brief description of the repository. #### Response Example ```json [ { "name": "my-project.git", "relative_path": "my-project.git", "description": "My project" } ] ``` ``` -------------------------------- ### Format Code with Cargo Source: https://github.com/wjqserver/gitserver/blob/main/docs/en/installation.md Apply standard code formatting to the entire project using the cargo fmt command. ```sh cargo fmt ``` -------------------------------- ### 快速开始: 发现模式 Source: https://github.com/wjqserver/gitserver/blob/main/docs/zh/library.md 使用 RepoStore 扫描目录自动发现裸仓库,并启动一个 Axum HTTP 服务。 ```rust use gitserver_core::discovery::RepoStore; use gitserver_http::{SharedState, router}; #[tokio::main] async fn main() -> anyhow::Result<()> { // 扫描 ./repos 目录, 最大深度 3 let store = RepoStore::discover("./repos".into(), 3)?; // 创建共享状态并构建路由 let state = SharedState::new(store); let app = router(state); // 启动服务 let listener = tokio::net::TcpListener::bind("127.0.0.1:3000").await?; axum::serve(listener, app) .with_graceful_shutdown(async { tokio::signal::ctrl_c().await.expect("install Ctrl+C handler"); }) .await?; Ok(()) } ``` -------------------------------- ### Gitserver Project Structure Source: https://github.com/wjqserver/gitserver/blob/main/docs/en/architecture.md Overview of the directory structure for the gitserver project, including the main crates and documentation folders. ```text repo/ ├── crates/ │ ├── gitserver/ # CLI binary entry point │ ├── gitserver-core/ # Core Git protocol operations │ ├── gitserver-http/ # HTTP layer (Axum) │ └── gitserver-bench/ # Performance benchmarks ├── docs/ │ ├── zh/ # Chinese documentation │ └── en/ # English documentation ├── Cargo.toml # Workspace definition └── Makefile ``` -------------------------------- ### Enable Push Support Source: https://github.com/wjqserver/gitserver/blob/main/docs/en/usage.md Command to allow push operations, which are disabled by default. ```sh gitserver --enable-receive-pack ./repos ``` -------------------------------- ### 直接使用公开处理器 Source: https://github.com/wjqserver/gitserver/blob/main/docs/zh/library.md 直接调用 gitserver_http::handlers 模块中的公开处理函数,用于自定义路由。 ```rust use axum::http::{HeaderMap, StatusCode}; use gitserver_core::discovery::RepoStore; use gitserver_http::{ SharedState, ServicePolicy, AuthConfig, handlers::{info_refs_endpoint, ServiceKind}, }; let store = RepoStore::discover("./repos".into(), 3)?; let state = SharedState::with_store_and_auth_policy( store, AuthConfig::default(), ServicePolicy::default(), ); // 直接调用 info/refs 处理器 let response = info_refs_endpoint( &state, "my-project.git", ServiceKind::UploadPack, HeaderMap::new(), ).await?; ``` -------------------------------- ### Repository Listing API Source: https://context7.com/wjqserver/gitserver/llms.txt The root endpoint returns all available bare Git repositories as JSON, with optional description from each repository's `description` file. ```APIDOC ## Repository Listing API The root endpoint returns all available bare Git repositories as JSON, with optional description from each repository's `description` file. ### Request Example ```bash # List all repositories curl -s http://127.0.0.1:3000/ | jq # Response: # [ # { # "name": "my-project.git", # "relative_path": "my-project.git", # "description": "My project" # }, # { # "name": "nested.git", # "relative_path": "org/nested.git" # } # ] # With authentication curl -s -u admin:secret http://127.0.0.1:3000/ # Using Bearer token curl -s -H "Authorization: Bearer my-token" http://127.0.0.1:3000/ ``` ``` -------------------------------- ### Git Pack Upload Source: https://github.com/wjqserver/gitserver/blob/main/docs/en/api.md Handles pack requests to return requested objects. ```http POST /{repo}/git-upload-pack ``` -------------------------------- ### Clone/Fetch (Protocol v2) Request Flow Source: https://github.com/wjqserver/gitserver/blob/main/docs/en/architecture.md Diagram illustrating the client-server interaction for clone and fetch operations using Git protocol v2, highlighting capability advertisement and command requests. ```text Client Server | GET /repo/info/refs | | git-protocol: version=2 | |-------------------------------->| | | protocol_v2::advertise_capabilities() |<--------------------------------| | | | POST /repo/git-upload-pack | | git-protocol: version=2 | |-------------------------------->| | | parse_command_request() | | ls-refs or fetch |<--------------------------------| ``` -------------------------------- ### Clone/Fetch (Protocol v1) Request Flow Source: https://github.com/wjqserver/gitserver/blob/main/docs/en/architecture.md Diagram illustrating the client-server interaction for clone and fetch operations using Git protocol v1, including ref advertisement and pack data transfer. ```text Client Server | | | GET /repo/info/refs | | ?service=git-upload-pack | |-------------------------------->| | | Resolve repo path | | Verify auth | | refs::advertise_refs() | | Return ref advertisement |<--------------------------------| | | | POST /repo/git-upload-pack | | Content-Type: ...-request | |-------------------------------->| | | Parse UploadPackRequest | | pack::generate_pack() | | Stream side-band-64k pack |<--------------------------------| ``` -------------------------------- ### 动态模式: 手动注册仓库 Source: https://github.com/wjqserver/gitserver/blob/main/docs/zh/library.md 手动注册和注销仓库,适用于多租户场景,无需文件系统扫描。 ```rust use std::sync::Arc; use gitserver_core::discovery::{DynamicRepoRegistry, MutableRepoRegistry, RepoInfo}; use gitserver_http::{SharedState, router, ServicePolicy, AuthConfig}; // 创建空注册表 let registry = Arc::new(DynamicRepoRegistry::new()); let state = SharedState::with_registry( registry.clone(), AuthConfig::default(), ServicePolicy::default(), ); // 注册仓库 (会验证路径是否为裸仓库) registry.register(RepoInfo { name: "my-project.git".into(), relative_path: "tenant-a/my-project.git".into(), absolute_path: "/data/repos/tenant-a/my-project.git".into(), description: Some("My project".into()), })?; // 注销仓库 registry.unregister("tenant-a/my-project.git")?; let app = router(state); ``` -------------------------------- ### 后台定期刷新仓库列表 Source: https://github.com/wjqserver/gitserver/blob/main/docs/zh/library.md 为发现模式设置后台任务,定期刷新仓库列表。动态模式不支持此功能。 ```rust use tokio::time::{interval, Duration, MissedTickBehavior}; // 克隆 state 用于后台任务 let refresh_state = state.clone(); tokio::spawn(async move { let mut ticker = interval(Duration::from_secs(30)); ticker.set_missed_tick_behavior(MissedTickBehavior::Skip); loop { ticker.tick().await; if let Err(e) = refresh_state.refresh().await { tracing::warn!("refresh failed: {e}"); } } }); ``` -------------------------------- ### Clone Repository from gitserver Server Source: https://github.com/wjqserver/gitserver/blob/main/README.md Clone a repository from a running gitserver instance using the standard Git client. Replace 'my-project' with your repository name. ```sh # Clone from the server git clone http://127.0.0.1:3000/my-project.git ``` -------------------------------- ### Add Gitserver Crates as Dependencies Source: https://github.com/wjqserver/gitserver/blob/main/docs/en/installation.md Include the gitserver-core and gitserver-http crates in your project's Cargo.toml file to use them as libraries. Ensure you specify the git repository. ```toml [dependencies] gitserver-core = { git = "https://github.com/WJQSERVER/gitserver" } gitserver-http = { git = "https://github.com/WJQSERVER/gitserver" } ``` -------------------------------- ### Configure service policy Source: https://github.com/wjqserver/gitserver/blob/main/docs/en/library.md Define which Git operations are permitted, such as enabling push (receive-pack) which is disabled by default. ```rust use gitserver_http::{SharedState, ServicePolicy, AuthConfig}; let state = SharedState::with_store_and_auth_policy( store, AuthConfig::default(), ServicePolicy { upload_pack: true, // clone/fetch upload_pack_v2: true, // protocol v2 receive_pack: true, // push (disabled by default) }, ); ``` -------------------------------- ### Check Push Status with curl Source: https://context7.com/wjqserver/gitserver/llms.txt Use curl to check the status of the git-receive-pack service. A 404 error indicates that the service is disabled. ```shell curl -s "http://127.0.0.1:3000/my-project.git/info/refs?service=git-receive-pack" ``` -------------------------------- ### 动态模式: 使用快捷方法注册仓库 Source: https://github.com/wjqserver/gitserver/blob/main/docs/zh/library.md 使用 SharedState 的快捷方法动态注册仓库。 ```rust let state = SharedState::with_dynamic_registry( AuthConfig::default(), ServicePolicy::default(), ); // 通过 state 注册 state.register_repo(RepoInfo { name: "project.git".into(), relative_path: "project.git".into(), absolute_path: "/data/repos/project.git".into(), description: None, })?; ``` -------------------------------- ### Implement Background Periodic Refresh Source: https://github.com/wjqserver/gitserver/blob/main/docs/en/library.md Uses a tokio interval to trigger repository refreshes every 30 seconds. Requires the state to be cloneable and accessible within the async task. ```rust use tokio::time::{interval, Duration, MissedTickBehavior}; // Clone state for the background task let refresh_state = state.clone(); tokio::spawn(async move { let mut ticker = interval(Duration::from_secs(30)); ticker.set_missed_tick_behavior(MissedTickBehavior::Skip); loop { ticker.tick().await; if let Err(e) = refresh_state.refresh().await { tracing::warn!("refresh failed: {e}"); } } }); ``` -------------------------------- ### Git Pack Negotiation Source: https://github.com/wjqserver/gitserver/blob/main/README.md Handles Git pack negotiation for uploads. ```APIDOC ## POST /{repo}/git-upload-pack ### Description Git pack negotiation for uploads. ### Method POST ### Endpoint `/{repo}/git-upload-pack` ``` -------------------------------- ### Run Benchmarks for Gitserver-Bench Crate Source: https://github.com/wjqserver/gitserver/blob/main/docs/en/installation.md Execute performance benchmarks specifically for the gitserver-bench crate. This helps in evaluating the performance of various Git operations. ```sh cargo bench -p gitserver-bench ``` -------------------------------- ### Git Client Operations Source: https://github.com/wjqserver/gitserver/blob/main/docs/en/usage.md Standard Git commands for interacting with the hosted repositories, including authentication via URL. ```sh # Clone a repository git clone http://127.0.0.1:3000/my-project.git # Fetch updates from remote git fetch # Clone with authentication git clone http://admin:secret@127.0.0.1:3000/my-project.git ``` -------------------------------- ### Repository Listing API Source: https://github.com/wjqserver/gitserver/blob/main/docs/en/api.md Retrieves a list of all bare Git repositories exposed by the server. Authentication is required if configured. ```APIDOC ## GET / ### Description Returns a list of bare Git repositories currently exposed by the server. Requires valid credentials if authentication is configured. ### Method GET ### Endpoint / ### Response #### Success Response (200) - **name** (string) - The name of the repository. - **relative_path** (string) - The relative path to the repository on the server. - **description** (string) - An optional description of the repository. #### Response Example ```json [ { "name": "my-project.git", "relative_path": "my-project.git", "description": "My project" }, { "name": "nested.git", "relative_path": "org/nested.git" } ] ``` ``` -------------------------------- ### Protocol v2 Capabilities Source: https://github.com/wjqserver/gitserver/blob/main/docs/en/api.md Server-advertised capabilities for protocol v2. ```text ls-refs=unborn fetch=shallow wait-for-done object-format=sha1 ``` -------------------------------- ### Push Request Flow Source: https://github.com/wjqserver/gitserver/blob/main/docs/en/architecture.md Diagram illustrating the client-server interaction for push operations, including ref advertisement and the receive-pack process with validation. ```text Client Server | GET /repo/info/refs | | ?service=git-receive-pack | |-------------------------------->| | | receive_pack::advertise_receive_refs() |<--------------------------------| | | | POST /repo/git-receive-pack | |-------------------------------->| | | receive_pack::receive_pack() | | 1. Parse update commands | | 2. Write pack to ODB | | 3. Validate ref updates (fast-forward check) | | 4. Update references | | 5. Return status report |<--------------------------------| ``` -------------------------------- ### Implement Background Periodic Refresh Source: https://context7.com/wjqserver/gitserver/llms.txt Spawns a background task to periodically refresh the repository list using a ticker. ```rust use tokio::time::{interval, Duration, MissedTickBehavior}; use gitserver_core::discovery::RepoStore; use gitserver_http::{SharedState, router}; #[tokio::main] async fn main() -> anyhow::Result<()> { let store = RepoStore::discover("./repos".into(), 3)?; let state = SharedState::new(store); let app = router(state.clone()); // Spawn background task for periodic refresh let refresh_state = state.clone(); tokio::spawn(async move { let mut ticker = interval(Duration::from_secs(30)); ticker.set_missed_tick_behavior(MissedTickBehavior::Skip); loop { ticker.tick().await; if let Err(e) = refresh_state.refresh().await { tracing::warn!("Repository refresh failed: {e}"); } } }); let listener = tokio::net::TcpListener::bind("127.0.0.1:3000").await?; axum::serve(listener, app).await?; Ok(()) } ``` -------------------------------- ### Run Clippy Linting with Warnings as Errors Source: https://github.com/wjqserver/gitserver/blob/main/docs/en/installation.md Perform linting on all targets and features using Clippy, treating all warnings as errors to enforce code quality. ```sh cargo clippy --all-targets --all-features -- -D warnings ``` -------------------------------- ### Protocol v2 Commands Source: https://github.com/wjqserver/gitserver/blob/main/docs/en/api.md Details on commands supported when using Git protocol version 2. ```APIDOC ## Protocol v2 Commands When the client specifies `version=2` in the `git-protocol` header, the `/info/refs` and `/git-upload-pack` endpoints support protocol v2. ### Server-Advertised Capabilities `ls-refs=unborn` `fetch=shallow wait-for-done` `object-format=sha1` ### ls-refs Command #### Description List repository references. #### Request Arguments - **peel** (boolean) - Request peeled ref information. - **symrefs** (boolean) - Request symbolic ref targets. - **unborn** (boolean) - Support unborn HEAD. - **ref-prefix** (string) - Filter by ref prefix (e.g. `refs/heads/`). ### fetch Command #### Description Fetch object packs. Supports shallow clones and depth limiting. #### Request Arguments - **want** (string) - Requested objects (OID). - **have** (string) - Objects the client already has (OID). - **done** (boolean) - Negotiation complete. - **ofs-delta** (boolean) - Support offset delta compression. - **deepen** (integer) - Limit clone depth. - **shallow** (string) - Client's existing shallow boundaries (OID). - **deepen-relative** (boolean) - Relative depth calculation. - **thin-pack**, **no-progress**, **include-tag**, **wait-for-done** (boolean) - Supported but ignored. ``` -------------------------------- ### Run All Workspace Tests Source: https://github.com/wjqserver/gitserver/blob/main/docs/en/installation.md Execute all tests across the entire Cargo workspace, including integration and load tests. Enable all features for comprehensive testing. ```sh cargo test --workspace --all-features ``` -------------------------------- ### Authentication Methods Source: https://github.com/wjqserver/gitserver/blob/main/docs/en/api.md Details on the supported HTTP authentication methods: Basic and Bearer. ```APIDOC ## Authentication The server supports two HTTP authentication methods: ### Basic Authentication #### Description Configured via `--auth-basic-username` and `--auth-basic-password`. Uses constant-time comparison to prevent timing attacks. ### Bearer Authentication #### Description Configured via `--auth-bearer-token`. Pass `Bearer ` in the `Authorization` header. #### Error Handling Failed authentication returns a 401 status with a `WWW-Authenticate` header. ``` -------------------------------- ### Embedding Gitserver into Existing Axum Router Source: https://context7.com/wjqserver/gitserver/llms.txt Mount the Git server routes under a custom path prefix in a larger Axum application. This allows integrating gitserver into an existing web service. ```rust use axum::Router; use gitserver_core::discovery::RepoStore; use gitserver_http::{SharedState, router}; #[tokio::main] async fn main() -> anyhow::Result<()> { let store = RepoStore::discover("./repos".into(), 3)?; let git_state = SharedState::new(store); let git_app = router(git_state); // Mount Git server under /git prefix let app = Router::new() .nest("/git", git_app) .route("/", axum::routing::get(|| async { "Main app" })); // Clients would use: git clone http://127.0.0.1:3000/git/my-project.git let listener = tokio::net::TcpListener::bind("127.0.0.1:3000").await?; axum::serve(listener, app).await?; Ok(()) } ``` -------------------------------- ### Git Ref Advertisement Source: https://github.com/wjqserver/gitserver/blob/main/README.md Provides Git ref advertisement for specified services. ```APIDOC ## GET /{repo}/info/refs ### Description Git ref advertisement. Supports `git-upload-pack` and `git-receive-pack` services. ### Method GET ### Endpoint `/{repo}/info/refs?service=` ### Query Parameters - **service** (string) - Required - The Git service to advertise (e.g., `git-upload-pack`, `git-receive-pack`). ``` -------------------------------- ### Perform Low-Level Git Operations Source: https://context7.com/wjqserver/gitserver/llms.txt Uses GitBackend to interact with Git repositories directly, bypassing the HTTP layer. ```rust use gitserver_core::{ discovery::RepoStore, backend::GitBackend, pack::{UploadPackRequest, UploadPackCapabilities, ShallowRequest}, }; #[tokio::main] async fn main() -> anyhow::Result<()> { // Discover and resolve repository let store = RepoStore::discover("./repos".into(), 3)?; let repo = store.resolve("my-project.git")?; // Create backend for Git operations let backend = GitBackend::new(repo.absolute_path.clone()); // Get ref advertisement let refs = backend.advertise_refs()?; for (name, oid) in &refs { println!("{} {}", oid, name); } // Generate a pack for requested objects let request = UploadPackRequest { wants: vec![/* object IDs the client wants */], haves: vec![/* object IDs the client already has */], done: true, capabilities: UploadPackCapabilities::default(), shallow: ShallowRequest::default(), object_ids: None, }; let pack_stream = backend.upload_pack(&request).await?; // pack_stream is a Stream of pack data chunks Ok(()) } ``` -------------------------------- ### Perform Health Check Source: https://github.com/wjqserver/gitserver/blob/main/docs/en/api.md Use this endpoint for readiness and liveness probes. It returns 503 during graceful shutdown. ```http GET /healthz ``` ```json { "status": "ok" } ``` -------------------------------- ### Use low-level handlers Source: https://github.com/wjqserver/gitserver/blob/main/docs/en/library.md Invoke specific Git protocol handlers directly for granular control over request processing. ```rust use axum::http::{HeaderMap, StatusCode}; use gitserver_core::discovery::RepoStore; use gitserver_http::{ SharedState, ServicePolicy, AuthConfig, handlers::{info_refs_endpoint, ServiceKind}, }; let store = RepoStore::discover("./repos".into(), 3)?; let state = SharedState::with_store_and_auth_policy( store, AuthConfig::default(), ServicePolicy::default(), ); // Call info/refs handler directly let response = info_refs_endpoint( &state, "my-project.git", ServiceKind::UploadPack, HeaderMap::new(), ).await?; ``` -------------------------------- ### Git Pack Receive Source: https://github.com/wjqserver/gitserver/blob/main/docs/en/api.md Receives pushed pack data and updates references. Requires --enable-receive-pack. ```http POST /{repo}/git-receive-pack ``` -------------------------------- ### Embed into an existing Axum router Source: https://github.com/wjqserver/gitserver/blob/main/docs/en/library.md Nest the Git server routes under a specific path within a larger Axum application. ```rust use axum::Router; use gitserver_core::discovery::RepoStore; use gitserver_http::{SharedState, router}; let store = RepoStore::discover("./repos".into(), 3)?; let git_state = SharedState::new(store); let git_app = router(git_state); // Mount under /git let app = Router::new() .nest("/git", git_app) // ... other routes ; ``` -------------------------------- ### Git Smart HTTP Protocol - Ref Advertisement Source: https://github.com/wjqserver/gitserver/blob/main/docs/en/api.md Handles the Git ref advertisement handshake for clone and fetch operations. Supports protocol v2. ```APIDOC ## GET /{repo}/info/refs ### Description Returns the Git ref advertisement used for the initial handshake in `git clone` and `git fetch`. `git-receive-pack` is disabled by default and requires `--enable-receive-pack`. ### Method GET ### Endpoint `/{repo}/info/refs?service=git-upload-pack` or `/{repo}/info/refs?service=git-receive-pack` ### Request Headers - **git-protocol** (string) - Optional: set to `version=2` to enable protocol v2. - **Accept-Encoding** (string) - Supports `gzip` and `zstd` compression. ### Response Headers - **Content-Type** (string) - `application/x-git-upload-pack-advertisement` or `application/x-git-receive-pack-advertisement`. - **Cache-Control** (string) - `no-cache`. - **Content-Encoding** (string) - `gzip` or `zstd` (if supported by client). ```