Git + GitHub CLI (gh) PowerUser Guide
Last updated: March 01, 2026
Author: Paul Namalomba
- SESKA Computational Engineer
- SEAT Backend Developer
- Software Developer
- PhD Candidate (Civil Engineering Spec. Computational and Applied Mechanics)
Contact: kabwenzenamalomba@gmail.com
Website: paulnamalomba.github.io
Overview
This guide is a practical deep dive into Git (core version control) and GitHub CLI (gh) (GitHub automation from the terminal). It covers repository creation/deletion, local and remote repo management, authentication (HTTPS/PAT, SSH, and gh), professional collaboration workflows (feature branches, PRs, rebase strategies), recovery techniques (reflog, resets, revert), and CLI-driven deployments (Git push deployments, remote servers via bare repos/hooks, and GitHub Actions triggered and operated via gh).
Contents
- Git + GitHub CLI (gh) PowerUser Guide
- Overview
- Contents
- Quickstart
- 1. Installation (Windows, Linux, macOS)
- 2. Identity, Config, and Safety Defaults
- 3. Authentication (Git HTTPS/PAT, SSH, and gh)
- 4. Repository Lifecycle (Create, Clone, Delete, Archive)
- 5. Daily Git Workflow (Add/Commit/Log/Diff)
- 6. Branching and Integration (Merge, Rebase, Cherry-pick)
- 7. Undo, Recovery, and Forensics (Restore, Reset, Reflog)
- 8. Remotes and Collaboration (Fetch/Pull/Push, Forks, Upstream)
- 9. Tags, Releases, and Versioning
- 10. Advanced Git (Worktrees, Submodules, Sparse Checkout, Bisect)
- 11. GitHub CLI (gh) Deep Dive (repo, pr, issue, api, workflow)
- 12. CLI-Driven Deployment (Git Push, Remote Hooks, GitHub Actions)
- 13. Security and Governance
- 14. Troubleshooting
- References and Further Reading
Quickstart
Minimal end-to-end flow: authenticate, create repo, commit, push, open PR.
# 1) Authenticate to GitHub
gh auth login
gh auth status
# 2) Create a new repo on GitHub and clone it
gh repo create OWNER/new-repo --public --clone
cd new-repo
# 3) First commit
echo "# new-repo" > README.md
git add -A
git commit -m "Initial commit"
git push -u origin main
# 4) Create a feature branch + PR
git switch -c feature/demo
echo "More content" >> README.md
git add -A
git commit -m "Update README"
git push -u origin feature/demo
gh pr create
1. Installation (Windows, Linux, macOS)
Git
Windows (recommended: Git for Windows + Git Credential Manager)
winget install --id Git.Git -e
# Optional: verify
git --version
macOS
brew install git
git --version
Ubuntu/Debian
sudo apt update
sudo apt install -y git
git --version
GitHub CLI (gh)
Windows
winget install --id GitHub.cli -e
gh --version
macOS
brew install gh
gh --version
Ubuntu/Debian (many distros package gh; use official instructions if you need latest)
sudo apt update
sudo apt install -y gh
gh --version
2. Identity, Config, and Safety Defaults
Set user identity (global)
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
Useful global defaults
# Use a modern default branch name (optional)
git config --global init.defaultBranch main
# Better push behavior
git config --global push.default simple
# Rebase-aware pulls (common in professional repos)
git config --global pull.rebase true
# Auto-stash local changes during rebase pulls
git config --global rebase.autoStash true
# Prune stale remote branches on fetch
git config --global fetch.prune true
# Make conflict resolution less painful
git config --global rerere.enabled true
Inspect config sources (useful for debugging surprises):
git config --list --show-origin
Line endings (Windows vs Linux)
If you collaborate cross-platform, decide on a policy and enforce it:
Windows typical
# Converts CRLF <-> LF automatically (works for many repos, but be consistent)
git config --global core.autocrlf true
Linux/macOS typical
git config --global core.autocrlf input
If the repo already has a .gitattributes, follow the repo policy (repo settings should win over personal preference).
Quality-of-life aliases (optional)
git config --global alias.s "status -sb"
git config --global alias.l "log --oneline --decorate --graph --all"
git config --global alias.d "diff"
git config --global alias.co "checkout"
3. Authentication (Git HTTPS/PAT, SSH, and gh)
You have two separate concepts:
- Git transport auth (push/pull): HTTPS (PAT) or SSH
- GitHub API auth (issues, PRs, actions):
gh auth
3.1 Git over HTTPS (PAT) + Credential Manager
GitHub no longer supports password auth for Git operations. Use: - Personal Access Token (PAT) - Git Credential Manager (recommended on Windows)
When using HTTPS remotes like:
git remote -v
# https://github.com/OWNER/REPO.git
Git will prompt for credentials; use: - Username: your GitHub username - Password: your PAT
To inspect credential helper:
git config --global credential.helper
3.2 Git over SSH (recommended for power users)
Generate an SSH key
ssh-keygen -t ed25519 -C "you@example.com"
# Press enter for default path; set a passphrase
Start ssh-agent and add key
Linux/macOS:
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
Windows (PowerShell):
Get-Service ssh-agent | Set-Service -StartupType Automatic
Start-Service ssh-agent
ssh-add $env:USERPROFILE\.ssh\id_ed25519
Add public key to GitHub
cat ~/.ssh/id_ed25519.pub
Copy into GitHub: Settings → SSH and GPG keys.
Use SSH remote
git remote set-url origin git@github.com:OWNER/REPO.git
ssh -T git@github.com
3.3 GitHub CLI authentication
Login
gh auth login
Explicit login patterns:
# Prefer SSH for Git operations
gh auth login -p ssh
# Authenticate to a specific host (GitHub Enterprise Server)
gh auth login --hostname github.company.com
Configure Git to use your gh auth for HTTPS operations (optional):
gh auth setup-git
Status + active account
gh auth status
Logout
gh auth logout
Refresh scopes/token (useful if Actions/Packages commands fail):
gh auth refresh
Print the active token (avoid pasting this into logs):
gh auth token
Select default protocol for Git operations
gh config set git_protocol ssh
# or
gh config set git_protocol https
4. Repository Lifecycle (Create, Clone, Delete, Archive)
4.1 Create a local repo
mkdir my-repo
cd my-repo
git init
4.2 Clone an existing repo
git clone https://github.com/OWNER/REPO.git
# or
git clone git@github.com:OWNER/REPO.git
4.3 Create a GitHub repo from the terminal (gh)
Create and optionally push the current directory:
# inside an existing local repo
gh repo create OWNER/REPO --private --source=. --remote=origin --push
Create a new repo and clone it:
gh repo create OWNER/new-repo --public --clone
4.4 Rename a GitHub repo (gh)
gh repo rename new-name
Fork a repo (and clone your fork):
gh repo fork OWNER/REPO --clone
Create from a template repo:
gh repo create OWNER/new-from-template --private --template OWNER/TEMPLATE_REPO --clone
4.5 Archive vs Delete (be deliberate)
Archive (reversible, safer)
gh repo archive OWNER/REPO
Delete (irreversible)
Before deletion, consider taking a mirror backup:
git clone --mirror git@github.com:OWNER/REPO.git
# Produces REPO.git directory with full refs
Then delete:
gh repo delete OWNER/REPO --confirm
5. Daily Git Workflow (Add/Commit/Log/Diff)
5.1 Inspect state
git status
5.2 Stage changes
# stage all tracked edits + new files
git add -A
# stage interactively (power tool)
git add -p
5.3 Commit
git commit -m "Explain what changed"
Amend the last commit (common for small fixes):
git commit --amend
Create a fixup commit (pairs well with git rebase -i --autosquash):
git commit --fixup <commit_sha>
Commit with editor message:
git commit
5.4 View history
git log
git log --oneline --decorate --graph --all
5.5 Compare changes
# unstaged differences
git diff
# staged differences
git diff --staged
# compare two refs
git diff main..feature-branch
5.6 File operations (tracked content)
Rename/move a file:
git mv oldname newname
Remove a tracked file:
git rm path/to/file
5.7 Ignore rules (.gitignore) and debugging ignores
Add patterns to .gitignore to prevent files being tracked.
Debug why a path is ignored:
git check-ignore -v path/to/file
6. Branching and Integration (Merge, Rebase, Cherry-pick)
6.1 Branch basics
git branch
git switch -c feature/login
# or (older)
# git checkout -b feature/login
Push a new branch to origin:
git push -u origin feature/login
Delete branches:
# local
git branch -d feature/login
# force delete local (unmerged)
git branch -D feature/login
# remote
git push origin --delete feature/login
6.2 Merge (preserves branch topology)
git switch main
git pull
git merge feature/login
6.3 Rebase (rewrites history; keep it disciplined)
Common workflow: keep your feature branch updated on top of main.
git switch feature/login
git fetch origin
git rebase origin/main
Interactive rebase (squash / reorder / edit messages):
git rebase -i origin/main
If you already pushed and you rebase, you will need a force push:
git push --force-with-lease
--force-with-lease is safer than --force because it refuses to overwrite someone else’s new pushes.
6.4 Cherry-pick (copy a commit)
# apply a specific commit onto current branch
git cherry-pick <commit_sha>
6.5 Resolve conflicts efficiently
When a conflict happens:
git status
# edit files to resolve
git add -A
# if in merge
git commit
# if in rebase
git rebase --continue
Abort a rebase if needed:
git rebase --abort
7. Undo, Recovery, and Forensics (Restore, Reset, Reflog)
These are the commands that differentiate beginners from professionals.
7.1 Discard local file edits
Discard unstaged edits for a file:
git restore path/to/file
Unstage (move from index back to working tree):
git restore --staged path/to/file
Restore a file from a specific commit:
git restore --source <commit_sha> -- path/to/file
7.2 Reset (moves branch pointer; can be destructive)
Think of reset as: move HEAD to a different commit, optionally changing index/worktree.
# keep changes staged (rare)
git reset --soft HEAD~1
# keep changes unstaged (common)
git reset --mixed HEAD~1
# discard changes completely (danger)
git reset --hard HEAD~1
7.3 Revert (safe for shared branches)
Revert creates a new commit that undoes changes (no history rewrite):
git revert <commit_sha>
7.4 Reflog (time machine)
If you “lost” commits after a reset/rebase, reflog usually saves you:
git reflog
# find the previous HEAD state
git reset --hard HEAD@{1}
7.5 Investigate who changed what
# who changed each line
git blame path/to/file
# find commit that introduced a string
git log -S "some text" -- path/to/file
7.6 Stash (parking local changes)
Stash tracked changes:
git stash push -m "wip"
git stash list
git stash pop
Include untracked files:
git stash push -u -m "wip + untracked"
Apply a specific stash without dropping it:
git stash apply stash@{1}
7.7 Clean (remove untracked files/directories)
Preview what would be removed:
git clean -nd
Remove untracked files + directories:
git clean -fd
8. Remotes and Collaboration (Fetch/Pull/Push, Forks, Upstream)
8.1 Remotes
git remote -v # list remotes and URLs
git remote add origin git@github.com:OWNER/REPO.git # add a remote named "origin"
git remote add upstream git@github.com:UPSTREAM_OWNER/REPO.git # if you forked and want to track the main repo
git remote set-url origin git@github.com:OWNER/REPO.git # change URL of origin
Rename a remote:
git remote rename origin github
Remove a remote:
git remote remove upstream
Prune deleted remote branches:
git fetch --prune
8.2 Fetch vs Pull
git fetch: update your view of the remote; does not change your working filesgit pull: fetch + integrate (merge or rebase depending on config)
git fetch origin # get latest from origin, but stay on current branch
git pull # implicitly does fetch + merge/rebase based on config
git pull --rebase # explicitly
8.3 Fork workflow
When working on a fork:
origin: your forkupstream: the main repository
git fetch upstream # get latest from main repo
git switch main # or master, depending on default branch name
git merge upstream/main # or rebase if you prefer a cleaner history
git rebase upstream/main # or keep your commits on top of the latest main
git push origin main # update your fork's main branch
9. Tags, Releases, and Versioning
9.1 Tags
Lightweight tag:
git tag v1.2.3
Annotated tag (recommended):
git tag -a v1.2.3 -m "Release v1.2.3"
Push tags:
git push --tags # pushes all tags
git push origin v1.2.3 # push a specific tag
Describe the current commit using the nearest tag:
git describe --tags --always
9.2 GitHub releases (gh)
Create a release (can upload assets too):
gh release create v1.2.3 --title "v1.2.3" --notes "Key changes..."
List releases:
gh release list
Upload an asset:
gh release upload v1.2.3 ./dist/app.zip
Download release assets:
gh release download v1.2.3
10. Advanced Git (Worktrees, Submodules, Sparse Checkout, Bisect)
10.1 Worktrees (multiple branches, one clone)
Worktrees let you check out multiple branches in parallel without stashing:
git worktree add ../my-repo-hotfix hotfix/urgent # from repo root
git worktree list # list worktrees
git worktree remove ../my-repo-hotfix # remove when done
10.2 Submodules (use only if necessary)
Add a submodule:
git submodule add git@github.com:OWNER/dep-repo.git deps/dep-repo
Clone repo with submodules:
git clone --recurse-submodules git@github.com:OWNER/REPO.git
Update submodules:
git submodule update --init --recursive
10.3 Sparse checkout (huge monorepos)
git clone --filter=blob:none --no-checkout git@github.com:OWNER/REPO.git
cd REPO
git sparse-checkout init --cone # use cone mode for simple directory patterns
git sparse-checkout set path/to/subdir another/subdir #
git checkout # checkout the default branch with only the specified paths
10.4 Bisect (find the commit that broke something)
git bisect start # start bisect session
git bisect bad # (HEAD is bad; the bug is present here)
git bisect good <good_commit_sha> # choose a known good commit
git bisect reset # end bisect session and return to original HEAD when finished
10.5 Rewrite history (danger zone)
Use history rewriting only when you understand the consequences.
- For local cleanups:
git rebase -i - For removing large files/secrets from history: prefer
git filter-repo(external tool) overfilter-branch
10.6 Hooks (local automation)
Hooks run scripts at certain points (pre-commit, commit-msg, pre-push). Common uses:
- Format/lint before committing
- Block committing secrets
- Enforce commit message rules
Local hooks live in .git/hooks/ by default. To share hooks across a team, store them in the repo and set a hooks path:
git config core.hooksPath .githooks
10.7 Git LFS (large files)
If you must version large binaries (datasets, PSDs, large media), use Git LFS instead of bloating normal Git history.
git lfs install # one-time install per machine (requires git-lfs installed)
# below: track patterns (writes to .gitattributes)
git lfs track "*.psd"
git lfs track "*.mp4"
# below: add to gitattributes and commit
git add .gitattributes
git commit -m "Configure Git LFS"
11. GitHub CLI (gh) Deep Dive (repo, pr, issue, api, workflow)
11.1 Repo operations
gh repo view --web # view repo in browser
gh repo clone OWNER/REPO # clone via gh (uses your auth settings)
gh repo list --limit 50 # list your repos
gh repo sync OWNER/FORK_REPO # sync a fork from upstream (default branch)
11.2 Pull Requests
gh pr create # create PR from current branch
gh pr list # list PRs
gh pr view 123 # view PR details
gh pr checkout 123 # checkout a PR locally
gh pr merge 123 # merge a PR (respects repo settings)
Review a PR:
gh pr review 123 --approve
# or request changes
# gh pr review 123 --request-changes -b "Reason..."
See PR status for your branches:
gh pr status
11.3 Issues
gh issue create # create a new issue interactively
gh issue list # list issues
gh issue view 42 # view issue details
11.4 Workflows and runs (GitHub Actions)
List workflows:
gh workflow list
View a workflow definition:
gh workflow view "Deploy" --yaml
Run a workflow manually (workflow_dispatch):
gh workflow run "Deploy" -f environment=prod
Watch runs:
gh run list --limit 20
gh run watch
# or view a specific run
gh run view <run_id> --log
Re-run a failed workflow:
gh run rerun <run_id>
Cancel a run:
gh run cancel <run_id>
11.5 Secrets and variables (for CI/CD)
Set a repository secret:
# reads from stdin
printf "%s" "MY_SECRET_VALUE" | gh secret set MY_SECRET
List secrets:
gh secret list
Set an Actions variable:
printf "%s" "staging" | gh variable set DEPLOY_ENV
List variables:
gh variable list
11.6 gh api (advanced automation)
When gh doesn’t have a subcommand, gh api gives you raw GitHub API access.
Example: list repo webhooks:
gh api repos/OWNER/REPO/hooks
Example: create a label:
gh api repos/OWNER/REPO/labels -f name="priority:high" -f color="B60205"
11.7 Aliases and extensions
Aliases:
gh alias set prs "pr list --limit 50"
Extensions (install community tooling):
gh extension list
# gh extension install OWNER/EXTENSION
12. CLI-Driven Deployment (Git Push, Remote Hooks, GitHub Actions)
Deployment is usually one of these patterns:
- Git push triggers CI/CD (GitHub Actions, GitLab CI, etc.)
- Git push deploys to a platform remote (some PaaS patterns)
- Git push to a server bare repo +
post-receivehook
12.1 Push-to-deploy via GitHub Actions (operate with gh)
Typical flow:
- You push to main or a tag
- GitHub Actions deploy workflow runs
- You observe, re-run, and troubleshoot with gh
# push code
git push origin main
# view runs
gh run list --limit 10
# watch logs
gh run watch
Manual deployment trigger:
gh workflow run "Deploy" -f environment=staging
12.2 Tag-driven releases and deployments
Many production systems deploy only from version tags.
# create + push a tag
git tag -a v2.0.0 -m "Release v2.0.0"
git push origin v2.0.0
# create a GitHub release
gh release create v2.0.0 --title "v2.0.0" --generate-notes
12.3 Remote server deployment using a bare repo + hook
This is the classic "git push production" pattern.
On the server (Linux)
Create a dedicated deploy user and a bare repo:
sudo adduser --disabled-password deploy
sudo mkdir -p /srv/git
sudo chown deploy:deploy /srv/git
sudo -u deploy git init --bare /srv/git/myapp.git
Create a working tree path:
sudo mkdir -p /var/www/myapp
sudo chown deploy:deploy /var/www/myapp
Add a post-receive hook to deploy on push:
sudo -u deploy nano /srv/git/myapp.git/hooks/post-receive
Hook example (minimal):
#!/bin/sh
set -eu
BRANCH="refs/heads/main"
while read oldrev newrev refname
do
if [ "$refname" = "$BRANCH" ]; then
GIT_WORK_TREE=/var/www/myapp git --git-dir=/srv/git/myapp.git checkout -f main
# Example: restart a service
# systemctl restart myapp.service
fi
done
Make it executable:
sudo -u deploy chmod +x /srv/git/myapp.git/hooks/post-receive
On your local machine
Add a remote and push:
git remote add production deploy@YOUR_SERVER:/srv/git/myapp.git
git push production main
Notes: - This is intentionally minimal. In production, you typically add build steps, atomic deploy directories, and rollbacks. - You must manage permissions carefully (deploy user, SSH keys, and service restart permissions).
12.4 Remote deployment key management (GitHub + servers)
Common pattern: - Use SSH deploy keys (server-only key) - Store tokens/keys as GitHub secrets
Use gh secret set for CI/CD secrets:
printf "%s" "ssh-private-key-material" | gh secret set DEPLOY_SSH_KEY
13. Security and Governance
Avoid committing secrets
- Add secrets to
.gitignore - Rotate any secret that accidentally hit Git history
- Use environment variables and secret stores in CI/CD
Quick checks:
# scan tracked files for suspicious strings
git grep -n "BEGIN RSA PRIVATE KEY" || true
git grep -n "AKIA" || true
Signed commits (optional)
Modern Git can sign commits/tags using either GPG or SSH signing, depending on your setup.
General idea: - generate signing key - configure Git to sign - verify on GitHub
Example: SSH-based commit signing (modern approach):
# Tell Git to use SSH keys for signing
git config --global gpg.format ssh
# Use your SSH public key as the signing key
git config --global user.signingkey ~/.ssh/id_ed25519.pub
# Sign commits by default
git config --global commit.gpgsign true
# Make a signed commit
git commit -S -m "Signed commit"
To get the “Verified” badge on GitHub, add the same public key under GitHub Settings → SSH and GPG keys.
Least privilege
- Use fine-grained PATs where possible
- Use SSH keys with passphrases
- Restrict secrets to environments (staging/prod) and to protected branches
14. Troubleshooting
Credentials keep failing
- Check
gh auth status - Ensure remote URL matches the intended auth method (
https://vsgit@github.com:)
git remote -v
gh auth status
Detached HEAD
You checked out a commit directly. Create a branch to keep work:
git switch -c fix/detached
“non-fast-forward” push rejected
You’re behind the remote:
git fetch origin
git rebase origin/main
# or merge
# git merge origin/main
git push
Accidental git reset --hard
Try reflog recovery:
git reflog
# find old HEAD
git reset --hard <sha>
References and Further Reading
- Git documentation: https://git-scm.com/docs
- Pro Git book (free): https://git-scm.com/book/en/v2
- GitHub CLI manual: https://cli.github.com/manual/
- GitHub docs (auth, SSH, PAT): https://docs.github.com/