Posted On: 2023-04-03
In previous posts, I've written about how, when tackling particularly challenging tasks, it's often beneficial to work on multiple alternative implementations in parallel. Previously, I accomplished this by making liberal use of Git's stash feature, which allowed me to quickly create snapshots of my current working changes, and easily restore them later on. It turns out, however, there's actually a simpler, better approach to developing multiple implementations in parallel: cloning the local workspace.
The clone operation is a foundational part of Git, one which (almost) every Git user has interacted with*. In simple terms, when a user clones a repository (called the "remote"), they not only get a copy of all the files in the remote, but also a copy of the history of every file as well. Git can then use that shared history to make comparisons between the two: new changes in the remote can be "pulled" into the local copy, and changes in the local can be "pushed" to the remote.
One of the super-powers* of Git, however, is that it is extremely permissive about what can be used as a remote repository. While most developers use Git to clone from a remote stored somewhere online (ie. in an online service like Github or Bitbucket), Git can actually clone anything with a Git history - even another folder on the same file system. When doing so, one folder becomes the "remote" for another folder, and the developer can push and pull changes between the two different folders - exactly how one would push/pull when working with an online remote. Conveniently, it turns out that being able to use a local folder as a remote is a great way to keep multiple parallel approaches neatly organized.
While I still use an online remote that serves both as a backup of my work and as a "source of truth"* for my project, I've started taking advantage of the ability to clone a local folder when I need to try multiple approaches. Whenever I get stuck (or just want to try a different approach), I can take my local folder (which is itself cloned from the online remote) and clone it, to get an exact duplicate of my work-in-progress. This effectively turns my folder into a "local remote" for any number of folders representing alternative approaches.
Since I can create any number of clones from the "local remote", I can try out numerous different approaches in parallel - each with its own history and set of changes. Once I'm happy with an approach, I can "push" all those changes so that they become a part of the "local remote" - effectively marking that as the "correct" approach. Importantly, since the "local remote" is still itself a work-in-progress (unlike the online remote, which has to be stable all the time), I can push changes early, and then perform any polishing/code cleanup in the "local remote" (which is where most of my work normally occurs.)
When describing this process, I've been asked how this differs from "forking" a Git project. While the processes are very similar (using Git's clone feature to make a long-lived copy, and then working from a clone off of that copy), the motivation is quite different. A fork is (usually) meant to remain permanantly separate from the original, while what I'm doing is something more like a "temporary fork": the whole point of the process is to decide on which (if any) approach I want to keep, and ultimately merge that approach not only into this "temporary fork", but all the way back to my online repository.
Trying multiple approaches has long been beneficial for me, but as I better learn to use Git's clone feature I'm able to reap those benefits faster and more flexibly. Leveraging local clones makes it easier to juggle multiple changes - whether that's by requiring less context-switching when changing implementations (no need to worry about stashing/unstashing), easily applying changes to every approach simultaneously (fix it in the "local remote", and then pull the fix into each approach), or even running various different implementations side-by-side (awkward to do when working with stashes, but trivially simple with the cloning-provided separate workspaces.) I hope this description of how I'm using cloning has inspired you - whether specifically to use Git clones for parallel development, or more broadly, since learning more about an already familiar tool can sometimes reveal how to better accomplish something unrelated.