Branches
a line of commits and the last commit on a line
A list of commits can be seen as a line in the sense of a continuous list of snapshots that follow each other. Technically, each commit keeps a reference to its parent (the former commit), so that we may reconstruct a whole line from a given commit.
We may conceptualize a branch as a line of a commits that lead to a tip commit.
There are as many distinct theoretical branches as there are commits, and we may have several actual branches pointing to the same commit.
All it takes to create a branch is to pick a name and decide what commit it points to. This commit becomes the current tip of the branch.
Branches are independent from each others: they allow to work in isolation. When we add a commit, the active branch is updated to point to the new commit, while others are untouched.
branches that live on the same line: fast-forward compatible
We may say that two branches live on the same line when the longer branch is the continuation of the shorter branch. The tip of the longer branch is a descendant of the tip of the short branch.
To fast forward a branch is to bring it closer to, or at the same point than a longer branch that lives on the same line. Technically, we make it point to a more recent commit on the line.
while the git command we use is called merge, there is no graph merge during a fast-forward.
branches that have forked: eligible for a merge commit
One branch has forked from the other one. The last commit they have in common is the common ancestor. The merge commit is one that aims to merge the paths coming from two parents. As such, it is a special commit that points to two parents instead of one.
Git compares files across the two parents and, when they are different, checks if one of them is stalled, aka has not changed since the last common ancestor. In that case, it favors the one that has received work, as it assumes the merge intends to make use of such work.
If both paths have worked on the ancestor version to change it, the merge cannot pick one version on its own. It asks the developer to resolve the difference between the two parents.
add the merge commit to the receiving branch
Once the merge commit has been created, the merge process doesn't merge the two branches into one, neither does it make both branches point to it.
Instead, the merge commit is only added to the receiving branch. The receiving branch is now "aware" of the two paths that led to the merge commit.
The other branch stays as-is. It is eligible for fast forward toward the receiving branch.
merge one branch (ex:dev) to current (ex:main) (repetition)
We first compare the two branches: the receiving branch (current), and the giving branch.
If the receiving branch is a parent of the giving branch, that is, it has not drifted away because it didn't do any commit on its own, then we can simply fast forward the receiving branch to the state of the giving branch, making them point to the same commit.
If the receiving branch has done at least one distinct commit, it means there was an actual fork, and a merge commit is required, to integrate the branch that has forked, and to preserve the fact that there was a fork. The merge commit only occurs on the receiving branch.
For example, we merge dev into main. dev is unaffected. main has a merge commit.
commands
list branches
## list branches
git branch
## includes remote-tracking branches
git branch -a
create, rename, delete branch commands
creating a branch does not switch to it.
git branch dev
git branch -m master main
git branch -d dev
branch switching
switching to a branch means to have HEAD pointing to the branch, which points to a commit. The idea of switching to a commit is to get a clean working directory and index that match this commit, so we may start working from this snapshot.
git switch dev
switching to a branch that comes from a remote
if the remote branch such as origin/dev does not have a matching local branch, the git switch command may create the dev local branch and switch into it.