GitHub Workflow best practices for collaboration
A source code control workflow derived from a 6-people team
Preface: This was extrapolated from my works with the student team over at OneRCH couple years ago.
How to follow this guide?
I. First Time: When you first setup local development. You only have to do it once and it also contain useful knowledge on why this approach is better than any alternative.
II. Development Routine: What you normally do as a stand-alone developer. This should go in-hands with next section Collaboration.
III. Collaboration: Now it is not just you anymore. This section provides standard solution in resolving conflict of changes.
IV. FAQ: Frequently Asked Questions pointing to appropriate section and some advanced/detailed answers
I. First Time
- Fork the organisation’s repo onerch/OneRCH via the web interface
- Clone your fork to local drive
- Verify your local clone status and configured remote
Normally this would resulted in your remote being the source you cloned, i.e. <username> /OneRCH or onerch/OneRCH.
- Add remote
upstream
from the organisation’s repo
git remote add upstream https://<username>@github.com/onerch/OneRCH.git
- Fetch latest updates from the organisation’s repo
At this stage your history is not the latest, some people might pushed their changes to remote upstream
.
git fetch upstream
Two very important things:
- Your fork (remote origin) will not be updated, only your local version fetched changes from the upstream.
- Nothing has been applied from the upstream onto your local branches yet.
II. Development Routine
The very first thing before/after your development is to include any changes from upstream remote.
- Apply updates to your local branch
git checkout --track origin/developing # For first time checkout
git fetch upstream
git checkout developing
git merge upstream/developing
- Branching for development
Once updated any changes in the base branch to derive from for development, start checkout new feature branch from base branch.
git branch --verbose --all
git checkout -b feat-large-feature developing
- Create Pull Request to merge to organisation’s branch
There are several methods to close a Pull Request:
-
Create a merge commit
- ✅ All commits included
- ✅ Another merge commit
-
Squash and Merge
- ✅ All commits ‘squashed’ into one
- ❌ Another merge commit
-
Rebase and Merge
- ✅ All commits included
- ❌ Another merge commit
III. Collaboration
Up to this point, its already sufficient with fetch, merge changes from upstream and create Pull Request to merge back to upstream.
This section focuses solely on resolving conflicts and best practice in cleaning up your commits for linear history.
Update your feature branch with latest changes
What is this for?
- ✅ Confirm that your commits do not contain breaking changes
- ✅ Ensure you’re working on the latest version of development branch
- ✅ Help your teammates to keep track easily with a linear history
This is essential to keep your development in-sync with others and vice versa. Besides that, this allows everyone to work concurrently on the same feature with as least overhaul as possible.
- Similar to 1st step in II. Development Routine, sync base branch from
upstream
remote against your local base branch
- Rebase changes from base branch onto your feature branch
git checkout feat-large-feature
git rebase developing
Cleanup your local commits history
What is this for?
- ✅ Combine commits: forgot to refactor all variables, accidentally left out
- ✅ Keep the entire repository’s history as linear as possible
- Check the SHA hash of the last commit you want to retain as-is, i.e. any commits made after this will be included in rebase
- pick, squash or essentially drop commits
- Re-write the commit message
git checkout feat-large-feature
git rebase -i <last-commit-retain-as-is-hash>
The rebase command also support relative (exclusive) distance from the commits pointed by HEAD. From previous example, making the third commit 35d9556 as the last-commit-to-retain-as-is with git rebase -i HEAD~3
.
Side Note: The interactive rebase display is sorted by older-to-newer from top-to-bottom, whereas the git log display is inversely sorted by newer-to-older from top-to-bottom.
How to cleanup and develop alongside at the same time?
When to use git merge —squash?
- When you want to cleanup the source code without affecting the commit history of your feature branch
- When you simply want to keep a copy of the cleanning commits of your checked-out branch.
git checkout -b fix-small-typo feat-large-feature
git merge --squash fix-small-typo
git commit -m "Squash Commit Message Title"
Conflict & code breaking changes
What is this for?
- ✅ Introduce featured implementation onto upstream
- ✅ Resolve redundant old version conflicts
- ✅ Adapt to the latest implementation from upstream
- ❌ Troubleshoot or Debug conflict changes
This is commonly encountered when you push changes to upstream or rebase with changes from upstream and the same regions editted by others.
- Fetch any updates from
upstream
- Try to merge to local base branch
- Check status and open conflicted files to manually resolve it.
IV. FAQ
What branch should I as a newcomer checkout and contribute?
A: Always update development base branch and checkout from there,
git checkout -b feat-new-feature developing
to start your changes on feature branch feat-new-feature.
What happens if origin/upstream can not be found, e.g. the organisation name is changed? A: git remote set-url <origin|upstream> https://
@github.com/ /OneRCH.git
What should I do before create PR?
A: See this
How to cleanup and develop alongside at the same time?
A: See this