This git fundamentals post will help you to understand how to collaborate using git with your colleagues. Considering you already know Kickstart Your Repo and Working On A Repa, now we can dig further using git effectively with other collaborators. Note that this won’t include an open-source project approach. Even the principle is the same, some of the projects have different requirements for pull requests. You can further investigate how to create pull requests for this. First of all, I would like to stress what a development process would be like without source control. A friendly piece of advice: if you think it is hard to work with git, think twice. It might take a while to understand and get used to working on git, but it is worths your time.
Without source control, the major problems are those:
- To work together, you should set up a NAS, cloud, or use something like a USB to share your work with your colleagues.
- It would be impossible to work on the same code at the same time. If not careful, you can override your friend’s work with your save. If you are careful, you should check the conflicts by hand.
- You can’t check the progress of your colleagues and create test builds using only the features you want to test out
The list above is the common problems, and imagine you can hit much more roadblocks in the development process.
Before diving further, we should talk about some theories first. To work effectively you and your collaborators should know the theory behind Git. To keep it simple, we will focus on 2 developers: Back-End and Front-End. Consider your repository as a station at the beginning of a road and each developer is at the same station. Since they are working on different stuff, they should take different paths from that station. When Front-End finishes his work, he puts his work into the road, as a new station. The same applies to Back-End developers as well. This time, when the Back-End developer puts her work into the road, it is automatically put after the Front-End station. Now that the road contains 2 developers’ work, when they start a new path they will both have those stations combined. To illustrate this in a graph
* Road 3 (All Back-End Merged) / | Back-End Work 3 * * Road 2 (All Front-End Merged) | | \ Back-End Work 2 * | * Front-End Work 2 | | | Back-End Work 1 * | * Front-End Work 1 \ | / * Road 1 (Base)
As you can see above, Road now includes all work done! Whenever someone creates a new path from Road 3, they will all have the work done so far, allowing everyone to keep up. All those roads and paths are called branches. Branching is one of the most important things you should learn while collaborating. There are different branching approaches around, you should find or create one that best suits your workflow. You can check GitFlow, an extension for making branching easily. But we will focus on our simple branching model, close to GitFlow rules.
Here, we have our basic branching rules every colleague should use:
- Main Branch: Master branch will be your release branch. Everything merged to here should have passed QA tests.
- Develop Branch: Everything worked on should be merged into develop. When the time comes, QA should test from the latest commit’s build. When everything is in order, develop merges into master for release.
- Feature Branches: Feature branches are the branches you will spend time on mostly. Since branches can be nested, if you create a branch feature/MyBranch it will be created under feature, just like a folder. Those features can be merged into develop branch.
When you create a repository, there will be a master branch by default. When you clone the repo for the first time (considering you didn’t directly checked-out to a different branch) you will also be checked out to the master branch. You can use that branch to push your initial commit including your .gitignore and readme files. Then, time to create your first branch:
git branch develop git checkout develop
This will create develop branch and check out to it. This branch includes everything committed to the master branch at the time you checked out. You can also create and check-out to a branch with a single command: 'git branch -b develop’. Now everything seems to be set up. but you need to push your branch to the server to let your colleagues access it.
git commit -m "Initial Develop Branch" git push
You will realize there is an error telling you that develop branch does not exist on the server, and it shows a code instead to set upstream. You can copy-paste that code to push it to remote. Once you have pushed develop into remote, you can only use push command instead. Now it is time for your colleagues to checkout to remote develop to create their branches.
git checkout --track origin/develop
This code pulls the develop branch and tracks it. Basically tracking is saying “this branch on my local is that branch on remote” in a short way.
Working on a feature branch
This section is a general approach for all your collaborators. It is time to create your branch to move on
git branch -b feature/MyFeatureBranch
Now you have your feature branch to work on. When you have created files, you are ready to commit. Don’t forget, committing is also useful when you want to revert your changes until you push to remote. Here is the code to do so:
git add * # Adds all files. You can add files one by one by giving file path git commit -m "Lovely Message" # Write something simple yet self-explanatory
You can continue committing your changes whenever you feel right. You can also push your code to remote. First, check if you have anything left to be committed and be sure you are on the correct branch.
With that command, you can see untracked files as well. If you need to commit files, you can do so. Otherwise, no necessary files have changed, you can set them to their first state.
# Reset all tracked files to their latest state git checkout . # Remove all untracked files git clean -n # Shows all untracked files git clean -f # Remove all untracked files if not necessary
You can also stash files to get back to them, but to keep it simple I am not going to explain it. You can further investigate how to use stash commands from Git SCM. Now that your branch is clean, you can either push it to remote or merge directly into develop. If you are working on a branch that should take time, you can push it to remote a prototype version, so that other colleagues can merge it to their branches to keep adding their code. If you want to keep going on that branch, you can use
If you haven’t pushed remote before, you will see that upstream error meaning there is no such branch on the remote. Simply use the given code and push it to remote. Now that you can continue committing changes into your local as long as it takes. If you want to finish this feature for good, then without pushing you can directly merge it into develop branch. To do so, you should checkout to develop branch.
git checkout develop # Checks out the develop branch git fetch # Looks for any changes for develop branch on remote git status # Check if you are behind the remote develop git pull # If you are behind, pull the latest changes
Now that you have the latest develop branch, you can merge your branch into develop and push it. Be sure that you are still on develop branch!
git merge feature/MyFeatureBranch git push
If there is no conflict between your changes and develop’s changes, it should directly merge. Otherwise, the console will give you a conflict error where you should edit conflicts. There are lots of different GUI merge tools to help you out there! I am using VSCode's internal merge layout but you can use other apps such as Meld on Windows, Kaleidoscope on macOS. You can also use GUI Git Clients such as Fork, SourceTree, and GitKraken, where they have conflict resolving GUI as well. Decide on an app, and learn their approach how they resolve conflicts. They have your code and the code on branch side-by-side. You can see who deleted what and added where, so you can add yours into the final one. This final one will be the resolved file.
You are asking where is the collaboration part, right? Well, above is the general workflow working on branches. But consider this, if everyone minds the rules above, they should do the very same thing on different branches, just like you did above! So, to sum it up:
- Create a branching rule. One of the most common approaches is master, develop, and feature branches. Be sure to know what merges into where.
- Don’t commit unnecessary changes. Commit often, when necessary.
- Check your status before committing and pushing.
- Use clear commit messages, your colleagues need to understand what you did from those messages.
- Don’t leave your HEAD with uncommitted changes, if you try to checkout you may conflict with existing ones. You can stash them, or revert them if unnecessary.
- Whenever you checkout to a branch used by multiple collaborators, always fetch and see if you are behind the remote branch.
- Solve conflicts and test them. If you are using Pull-Requests for merging into master, ask the pull-request sender to fix conflicts.