313 lines
8.2 KiB
Markdown
313 lines
8.2 KiB
Markdown
# Git Tools Module
|
|
|
|
## GitTools HeroScript
|
|
|
|
### `!!git.define`
|
|
|
|
Configure or retrieve a `GitStructure`, if not set will use the default
|
|
|
|
```heroscript
|
|
!!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.
|
|
|
|
```heroscript
|
|
!!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
|
|
|
|
```heroscript
|
|
!!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.
|
|
|
|
```heroscript
|
|
!!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.
|
|
|
|
```heroscript
|
|
!!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
|
|
|
|
```v
|
|
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
|
|
|
|
```v
|
|
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
|
|
|
|
```v
|
|
// 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
|
|
|
|
```v
|
|
// 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
|
|
|
|
```v
|
|
// 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
|
|
|
|
```v
|
|
// 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
|
|
|
|
```v
|
|
// 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
|
|
|
|
```v
|
|
// 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:
|
|
|
|
```v
|
|
// 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:
|
|
|
|
```bash
|
|
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
|