Git Repository Operations
Standard operating procedures for git operations across the domus ecosystem.
Prerequisites
Credential Vault
SSH keys and GitHub tokens are stored in encrypted gocryptfs vaults.
# Check vault status
gcvault status
# Mount credentials vault (required for git push)
gcvault mount credentials
VAULT STATUS SIZE FILES
───────────────────────────────────────────────────────────
credentials ✗ UNMOUNTED - -
work-sensitive ✗ UNMOUNTED - -
network-configs ✗ UNMOUNTED - -
personal ✗ UNMOUNTED - -
| Git push operations will fail with "Repository not found" if vault is unmounted. |
Repository Structure
Daily Workflows
Single Repo Push
# Standard push
git push origin main
# With explicit SSH agent
SSH_AUTH_SOCK=/run/user/1000/ssh-agent.socket git push origin main
# Push to all remotes
git remote | xargs -I{} git push {} main
Commit Patterns
Heredoc Commits (Preferred)
Multi-line commit messages with heredoc:
gach << 'EOF'
docs(secrets): Convert markdown to AsciiDoc format
- Converted 2025-SEC-001-Reference.md to .adoc
- Converted 2025-SEC-002-Complete-Architecture.md to .adoc
- Standardized on AsciiDoc across domus-secrets-ops
EOF
The gach function (git add + commit with heredoc):
# In ~/.zshrc
gach() {
git add -A && git commit -m "$(cat)"
}
gacp() {
git add -A && git commit -m "$(cat)" && git push
}
Conventional Commits
| Prefix | Usage | Example |
|---|---|---|
feat |
New feature |
|
fix |
Bug fix |
|
docs |
Documentation |
|
refactor |
Code restructure |
|
chore |
Maintenance |
|
Creating New Repos
GitHub Private Repo
# Initialize locally
cd ~/atelier/_projects/personal/new-project
git init
git add -A
git commit -m "feat: Initial scaffold"
# Create on GitHub and push
gh repo create new-project --private --source=. --push --description "Project description"
If remote already exists:
# Add remote manually
git remote add origin git@github.com:EvanusModestus/new-project.git
# Create repo via gh (will fail to add remote but creates repo)
gh repo create new-project --private --description "Project description"
# Push
SSH_AUTH_SOCK=/run/user/1000/ssh-agent.socket git push -u origin main
GitLab Mirror
# Create repo on GitLab
glab repo create new-project --private --description "Project description"
# Add remote
git remote add gitlab git@gitlab.com:EvanusModestus/new-project.git
# Push
SSH_AUTH_SOCK=/run/user/1000/ssh-agent.socket git push gitlab main
Gitea (Self-Hosted)
Gitea runs at gitea-01.inside.domusdigitalis.dev for local backups.
# Create repo via tea CLI
tea repo create --name new-project --private
# Add Gitea remote (uses SSH config alias)
git remote add gitea git@gitea:evanusmodestus/new-project.git
# Push
SSH_AUTH_SOCK=/run/user/1000/ssh-agent.socket git push gitea main
| Gitea repos are accessible even when internet is down. |
Full Multi-Remote Setup
Set up all three forges for a new repo:
# Initialize
cd ~/atelier/_projects/personal/new-project
git init && git add -A && git commit -m "feat: Initial commit"
# GitHub (primary)
gh repo create new-project --private --source=. --push
# GitLab (mirror)
glab repo create new-project --private
git remote add gitlab git@gitlab.com:EvanusModestus/new-project.git
git push gitlab main
# Gitea (local backup)
tea repo create --name new-project --private
git remote add gitea git@gitea:evanusmodestus/new-project.git
git push gitea main
Adding Remotes to Existing Repo
For an existing GitHub repo, add GitLab and Gitea:
# Get repo name from GitHub
REPO_NAME=$(gh repo view --json name -q '.name')
echo $REPO_NAME
# Create on GitLab and Gitea
glab repo create ${REPO_NAME} --private
tea repo create --name ${REPO_NAME} --private
# Add remotes
git remote add gitlab git@gitlab.com:EvanusModestus/${REPO_NAME}.git
git remote add gitea git@gitea:evanusmodestus/${REPO_NAME}.git
# Load SSH keys if needed
SSH_AUTH_SOCK=/run/user/1000/ssh-agent.socket ssh-add ~/.ssh/id_ed25519_gitlab
SSH_AUTH_SOCK=/run/user/1000/ssh-agent.socket ssh-add ~/.ssh/id_ed25519_gitea
# Push to all remotes
git remote | xargs -I {} git push {} main
Verify remotes:
git remote -v
# origin git@github.com:EvanusModestus/new-project.git
# gitlab git@gitlab.com:EvanusModestus/new-project.git
# gitea git@gitea:evanusmodestus/new-project.git
Troubleshooting
"Repository not found"
ERROR: Repository not found.
fatal: Could not read from remote repository.
Causes:
-
Vault unmounted - SSH keys not accessible
gcvault mount credentials -
Repo doesn’t exist - Create it first
gh repo create repo-name --private -
Wrong remote URL - Check configuration
git remote -v git remote set-url origin git@github.com:EvanusModestus/repo-name.git
SSH Agent Issues
# Check agent
echo $SSH_AUTH_SOCK
# List keys
ssh-add -l
# If empty, start agent
eval $(ssh-agent)
ssh-add ~/.ssh/id_ed25519
# Or use explicit socket
SSH_AUTH_SOCK=/run/user/1000/ssh-agent.socket git push
ssh-add Hangs on Passphrase
If ssh-add hangs after entering passphrase (no response, no error):
# Use explicit SSH_AUTH_SOCK
SSH_AUTH_SOCK=/run/user/1000/ssh-agent.socket ssh-add ~/.ssh/id_ed25519_gitlab
# Verify key is valid first
ssh-keygen -y -f ~/.ssh/id_ed25519_gitlab
# Should prompt for passphrase and print public key
# Get passphrase from gopass
gopass show -c v3/domains/d000/identity/ssh/gitlab
Per-forge keys:
# GitHub
SSH_AUTH_SOCK=/run/user/1000/ssh-agent.socket ssh-add ~/.ssh/id_ed25519_github
# GitLab
SSH_AUTH_SOCK=/run/user/1000/ssh-agent.socket ssh-add ~/.ssh/id_ed25519_gitlab
# Gitea
SSH_AUTH_SOCK=/run/user/1000/ssh-agent.socket ssh-add ~/.ssh/id_ed25519_gitea
glab OAuth Token Expired
ERROR: oauth2: "invalid_grant" "The provided authorization grant is invalid, expired..."
Fix:
# Clear stale config
rm -rf ~/.config/glab-cli
# Re-authenticate
glab auth login
# Generate new PAT at:
# https://gitlab.com/-/user_settings/personal_access_tokens?scopes=api,write_repository
# Select SSH as default protocol
# Save PAT to gopass
gopass edit v3/domains/d000/cloud/gitlab/evanusmodestus/pat
Automation Scripts
domus-push-all
Location: ~/.local/bin/domus-push-all
#!/bin/bash
# Push all domus-* repos to all remotes
REPOS=(
~/atelier/_bibliotheca/domus-*
~/atelier/_projects/personal/netapi
~/atelier/_projects/personal/domus-cli
)
for repo in "${REPOS[@]}"; do
[ -d "$repo/.git" ] || continue
echo "=== $(basename $repo) ==="
if [[ "$1" == "--status" ]]; then
git -C "$repo" status --short
continue
fi
for remote in $(git -C "$repo" remote); do
if [[ "$1" == "--dry-run" ]]; then
echo "Would push to $remote"
else
SSH_AUTH_SOCK=/run/user/1000/ssh-agent.socket git -C "$repo" push "$remote" main
fi
done
done
Quick Reference
Credentials & Agent
| Task | Command |
|---|---|
Mount credentials |
|
Check vault status |
|
Push with agent |
|
Test SSH auth |
|
Multi-Repo Operations
| Task | Command |
|---|---|
Push all repos |
|
Check all repos |
|
Push to all remotes |
|
Creating Repos
| Forge | Command |
|---|---|
GitHub |
|
GitLab |
|
Gitea |
|
Adding Remotes
| Forge | Command |
|---|---|
GitHub |
|
GitLab |
|
Gitea |
|