Sunday, 28 August 2016

Git cheat sheet

Switching repositories and branches

Cloning a remote repository:

$ git clone

Cloning a remote repository with preserving UNIX-style line endings:

$ git clone --config core.autocrlf=false

Getting a list of all localbranches:

$ git branch

Deleting local branch:

$ git branch -d my_branch
Deleted branch my_branch (was 6d5921868b).

Getting a list of all remote branches:

$ git branch -r

Example output:

origin/HEAD -> origin/master

Checking out the remote branch (for the first time):

$ git checkout -b branch_name remote_name/branch_name


$ git checkout -b release/2.3 origin/release/2.3
Branch release/2.3 set up to track remote branch release/2.3 from origin.
Switched to a new branch 'release/2.3'

To create new local branch:

$ git checkout -b issue-007
Switched to a new branch "issue-007"

This is the compact version for:

$ git branch issue-007
$ git checkout issue-007

Switching to another local branch:

$ git checkout branch_name


$ git checkout master
Your branch is behind 'origin/master' by 179 commits, and can be fast-forwarded.
(use "git pull" to update your local branch)
Switched to branch 'master'

To checkout commit specified with its hash:

$ git checkout 3e6dc47cde0e45bb3198ac4618367afc57ddf6a3
$ git checkout 3e6dc47cde0e45bb3198ac4618367afc57ddf6a3
Checking out files: 100% (5111/5111), done.
M features/feature1
M framework/module2
Note: checking out '3e6dc47cde0e45bb3198ac4618367afc57ddf6a3'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

git checkout -b

HEAD is now at 3e6dc47cde... Fixed EULA BK brand;

If local branch is behind the remote by 1 or more commits, it can be updated:

$ git pull

Note that this takes local repository in the state of detached head. HEAD is symbolic name for the currently checked out commit and in this state it points directly to a commit instead of pointing to a branch (e.g. refs/heads/master).

To fix detached head (and delete all local changes) do the following:

$ git branch temp
$ git checkout
$ git branch -d temp

In order to switch from one to another branch we have to have all changes either committed or stashed. To stash local changes do the following:

$ git stash
Saved working directory and index state WIP on my_branch: 6d94b73b53 JIRA-123 Fixed memory leak
HEAD is now at 6d94b73b53 JIRA-123 Fixed memory leak

To list all stashes on the current branch:

$ git stash list
stash@{0}: WIP on my_branch: 6d94b73b53 JIRA-123 Fixed memory leak

If single stash is saved, it can be applied with this:

$ git stash apply

If you were on some branch (e.g. master) and made some changes but now want to move them to a new branch and revert working version of master to the state before your changes, do the following:

$ git stash
$ git checkout -b my_new_branch
$ git stash pop

Checking the current status of the local repository

Checking out the status of the current local repository:

$ git status

Checking the name of the remote:

$ git remote

Getting SHA-1 of the last commit on the current branch:

$ git rev-parse HEAD

Getting short version of the hash:

$ git rev-parse --short HEAD

To see what has changed in the last commit:

$ git show commit_hash

To see which files have been modified and how in last N commits in the specific directory:

$ git log option -N path_to_directory

path_to_directory can be relative path from the current directory.
option can be:
-p - full patch
--stat - numbers of changed lines
--numstat - like --stat but machine-readable
--name-status shows the file name and status: Added (A), Copied (C), Deleted (D), Modified (M), Renamed (R).
--name-only - just the filenames

Adding changed file (already tracked but modified) or new file to the commit:

$ git add my_file

The same applies for directories.

In order to stage all files (both newly added files and also old modified) we can use:

$ git add .

It is possible to use wildcards to denote all files from some directory:

$ git add dir_1/file_1 dir_1/file_2 dir_1/dir_2/*.*

Add files from dir_1 which have same name but different extension:

$ git add dir_1/file_1.*

If we want to delete some file, we can delete it in usual way and then execute git add:

$ rm my_file
$ git add my_file

This can be done with a single git command:

$ git rm add my_file

Modified file can be unstaged (in the working directory), staged (indexed/cached) and commited (HEAD points to its last commit).

If we want to remove staged file from the commit index (to "unstage" it) but at the same time to keep changes in the file:

$ git reset some_file

If we want to revert unstaged (unindexed) changes to the last committed revision of file we can simply check out the file:

$ git checkout some_file

Working with submodules

Let's say that ProjectA resides in Repository1 and is dependent (uses) ProjectB which resides in Repository2. ProjectB might be shared among multiple projects and its development is independent from development of ProjectA.

When we checkout ProjectA, we would like also to pull the latest ProjectB. Submodules provide a way for this. Repository2 will be pulled in a subdirectory in Repository1.

How to check if current repository have any submodules?

$ git submodule
f97bae646f5341216752c4c19950e4b4c15bf616 dir1/dir2/submodule1 (remotes/origin/HEAD)
6e1db0f970c11ec571cf17516d5d8a4b93bd66ce dir3/submodule2 (remotes/origin/HEAD)
3ac8aba9e57c273e249724f8458622e51dbea233 dir4/submodule3 (remotes/origin/HEAD)

What happens if you pull repository but not its submodules (you don't update submodules)? Git can detect that there are new commits in submodules:

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
(use "git add ..." to update what will be committed)
(use "git checkout -- ..." to discard changes in working directory)

modified: dir1/dir2/submodule1 (new commits)
modified: dir3/submodule2 (new commits)
modified: dir4/submodule3 (new commits)

no changes added to commit (use "git add" and/or "git commit -a")

How to update submodules?

$ git submodule update --recursive --remote
Submodule path 'dir1/dir2/submodule1': checked out '6e1db0f970c21ec571cf17516d5d8d4b93bd66ce'
Submodule path 'dir3/submodule2': checked out '3ac8aba9e57c273e244724f845862ee51dbea233'
Submodule path 'dir4/submodule3': checked out '8d58faf56d1a3f5ab50da24ef66c624be9678ba6'

To revert them to the latest locally checked out version:

$ git submodule update
Submodule path 'dir1/dir2/submodule1': checked out 'd5011032541d2fb81e484c78ff8306633a219c66'
Submodule path 'dir3/submodule2': checked out 'b15ab11cd92e1f88ed2b334d0f01a8130ddae28a'
Submodule path 'dir4/submodule3': checked out '3ed4ac1d8dc8bd9862d9e5be2a18f22713899b85'

Creating new commits

Saving changes into the repository (creating a new commit containing changes in all staged files):

$ git commit

After this, there will be no staged files.

Git will prompt you to enter the commit message (in vi editor; ESC to exit editing mode, :wq to save changes and quit). Commit message can be specified when committing:

$ git commit -m "Code updated"

Staging, committing and specifying message can be done in one go:

$ git commit -a -m "Code updated"

If commit has not been pushed to remote yet, you can still change commit message:

$ git commit --amend

Pushing local commits to remote

If local branch is ahead of remote by 1 or more commits, they can be published (pushed to remote):

$ git push

In the previous command we didn't specify remote branch which means we assumed it's specified in the git configuration. If default remote branch has not been set specified there we might get message like this:

$ git push
warning: push.default is unset; its implicit value has changed in
Git 2.0 from 'matching' to 'simple'. To squelch this message
and maintain the traditional behaviour, use:

git config --global push.default matching

To squelch this message and adopt the new behaviour now, use:

git config --global push.default simple

When push.default is set to 'matching', git will push local branches
to the remote branches that already exist with the same name.

Since Git 2.0, Git defaults to the more conservative 'simple'
behaviour, which only pushes the current branch to the corresponding
remote branch that 'git pull' uses to update the current branch.

See 'git help config' and search for 'push.default' for further information.
(the 'simple' mode was introduced in Git 1.7.11. Use the similar mode
'current' instead of 'simple' if you sometimes use older versions of Git)

We can either set push.default or simply specify remote and branch within pull command:

$ git push origin master

To set push.default use:

$ git config --global push.default matching


$ git config --list --global Name

After publishing local commits, local branch is up-to-date with remote.

It is possible to update another branch without checking it out:

user@my_computer ~/Documents/my_dev/my_projects/ProjectA (some_branch)
$ git pull origin master

The code above will update master branch although we're on some_branch.

If you've created local branch and want to push it to the remote (e.g. origin) prior to setting upstream branch, the following error occurs:

$ git push origin
fatal: The current branch my_new_branch has no upstream branch.
To push the current branch and set the remote as upstream, use

git push --set-upstream origin my_new_branch

Do what Git suggests:

$ git push --set-upstream origin my_new_branch

Working with local changes

Modified file can be unstaged (in the working directory), staged (indexed/cached) and commited (HEAD points to its last commit). It is possible to show differences between any of these three states of the file.

To view all differences between unstaged (working) and staged (cached/indexed) version of the file:

$ git diff my_file

To view all differences between staged (cached/indexed) and last committed (HEAD) version of the file:

$ git diff --cached my_file

To view all differences between unstaged (working) and last committed (HEAD) version of the file:

$ git diff HEAD my_file

To list all staged (cached/indexed) files:

git diff --name-only --cached

To view all differences in all modified but unstaged and staged files in the current directory:

$ git diff .

If you've created some commits locally and haven't pushed them to remote your local branch will be ahead by N commits:

$ git status
On branch branch_a
Your branch is ahead of 'origin/branch_a' by 84 commits.
(use "git push" to publish your local commits)
Untracked files:
(use "git add ..." to include in what will be committed)


nothing added to commit but untracked files present (use "git add" to track)

If you want to dismiss these commits and pull the remote, you can do the following:

$ git reset --hard origin/branch_a
HEAD is now at 0cdeba9a9a Implemented new Service skeleton. Fixed typo.

Managing what shall be under revision control

It is often necessary to prevent adding under git control files with certain name and/or extension (e.g. temporary, backup, log, intermediate files etc...). Ignoring this files is set in a file called .gitignore which is located in repository's root directory. This file is like any other and can be updated and pushed to remote. To see its content we can use:

$ cat ../../.gitignore
## Ignore Visual Studio temporary files, build results

# User-specific files

# cUser-specific files (MonoDevelop/Xamarin Studio)

# Build results
[Rr]elease [Ll]ib/
[Rr]elease [Ss]tatic/
[Rr]elease [Ss]tatic [Ll]ib/
[Dd]ebug [Ll]ib/
[Dd]ebug [Ss]tatic/
[Dd]ebug [Ss]tatic [Ll]ib/

To see which files are ignored by git:

$ git status --ignored


To merge branch other_branch into current one use:

$ git merge other_branch

In this case Git will choose which merging algorithm to use. If branches did not diverge (tip of the current branch is in the chain of commits on the other branch) Git will use Fast-forward merge: it will simply move the HEAD index to the top of the other branch without creating new commits.

If branches diverged, fast-forwarding is not possible so Git uses 3-way merge. Manual solution of conflicts is necessary if different branches contain changes made on the same lines in file(s).

We can force creation of a new commit (a merge commit) even if fast-forwarding is possible:

$ git merge --no-ff other_branch

This is a preferred approach as it will keep history of merges (via merge commits).

It is possible to merge into current branch a single commit from some other branch. This is called "cherry-picking". First you have to fetch the branch where desired commit resides and you have to know the hash of that commit you want to "cherry-pick".

$ git fetch origin some_branch
$ git cherry-pick commit_hash

Cherry-picking is a merge operation. Git might not be able to merge automatically some files. Such files will be listed as "Unmerged" in git status output:

$ git status
On branch my_branch
You are currently cherry-picking commit 6d91a73b53.
(fix conflicts and run "git cherry-pick --continue")
(use "git cherry-pick --abort" to cancel the cherry-pick operation)

Changes to be committed:

modified: fileA
modified: fileB

Unmerged paths:
(use "git add ..." to mark resolution)

both modified: fileC
both modified: fileD

Untracked files:
(use "git add ..." to include in what will be committed)


We have to resolve conflicts in fileC and fileD.

Where there are merges, there are conflicts. And you don't want to scroll up and down the conflicted file in order to look for and compare lines which are different on remote and local copy. If on Windows, download and install WinMerge tool. During the installation opt in to add WinMerge's path to the system paths (Path environment variable). Once WinMerge is installed, set it as a default merge tool for Git - open C:\Users\USER\.gitconfig (we're applying this rule for all USER's repositories) and copy the following section into it:

prompt = false
keepBackup = false
keepTemporaries = false
tool = winmerge
[mergetool "winmerge"]
name = WinMerge
trustExitCode = true
cmd = "/c/Program\\ Files\\ \\(x86\\)/WinMerge/WinMergeU.exe" -u -e -dl \"Local\" -dr \"Remote\" $LOCAL $REMOTE $MERGED
tool = winmerge
[difftool "winmerge"]
name = WinMerge
trustExitCode = true
cmd = "/c/Program\\ Files\\ \\(x86\\)/WinMerge/WinMergeU.exe" -u -e $LOCAL $REMOTE

To verify that changes have been properly applied, list local git config:

$ git config --list --global
mergetool.winmerge.cmd=/c/Program\ Files\ \(x86\)/WinMerge/WinMergeU.exe -u -e -dl "Local" -dr "Remote" $LOCAL $REMOTE $MERGED
difftool.winmerge.cmd=/c/Program\ Files\ \(x86\)/WinMerge/WinMergeU.exe -u -e $LOCAL $REMOTE

To test launching WinMerge from the command line, we can diff current HEAD and its parent:

$ git difftool HEAD HEAD~1

This shall open Local file (working copy) on the Left-hand side pane and Remote on the Right-side pane of the WinMerge. (Remember it as Local-Left / Remote-Right)

In order to resolve conflicts in particular file, we can launch WinMerge as a merge tool and provide a file name (with its relative path):

USER@Machine ~/dev/project (my_branch|CHERRY-PICKING)
$ git mergetool fileC

Normal merge conflict for 'fileC':
{local}: modified file
{remote}: modified file

Local file version (working copy) opens in the Left pane and Remote file version opens in a Right pane. Change file in Left pane and save changes.

After we've resolve conflicts in fileC, Git adds that file to the list of indexed files (ready to be committed):

USER@Machine ~/dev/project (my_branch|CHERRY-PICKING)
$ git status
On branch my_branch
You are currently cherry-picking commit 6d91a73b53.
(fix conflicts and run "git cherry-pick --continue")
(use "git cherry-pick --abort" to cancel the cherry-pick operation)

Changes to be committed:

modified: fileA
modified: fileB
modified: fileC

Unmerged paths:
(use "git add ..." to mark resolution)

both modified: fileD

Untracked files:
(use "git add ..." to include in what will be committed)


Once all conflicted files are resolved, git status notifies us that we can continue cherry-picking:

USER@Machine ~/dev/project (my_branch|CHERRY-PICKING)
$ git status
On branch my_branch
You are currently cherry-picking commit 6d91a73b53.
(all conflicts fixed: run "git cherry-pick --continue")
(use "git cherry-pick --abort" to cancel the cherry-pick operation)

Changes to be committed:

modified: fileA
modified: fileB
modified: fileC
modified: fileD

Untracked files:
(use "git add ..." to include in what will be committed)


We can now complete cherry-picking:

USER@Machine ~/dev/project (my_branch|CHERRY-PICKING)
$ git cherry-pick --continue
[my_branch a9c57b587e] JIRA-1234 Fix memory leak
Author: user_name_2
Date: Thu Mar 2 16:13:51 2017 +0100
8 files changed, 79 insertions(+), 12 deletions(-)

Git configuration

Git keeps configuration at three levels: System, Global and Local. Local overrides Global and Global overrides System.


Configuration at this level applies across all repositories of all users at the local system. It is located in file /etc/gitconfig.

To list configuration that applies at this level (all repositories, all users):

$ git config --list --system


Global config file contains configuration which applies for all repositories of the currently logged user on the local machine. Its content, if only email and name are set (and are set to be same across all repositories), looks similar to this:

$ cat ~/.gitconfig
email =
name = Your Name

To list configuration that applies at this level (all repositories of current user):

$ git config --list --global Komazec

To set global email and username:

git config --global ""
git config --global "Your Name"


Local config file contains configuration which applies only for the repository it belongs to. Its content can be similar to this:

$ cat .git/config
   repositoryformatversion = 0
   filemode = true
   bare = false
   logallrefupdates = true
[remote "origin"]
   url = https://repo_domain_name/YourName/your_repo.git
   fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
   remote = origin
   merge = refs/heads/master

To list configuration that applies at this level (local repository, for current user):

$ git config --list --local

Configuration set for a particular repository (in its local config file) overrides configuration from global config file.

If you try to commit but have not set email and username, the following error occurs:

$ git commit

*** Please tell me who you are.


git config --global ""
git config --global "Your Name"

to set your account's default identity.
Omit --global to set the identity only in this repository.

fatal: unable to auto-detect email address (got 'YourName@YourName-YourComputerName.(none)')

How to set URL of the remote

If you clone remote repository, the URL you use will be set as value if remote.origin.url. That can be either HTTPS or SSH-based URL. If you used HTTPS-based URL to clone the repository but now want to switch to SSH-based URL, you can do the following:

Check what are current remotes (I am using GitHub repo hosting in the example):

$ git remote -v
origin (fetch)
origin (push)

Set new URL:

$ git remote set-url origin

Verify change:

$ git remote -v
origin (fetch)
origin (push)

How to set up SSH authentication with Git server

Create SSH key pair:

$ ssh-keygen -t rsa -b 4096 -C

Run local SSH agent:

$ eval "$(ssh-agent -s)"

Add identity:

$ ssh-add ~/.ssh/id_rsa
Identity added: /home/user_name/.ssh/id_rsa (/home/user_name/.ssh/id_rsa)

Check if have xclip installed. If not, install it:

$ sudo apt-get install xclip

Copy public key to clipboard:

$ xclip -sel clip < ~/.ssh/

..and paste it to designated place in the remote Git hosting system. (In case of GitHub, Settings-->SSH and GPG keys-->Add SSH key)

Working with tags

To pull all tags from remote:

$ git pull --prune --tags

To add a tag to the current commit:

$ git tag -a alpha-1-release -m "MyProduct Alpha 1 release"

To add a tag to the commit specified by its hash:

$ git tag -a alpha-1-release 4fceb02 -m "MyProduct Alpha 1 release"

To push tags to remote:

$ git push --tags origin master

To see tags and hashes of matching commits:

$ git show-ref --tags
05dab0b04b74bba928e97fd1305130e59692141e refs/tags/my_tag_1
47acb8f214a5a426bd68759b19154897a1e4a3d2 refs/tags/my_tag_2
6d24c915fab9a6509f1f9e7915a55b5d8de3a4da refs/tags/my_tag_3

To rename tag:

$ git tag new old
$ git tag -d old
$ git push origin :refs/tags/old
$ git push --tags

Note that colon (:) is used (it instructs Git to remove tag from remote).

To see all commits of some particular contributor:

$ git log --author=Bojan

Unix bash cheat sheet

Getting the current directory:

$ pwd

To find some executable:

$ where perl

$ which perl

Viewing the whole content of the file:

$ cat /bin/man2html

Viewing only the first line of the file:

$ head -n 1 file.txt

Viewing only the last line of the file:

$ tail -n 1 file.txt

Editing file:

$ vi /bin/man2html

Initially, vi opens in command mode.

i - to enter edit (insert) mode
ESC - to exit edit mode
:wq - write and quit
:q! - quit without saving changes

How to compile OpenVpn for Windows from source code

OpenVpn suggests cross-compilation - compiling Windows executables with Unix build toolchain. This can be accomplished either by using Linux/Unix or Cygwin on Windows.

This article demonstrates compiling OpenVpn with Cygwin on Windows.

The first step is to get build scripts from

When cloning OpenVpn repositories to Windows machine, make sure Git client for Windows does not automatically convert Unix-style line endings (LF) in source files into Windows-style line endings (CRLF). If this happens UNIX tools that run in Cygwin will report an error complaining about extra CR characters. So, when cloning, use the following command:

$ git clone --config core.autocrlf=false

Required Cygwin packages are listed here:

Package name Cygwin installer path
diffutils All --> Utils
m4All --> Interpreters
makeAll -> Devel
mingw64-i686-binutilsAll -> Devel
mingw64-i686-gcc-coreAll -> Devel
mingw64-i686-headersAll -> Devel
mingw64-i686-pthreadsAll -> Devel
mingw64-i686-runtimeAll -> Devel
mingw64-x86_64-binutilsAll -> Devel
mingw64-x86_64-gcc-coreAll -> Devel
mingw64-x86_64-headersAll -> Devel
mingw64-x86_64-pthreadsAll -> Devel
mingw64-x86_64-runtimeAll -> Devel
patchAll -> Devel
patchutilsAll -> Devel
perlAll --> Interpreters
unzipAll --> Archive
wgetAll --> Web

Download Perl script man2html and save it as a file with no extensions in /bin directory (C:\cygwin64\bin). Script URL is: If build is run with no having this script, the following error is reported at the output:

checking for man2html... no
configure: error: man2html is required for win32
FATAL: Configure pkcs11-helper

Make sure that man2html's shebang contains correct path to perl. In order to find perl's path in Cygwin we can do the following:

$ which perl

In my case shebang


has to be replaced with:


In order to build x64 version of OpenVpn go to ../OpenVpn/openvpn-build/generic and execute:

$ IMAGEROOT=`pwd`/image-win64 CHOST=x86_64-w64-mingw32 CBUILD=i686-pc-cygwin ./build

A bit about Cygwin

Checking whether some particular package has been installed (e.g. ca-certificates):

$ cygcheck -c ca-certificates
Cygwin Package Information
Package Version Status
ca-certificates 2.9-1 OK

How to create and submit Git patch

Some open-source projects prefer submitting Git patch files to pull requests.

Linux kernel:

Tuesday, 23 August 2016

Why is async void bad?

Methods returning void are not awaitable. await operator can be applied only to methods which are returning Task or Task

Let's assume that method Bar is async void. Consequences of  having method Foo calling method Bar are the following:

  • This is a fire and forget model: Foo can't get information when Bar terminates as it can't await on async void method. Foo continues to run before Bar call is completed.
  • If Bar throws an exception, Foo can't catch it as there is no Task object to carry the exception object.
For these reasons async void methods shall be avoided. But this rule has a single exception; top-level events (e.g. GUI events) of void type can be async,