I have thousands of Github clones on my computer. You might also know that I have a massive OCD for organizing things. I organize my personal documents by year, going back to 1994 and photos by date. I freak out if there are too many top level folders.
Most people git clone a repo (eg. grape), then git clone their forks into another folder (eg. grape2), which makes a huge mess and makes me nervous.
This is how I organize my source code.
|-- source
| |-- dotfiles
| |-- hyperclient
| | |-- codegram
| | `-- dblock
| `-- grape
| |-- grape
| | |-- ruby-grape
| | `-- dblock
| `-- grape-swagger
| |-- ruby-grape
| `-- dblock
A Source Directory
All my source code lives in ~/source. It’s lowercase and sometimes I want to make it ~/Source like ~/Movies, but I dislike capitalizing words that are not complete sentences.
~$ ls -la ~/source/
total 0
drwxr-xr-x 5 dblock staff 170 Mar 25 11:26 .
drwxr-xr-x+ 42 dblock staff 1428 Mar 24 11:12 ..
drwxr-xr-x 10 dblock staff 340 Mar 23 11:53 dotfiles
Clones
I clone my own projects directly under source, starting with my own dblock/dotfiles.
~/source/dotfiles (master)$ ls -la
total 16
drwxr-xr-x 10 dblock staff 340 Mar 23 11:53 .
drwxr-xr-x 7 dblock staff 238 Mar 25 16:09 ..
drwxr-xr-x 16 dblock staff 544 Mar 25 11:26 .git
-rw-r--r-- 1 dblock staff 8 Mar 23 10:09 .gitignore
-rw-r--r-- 1 dblock staff 764 Mar 23 10:09 README.md
~/source/dotfiles (master)$ git remote -v
origin git@github.com:dblock/dotfiles.git (fetch)
origin git@github.com:dblock/dotfiles.git (push)
Forks
For forks, I often need both the upstream repository and my fork, so I clone into subfolders named after the repo owner. For example, I forked codegram/hyperclient as follows.
~/source/hyperclient$ ls -la
total 0
drwxr-xr-x 4 dblock staff 136 Mar 25 11:43 .
drwxr-xr-x 5 dblock staff 170 Mar 25 11:43 ..
drwxr-xr-x 22 dblock staff 748 Mar 25 11:43 codegram
drwxr-xr-x 22 dblock staff 748 Mar 25 11:43 dblock
There are two git remotes in dblock, origin and upstream.
~/source/hyperclient/dblock (master)$ git remote -v
origin git@github.com:dblock/hyperclient.git (fetch)
origin git@github.com:dblock/hyperclient.git (push)
upstream git@github.com:codegram/hyperclient.git (fetch)
upstream git@github.com:codegram/hyperclient.git (push)
Organizations
I organize larger groups of projects together by org (eg. artsy or grape) and sometimes theme (eg. slack). This lets me cleanly separate projects that are for my job at Artsy from open-source projects in which I am heavily involved and that have a lot of Github repositories.
~/source$ ls -la
total 0
drwxr-xr-x 6 dblock staff 204 Mar 25 11:40 .
drwxr-xr-x+ 42 dblock staff 1428 Mar 24 11:12 ..
drwxr-xr-x 10 dblock staff 340 Mar 23 11:53 dotfiles
drwxr-xr-x 5 dblock staff 170 Mar 25 11:24 artsy
drwxr-xr-x 2 dblock staff 68 Mar 25 11:40 grape
drwxr-xr-x 26 dblock staff 884 Mar 25 11:28 slack
I often lose sleep over whether I should rename grape to ruby-grape, which is the actual name of the Ruby Grape organization.
Projects
I create a subfolder for each forked project within an org.
~/source/grape$ ls -la
total 0
drwxr-xr-x 5 dblock staff 170 Mar 25 11:43 .
drwxr-xr-x 6 dblock staff 204 Mar 25 11:40 ..
drwxr-xr-x 4 dblock staff 136 Mar 25 11:43 grape
drwxr-xr-x 4 dblock staff 136 Mar 25 11:43 grape-swagger
drwxr-xr-x 4 dblock staff 136 Mar 25 11:43 grape-with-roar
Forks within Organizations
I clone forks into subfolders named after the repo owner the same way as forks outside of organizations described above.
~/source/grape/grape-swagger$ ls -la
total 0
drwxr-xr-x 4 dblock staff 136 Mar 25 11:43 .
drwxr-xr-x 5 dblock staff 170 Mar 25 11:43 ..
drwxr-xr-x 22 dblock staff 748 Mar 25 11:43 dblock
drwxr-xr-x 22 dblock staff 748 Mar 25 11:43 ruby-grape
There are two git remotes in dblock, origin and upstream.
~/source/grape/grape-swagger/dblock (master)$ git remote -v
origin git@github.com:dblock/grape-swagger.git (fetch)
origin git@github.com:dblock/grape-swagger.git (push)
upstream git@github.com:ruby-grape/grape-swagger.git (fetch)
upstream git@github.com:ruby-grape/grape-swagger.git (push)
Scripts
I cooked a little script, github-clone that creates this folder structure and adds an upstream remote. It supports both HTTP and GIT remotes.
~/source/grape$ github-clone git@github.com:ruby-grape/grape-entity.git
github-clone: cloning ruby-grape/grape-entity into grape-entity/ruby-grape and grape-entity/dblock
Cloning into 'ruby-grape'...
remote: Counting objects: 1152, done.
remote: Total 1152 (delta 0), reused 0 (delta 0), pack-reused 1152
Receiving objects: 100% (1152/1152), 374.82 KiB | 0 bytes/s, done.
Resolving deltas: 100% (570/570), done.
Checking connectivity... done.
Cloning into 'dblock'...
remote: Counting objects: 1055, done.
remote: Total 1055 (delta 0), reused 0 (delta 0), pack-reused 1055
Receiving objects: 100% (1055/1055), 345.14 KiB | 0 bytes/s, done.
Resolving deltas: 100% (525/525), done.
Checking connectivity... done.
/Users/dblock/source/grape/grape-entity
dblock ruby-grape
~/source/grape$
The above cloned ruby-grape/grape-entity and dblock/grape-entity and set an upstream remote in grape-entity/dblock.
~/source/grape$ ls -la grape-entity/
total 0
drwxr-xr-x 4 dblock staff 136 Mar 25 11:46 .
drwxr-xr-x 6 dblock staff 204 Mar 25 11:46 ..
drwxr-xr-x 17 dblock staff 578 Mar 25 11:46 dblock
drwxr-xr-x 22 dblock staff 748 Mar 25 11:46 ruby-grape
Happy cloning and organizing. How do you do it?
