Skip to content

develop.gittools #

Git Tools Module

A comprehensive Git management module for V that provides high-level abstractions for Git operations, repository management, and automation of common Git workflows.

Features

  • Repository management (clone, load, delete)
  • Branch operations (create, switch, checkout)
  • Tag management (create, switch, verify)
  • Change tracking and commits
  • Remote operations (push, pull)
  • SSH key integration
  • Submodule support
  • Repository status tracking
  • Light cloning option for large repositories

Basic Usage

Repository Management

import freeflowuniverse.crystallib.develop.gittools

// Initialize with code root directory
mut gs := gittools.new(coderoot: '~/code')!

// Clone a repository
mut repo := gs.clone(GitCloneArgs{
    url: 'git@github.com:username/repo.git'
    sshkey: 'deploy_key'  // Optional SSH key name
})!

// Or get existing repository
mut repo := gs.get_repo(name: 'existing_repo')!

// Delete repository
repo.delete()!

Branch Operations

// Create and switch to new branch
repo.branch_create('feature-branch')!
repo.branch_switch('feature-branch')!

// Check status and commit changes
if repo.has_changes() {
    repo.commit('feat: Add new feature')!
    repo.push()!
}

// Pull latest changes
repo.pull()!

// Pull with submodules
repo.pull(submodules: true)!

Tag Management

// Create a new tag
repo.tag_create('v1.0.0')!

// Switch to tag
repo.tag_switch('v1.0.0')!

// Check if tag exists
exists := repo.tag_exists('v1.0.0')!

// Get tag information
if repo.status_local.tag == 'v1.0.0' {
    // Currently on tag v1.0.0
}

Advanced Features

SSH Key Integration

// Clone with SSH key
mut repo := gs.clone(GitCloneArgs{
    url: 'git@github.com:username/repo.git'
    sshkey: 'deploy_key'
})!

// Set SSH key for existing repository
repo.set_sshkey('deploy_key')!

Repository Status

// Update repository status
repo.status_update()!

// Check various status conditions
if repo.need_commit() {
    // Has uncommitted changes
}

if repo.need_push_or_pull() {
    // Has unpushed/unpulled changes
}

if repo.need_checkout() {
    // Needs to checkout different branch/tag
}

Change Management

// Check for changes
if repo.has_changes() {
    // Handle changes
}

// Reset all changes
repo.reset()!
// or
repo.remove_changes()!

// Update submodules
repo.update_submodules()!

Repository Configuration

GitRepo Structure

pub struct GitRepo {
pub mut:
    provider      string              // e.g., github.com
    account       string              // Git account name
    name          string              // Repository name
    status_remote GitRepoStatusRemote // Remote repository status
    status_local  GitRepoStatusLocal  // Local repository status
    status_wanted GitRepoStatusWanted // Desired status
    config        GitRepoConfig       // Repository configuration
    deploysshkey  string              // SSH key for git operations
}

Status Tracking

// Remote Status
pub struct GitRepoStatusRemote {
pub mut:
    ref_default string            // Default branch hash
    branches    map[string]string // Branch name -> commit hash
    tags        map[string]string // Tag name -> commit hash
}

// Local Status
pub struct GitRepoStatusLocal {
pub mut:
    branches map[string]string // Branch name -> commit hash
    branch   string           // Current branch
    tag      string           // Current tag
}

// Desired Status
pub struct GitRepoStatusWanted {
pub mut:
    branch   string
    tag      string
    url      string // Remote repository URL
    readonly bool   // Prevent push/commit operations
}

Error Handling

The module provides comprehensive error handling:

// Clone with error handling
mut repo := gs.clone(url: 'invalid_url') or {
    println('Clone failed: ${err}')
    return
}

// Commit with error handling
repo.commit('feat: New feature') or {
    if err.msg().contains('nothing to commit') {
        println('No changes to commit')
    } else {
        println('Commit failed: ${err}')
    }
    return
}

Testing

Run the test suite:

v -enable-globals test crystallib/develop/gittools/tests/

Notes

  • SSH keys should be properly configured in ~/.ssh/
  • For readonly repositories, all local changes will be reset on pull
  • Light cloning option (config.light: true) creates shallow clones
  • Repository status is automatically cached and updated
  • Submodules are handled recursively when specified
  • All operations maintain repository consistency

Constants #

const gitcmds = 'clone,commit,pull,push,delete,reload,list,edit,sourcetree,cd'

fn cachereset #

fn cachereset() !

Reset all caches and configurations for all Git repositories.

fn configreset #

fn configreset() !

Reset the configuration cache for Git structures.

fn get #

fn get(args_ GitStructureArgGet) !&GitStructure

