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, and git 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>