So, I’ve never considered myself a particularly adept git user; worse, my last few (collaborative) coding experiences involved janky dropbox protocols so project members didn’t have to use git. Now that I’m a project that doesn’t involve dropbox, and everyone accepts using git (and github) to collaboratively code, the question of workflow came up. In particular, “how should we use git to most effectively write code?” Because I didn’t want to tackle the issue of how each project member should use git for their individual needs (that’s pretty personal, and I’m still working out my own philosophy), I figured it’d be more fruitful to address the question of how the group should collectively manage code development.
I originally wanted to implement a rebase-based workflow, a la The Every Deployable Github Workflow but (long story short) github won’t let you execute that work flow.1 So, I decided to stick with the “integration manager” theme where I’d use my github repo as the “blessed repository” and also play the role of the integration manager. I like the idea of a, senior, integration manager since it places the responsibility of handling merges — an operation that can go awry if handled by someone new to git — into the hands of one person, thus minimizing the chance of any git-related errors. Ideally (and with competent team mates), the integration manager won’t have to do anything other than a cursory code-review, since any pull-requests should be yield conflict-free merges. However, life isn’t perfect, so we want the integration manager to be the guy with the most git-ninja skills in the room.
Because I understand that git can be something of an overwhelming tool for beginners, I figured I’d graphically demonstrate what the development cycle of a feature might look inside this merge-based gitflow. It starts with a few ideas/rules:
- the code is the master branch is “pure” in the sense that anyone should be able to fork the repo, and branch off of master and be good-to-go.
- topic branches should have meaningful names (a rule the diagrams below violate, unfortunately).
- branches named “someone/topic_branch” are private to that someone, and shouldn’t be considered stable to pull without consulting that someone (or a pull-request to the integration manager).
- no one works on the same topic branch. If two people want to work on the same topic branch, they create their own branches, appropriately named, and have the integration manager pull their private branches back into the topic branch.
So, let’s see how this would work (somewhat) in practice:
- we’ll demo this with a collaboration between Alice and Bob. They’ve decided to develop a (complicated) feature and dedicated branch
DEVto it. The repo might look something like:
Alice’s private branch off of DEV is named
Alice(it’s head is indicated by the rectangular tag), Bob’s private branch is named
Boband both have created independent commits. Now,
- Alice might decide that her progress by her second commit is stable enough to make it to the
DEVbranch. At this point, she’d submit a pull-request to the integration manager, noting that he’s to pull
DEVhasn’t progressed since Alice (and Bob) branched off it, this pull is just a fast-forward of
DEV‘s HEAD. The resulting history tree may look something like so:
- Sometime, and a few lines of code, later, Alice has pushed another commit and Bob has realized that he needs to merge in the updated
DEVinto his branch. He does so, and makes some more head way, pushing another commit up, as well:
# on Bob's computer git fetch origin git checkout Bob git merge DEV # ... Bob does more work ... # git commit git push origin Bob
The repo history, now, might look like this
The thing to note, here, is that while
Alicewere one-and-the-same in the previous figure,
Alicehas (again) diverged from
DEVwith the new commit. So, we’re looking at 3 branches. Next,
- let’s say that with Bob’s last commit, he’s decided that that’s all the work he’s going to do on
DEV, and sends a pull-request to the integration manager (and lets the manager know he’s done).
Bobthen get’s merged into
DEV, which then has
DEVinto her branch (just to make sure her work is still compatible with the code in
Alice, is not done hammering at this feature, so
- she makes one final commit and issues a pull-request to the integration manager (and let’s him know she’s done). At this point, the integration manager knows that
DEVis done being developed and merges
DEVinto Master for a history like:
Now some people may be inclined to do some clean up, after all this merging, and delete branches. For the sake of reverting changes, or rolling back bad code, I’m encouraging the integration manager to be lazy and not delete any topic branch (private or otherwise).
1 Really, the problem is that github will not let you push local changes up to a remote branch unless the changes would result in a fast-forward of the remote branch’s HEAD. So, say you were tracking a remote branch,
origin/dev with a local branch,
dev. Once you rebase
dev onto another branch, you can’t (simply)
git push origin dev back up to
origin/dev since that requires something more than a fast-forward of
origin/dev‘s HEAD; you can, however, push it up via
git push -f origin dev. But, I consider that really sloppy practice, especially for beginners, so I’m trying not to encourage it.