Session 4: Alice & Bob become Git experts by branching and merging
Alice & Bob define the branching policy
Here is a branching policy for a data centre:
(L3) Temporary branches for hot fixes: '<issue>_hotfix'
(L2) Permanent branch for operations system: 'ops'
(L1) Permanent branch for test system: 'tst'
(L0) Permanent branch for development: 'master'
(L-1) Temporary branches for feature implementation: '<feature>_impl'
Merging from upper to lower level is a safe action and can be done frequently. Merging from lower to upper level must be done with care and is considered a "delivery".
Alice creates the permanent branches: checkout -b, checkout, gitk, push -u
Branch master
doesn't need to be created. It is created by Git and
always there.
Create local branches (use -b flag):
git checkout -b tst # starting from HEAD
git checkout -b ops <start_point> # starting from start_point (e.g. commit)
Switch between branches:
git status # always make sure to have a clean working directory!
git checkout <branch>
Add commits to each branch, then use the graphical repository browser
for the inspection (may sometimes be more convenient than git log
and git diff
):
gitk &
Push branches to Git server (use -u flag):
git push -u <remote> <local_branch>:<remote_branch>
git push -u eodc tst:tst
git push -u eodc ops:ops
Bob gets the new remote branches: checkout -t
git fetch eodc # update remote tracking branches
git branch -a # view list of branches
git checkout -t eodc/tst # use -t to set up "upstream" configuration
git checkout -t eodc/ops
Bob delivers work on a feature branch: checkout -b, push -u, merge request
git checkout master
git checkout -b <feature>_impl
He does some work, then stages and commits it:
git add <file>...
git commit
git push -u eodc <feature>_impl:<feature>_impl
Finally, Bob submits a merge request to Alice (talk, send an email, or press GitLab's New Merge Request button).
Alice integrates Bob's changes: merge, tag, branch -d
git fetch eodc
git checkout -t eodc/<feature>_impl
Alice can and should inspect the changes made by Bob. She talks to him in case of disagreement.
Alice merges feature branch into master:
git checkout master
git merge --no-commit <feature>_impl # Don't abuse --no-commit!
git status
git diff
In case of conflicts, Alice resolves them. She also has the option to abort the merge. See the sections on conflict resolution and aborting below.
If everything OK, Alice commits and tags:
git commit
git tag -a -m "DCR-001: Feature XYZ" DCR-001-0
Alice pushes to Git server and removes obsolete feature branch:
git push eodc master
git branch -d <feature>_impl # delete local branch
git push eodc :<feature>_impl # delete remote branch
Alice notifies Bob about integration action.
Bob verifies integration: fetch --prune
git fetch eodc # fetch is additive, it doesn't delete branches
git fetch --prune eodc # prune obsolete remote tracking branches
git checkout master
git pull
gitk &
git branch -d <feature>_impl
Alice's options for conflict resolution: checkout --ours|--theirs|-m, add
When a git merge
reports about conflicts:
- Look at the diffs:
git diff
will show a three-way diff, highlighting changes from both the HEAD and MERGE_HEAD versions. - Look at the diffs from each branch:
git log --merge -p <path>
will show diffs first for the HEAD version and then the MERGE_HEAD version. - Look at the originals:
git show :1:filename
shows the common ancestor,git show :2:filename
shows the HEAD version, andgit show :3:filename
shows the MERGE_HEAD version.
Alice can use the following commands in order to resolve conflicts:
git checkout --ours -- <file>
git checkout --theirs -- <file>
git checkout -m -- <file> # gets conflicts back
vi <file> # find conflict markers and fix things
git add <file> # mark conflict as resolved.
git commit
Alice's options for aborting a failed merge: merge --abort, reset --hard, revert -m 1
If things go entirely wrong, the merge can be aborted before committing by one of the following commands:
git merge --abort # requires a newer Git version
git reset --hard HEAD
Revert the merge after committing but before pushing as follows:
git reset --hard HEAD^
Revert the merge after pushing as follows:
git revert -m 1 <commit>