The labs on this site need JavaScript to run. The same content is written out below.
Learn › Architecture and operations › Collaboration
Merge and rebase
Three ways to combine two branches
While you work on the feature branch, new commits also appear on main. Whether you combine the two with merge or with rebase changes the shape of the commit graph, and if both changed the same line, you get a merge conflict.
Checked against real execution · Checked by creating a temporary repository with git 2.55
Concepts in this lab
- Merge and rebase
- Two ways to combine the changes of two branches. A merge joins both histories as they are (if the histories have diverged, a merge commit is created, and if they have not, only the branch pointer moves forward). A rebase moves your commits to after the latest point of the target branch and applies them again, which makes the history a single line. A rebase re-creates existing commits as new commits, so do not use it on commits that you have already shared with others.
- Merge conflict
- A situation in which two branches changed the same part of the same file in different ways, so Git cannot combine them automatically. A person looks at the parts marked as conflicting, decides which side to keep or how to combine the two, edits the file, and then completes the merge.
- Git fetch, pull, and push
- The fetch command downloads new changes from the remote repository but does not apply them to your working branch. The pull command does a fetch and then also merges the downloaded changes into the current branch. The push command uploads your local commits to the remote repository.
- Git-flow and GitHub Flow
- Strategies for managing branches. Git-flow keeps a branch for releases and a branch that integrates development, and it manages features, release preparation, and urgent fixes on their own separate branches. It suits products that release versions on a fixed schedule. GitHub Flow is a simple approach in which you create a short-lived working branch from a single base branch, merge it after review, and deploy right away. It suits services that deploy at any time.
- Code review and pull requests
- A pull request (PR) is a request to merge the changes on a working branch into the base branch. Code review is the process in which other developers examine the changes before they are merged. It finds defects early, keeps the code consistent, and shares knowledge within the team.
Try these
- Default settings — merge. A merge commit that joins the two lines is created.
- Merging after a rebase — The commits of feature are moved and attached to the end of main. The result is a single line.
- When main has no new commits — main just moves forward, with no merge commit (fast-forward).
- When both changed the same line — A merge conflict occurs. A person has to choose.
- Rebasing a branch that is already pushed — It now differs from the commits on the remote, so you have to push by force.
- squash — Several commits of feature are squashed into one and added to main.
Running with the default settings
- This is the starting state. The feature branch split off at commit B and added two commits, D and E. In the meantime, commit C, pushed by someone else, appeared on main.
- A new commit M that combines the contents of C and E is created. M is a merge commit with two parents (C and E). The existing commits D and E stay as they are, and the graph keeps a record of when the lines split and when they were joined.
Result of this run
- merge does not touch existing commits and adds one merge commit. The history stays as it really happened, but the graph gets complicated when there are many branches.
Code
git switch main
git merge feature
Assumptions of this model
This is an example of a small repository with five commits. It assumes that a conflict occurs in only one place in one file. The behavior of each command follows the explanations in the official Git documentation (git-merge, git-rebase). Teams usually decide on a merge method (merge commit, squash, or rebase) and stick to it. Rather than one being correct, it is a choice of what shape to leave the history in. It was checked by creating a temporary repository with git 2.55 on the PC used to write this lab. merge created a merge commit with two parents and kept the hashes of the existing commits, and when main had no new commits, it was a fast-forward. After rebase, the hashes of D and E changed and the history became a single line without a merge commit; for a branch that was already pushed, a normal push was rejected and a force push was needed. The squash commit had one parent, and git did not recognize that feature had been merged. The conflict markers were also exactly as shown on the screen.
Previous lab: Distributed tracing