Advanced

When working with git, you can encounter various situations that require further knowledge. This chapter discusses advanced topics and offers some good-to-know tips and tricks.

Branching

Branching is an important tool in collaborative software engineering. Use branches, when you want to develop a new feature independently from the rest of the code base and your teammates.

$ git branch <name>

This command creates a new local branch named <name>. Be aware, that the newly created branch is an exact copy of the branch you are currently working on.

To actually switch to the new branch or any other existing branch, use

git checkout <branch>

A handy shortcut that combines creating a branch and switching to it in one go is

$ git checkout -b <branch>

After creating a new branch and working on it, you want to push your work on the remote. Git needs some information to push the changes to the correct remote branch, so executing

$ git push --set-upstream origin <branch>

actually creates the branch on the remote and links the local branch to the remote branch.

Merging

The most problems when using git occur during the integration phase, where different versions of artifacts are merged into one. If you want to manually merge a branch back into another branch, use

$ git merge <branch>

When executing this instruction, git tries to do most of the merging automatically, but sometimes auto-merging can fail and you have to resolve a merge conflict.

Merge conflicts can occur when manually merging or anytime you pull changes from the remote, because on every pull, git issues an auto-merge that can fail.

Before you can push a new commit to the remote again, you have to inspect all files that are in conflict. A file in conflict contains markers that git automatically adds and can look like this

<<<<<<< HEAD:hello_world.py
print(“Hello World!")
=======
print(“Hello!")
print(“Good Bye, World!")
>>>>>>>24b9b78:hello_world.py

Between the first line containing the ←symbols and the line of equal signs, the local version of the source code is listed. Below that, the remote version of the source code is listed. It is now your task to either completely dismiss one of the two versions by deleting one version and all markers, or create a third version that combines both the local and the remote version. A possible solution to this conflict can look like this

print(“Hello World!")
print(“Good Bye, World!")

This version incorporates some of the remote changes and some of the local changes. Now, with all conflicts resolved, you are able to commit again and push to the remote.

Rebasing

Sometimes while branching you want to keep up with the latest changes in the main branch. Or, in rare cases, you need to change the base branch for your features. To solve this you can use the git rebase command.

$ git rebase -i <remote-alias>/<branch>

The flag -i indicates that we want the interactive mode which means that we are able to select the commits we want to use during the procedure. What happens is that your branch is wound back to where it was forked from in the first place. Then, the start point is set to the latest commit in <remote-alias>/<branch> and git tries to add your commits again onto the new state.

Sometimes a merge conflict can occur. Solve it as stated above and continue the rebase with this command:

$ git rebase --continue

Or, if you changed your mind, simply abort the rebase with this command.

$ git rebase --abort

After your rebase has finished successfully you have to push it to the upstream repository. Since we overwrote the whole branch history we also have to force this here with this command:

$ git push --force

Advanced Pull

In the basics chapter we learned about simple pulling. If you already had some changes in your local copy it is likely that an unnecessary merge commit will be generated after a pull. To avoid this you can use the pull command with an additional --rebase flag to get the latest updates from the upstream repository.

$ git pull --rebase