DEV Community

Cover image for Professional Git Workflow & GitHub Setup for (React) Developers (incl screencast)
Johannes Kettmann for Profy.dev

Posted on • Originally published at profy.dev

Professional Git Workflow & GitHub Setup for (React) Developers (incl screencast)

If you’re a solo developer working on your own projects your Git workflow is usually simple: You work on the main (or master) branch all day every day.

You probably know that professional developer teams don't work like this. Multiple devs all committing to the main branch can quickly become chaotic. And it’s likely that unreviewed or untested code makes it into production eventually. Danger!

Professional teams use processes and workflows to prevent this from happening. And the most common Git workflow used in developer teams (at least from my experience):

Trunk-Based Development (or more correctly Scaled Trunk-Based Development).

If your goal is to find a job as a professional developer I highly recommend getting used to this workflow upfront. The more you know how to work like a professional the less you’ll be overwhelmed on your first job.

I promise: it’s not very difficult if you know the basics of Git. But there is a lot of glossary around it that might confuse you at first.

Watch the video below to see me walk through one cycle of the workflow. Below the video you can find instruction on how to set up branch protection in your GitHub repository to enforce this workflow and a detailed walkthrough based on screenshots.

This series of articles and the application I'm building are part of my upcoming React Job Simulator. Build a project hands-on like a professional team and gain job-like experience.

Table of Contents

  1. Trunk-Based Development in a Nutshell
  2. Branch Protection: Enforce usage of Pull Requests
  3. A tour through the Trunk-Based Development workflow
    1. Open a Pull Request
    2. Continuous Integration Pipeline
    3. Code Reviews
    4. Handling Review Comments
    5. Approving a Pull Request
    6. Merging the Pull Request
    7. The history of the main branch
    8. Updating the local main branch
  4. Summary

Trunk-Based Development in a Nutshell

  • You check out a new branch from the main branch.
  • You commit your code on this branch and push it to the GitHub repo.
  • You open a Pull Request (or Merge Request as GitLab calls it).
  • Automated tests verify that the application behaves as expected.
  • A teammate reviews your code and you adjust it according to the feedback.
  • You merge your branch into the main branch via the Pull Request (short PR).

If this is all sounds like Gibberish, no worries. Have a look at my free course where you can learn and practice this workflow.

What the heck is a Pull Request?

I always found the name Pull Request on GitHub confusing. GitLab calls it a Merge Request which is much more descriptive. Basically, a Pull Request is a way to ask for permission to merge your code into the main branch:

Hey team, can somebody have a look at this code and tell me if it’s any good? I’d like to get it into the main branch so our users can benefit from it.”

You can think of a Pull Request as a feature on top of a Git branch that allows you to get feedback from your teammates. And as mentioned it also allows you to automatically run checks and tests on your code changes before they go to the main branch.

To summarize, Pull Requests are

  • a mechanism to gather feedback and thus increase code quality
  • a tool to run automation (e.g. tests) on your code to decrease the risk of introducing bugs into production code.

Branch Protection: Enforce usage of Pull Requests

Processes and workflows are great. But people are lazy and look for workarounds. So ideally we want to force everyone on the team to use Pull Requests instead of committing directly to the main branch.

Luckily GitHub has our back with a feature called “branch protection”. To protect the main branch open your repository’s settings on GitHub, select “Branches” in the left menu, and click on the “Add rule” button.

GitHub add branch protection rule

GitHub branch protection

A few notes about the selected rules:

  • In a team of developers the option “Require a Pull Request before merge” → “Require approvals” is mostly activated. This way we can enforce that developers review and approve each other’s code. That is one safeguard against new bugs and ideally increases code quality and coherence.
  • The option “Require linear history” is not necessary but from my experience many teams use it nowadays. It prevents merge commits on the respective branch. Instead you have to either “Squash and merge” a Pull Request or “Rebase” it. You can see the “Squash and merge” in action including an explanation here in the video.
  • The “Include administrators” option is important if you want to enforce the workflow for yourself in your own repositories. Since you’re the administrator the rules wouldn’t apply to you otherwise.

If a developer now creates a commit on the main branch and tries to push it they will see an error message.

Push to main branch fails

