git-repo-workspace-layout
Skill0 starsChanged 8 days agoMITView on GitHub
Use when cloning repos or moving them between owners/hosts.
- Deletes or force-pushes
- Commits and pushes
In this repository6 other files it gives its agents.
The file
We split this skill into the rules it gives an agent
4 rules. About 0 are common, 2 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 22
Before pushing a repository somewhere new — including the first push of a private one.
- Very specific: line 149
Prefer --mirror even for a single-branch source: tags and non-heads refs are dropped by a plain clone.
- Very specific: line 151
Verify by content, not by "push succeeded": clone the target elsewhere and compare git rev-parse HEAD^{tree}, git rev-list --count HEAD and …
- Distinctive: line 160
Before staging anything env-shaped, scan the staged blob, not the working file:
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Repository workspace layout
When to Use
- Cloning anything and deciding where it should live.
- A machine accumulates repos and nobody can tell which
apiis which. - Moving a repo between owners, organisations or hosts.
- Before pushing a repository somewhere new — including the first push of a private one.
The layout
<repos-root>/<host>/<owner>/<repo>~/repos/github.com/<owner>/<repo>
~/repos/github.com/<org>/<repo>
~/repos/gitlab.com/<group>/<repo>
C:\src\github.com\<owner>\<repo>The path mirrors the remote URL, so two different owners can both have a repository called
api without inventing suffixes. This is not cosmetic: name collisions across organisations
are normal, and a flat ~/projects/api layout silently merges two histories the first time
someone clones the second one.
Rules that keep it working:
- Everything git lives under one root. Not
$HOMEitself, not scattered across~/Desktop. - Toolchains, virtualenvs and downloaded binaries do not go in the repos root — they belong in a tool directory or a container.
- Throwaway experiments belong in a scratch directory outside the repos root, so they can never be committed to a real clone by accident.
- Case matters where the filesystem says it does. Windows and default macOS filesystems are
case-insensitive, Linux is not: a repo owned by
Acmeand one owned byacmeare the same directory on Windows. If you need both, one of them needs a different root.
The clone helper
A shell function that derives the destination from the URL. Add to ~/.bashrc / ~/.zshrc:
clone() {
local url path
case "$1" in
http*|git@*|ssh://*) url="$1" ;;
*/*) url="https://github.com/$1.git" ;;
*) printf 'clone: give a URL or owner/repo\n' >&2; return 1 ;;
esac
path="${url%%.git}"; path="${path#*://}"; path="${path#*@}"; path="${path/://}"
path="$HOME/repos/$path"
if [ -d "$path/.git" ]; then
printf 'clone: %s already exists\n' "$path"; cd "$path" && return 0
fi
mkdir -p "$(dirname "$path")" && git clone "$url" "$path" && cd "$path"
}PowerShell equivalent ($PROFILE):
function clone {
param([Parameter(Mandatory)][string]$Ref)
if ($Ref -notmatch '^(https?://|git@|ssh://)') { $Ref = "https://github.com/$Ref" }
$path = $Ref -replace '\.git$','' -replace '^[a-z+]+://','' -replace '^git@','' -replace ':','/'
$dest = Join-Path $HOME "repos/$path"
if (Test-Path (Join-Path $dest '.git')) { Write-Host "clone: $dest already exists"; Set-Location $dest; return }
New-Item -ItemType Directory -Force (Split-Path $dest) | Out-Null
git clone $Ref $dest; if ($LASTEXITCODE -eq 0) { Set-Location $dest }
}Handles a full URL or owner/repo shorthand, creates the owner directory, and re-running on
an existing clone just changes into it.
Non-interactive shells do not load .bashrc (it usually starts with a guard returning
early when $PS1 is unset), so agent tool calls and cron jobs will not have clone. Write
the git clone out in full there, or invoke bash -ic, and expect terminal-control noise on
stderr from the latter.
Moving a repo between owners
The path mirrors the URL, so an owner change moves the clone too — and the clone carries
state that breaks silently if it is only mv'd.
- On the target, check for a name collision and record what the move may drop:
Confirm your role:gh api orgs/<org>/repos --paginate --jq '.[].name' gh api repos/<owner>/<repo>/actions/secrets --jq '.total_count' gh repo view <owner>/<repo> --json visibility,defaultBranchRef,hasIssuesEnabledgh api orgs/<org>/memberships/<you> --jq '.role'→admin. - Transfer with the host's API (GitHub:
gh api -X POST repos/<owner>/<repo>/transfer -f new_owner=<org>). The response echoes the pre-transfer owner; verify separately withgh repo view <org>/<repo>. - Move the clone and re-point it, leaving the old owner directory if other clones still
use it:
mkdir -p <repos-root>/<host>/<new-owner> mv <repos-root>/<host>/<old-owner>/<repo> <repos-root>/<host>/<new-owner>/<repo> cd <repos-root>/<host>/<new-owner>/<repo> git remote set-url origin <new-url> git fetch -q origin && git status -sbMove-Item <repos-root>\<host>\<old-owner>\<repo> <repos-root>\<host>\<new-owner>\<repo> - Rebuild anything with an absolute path baked in. A POSIX
.venvhardcodes the interpreter path in everybin/*shebang and in editable-install metadata; Windows.venv\Scripts\*.exelaunchers embed it too. After a move,uv run/pytest/pip -efail with a path that no longer exists, or worse, quietly import the old tree. Delete and recreate (rm -rf .venv && uv sync), then run the suite from the new path. The same applies tonode_moduleswith native builds, compiled test fixtures, and lockfile tools that record a prefix. - Old URLs keep working — GitHub redirects after a transfer, so
git ls-remoteon the old URL still returns branches. Update references anyway, but anything left behind (editor caches, shell history, agent session dirs) is a record, not a live reference. - Sweep the repo for stale references to the old owner:
git grep -nI 'github\.com/<old-owner>', plus the repo's own description and homepage, which no move updates.
Mirroring between hosts
A one-shot copy that keeps every branch, tag and ref:
git clone --mirror https://<host>/<owner>/<repo>.git <repos-root>/<host>/<owner>/<repo>.git
cd <repos-root>/<host>/<owner>/<repo>.git
git remote add <target> https://<target-host>/<owner>/<repo>.git
GIT_TERMINAL_PROMPT=0 git push --mirror <target>--mirrorpushes refs exactly, deleting remote refs absent locally, so a second run re-syncs instead of accumulating. Point it at the target remote, neverorigin.- Prefer
--mirroreven for a single-branch source: tags and non-headsrefs are dropped by a plain clone. - Verify by content, not by "push succeeded": clone the target elsewhere and compare
git rev-parse HEAD^{tree},git rev-list --count HEADand the file count with the source.
Secret hygiene before pushing
- A file can be added despite
.gitignorewithgit add -f. Do not add a!<path>negation instead — that un-ignores every future file of that shape. Once tracked, the file is no longer subject to the ignore rule at all, so any comment claiming it is untracked is now a lie: fix the comment. - Before staging anything env-shaped, scan the staged blob, not the working file:
Compare the header names against real credentials; a placeholder is fine, a live key is not.git show :<path> | grep -E '^[A-Z_]+=.+$' - To scan history before publishing a repository:
git rev-list --all --objects | awk '{print $1}' | git cat-file --batch \ | grep -aiE '(ghp_|gho_|github_pat_|sk-|AKIA|BEGIN [A-Z ]*PRIVATE KEY)'gitleaksortrufflehogin Docker is stronger if available. - Committing a secret and deleting it in the next commit does not remove it — rotate the secret, then rewrite history if it truly must go. Rotation is the part that matters.
Pitfalls
ssh://git@<host>:<port>/<owner>/<repo>loses the port when naively splitting on:(it ends up in the path). Use the https URL for non-standard ports, or parse with git itself.- Tools and dependencies do not belong in the repos root. On a machine without admin rights,
install user-locally (a tool directory plus a
PATHentry) or use a container — but keep the result out of the repository. - Windows:
core.autocrlfrewrites line endings on checkout; a repo withLF-only scripts breaks when they arrive asCRLF(bad interpreter: /bin/bash^M). Setcore.autocrlf=inputand keep a.gitattributeswith* text=auto. - Windows: filesystem is case-insensitive, so a repo tracking both
README.mdandreadme.mdcannot be checked out there.git config core.ignorecase trueis set by git already; the problem is real, the fix is not. - Long paths: enable
core.longpathsand the OS policy before cloning a deep monorepo. - A repo that was cloned with
--depth 1cannot be pushed from usefully, andgit worktreefrom it sees only one commit. Re-clone full for anything you will develop.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

