I got in touch with git when I was starting using Github. However as these projects were merely single contributor projects, some basic commands did it for my work there. There was no branching, no rebasing or whatsoever. Now after working on a daily basis with git and using it in big(ish) teams, I thought to write down a little guide for newbies on how to work with git.

Obviously best way to get on with git is to read the official documentation at https://git-scm.com/book/en/v2/ which is quite comprehensive. I try to sueez the information a bit into a single page focus on the most important stuff

What is git

Well most of us developers know what’s git. However some come from a different vcs like svn, so therefore let’s see what Wikipedia says:

Git is a version control system for tracking changes in computer files and coordinating work on those files among multiple people. It is primarily used for source code management in software development,[8] but it can be used to keep track of changes in any set of files. As a distributed revision control system it is aimed at speed,[9] data integrity,[10] and support for distributed, non-linear workflows.[11]

As with most other distributed version control systems, and unlike most client–server systems, every Git directory on every computer is a full-fledged repository with complete history and full version tracking abilities, independent of network access or a central server.[13]
Source: https://en.wikipedia.org/wiki/Git

Important is to understand that the last part: it is a distributed version control systems which means you can work (e.g. branch) locally without having a connection to the internet. I see the following benefits over other version control systems:

  • it is decentralized so every developer has a local copy of the full version history of the project on their individual machine
  • feature branches allow to do experimental development and rapid prototyping without breaking existing code
  • you can rewrite the history, this helps to have a clean commit history

Here some additional resources to read

Just for completeness, there are also critics or adovation for other source controls and here are some interesting points about

So, git is not necessarily superior to other version controls but it does some things nice and is - so would I say - a defacto standard by now. So it is essential a developer knows about it.

Install and configure git

Installation on Linux is usually easy as most distrbibutions come with a git-package. On Windows you can download the executable from the official page or you use a package manager like chocolatey.

Before committing or pushing, ensure you have set your user name and email correctly configured. This information is used for the commits, and is imprtant to be correct as the e-mail address is what “identifies” you as a commiter

git config --list --show-origin
git config --global user.name "Name Surname"
git config --global user.email "[email protected]"
git config credential.helper 'cache --timeout 3600'

Workflow

There are different ways to work with git, but mainly there are 2 common workflows which are mostly used: Gitflow and GitHub Flow. Which flow fits better for you, depends on the needs of the projects and shall be carefully discussed with the respective developers.

Usually you use a platform like Github, Gitlab or Bitbucket to host your code. This helps you to easily share code among other developers and brings other benefits like Pull/Merge Requests. Later more to that.

Where to start

Well you can start by creating your first project from scratch. Usually git init suffices. Now you can start creating code and adding them to your git repo.

git add myclass.java
git commit -m "My first commit"

If you want to share the project with others you usually would upload it to a remote repo. Thus you need to let your git repo know where that is. Each remote has a name - usually origin. You may have more than one remote, but lets start with one. Ensure youe have an empty remote repository created (e.g. on Github), so the changes can be pushed to it. Then configure the remote and push it upstream.

git remote add origin https://{username}@github.com/wyssmann/demo.git
git push --set-upstream origin master

The example above shows a connection to github using https, but you could also use ssh

Create Branches

A “branch” is an active line of development. The most recent commit on a branch is referred to as the tip of that branch. The tip of the branch is referenced by a branch head, which moves forward as additional development is done on the branch. A single git repository can track an arbitrary number of branches, but your working tree is associated with just one of them (the “current” or “checked out” branch), and HEAD points to that branch.

Source: https://stackoverflow.com/questions/1457103/how-are-git-tags-different-from-git-branches

Whereas in svn you have a trunk in git you have a master branch is a permanent branch which contains latest code which is in a production-ready state. So you usually work in “feature” branches. A branch usually looks like prefix/unique-identifier whereas the prefix is something like feature, bugfix or your username. Later is usually the commn whay when working on Github. The unique-identifier can be whatever but tTry to find a unique name to avoid name collisions when working on your branch. The branch is individual to a Developer and often to small implementations. It not always reflects an issue or a story. Usually it makes sense to have some common rules. In the company I am working we usually use feature, bugfix, release as prefix and the issue/story item as unique-identifier.

Also essential is that only one person is working on a branch to avoid collision or that you overrite changes of somebody else - yes multiple people could work on the same branch if you are very careful, but I personally don’t like it.

Below we clone an existing repo, make a branch, add and commit a new file. This happens locally so far nobody knows about your changes other than you.

git clone https://path/to/repo
git checkout -b feature/myfeature
git add . (add path/test.yaml)
git commit -m "Message" (commit -a)

Now you need to push your changes upstream as already shown above. You can also use the short-form -u?

git push -u origin feature/myfeature

Master Branch

As already mentioned, the master branch must always be potentially releasable. If you merge features into master, you acknowledge these changes will be contained in the next release. Usually would configure your remote in way that it is not possible to push changes of a master branch. Also would you ensure that only certain people can merge changes to the master or at least that they only can merge them once a peer review has happened.