Retrieve a GitStructure instance based on the given arguments.

fn new #

fn new(args_ GitStructureArgsNew) !&GitStructure

Retrieve or create a new GitStructure instance with the given configuration.

fn reset #

fn reset()

struct GetRepoUrlArgs #

@[params]
struct GetRepoUrlArgs {
pub mut:
	with_branch bool // // If true, return the repo URL for an exact branch.
}

struct GitCloneArgs #

@[params]
struct GitCloneArgs {
pub mut:
	url    string
	sshkey string
}

struct GitLocation #

@[heap]
struct GitLocation {
pub mut:
	provider      string // Git provider (e.g., GitHub)
	account       string // Account name
	name          string // Repository name
	branch_or_tag string // Branch name
	path          string // Path in the repository (not the filesystem)
	anker         string // Position in a file
}

GitLocation uniquely identifies a Git repository, its online URL, and its location in the filesystem.

fn (GitLocation) patho #

fn (mut l GitLocation) patho() !pathlib.Path

Return a crystallib path object on the filesystem pointing to the locator

struct GitRepo #

@[heap]
struct GitRepo {
pub mut:
	gs            &GitStructure @[skip; str: skip] // Reference to the parent GitStructure
	provider      string              // e.g., github.com, shortened to 'github'
	account       string              // Git account name
	name          string              // Repository name
	status_remote GitRepoStatusRemote // Remote repository status
	status_local  GitRepoStatusLocal  // Local repository status
	status_wanted GitRepoStatusWanted // what is the status we want?
	config        GitRepoConfig       // Repository-specific configuration
	last_load     int                 // Epoch timestamp of the last load from reality
	deploysshkey  string              // to use with git
}

GitRepo holds information about a single Git repository.

fn (GitRepo) branch_create #

fn (mut repo GitRepo) branch_create(branchname string) !

Create a new branch in the repository.

fn (GitRepo) branch_switch #

fn (mut repo GitRepo) branch_switch(branchname string) !

fn (GitRepo) checkout #

fn (mut repo GitRepo) checkout() !

Checkout a branch in the repository.

fn (GitRepo) commit #

fn (mut repo GitRepo) commit(msg string) !

Commit the staged changes with the provided commit message.

fn (GitRepo) delete #

fn (mut repo GitRepo) delete() !

Deletes the Git repository

fn (GitRepo) display_current_status #

fn (mut repo GitRepo) display_current_status() !

fn (GitRepo) get_changes_staged #

fn (repo GitRepo) get_changes_staged() ![]string

Retrieves a list of staged changes in the repository.

This function returns a list of files that are staged and ready to be committed.

Returns:- An array of strings representing file paths of staged changes.

  • Throws an error if the command execution fails.

fn (GitRepo) get_changes_unstaged #

fn (repo GitRepo) get_changes_unstaged() ![]string

Retrieves a list of unstaged changes in the repository.

This function returns a list of files that are modified or untracked.

Returns:- An array of strings representing file paths of unstaged changes.

  • Throws an error if the command execution fails.

fn (GitRepo) get_last_local_commit #

fn (repo GitRepo) get_last_local_commit() !string

get commit for branch, will return '' if local branch doesn't exist remotely

fn (GitRepo) get_last_remote_commit #

fn (repo GitRepo) get_last_remote_commit() !string

is always the commit for the branch as known remotely, if not known will return ""

fn (GitRepo) get_parent_dir #

fn (repo GitRepo) get_parent_dir(args GetParentDir) !string

fn (GitRepo) get_path #

fn (repo GitRepo) get_path() !string

fn (GitRepo) get_path_of_url #

fn (repo GitRepo) get_path_of_url(url string) !string

gets the path of a given url within a repo ex: 'https://git.ourworld.tf/ourworld_holding/info_ourworld/src/branch/main/books/cocreation/SUMMARY.md' returns <repo_path>/books/cocreation/SUMMARY.md

fn (GitRepo) get_relative_path #

fn (repo GitRepo) get_relative_path() !string

Relative path inside the gitstructure, pointing to the repo

fn (GitRepo) gitlocation_from_path #

fn (mut gs GitRepo) gitlocation_from_path(path string) !GitLocation

Create GitLocation from the path within the Git repository

fn (GitRepo) has_changes #

fn (mut repo GitRepo) has_changes() !bool

Check if there are any unstaged or untracked changes in the repository.

fn (GitRepo) init #

fn (mut repo GitRepo) init() !

Check if repo path exists and validate fields

fn (GitRepo) need_commit #

fn (mut repo GitRepo) need_commit() !bool

Check if there are staged changes to commit.

