Files
herolib/lib/develop/gittools
2025-12-01 10:35:46 +01:00
..
...
2025-08-15 06:30:12 +02:00
...
2025-10-26 21:14:10 +04:00
...
2025-08-15 08:52:46 +02:00
...
2025-12-01 10:35:46 +01:00
...
2025-10-26 18:14:32 +04:00
...
2025-10-13 08:30:42 +04:00
...
2025-08-15 06:30:12 +02:00
...
2025-12-01 10:35:46 +01:00
...
2025-08-21 12:05:20 +02:00

Git Tools Module

GitTools HeroScript

!!git.define

Configure or retrieve a GitStructure, if not set will use the default

!!git.define
    coderoot:'/tmp/code' //when we overrule the location, the default is ~/code
    light:true //depth of git clone is 1
    log:true 
    debug:false //give more error reporting
    offline:false //makes sure will not try to get to internet, but do all locally
    ssh_key_path:'' //if a specific ssh key is needed
    reload:false //if set then will remove cache and load full status, this is slow !

!!git.clone

Clones a Git repository from a specified URL into the configured coderoot.

!!git.clone
 url: 'https://github.com/incubaid/test_repo.git'
    pull: true // Optional: if true, pulls latest changes after cloning
    reset: false // Optional: if true, resets the repository before cloning/pulling
 light: true // Optional: if true, clones only the last history (default: is from git structure as defined above)
 recursive: false // Optional: if true, also clones submodules (default: false)

!!git.repo_action

Performs various Git operations on an existing repository, the filter matches more than 1 repo, gives error if none found

!!git.repo_action 
    filter: 'incubaid/test_repo'
 action: 'pull' // pull, commit, push, reset, branch_create, branch_switch, tag_create, tag_switch, delete
 message: 'feat: Added new feature' // Optional: for 'commit' action
 branchname: 'feature-branch' // Optional: for 'branch_create' or 'branch_switch' actions
 tagname: 'v1.0.0' // Optional: for 'tag_create' or 'tag_switch' actions
 submodules: true // Optional: for 'pull' action, if true, also updates submodules
    error_ignore: false // Optional: if true, ignores errors during the action and continue for the next repo

Parameters:

  • filter (string, required): A substring to filter repositories by name or relative path. This can match multiple repositories.
  • action (string, required): The Git operation to perform. Valid values:
    • pull: Pulls latest changes from the remote.
    • commit: Commits staged changes. Requires message.
    • push: Pushes local commits to the remote.
    • reset: Resets all local changes (hard reset).
    • branch_create: Creates a new branch. Requires branchname.
    • branch_switch: Switches to an existing branch. Requires branchname.
    • tag_create: Creates a new tag. Requires tagname.
    • tag_switch: Switches to an existing tag. Requires tagname.
    • delete: Deletes the local repository.

!!git.list

Lists known Git repositories managed by the gittools module.

!!git.list
 filter: 'my_project' // Optional: filter by repository name or path
    reload: true //if true then will check the status of those repo's against the remote's

!!git.reload

Forces a reload of all Git repositories in the cache, re-scanning the coderoot and updating their statuses.

!!git.reload
 filter: 'my_project' // Optional: filter by repository name or path

Get a specific path starting from url

below is powerful command, will get the repo, put on right location, you can force a pull or even reset everything

import incubaid.herolib.develop.gittools
//  path      string
//  git_url   string
//  git_reset bool
//  git_root  string
//  git_pull  bool
//  currentdir bool // can use currentdir, if true, will use current directory as base path if not giturl or path specified
mydocs_path:=gittools.path(
    git_pull:true,
    git_url:'https://git.threefold.info/tfgrid/info_docs_depin/src/branch/main/docs'
)!

println(mydocs_path)

//the returned path is from pathlib, so its easy to further process

//more complete example

@[params]
pub struct GitPathGetArgs {
pub mut:
    someotherparams string // you can add other params here if you want
    //gittools will use these params to find the right path
 path      string
 git_url   string
 git_reset bool
 git_root  string
 git_pull  bool
}
pub fn something(args GitPathGetArgs) !string{
    mut path := gittools.path(path: args.path, git_url: args.git_url, git_reset: args.git_reset, git_root: args.git_root, git_pull: args.git_pull)!
 if !path.is_dir() {
  return error('path is not a directory')
 }
 if path.file_exists('.site') {
  move_site_to_collection(mut path)!
 }
    return path.path
}

Repository Management

import incubaid.herolib.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 & Status

The gittools module uses an imperative model. The GitRepo struct holds the current status of a repository in a unified GitStatus object. To change the state, you call explicit functions like repo.branch_switch('my-feature').

GitRepo and GitStatus Structure

// GitRepo represents a single git repository.
pub struct GitRepo {
pub mut:
    provider      string
    account       string
    name          string
    config        GitRepoConfig
    status        GitStatus   // Unified struct holding the CURRENT repo status.
}

// GitStatus holds all live status information for a repository.
pub struct GitStatus {
pub mut:
 // State from local and remote (`git fetch`)
 branches map[string]string // branch name -> commit hash
 tags     map[string]string // tag name -> commit hash
 
 // Current local state
 branch   string // The current checked-out branch
 tag      string // The current checked-out tag (if any)
 ahead    int    // Commits ahead of remote
 behind   int    // Commits behind remote
 
 // Overall status
 has_changes bool   // True if there are uncommitted local changes
 error       string // Error message if any status update fails
}

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 herolib/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