When working on your branch commit regurarly. In case something goes wrong you can go back. Ensure to write useful git commit messages according to these 7 rules:

  • Separate subject from body with a blank line
  • Limit the subject line to 50 characters
  • Capitalize the subject line
  • Do not end the subject line with a period
  • Use the imperative mood in the subject line
  • Wrap the body at 72 characters
  • Use the body to explain what and why vs. how

There may be some additional rules like to directly transit issues from one state to an other (e.g. close issues witha commit). But this depends on your remote.

You can also create branches from your branches or stash changes in a dirty working directory away and reuse them later.

Tags

Git also knows the concept of tags and as https://stackoverflow.com/questions/1457103/how-are-git-tags-different-from-git-branches point out

A tag represents a version of a particular branch at a moment in time. A branch represents a separate thread of development that may run concurrently with other development efforts on the same code base. Changes to a branch may eventually be merged back into another branch to unify them. From the theoretical point of view:

tags are symbolic names for a given revision. They always point to the same object (usually: to the same revision); they do not change. branches are symbolic names for line of development. New commits are created on top of branch. The branch pointer naturally advances, pointing to newer and newer commits.

Closing Work

Before you create a Pull Request (PR) apply the changes from master branch in order to ensure a smooth merge of your PR (i.e. no merge conflicts)

git fetch
git rebase origin/master
git push -f origin feature/myfeature
Squash your Commits and clean your History before you merge

Rewrite your history

Before creating a pull request ensure that your history is clean so it makes it easier for the reviewers - see also Rewriting History

One of the cardinal rules of Git is that, since so much work is local within your clone, you have a great deal of freedom to rewrite your history locally. However, once you push your work, it is a different story entirely, and you should consider pushed work as final unless you have good reason to change it. In short, you should avoid pushing your work until you’re happy with it and ready to share it with the rest of the world.

Git allows you to “rewrite” the commits already done by

  • change the order of commits
  • change the commit message
  • *modify files in a commit
  • squash multiple commits to a single one
  • split a commit into multiple commits
  • removing commits

You need to be careful cause a some of these operations changes the SHA-1 of the commit. This means when you already pushed your changes to your remote and the e.g. changing the last commit, it will appear that there is one change in the remote and one locally. So you should force push your changes. However, this lead to the same problem if somebody is working on the same branch.

Changing the last commit

This is like a small rebase. The following command replaces that last commit with your new, improved commit:

git commit --amend

Changing Multiple Commit Messages

The following command does modify not only the last but all commits as far back as you want (e.g. in the example below we will edit the last 3 commits). You can also specify a commit-hash

git rebase -i HEAD~3

Also provide the -i option to make the rebasing interactive so the tools stops after each commit you want to modify. Running this command gives you a list of commits in your text editor that looks something like this:

pick f7f3f6d changed my name a bit
pick 310154e updated README formatting and added blame
pick a5f4a0d added cat-file
 
# Rebase 710f0f8..a5f4a0d onto 710f0f8
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#  x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

Commits are listed in the opposite order than you normally see them using the log command i.e. oldest commit is shown on top. This also indicates the order in which the commits will be processed.

You need to edit the script so that it stops at the commit you want to edit. To do so, change the word pick to the word edit or reqordfor each of the commits you want the script to stop after. When you save and exit the editor, Git rewinds you back to the last commit in that list and drops you on the command line

Squash vs. Fixup

Squash squashes the changes of multiple commits into a single one. Fixup is basically the same as a squash. The main difference is that for a squash git gives you a dialog to modify the commit messages (per default containing the commit messages of each individual commit) whereas fixup ignores the commit messages of the commits.

Create PR

With a Pull Request (PR) or Merge Request - naming depends on the remote - a developer asks the changes to be merged to another branch. This is usually done via the GUI of the remote usually adding some additional feedback what is expected to be reviewed and other useful information to the reviewers

One or more peers opens the PR in the remote and reviews the code in accordance with Code Review (Pull Request). Usually it’s good to

  • add comments directly on the affected line of code
  • add more information or questions to the activity

After the review, the reviewer either approves or marks the PR as “needs more work”:

PR needs more work

In case the code needs rework, the author shall continue to work on the branch until the peers ack the PR. Here a useful command to Fixup your PR issues :

git commit –fixup $(git rev-parse HEAD)
git push origin feature/myfeature

PR approved

Once the PR is approved there is nothing else to do for the reviewer. So the PR can be merged. It’s usually a good practice to delete the branch in the remote

Keep in mind that deleting the branch on the remote does not delete your local branch. You have to do this manually

git branch -d feature/myfeature

In case you did not delete the remote branch during the merge of the PR, you can delete them afterwards via the GUI of the remote or you can run this command form your local workspace

git push origin :feature/myfeature

E-Learning

Branching

Maven and releaseing

  • https://community.atlassian.com/t5/Questions/What-about-version-in-pom-xml-for-feature-branches/qaq-p/207600 (interesting point of view, to further elaborate)

    This is one of the real problems with maven. Checking the version into a file in Git is a bad idea (we have the same problem in Stash though)

  • https://gist.github.com/lemiorhan/97b4f827c08aed58a9d8
  • https://dzone.com/articles/why-i-never-use-maven-release ( Read also comments, very interesting)

For svn users