fn (GitRepo) need_push_or_pull #

fn (mut repo GitRepo) need_push_or_pull() !bool

Check if the repository has changes that need to be pushed.

fn (GitRepo) open_vscode #

fn (repo GitRepo) open_vscode() !

Opens Visual Studio Code for the repo

fn (GitRepo) patho #

fn (repo GitRepo) patho() !pathlib.Path

Return rich path object from our library crystal lib

fn (GitRepo) pull #

fn (mut repo GitRepo) pull(args_ PullCheckoutArgs) !

Pull remote content into the repository.

fn (GitRepo) push #

fn (mut repo GitRepo) push() !

Push local changes to the remote repository.

fn (GitRepo) remove_changes #

fn (mut repo GitRepo) remove_changes() !

Removes all changes from the repo; be cautious

fn (GitRepo) reset #

fn (mut repo GitRepo) reset() !

alias for remove changes

fn (GitRepo) sourcetree #

fn (repo GitRepo) sourcetree() !

Opens SourceTree for the Git repo

fn (GitRepo) status_update #

fn (mut repo GitRepo) status_update(args StatusUpdateArgs) !

fn (GitRepo) tag_create #

fn (mut repo GitRepo) tag_create(tagname string) !

Create a new branch in the repository.

fn (GitRepo) tag_exists #

fn (mut repo GitRepo) tag_exists(tag string) !bool

Create a new branch in the repository.

fn (GitRepo) tag_switch #

fn (mut repo GitRepo) tag_switch(tagname string) !

struct GitRepoConfig #

struct GitRepoConfig {
pub mut:
	remote_check_period int = 3600 * 24 * 3 // Seconds to wait between remote checks (0 = check every time), default 3 days
}

GitRepoConfig holds repository-specific configuration options.

struct GitRepoStatusLocal #

struct GitRepoStatusLocal {
pub mut:
	branches map[string]string // Branch name -> commit hash
	branch   string            // the current branch
	tag      string            // If the local branch is not set, the tag may be set
}

GitRepoStatusLocal holds local status information for a repository.

struct GitRepoStatusRemote #

struct GitRepoStatusRemote {
pub mut:
	ref_default string            // is the default branch hash
	branches    map[string]string // Branch name -> commit hash
	tags        map[string]string // Tag name -> commit hash
}

GitRepoStatusRemote holds remote status information for a repository.

struct GitRepoStatusWanted #

struct GitRepoStatusWanted {
pub mut:
	branch   string
	tag      string
	url      string // Remote repository URL, is basically the one we want	
	readonly bool   // if read only then we cannot push or commit, all changes will be reset when doing pull
}

this is the status we want, we need to work towards off

struct GitStructure #

@[heap]
struct GitStructure {
pub mut:
	key      string              // Unique key representing the git structure (default is hash of $home/code).
	config   GitStructureConfig  // Configuration settings for the git structure.
	coderoot pathlib.Path        // Root directory where repositories are located.
	repos    map[string]&GitRepo // Map of repositories, keyed by their unique names.
	loaded   bool                // Indicates if the repositories have been loaded into memory.
}

GitStructure holds information about repositories within a specific code root. This structure keeps track of loaded repositories, their configurations, and their status.

fn (GitStructure) cachereset #

fn (mut gitstructure GitStructure) cachereset() !

Resets the cache for the current Git structure, removing cached data from Redis.

fn (GitStructure) clone #

fn (mut gitstructure GitStructure) clone(args GitCloneArgs) !&GitRepo

Clones a new repository into the git structure based on the provided arguments.

fn (GitStructure) do #

fn (mut gs GitStructure) do(args_ ReposActionsArgs) !string

do group actions on repo args

 cmd      string // clone,commit,pull,push,delete,reload,list,edit,sourcetree,cd
 filter   string // if used will only show the repo's which have the filter string inside
 repo     string
 account  string
 provider string
 msg      string
 url      string
 pull     bool
 script   bool = true // run non interactive
 reset    bool = true // means we will lose changes (only relevant for clone, pull)

fn (GitStructure) get_repo #

fn (mut gitstructure GitStructure) get_repo(args_ ReposGetArgs) !&GitRepo

Retrieves a single repository based on the provided arguments. if pull will force a pull, if it can't will be error, if reset will remove the changes If the repository does not exist, it will clone it