A tour through the Trunk-Based Development workflow

Open a Pull Request

git checkout -b migrate-to-styled-components
Enter fullscreen mode Exit fullscreen mode

Now we write our code, commit and push it to the remote repository on GitHub.

git commit -m "Migrate home page to styled-components"
git push origin migrate-to-styled-components
Enter fullscreen mode Exit fullscreen mode

On GitHub, you should now see a banner to create a Pull Request.

Create Pull Request banner on GitHub

Once you click the button you see a form where you can enter a title and description. Next click the “Create Pull Request” button.

Create Pull Request form on GitHub

Congrats, you opened your first Pull Request! This is what you should see now:

Pull Request on GitHub

Continuous Integration Pipeline

Did you note the status checks at the bottom of the PR?

Status check for Continuous Integration Pipeline

This is a really handy feature. You can run scripts like npm run lint or npm run test within your Pull Requests to decrease the risk of introducing bugs. This is called a Continuous Integration pipeline. I’ll leave it as a cliffhanger for tomorrow’s article. If you can’t wait you can already watch me set it up in the video.

Code Reviews

In a real-world team, your code is typically reviewed by at least one teammate. This again prevents bugs and helps keep the codebase clean and consistent. A Pull Request is also a great way of discussing your code in case you’re stuck.

So let’s switch to another account with access to the repository. Here is how our imaginary teammate would review your code.

Pull Request - files changed

Our teammate can add comments to the code.

Pull Request - review comments

Finally, they submit the review.

Pull Request - Submit review

As the author of the Pull Request, we can now see the comments.

Pull Request - Review from author's perspective

Handling Review Comments

We have two options now: we can update our code according to the comments or start a discussion.

To adjust our code we simply head back to our local machine, change the code, commit and push it. You can see the new commit below the review comments. You can also add a comment and resolve the conversation.

Pull Request - Resolve comment

Finally, you can request a new review:

Pull Request - Request new review

Approving a Pull Request

Once your teammate is pleased they can approve your Pull Request by submitting a review. They might add a useless yet affirmative emoji comment to make you happy.

Pull Request - Approve

Merging the Pull Request

Finally, it’s time to merge our Pull Request. Now our code changes will be added to the main branch.

Pull Request - Approved

Remember that we set the “Require linear history” option in our branch protection rules? That’s why we see a “Squash and merge” button instead of a simple “Merge” button by default.

Let’s see what happens when we push the button:

Pull Request - Squash and Merge

And once we press the confirmation button we’re all set.

Pull Request - Squashed and merged

The history of the main branch

I didn’t explain yet what the “Squash and merge” button does, right? The Pull Request (or our Git branch) contained multiple commits:

Commits in pull request

When we look at the commit history of our main branch we don’t see these commits anymore. Instead, there’s only a single commit that points to the Pull Request (via the link #6):

Squashed commit in main branch

All the commits of our original branch have been squashed into a single commit. The benefit here is that you don’t need to keep the commits in the Pull Request super tidy. For example, commits that are simple fixes during the review process like “Remove unused class name” don’t really need to show up in the history of the main branch.

Updating the local main branch

As the last step (that’s easy to forget) we sync our local main branch with the remote repository. Since the merge happened on GitHub our local machine doesn’t know about these changes in the main branch yet.

git pull origin main
Enter fullscreen mode Exit fullscreen mode

When we work in a team of developers we should actually do this every time we start working on a new branch.

Summary

In this article you learned how to set up a GitHub repository with branch protection to enforce a popular Git workflow called Trunk-Based Development. By now, I hope you're less intimidated by Git & GitHub thanks to the detailed walkthrough.

React Job Simulator waitlist

Discussion (1)

Collapse
scottrinoz profile image
Scott Robertson

Where I work, we are actually normally two steps away from master/main. We have a Project/Feature branch that acts as a defacto main for the current feature we are building as a team, and individualy, work on a Story branch off project, not only can we not commit to main, we also can't commit to the project without a pull request, and PRs from Project into main are only allowed by a select few. The expectation is that we continually pull from project to local and resolve diffs before committing and raising new PRs. For us main is sacrosanct and never gets touched until code is in production.(Which is a whole another level)