Git is an incredible tool for managing your software development projects. Combine this with Github/Gitlab and you have a powerful environment to work on large scale projects as a team. Note that this gist is not a tutorial. Instead it is meant to serve as a guide to how to use what Github/Gitlab provide.
Along with Git and co I've also included general recommendations on how to make progress on your software engineering project.
Most of it is just "opinion" based on my software engineering experience. So you should feel free to experiment and figure out what works out the best for you.
At the end of this gist, you will find a handy list of useful Git commands.
- The
main
branch should always work at all points in its commit history. Never intentionally merge broken code to it. If the team needs to collaborate on a piece of code that is broken, create adevelopment
branch and merge it intomain
when you are done. - Only merge adequately well-written code to
main
. "Merge it now and we can clean it up later" is a bad idea.
The key idea here is to maintain production quality code on main
from which releases can be made at any time without having to do cleanups or fix anything.
- Since the
main
branch has to maintain high quality, make it a rule to never directly commit tomain
. For any new task, one should create a branch off top ofmain
and work on it. This working branch can contain temporary or even broken code. - Once a task is done, a PR should be raised to merge it into
main
. This PR needs to be reviewed for code quality, performance, and correctness. - Use
Squash & Merge
option to merge the PR. This should be available in the PR UI. This squashes all commits being merged intomain
through the PR into a single commit. The commit message can then be neatly written while merging (also through the UI). - Who should review? Generally a few people who regularly work with the specific component. Often, the project owner can take a cursory look to get acquainted with the latest changes.
If you are following these guidelines, you will likely be doing one PR for each task. This means that the PRs will remain small.
Squash and Merge option will help maintain a useful and readable (understandable and clean) history of the main
branch.
Moreover, it also makes it easy to revert certain PRs/tasks entirely by simply reverting the single commit that resulted from Squash and Merge.
Consider this PR for a tool called WowConcert, that I made during one of my course projects.
- Note that the working branch is called
ajain-ab-test
and the entire task was accomplished on this branch before review and merge. - The branch is reviewed by a teammate who asks questions to understand the code better.
- Furthermore, while working a lot of commits were made on the working branch. Many commits don't quite have useful commit messages (outside of the context of the task).
- However, the PR is ultimately squashed and merged to result in a single commit with a very readable message. This single commit contains the entirety of this work.
- This also maintains guideline #1 that
main
is never broken since it works both before and after this commit. The same can't be said had we simply merged without squashing since we allow breaking commits on working branches.
Simple example of reviewing PR for code quality.
- Prefer
rebase
overmerge
while sync-ing your working branch with themain
or any other branch, as far as possible.
At times you may need to merge the changes contained in two branches or simply sync-up your working branch with the latest changes on main
.
- In Git, it may be tempting to simply
merge
. However,rebase
is interestingly simpler to understand. - Rebase puts all your new commits on the current branch on top of all commits of the branch you are rebasing on. This makes the commit history easy to understand since commits are not interleaved.
- Rebasing doesn't generate any automated merge commits and so once again the commit history will look a lot simpler.
- Rebasing may involve a bit more effort than merge, since your commits will be replayed on top of the branch you are rebasing on top of one by one and you will be required to fix conflicts for each commit if needed.
- While playing with
rebase
you may need to at times use--force push
. Be very careful using this. This is another reason we have #3 so that we don't accidently force push to main.
-
Have a tight code-build-test loop. You should be able to build your code and test your build quickly while developing software. Try not to write thousands of lines of code that isn't (atleast) built (or tested). The more you wait on this, the harder the task gets in getting things to work later on. A tight development loop avoids this and you will find yourself motivated by being able to incrementally build.
-
Build skeleton first. #8 implies making incremental changes to the software being developed. This means that a basic version of application that is able to run is the first requirement. Try to reach this skeleton as early as possible, then continue to extend it and add features in a tight development loop.
-
This follows from #8. Automate your build and test process as much as possible. This generally means having some
shell
orpython
scripts that let you build your project quickly. As the project grows, these scripts will also grow, they may just get longer or may become more sophisticated allowing more and more settings. It is a good idea to use build systems like maven or cmake.
Sometimes writing scripts that don't directly contribute to your project may not sound like a great idea. But it is an investment. Automating build process or tests will save many development hours later on and will make your life easy. It also helps avoid procrastination when it comes to building and testing.
This leads to a more generic guideline.
- Take some time to create a usable dev environment:
- Set up your IDE / editor with proper and useful plugins.
- Create keyboard shortcuts for tasks that you usually find yourself clicking around for.
- Set an aesthetic colour scheme - yes it matters sometimes!
- Have a shell prompt that contains information you require (eg. your git branchname might be useful information to print in the prompt).
A little bit of investment will save a lot of time later on.
Git has a lot of features and is extremely powerful. However 95% of the times you don't need the entire arsenal at hand. Here is a list of git commands that you may possibly need. Note that you don't even need to know these all, just a small subset of these will help you get through most of the tasks.
0: fetch, push, pull, commit, log, add, diff, checkout, branch, clone
1: rebase, merge, reset
2: cherry-pick, revert, stash, reflog
3: rebase -i, submodules, anything with --force
- Check out Git
bisect
. - Writing meaningful commit messages
- Try out a linter to improve code formating.
- Set up
.gitignore
.