Args:

 ReposGetArgs {
 filter   string // Optional filter for repository names
 name     string // Specific repository name to retrieve.
 account  string // Git account associated with the repository.
 provider string // Git provider (e.g., GitHub).
 pull     bool   // Pull the last changes.
 reset    bool   // Reset the changes.
 reload   bool   // Reload the repo into redis cache
 url      string // Repository URL, used if cloning is needed.

Returns:- &GitRepo: Reference to the retrieved or cloned repository.

Raises:- Error: If multiple repositories are found with similar names or if cloning fails.

fn (GitStructure) get_repos #

fn (mut gitstructure GitStructure) get_repos(args_ ReposGetArgs) ![]&GitRepo

Retrieves a list of repositories from the git structure that match the provided arguments. if pull will force a pull, if it can't will be error, if reset will remove the changes

Args:

 ReposGetArgs {
 filter   string // Optional filter for repository names
 name     string // Specific repository name to retrieve.
 account  string // Git account associated with the repository.
 provider string // Git provider (e.g., GitHub).
 pull     bool   // Pull the last changes.
 reset    bool   // Reset the changes.
 reload   bool   // Reload the repo into redis cache
 url      string // Repository URL, used if cloning is needed.

Returns:- []&GitRepo: A list of repository references that match the criteria.

fn (GitStructure) get_working_repo #

fn (mut gitstructure GitStructure) get_working_repo() ?GitRepo

returns the git repository of the working directory by locating the parent directory with .git.

Returns:- GitRepo: Reference to the initialized repository.

Raises:- None: If .git is not found in the parent directories.

fn (GitStructure) gitlocation_from_path #

fn (mut gs GitStructure) gitlocation_from_path(path string) !GitLocation

Get GitLocation from a path within the Git repository

fn (GitStructure) gitlocation_from_url #

fn (mut gs GitStructure) gitlocation_from_url(url string) !GitLocation

Get GitLocation from a URL

fn (GitStructure) init #

fn (mut gitstructure GitStructure) init() !

just some initialization mechanism

fn (GitStructure) load #

fn (mut gitstructure GitStructure) load(args StatusUpdateArgs) !

Loads all repository information from the filesystem and updates from remote if necessary. Use the reload argument to force reloading from the disk.

Args:- args (StatusUpdateArgs): Arguments controlling the reload behavior.

fn (GitStructure) repo_new_from_gitlocation #

fn (mut gitstructure GitStructure) repo_new_from_gitlocation(git_location GitLocation) !&GitRepo

just some initialization mechanism

fn (GitStructure) repos_print #

fn (mut gitstructure GitStructure) repos_print(args ReposGetArgs) !

Print repositories based on the provided criteria, showing their statuses

struct GitStructureArgGet #

@[params]
struct GitStructureArgGet {
pub mut:
	coderoot string
	reload   bool
}

struct GitStructureArgsNew #

@[params]
struct GitStructureArgsNew {
pub mut:
	coderoot     string
	light        bool = true // If true, clones only the last history for all branches (clone with only 1 level deep)
	log          bool = true // If true, logs git commands/statements
	debug        bool = true
	ssh_key_name string // name of ssh key to be used when loading the gitstructure
	reload       bool
}

struct GitStructureConfig #

struct GitStructureConfig {
pub mut:
	coderoot     string
	light        bool = true // If true, clones only the last history for all branches (clone with only 1 level deep)
	log          bool = true // If true, logs git commands/statements
	debug        bool = true
	ssh_key_name string
}

struct PullCheckoutArgs #

@[params]
struct PullCheckoutArgs {
pub mut:
	submodules bool // if we want to pull for submodules
}

struct RepoInitParams #

@[params]
struct RepoInitParams {
	ssh_key_name string // name of ssh key to be used in repo
}

struct ReposActionsArgs #

@[params]
struct ReposActionsArgs {
pub mut:
	cmd       string // clone,commit,pull,push,delete,reload,list,edit,sourcetree
	filter    string // if used will only show the repo's which have the filter string inside
	repo      string
	account   string
	provider  string
	msg       string
	url       string
	branch    string
	recursive bool
	pull      bool
	script    bool = true // run non interactive
	reset     bool = true // means we will lose changes (only relevant for clone, pull)
}

struct ReposGetArgs #

@[params]
struct ReposGetArgs {
pub mut:
	filter   string // Optional filter for repository names
	name     string // Specific repository name to retrieve.
	account  string // Git account associated with the repository.
	provider string // Git provider (e.g., GitHub).
	pull     bool   // Pull the last changes.
	reset    bool   // Reset the changes.
	reload   bool   // Reload the repo into redis cache
	url      string // Repository URL
}

ReposGetArgs defines arguments to retrieve repositories from the git structure. It includes filters by name, account, provider, and an option to clone a missing repo.

struct StatusUpdateArgs #

@[params]
struct StatusUpdateArgs {
	reload       bool
	ssh_key_name string // name of ssh key to be used when loading
}