Branching Strategy in Practice
Goal
You create a repository from scratch, see with your own eyes how the results of three merge methods (no-ff merge, fast-forward, cherry-pick) remain differently in the history, then count the results as numbers and write a strategy comparison table.
Why it matters
Arguments about branching strategy usually end as a fight over taste. But the real question that decides is one: when an outage happens, how do we plan to find the culprit commit in this repository? A --no-ff merge leaves "when this bundle was integrated", fast-forward gives a straight-line history but erases the integration point, and a squash merge fixes the bisection resolution at the PR size and makes it so that, from Git's point of view, the branch has never been merged. This difference stays with you not by reading an explanation but by counting with git rev-list --min-parents=2.
Steps
This image has no global git identity configured. In every repository you create, if you do not set git config user.email / git config user.name locally, commits fail.
- Create a repository at
/root/gitx1/repo. The current branch must bemain, this repository must have a localuser.emailanduser.nameset, and there must be at least 1 commit containingREADME.md. - Create a
feature/loginbranch and stack 2 commits. The commit subjects must be exactlylogin: formandlogin: validation, and the branch must have alogin.txtfile. There must be exactly 2 commits that start withlogin:. - Move to
mainand mergefeature/loginso that a merge commit remains (a commit with two parents). After the merge,mainmust havelogin.txt. - From
main, create afeature/quickbranch and make one commit that addsquick.txt. The subject is exactlyquick: typo. Then merge it intomainby fast-forward only. This commit must have 1 parent, and the number of merge commits onmainmust remain the 1 created in step 3. - At the current position of
main, attach an annotated tagv1.0.0. The tag message must not be empty. - From the point
v1.0.0, create arelease/1.0branch and make a commit that addshotfix.txt. The subject is exactlyhotfix: null guard. Then apply the same change tomainas well. Conditions: the contents ofhotfix.txton the two branches must be the same, both must have ahotfix: null guardcommit, but the hashes of the two commits must be different. - Clean up the branches. Delete
feature/quick, keepfeature/login, and create a newfeature/wipbranch and stack at least 1 commit on it that is not inmain(it must still be unmerged). - Write
/root/gitx1/strategy.md. It must include:merge_commits=— the number of merge commits onmainbranches=— the number of local branches in this repositorytags=— the number of tags- An explanation of the three strategies: Git Flow / GitHub Flow / Trunk-Based
- A judgment of which strategy this repository is closest to (one of the expressions 'this repository', 'we' or 'currently' must appear)
Notes
- Identity setup: inside the repository, run
git config user.email "you@lab.local"andgit config user.name "Lab". Do not use--global. - Default branch name: use
git init -b main, or aftergit init, change it withgit symbolic-ref HEAD refs/heads/main. - Counting numbers: merge commits are
git rev-list --min-parents=2 --count main, branches aregit branch --format='%(refname:short)' | grep -c ., and tags aregit tag | grep -c .. - Common mistake 1: using a plain
git mergein step 3. If there is no diverged history, it fast-forwards and no merge commit is created. - Common mistake 2: using
git merge release/1.0in step 6. One more merge commit is created and the step 4 grading breaks. Use the command that brings over just one commit. - Commit subjects must match exactly, down to case and spaces. Check with
git log --format='%s'.
Create the repository and set the identity
Create a repository at /root/gitx1/repo. The current branch must be main, this repository must have a local user.email and user.name set, and there must be at least 1 commit containing README.md.
Run git init in /root/gitx1/repo, but make the default branch name main. This image has no global git identity, so if you do not set user.email and user.name directly in this repository, the commit itself fails.
Stack 2 commits on a feature branch
Create a feature/login branch and stack 2 commits. The commit subjects must be exactly login: form and login: validation, and the branch must have a login.txt file. There must be exactly 2 commits that start with login: .
Create the feature/login branch and commit login.txt in two parts. The commit subjects must be exactly the same as the instructed strings, and there must be exactly 2 commits that start with login:.
Merge without fast-forward
Move to main and merge feature/login so that a merge commit remains (a commit with two parents). After the merge, main must have login.txt.
Move to main and merge feature/login, but merge it so that a commit with two parents remains. A plain merge fast-forwards and the integration record disappears.
Raise a small fix by fast-forward
From main, create a feature/quick branch and make one commit that adds quick.txt. The subject is exactly quick: typo. Then merge it into main by fast-forward only. This commit must have 1 parent, and the number of merge commits on main must remain the 1 created in step 3.
Create feature/quick, commit quick.txt, and merge into main by fast-forward only. If a merge commit is created, this step fails. If you use --ff-only, it refuses altogether when the condition is not met.
Attach a release tag
At the current position of main, attach an annotated tag v1.0.0. The tag message must not be empty.
Attach the v1.0.0 tag to main. A lightweight tag is just a pointer, so the author and message are not kept. Use the option that creates a tag object.
Bring the release branch hotfix into main
From the point v1.0.0, create a release/1.0 branch and make a commit that adds hotfix.txt. The subject is exactly hotfix: null guard. Then apply the same change to main as well. Conditions: the contents of hotfix.txt on the two branches must be the same, both must have a hotfix: null guard commit, but the hashes of the two commits must be different.
Create release/1.0 from v1.0.0, commit hotfix.txt, and then apply the same change to main as well. Do not merge the whole branch; bring over just that one commit.
A cherry-pick re-applies the change and creates a new commit — it does not move anything. However, as in this lab, when release/1.0 was branched right at the tip of main, the parents of the two commits are the same. So use git cherry-pick -x. One line, (cherry picked from commit ...), is added to the message, so where it came from remains in the history, and thanks to that line the commit objects are also reliably distinguished. This is exactly the approach recommended in practice when applying a hotfix to several branches.
Clean up only the merged branches
Clean up the branches. Delete feature/quick, keep feature/login, and create a new feature/wip branch and stack at least 1 commit on it that is not in main (it must still be unmerged).
Delete branches that have already been merged and keep branches that have not. First check what can be safely deleted with git branch --merged main. Using -d instead of -D prevents the accident of deleting an unmerged branch by mistake.
Count the repository state and write the strategy comparison table
Write /root/gitx1/strategy.md. It must include:
merge_commits=— the number of merge commits onmainbranches=— the number of local branches in this repositorytags=— the number of tags- An explanation of the three strategies: Git Flow / GitHub Flow / Trunk-Based
- A judgment of which strategy this repository is closest to (one of the expressions 'this repository', 'we' or 'currently' must appear)
In /root/gitx1/strategy.md, write the three lines merge_commits= / branches= / tags= with values counted in the actual repository, compare the three branching strategies, and then write a judgment of which this repository is closest to. Count the numbers with git commands.