After tweeting a pre-coffee thought on my favorite Github workflow the other day, I decided an article’s detail might be required as a follow-up. So without further ado, here are some detailed notes about those things I said:
Short answer: Yup. Long answer: Yes, but there’s a good reason to consider yet another Git project workflow. Working off a single repo with multiple people is relatively simple, but it opens itself up to situations where conflicts can be common and toes are being stepped on. Multiple forks of the same project allows for more freedom for each developer, but still keeps the main codebase clean of any random feature branches. Conflict rates go down between members and pull requests feel a little more purposeful.
While working on a project with a lot of moving parts and a lot of team members, branches can become messy, stale, and forgotten quickly. With this forked approach, the main repo remains clean while individual forks can be managed in any manner that the developer sees fit—this flow doesn’t affect the main project branch in any way.
This setup does work with any type of team-based project, but I find that it fits better with long-term projects—large-scale websites and products, for example.
So how do we set this up?
The first thing to do is have everybody who’s involved with the project fork the its repo. If the original repository is private, its fork will also be private. If you are paying for private repos, this private fork will not count against your limit. Additionally, any pull requests from your fork opened on Github will favor the originating repo by default.
The next step is to edit your .git/config file for the project. You will need to add every team member as a different remote. For example:
[remote “jen”] url = email@example.com:jensUsername/project.git fetch = +refs/heads/*:refs/remotes/jen/* [remote “bill”] url = firstname.lastname@example.org:billsUsername/project.git fetch = +refs/heads/*:refs/remotes/bill/* [remote “origin”] url = email@example.com:myUsername/project.git fetch = +refs/heads/*:refs/remotes/origin/*
Now you can use
git fetch jen to retrieve her latest commits. Keen!
Note: Sometimes Github.app gets a little weird when dealing with multiple remotes. I highly recommend using the command line for this workflow.
Now that you have access to each team member’s fork, you may want to check out some code that is needing reviewed or tested. To check out somebody else’s remote branch, run
git checkout -t jen/feature-branch-name. This will create a new local branch that tracks against the “jen” remote. If Jen pushes to her origin, you can fetch the branch and get the updates as if it was your own remote branch.
git fetch &
git rebase work just fine in this case.
git push on the other hand sometimes needs guidance. Depending on your configuration, a push might create a new remote branch on your fork. Be specific with
git push just to be safe.
git push jen might be necessary if you are committing to her feature branch, for example.
Note: I prefer the two-step process of
git fetch and
git rebase instead of
git pull. I don’t like to merge things in automatically just in case.
git pull isn’t enough. To perform a bulk fetch/update on every available upstream branch, I recommend using
git up. git-up is a clever alias that is extremely helpful with this workflow (the link has a great pro-con breakdown of
git pull versus
git up). git-up grabs all the latest commits from all upstream branches, prunes dead branches, and fast-forwards your local branches to the latest upstream branch commits.
While it is entirely optional to use git-up, I just find it’s easier to update everything at once. This reduces the chances of a conflict and it’s nice to see what feature branches are being worked on.
Another bonus is that this sets up a protocol of sorts. Nobody is committing directly to the original repo (except in an emergency hotfix situation), but all the benefits of using Github remain. Issues and Milestones behave the same way, while still allowing for mentions in pull requests. Pull requests are the only way that any code from others is allowed into the main repo.
Essentially, every team member is contributing to the project as if it was an open source project. It feels natural.
I am just throwing this workflow out there as an alternative for team projects. While it may not make sense for smaller projects with one or two contributors, it’s definitely a sane and organized way to approach something with a large scale. Let me know what you think about it. I’m not a git master by any means, but I am learning as I go.