On one of the projects we used a joint development model "shared repository" while working with GitHub. Everyone in the team had "writing" access to one common repository, and branches were used to isolate changes and work on a specific task.
Each "branch" corresponded to a separate task. A "branch" name was assigned according to a task number. This was performed in order to be able to understand easily which task it relates to. After completing work on the task, the code from a certain "branch" was pushed into GitHub server. On GitHub site, the developer manually made a "pull request" for his branch, which meant that the code was ready to be checked by the reviewer. The name of "pull request" also contained a task number and was marked "FE" or "BE", according to where changes had been made: on the client (front-end) or on the back-end side.
A reviewer was appointed every day among the developers in turn. His task was to check the "pull requests" made by developers (on demand or at certain working hours), add them to the master (the main branch of the repository with the current code version), or leave comments to the code and send some task for revision.
If a reviewer did not find any errors in the "pull request," he filled in the changes to the master and closed it.