If you’re just starting with Git, you have probably only used Git as the sole developer working on your own repository. When working with a team, more care is needed to manage simultaneous development and avoid conflicts with other team members as much as possible.

There are many “workflows” one can use with Git that describe when and where to add commits, how to use branches and merging, etc. The one I’ll suggest here is suggested by GitHub, and it is known as “The GitHub Flow.” This article by Scott Chacon gives even more detail and motivation for the flow.

Overall, following the workflow entails:

  1. Keep the main branch “clean” (always containing fully tested, working code)
  2. Always do development work in separate, individual branches
  3. Use pull requests to manage the integration of that development work back into the main branch.

Branching

The main branch should only ever hold tested, complete, working code. As the GitHub flow description states, “anything in the main branch is always deployable.” Each new feature or fix or user story should be developed within its own branch, with as many commits as needed in that branch to get it right before merging it into main. With separate branches for each feature, the development can be done in parallel while minimizing edit conflicts in files.

This means you should almost never create commits on the main branch. Almost all of your development work should be done in individual development branches. Your individual branches should usually be named with a combination of your name and the task or work being completed in that branch.

To create a new branch: git branch BRANCHNAME

Then switch to the branch: git switch BRANCHNAME

Always verify you are in the correct branch using git status.

See the “Branching” and “Merging” sections of the Git Cookbook for other relevant Git commands for managing branches.

Merging

Once the work in a development branch is complete and ready to be integrated into the main branch, there are few steps to follow:

Merge First

Before opening a pull request, first merge any recent changes from the main branch back into your development branch. That is, if anything has changed in main since you first created your branch, you want those changes incorporated into your branch also. In this way, you can make sure the merge back into main will go smoothly.

To do this:

  1. First, make sure you have the latest version of everything from GitHub by running git fetch.
  2. Then, while your development branch is the active branch (remember, you can always check that using git status and/or git branch -v), run git merge origin/main. That will merge the main branch as it exists on GitHub into your currently active branch.
  3. If you end up in an interface asking you to type a message for the new merge commit, you just need to exit that program to accept the default message. The default editor in many cases is a program called Vim, which you can exit by typing :q and pressing enter.

Merge Conflicts

If the merge results in a conflict, Git will warn you about this. In that case, this guide can help you resolve it. However, you do not want to run git add . in their step 7. That is likely to bring more files and changes into the commit than you want. Instead, specify individual files using git add until the “to be committed” part of git status contains everything you want to commit in the merge.

Please ask me for help if you run into this and don’t work it out quickly yourself.

Test Merged Code

Once you have successfully merged main into your development branch, test the resulting code. The merge may be successful (with no conflicts or with conflicts resolved) and still break something. So test the code and make sure everything is still working. A good suite of unit tests will help a lot here.

If everything works and you are confident in the code, then you can git push your branch up to Github and open the pull request.

The Pull Request

Opening a pull request in Github will initiate the merging of the branch back into the main branch, and it allows for the following:

  1. The team can review the code, discuss the changes, suggest improvements, and add more commits as needed until they agree it is in good shape to merge.
  2. A continuous integration tool (e.g., Github Actions) can automatically tell you if the resulting merge will pass your unit tests.
  3. The merge itself can be completed with a few clicks in GitHub’s web interface.

Decide in your team how you will manage pull requests. At least one other member of the team should review the changes, provide feedback, suggest or make changes, and eventually sign off on the pull request. (If you need to make more changes, make them in additional commits to the development branch — the open pull request will reflect those automatically when you push them to Github.)

Also decide among yourself if you want the whole team to review pull requests or assign just one additional team member for each. If you have one person review each pull request, you will need to figure out how to assign someone to each pull request.

When the pull request is reviewed and accepted, merge it, and a new commit will be created in the main branch with the added feature. The main branch has now been updated with that new feature and with tested, working code. Hooray!

Update Everyone’s Local Repository

With the branch merged on Github, everyone on the team now needs to update their local copies of the main branch by running git pull while on the main branch.

Be sure to communicate with everyone or otherwise have some process for people to know when a pull request has been merged so they can do this right away.

Delete Your Branch (when done)

Once your branch is merged into main, delete it to clean things up. This will not delete the commits you made; it will just remove the branch label that is no longer needed.

To delete a branch locally (on your own computer): git branch -d BRANCHNAME

To delete a branch in Github, use the “Delete branch” button that should appear in the pull request after it is merged and closed.