Git Integration
Overview
IVPM provides deep integration with Git for managing source dependencies. This includes cloning repositories, tracking changes, and synchronizing with upstream sources.
Clone Options
Authentication and Transport
When cloning a Git dependency, IVPM chooses between SSH
(git@host:path) and HTTPS (https://host/path) per host using a
configurable auth order. The HTTPS form lets a credential helper – most
commonly the GitHub CLI (gh) – authenticate, while the SSH form relies on
your SSH key / agent.
An auth order is a list of methods, tried left to right; the first applicable one wins:
ghClone the
https://URL as written ifghis installed and authenticated for that host (its credential helper does the auth). Skipped whenghis absent or not logged in.sshRewrite the URL to
git@host:path. Always applicable (terminal).httpsClone the
https://URL exactly as written. Always applicable (terminal).
The default order is gh, ssh: prefer gh when it can authenticate the
host, otherwise fall back to SSH (the historical behavior). A machine without
gh therefore behaves exactly as before. file:// URLs and non-URL local
paths are never rewritten.
The gh auth status probe is cached per host, so an update fetching many
dependencies from one host only runs gh once.
Forcing a transport
Per-package in ivpm.yaml:
deps:
- name: my-lib
url: https://github.com/org/my-lib.git
ssh: true # force SSH: git@github.com:org/my-lib.git
- name: other-lib
url: https://github.com/org/other-lib.git
ssh: false # force HTTPS exactly as written
ssh: true forces SSH; ssh: false forces the URL as written. The legacy
anonymous: true also forces the URL as written; anonymous: false no
longer forces SSH – it defers to the auth order (use ssh: true to force
SSH).
Command-line (applies to both clone and update):
$ ivpm clone --ssh https://github.com/org/project.git # force SSH
$ ivpm clone --anonymous https://github.com/org/project.git # force HTTPS
$ ivpm clone --git-auth-order gh,https https://github.com/org/project.git
Configuring the auth order
Without a per-package or CLI override, the order is resolved per host. Full precedence, most specific first:
Per-package
ssh:/anonymous:.CLI
--ssh/--anonymous.CLI
--git-auth-order gh,ssh,https(flat, this invocation only).A host-glob rule from the config files / site config – first match wins across: user file, then site file, then the
ivpm_site_configpackage.Default order:
IVPM_GIT_AUTH_ORDERenv, then the user config file, then the site config file, then the built-in default (gh, ssh).
A matching host rule beats the flat IVPM_GIT_AUTH_ORDER – the env var is
the default for unmatched hosts. --git-auth-order is flat and bypasses
host matching for that one command.
Config files
Two declarative files share one schema and are checked user first, then
site (a user rule overrides a site rule; the first git-auth-order found
wins):
Scope |
Default path |
Override env |
|---|---|---|
User |
|
|
Site |
|
|
# Default order for hosts without a matching rule (optional)
git-auth-order: [gh, ssh]
# Per-host rules, most specific first; host is an fnmatch glob (optional)
git-auth:
- host: "*.internal.corp" # internal GHE/GitLab -> always SSH
order: [ssh]
- host: "github.com" # public GitHub -> gh, fall back to SSH
order: [gh, ssh]
Missing files are ignored. A malformed file (bad YAML, or a top level that is
not a mapping) is logged at WARNING and skipped – it never aborts a clone.
Org-managed defaults
Sites can set auth defaults programmatically with a
SiteConfig subclass (the lowest-priority rule source;
the config files layer on top). The recommended way to ship one is an
extension that declares an ivpm.site_config entry point (see
Writing Custom Handlers); the legacy ivpm_site_config module is also honored.
# src/acme_ivpm/site_config.py
from ivpm.site_config import SiteConfig
class MySiteConfig(SiteConfig):
def get_default_git_auth_order(self):
return ["gh", "ssh"]
def get_git_auth_rules(self):
return [
("*.internal.corp", ["ssh"]),
("github.com", ["gh", "ssh"]),
]
# pyproject.toml of the extension package
[project.entry-points."ivpm.site_config"]
acme = "acme_ivpm.site_config:MySiteConfig"
Run ivpm show site-config to confirm the config is registered and to see the
resolved auth order it applies. When several site configs are installed, pin one
with IVPM_SITE_CONFIG_NAME or a site-config: <name> config-file key.
Diagnostics
Run a clone with --log-level DEBUG to see how the transport was chosen –
the effective URL, the resolved auth order, the loaded config files, and the
relevant credentials (SSH agent/keys for git@; gh auth status and the
git credential helper for https):
$ ivpm clone --log-level DEBUG https://github.com/org/project.git
URL Formats
IVPM supports multiple Git URL formats:
# HTTPS (transport chosen by the auth order: default gh, else SSH)
- name: lib1
url: https://github.com/org/lib1.git
# SSH (used directly)
- name: lib2
url: git@github.com:org/lib2.git
# File protocol (local; never rewritten)
- name: lib3
url: file:///path/to/repo.git
# Git protocol
- name: lib4
url: git://github.com/org/lib4.git
Version Selection
Branch Selection
Clone a specific branch:
deps:
- name: my-lib
url: https://github.com/org/my-lib.git
branch: develop
Behavior:
Checks out the specified branch
Tracks the remote branch
Can be updated with
ivpm sync
Command-line (clone):
$ ivpm clone https://github.com/org/project.git -b feature/new
If the branch exists remotely, it tracks it. If not, creates a new local branch.
Tag Selection
Clone a specific release tag:
deps:
- name: my-lib
url: https://github.com/org/my-lib.git
tag: v1.2.0
Behavior:
Checks out the specified tag
Detached HEAD state
Immutable (won’t change with sync)
Use case: Production deployments, reproducible builds
Commit Selection
Clone to a specific commit:
deps:
- name: my-lib
url: https://github.com/org/my-lib.git
commit: abc123def456
Behavior:
Checks out exact commit
Detached HEAD state
Maximum reproducibility
Use case: Pinning exact versions for critical dependencies
Default Behavior
No branch/tag/commit specified:
deps:
- name: my-lib
url: https://github.com/org/my-lib.git
Clones the repository’s default branch (usually main or master).
Clone Depth
Shallow Clones
Limit history depth for faster cloning:
deps:
- name: large-repo
url: https://github.com/org/large-repo.git
depth: 1
Benefits:
Faster clone
Less disk space
Reduced bandwidth
Limitations:
Limited history
Cannot easily switch branches
Some Git operations restricted
Depth values:
depth: 1- Only latest commitdepth: 10- Last 10 commitsUnspecified - Full history (default)
Full History
deps:
- name: my-lib
url: https://github.com/org/my-lib.git
# No depth specified = full history
Benefits:
Complete history
Full Git functionality
Easy branch switching
Better for development
Use when:
Actively developing the package
Need to browse history
Switching between branches/tags
When to Use Each
Scenario |
Recommendation |
Reason |
|---|---|---|
Active development |
Full history |
Need Git features |
Cached dependency |
|
Speed, space |
Read-only use |
|
Speed, space |
Production deploy |
|
Minimal, reproducible |
CI/CD |
|
Speed |
Git Submodules
Automatic Support
IVPM automatically initializes submodules when .gitmodules is present:
deps:
- name: repo-with-submodules
url: https://github.com/org/repo.git
What happens:
Clone main repository
Detect
.gitmodulesRun
git submodule update --init --recursiveAll submodules ready to use
No Configuration Needed
Submodule initialization is automatic - no special configuration required.
Nested Submodules
The --recursive flag handles nested submodules automatically.
Example Structure:
repo/
├── .gitmodules
├── submodule1/
│ └── .gitmodules
│ └── nested-submodule/
└── submodule2/
All levels initialized automatically.
Status Command
Checking Package Status
View the status of all Git dependencies:
$ ivpm status
Output example:
Package: my-library
Path: packages/my-library
Branch: main
Status: Clean
Remote: origin/main
Ahead: 0, Behind: 0
Package: test-utils
Path: packages/test-utils
Branch: develop
Status: Modified
Modified files:
M src/utils.py
?? new_file.py
Remote: origin/develop
Ahead: 2, Behind: 1
What It Shows
For each Git package:
Package name
Local path
Current branch
Status: Clean, Modified, Staged, Ahead/Behind
Modified files (if any)
Untracked files (if any)
Commits ahead/behind remote
Use Cases
Before committing:
$ ivpm status # Check for uncommitted changes
After pulling:
$ git pull
$ ivpm status # Check dependency status
Daily standup:
$ ivpm status # Review what you're working on
Status for Specific Package
$ cd packages/my-library
$ git status
Sync Command
Synchronizing with Upstream
Update all Git packages from their remote origins:
$ ivpm sync
What it does:
For each Git package on a branch:
git fetch origingit merge origin/<branch>
Packages NOT synced:
Packages on tags (immutable)
Packages on specific commits (immutable)
Packages with uncommitted changes (safety)
Handling Conflicts
If ivpm sync encounters merge conflicts:
$ ivpm sync
# Error in packages/my-library
$ cd packages/my-library
$ git status
# Resolve conflicts manually
$ git add resolved-file.py
$ git commit
$ cd ../..
$ ivpm sync # Continue with remaining packages
Selective Sync
Sync specific packages manually:
$ cd packages/specific-package
$ git pull
$ cd ../..
Safe Sync Strategy
# Check status first
$ ivpm status
# Stash local changes if needed
$ cd packages/my-library
$ git stash
$ cd ../..
# Sync
$ ivpm sync
# Restore changes
$ cd packages/my-library
$ git stash pop
$ cd ../..
When NOT to Sync
Don’t sync if:
You have uncommitted changes you want to keep
You’re working on a feature branch
You’ve pinned to a specific commit/tag
You’re testing local modifications
Complete Git Workflows
Workflow 1: Contributing to a Dependency
# 1. Create feature branch
$ cd packages/dependency
$ git checkout -b fix/issue-123
# 2. Make changes
$ vim src/file.py
$ git add src/file.py
$ git commit -m "Fix issue 123"
# 3. Push to fork
$ git remote add myfork git@github.com:me/dependency.git
$ git push myfork fix/issue-123
# 4. Create pull request on GitHub
# 5. After merge, switch back
$ git checkout main
$ git pull
$ cd ../..
Workflow 2: Testing Upstream Changes
# 1. Check current status
$ ivpm status
# 2. Fetch latest
$ cd packages/my-library
$ git fetch origin
# 3. Check what's new
$ git log HEAD..origin/main
# 4. Test changes
$ git checkout origin/main # Detached HEAD
$ cd ../..
$ ivpm activate -c "pytest"
# 5. If good, merge
$ cd packages/my-library
$ git checkout main
$ git merge origin/main
$ cd ../..
Workflow 3: Bisecting a Bug
# Start bisect in dependency
$ cd packages/buggy-lib
$ git bisect start
$ git bisect bad # Current version is bad
$ git bisect good v1.0.0 # Known good version
# Test each commit
$ cd ../..
$ ivpm activate -c "pytest"
$ cd packages/buggy-lib
$ git bisect good # or 'bad'
# Repeat until found
# Done
$ git bisect reset
$ cd ../..
Workflow 4: Pinning After Testing
# 1. Test current state
$ ivpm activate -c "pytest"
# 2. Get current commit
$ cd packages/my-library
$ git rev-parse HEAD
abc123def456...
$ cd ../..
# 3. Pin in ivpm.yaml
# - name: my-library
# url: https://github.com/org/my-library.git
# commit: abc123def456
# 4. Verify
$ rm -rf packages/my-library
$ ivpm update
$ ivpm activate -c "pytest"
Integration with Git Hooks
Pre-commit Hook
Check package status before committing:
# .git/hooks/pre-commit
#!/bin/bash
echo "Checking IVPM package status..."
if ivpm status | grep -q "Modified\|Untracked"; then
echo "Warning: Uncommitted changes in dependencies"
ivpm status | grep -A 10 "Modified\|Untracked"
read -p "Continue anyway? (y/n) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
exit 1
fi
fi
Post-merge Hook
Update dependencies after merge:
# .git/hooks/post-merge
#!/bin/bash
if git diff-tree --name-only HEAD@{1} HEAD | grep -q "ivpm.yaml"; then
echo "ivpm.yaml changed, running ivpm update..."
ivpm update
fi
Advanced Patterns
Multiple Remotes
$ cd packages/my-library
# Add upstream remote
$ git remote add upstream https://github.com/org/my-library.git
# Fetch from upstream
$ git fetch upstream
# Merge upstream changes
$ git merge upstream/main
$ cd ../..
Working with Forks
# Use your fork
deps:
- name: my-library
url: https://github.com/myuser/my-library.git
branch: my-feature
$ cd packages/my-library
# Add original as upstream
$ git remote add upstream https://github.com/org/my-library.git
$ git fetch upstream
# Keep fork updated
$ git merge upstream/main
$ git push origin main
Sparse Checkout
For very large repositories, use sparse checkout:
$ cd packages/huge-repo
$ git sparse-checkout init --cone
$ git sparse-checkout set path/to/needed/files
$ cd ../..
Best Practices
Use branches for development - Not tags or commits
Commit before sync - Don’t lose local changes
Regular status checks - Know what’s modified
Document pin decisions - Comment why you pinned a commit
Use tags for releases - Immutable, semantic
Shallow clones for cache - Speed up cached dependencies
Full history for dev - Better debugging and history
Check before updating -
ivpm statusfirstStash when needed -
git stashfor temporary changesUse .gitignore - Never commit
packages/directory
Troubleshooting
Detached HEAD State
Symptom: Git says “detached HEAD”
Cause: Checked out a tag or commit
Solution:
$ cd packages/my-library
$ git checkout main # Or any branch
$ cd ../..
Merge Conflicts During Sync
$ cd packages/conflicted-package
$ git status
$ # Resolve conflicts in files
$ git add resolved-files
$ git commit
$ cd ../..
Cannot Push Changes
Symptom: Permission denied when pushing
Check:
Is remote URL correct?
Do you have write access?
Is SSH key configured?
Solution:
$ cd packages/my-library
$ git remote -v # Check URL
$ git remote set-url origin git@github.com:me/my-library.git
$ cd ../..
Submodule Issues
Symptom: Submodules not initialized
Solution:
$ cd packages/repo-with-submodules
$ git submodule update --init --recursive
$ cd ../..
Worktrees
When you check out a branch into a linked git worktree, IVPM automatically
reuses the already-materialized packages from your main worktree – unchanged
dependencies resolve from local disk instead of being re-cloned, with no
configuration required. See Git Worktrees for the full story.
See Also
Development Workflows - Complete development workflows
Git Worktrees - Accelerated updates inside linked git worktrees
Package Types & Sources - Git package configuration
Getting Started with IVPM - Basic Git operations