How to organize your GitHub repository clones locally

As a software engineer, cloning repositories using Git is a common task. But without a scalable system, your local clones can quickly get disorganized—think collisions from cloning repos with the same name, or a cluttered projects folder with repos from different owners and scopes.

Solution: The GitHub Tree structure

The GitHub Tree structure is a simple yet effective way to organize your repositories by mirroring GitHub. It helps establish a clear structure that scales as your collection grows.

Here’s a quick example of what the hierarchy might like on your machine:

~/Developer
└── github
    └── <GitHub org / username>
        └── <GitHub repo name>
  • ~/Developer: Your main coding directory (or swap it for whatever path you like).

    Tip

    macOS gives Developer a special icon, which is a neat bonus.

  • github: A folder to reflect GitHub’s layout.

    This is useful in case you use ever use other platforms like GitLab, Bitbucket, etc. In my case, we had a private GitHub Enterprise server at work, so I had a github and github-work directory.

  • <GitHub org / username>: A subfolder for each organization or username.

  • <GitHub repo name>: Where the cloned repo lives.

Cloning repositories

To clone a repo you own, run this command with the target path:

Terminal
git clone git@github.com:my-user/my-repo.git ~/Developer/github/my-user/my-repo

Tip

If the ~/Developer/github/my-user/ folder doesn’t exist yet, git clone will create it automatically.

Forked repositories

For repos you’ve forked, keep things tidy by cloning them into the original organization’s namespace:

  1. Fork the repo on GitHub.

  2. Clone your fork into the original org’s directory.

    For example, if you forked vercel/next.js, clone it like this:

    Terminal
    git clone git@github.com:my-fork/next.js.git ~/Developer/github/vercel/next.js
  3. Add the upstream remote.

    Connect to the original repo (call it up for “upstream”):

    Terminal
    git remote add up git@github.com:vercel/next.js.git

    Sync with the original whenever needed:

    Terminal
    git pull up <branch-name>

This points origin to your fork, and up to the original repo.

Speed things up with a zsh function

Want to clone faster? Add this handy function to your .zshrc:

gclone() {
    if [[ -z "$1" ]]; then
        echo "Usage: gclone <github-repo-url>"
        return 1
    fi

    local repo_url="$1"
    local stripped="${repo_url##*github.com[:/]}"
    stripped="${stripped%/}"
    if [[ "$stripped" != */* ]]; then
        echo "Invalid GitHub URL: $repo_url"
        return 1
    fi

    local clone_path=~/Developer/github/"${stripped%%/*}"/"${stripped#*/}"
    clone_path="${clone_path%.git}"

    git clone "$repo_url" "$clone_path" && cd "$clone_path"
}

Use it like this:

gclone git@github.com:organization/repository.git

It’ll clone the repo to ~/Developer/github/organization/repository and take you right there.

Warning

The upstream remote isn’t automatically added because there’s no way to infer the original repo.

Benefits of GitHub Tree

By organizing your repositories with the GitHub Tree structure, you’ll enjoy several benefits:

Mirrors GitHub’s layout

  • You don’t have to think about how to organize your clones; you’re simply following GitHub’s structure.
  • Avoid name collisions as GitHub ensures unique repository names within an org.

Finding repos is easy

  • The structure is familiar, so you can locate repos fast.
  • Easily grep across multiple repositories with the results clearly indicating repository paths.

Scoped Git configs

If you juggle personal and work projects with different Git identities (e.g., emails), this setup simplifies configuration.

Here’s an example of a ~/.gitconfig config toggling three different profiles based on the org:

# Default (personal)
[user]
    name = Hiroki Osame
    email = personal@email.com

# Work org A
[includeIf "gitdir:~/Developer/github/org-a/"]
    path = ~/Developer/github/org-a/.gitconfig

# Work org B
[includeIf "gitdir:~/Developer/github/org-b/"]
    path = ~/Developer/github/org-b/.gitconfig

Then, in each org directory, create the profile (e.g., ~/Developer/github/org-a/.gitconfig):

[user]
    name = Hiroki Osame
    email = work@email.com

Now, whenever you commit in your personal repositories, Git will use your personal email. And when you commit to repos in your work org, it will use your work email.

Give it a spin!

That’s it! The GitHub Tree structure gets you organized fast with a system that’s intuitive and grows with you. Try it out, and if you’ve got feedback or tweaks, I’d love to hear them!


Thanks for reading! Hope you'll stick around.
— Hiroki Osame
Open source Engineer. Living in Tokyo. Working at Square.