If you get the following error:
$ git checkout ModuleA/Project2/JIRA-123
error: Your local changes to the following files would be overwritten by checkout:
Module2/SomeDir/SomeFile.cpp
Please commit your changes or stash them before you switch branches.
Aborting

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).

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

Sometimes we have a bunch of files modified but want to stash only some of them (and possibly discard the other). For example, we have modified many files but want to stash only those in solution1/project1:
~/dev/projects (branchA)
$ git status
On branch branchA
Your branch is up-to-date with 'origin/branchA'.
Changes not staged for commit:
(use "git add ..." to update what will be committed)
(use "git checkout -- ..." to discard changes in working directory)
(commit or discard the untracked or modified content in submodules)
...
modified: tools/gadget/file1
modified: solution1/project1/file2
modified: solution1/project1/file3
modified: solution1/project1/file4
modified: web/src/file5
...

Since Git version 2.13 it is possible to use git stash command and specify which files shall be stashed (note that path to each file has to be specified so includes all directories within the root repo directory otherwise you'll get error message like error: pathspec 'A/b' did not match any file(s) known to git. Did you forget to 'git add'?):
~/dev/projects (branchA)
$ git stash push solution1/project1/file2 solution1/project1/file3 solution1/project1/file4
Saved working directory and index state WIP on branchA: 64807ad229 some_commit_comment

We can verify that new stash is on the top of the list of all stashes on the current branch:
$ git stash list
stash@{0}: WIP on branchA: 64807ad229 some_commit_comment
stash@{1}: WIP on my_branch: 6d94b73b53 JIRA-123 Fixed memory leak

Getting SHA-1 of the last commit on the current branch:
$ git rev-parse HEAD
e39616c0cc351c027cff762008b2da77ee1cc6cc

Getting short version of the hash:
$ git rev-parse --short HEAD
e39616c0cc

To see what has changed in the commit with id 'commit_hash':
$ 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

To display commit history, branches, merges...all in a single graph with a one line comments use this very cool command:
$ git log --oneline --abbrev-commit --all --graph

In order to stage all files (both untracked and modified but not staged files) 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

We can also use:
$ git reset HEAD some_file

...to unstage single file or:
$ git reset HEAD some_directory

...to unstage all modified files from the specified directory.

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

To do this for all files:
$ git checkout .

This will affect only files in the current directory so if you want to do this for all files in the repository, first move to the repository's root directory.

To remove all untracked files:
$ git clean -f

To check what will be removed with 'git clean' (dry run):
$ git clean -n

To remove all untracked files and directories:
$ git clean -fd

or use -fdx to remove ignored files as well.

To discard changes in ALL modified but not staged files:
$ git checkout -- .

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.

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)

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

To see the latest commit:
$ git show

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:

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

(!) NOTE: --set-upstream is not longer supported. Use --set-upstream-to:

$ git branch --set-upstream-to origin/master

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 increase the context (number of lines printed around the line with the difference) use -U:
$ git diff -U10 my_file

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

or:
$ git diff --staged my_file

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

To view all differences in all modified but unstaged and staged files in the current directory:
$ git diff .

Once you perform commit locally, you can't use just git diff to see the changes which will be pushed to the remote.
To see all differences in all files which were committed locally and same files on the remote:
$ git diff origin/my_branch HEAD

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)

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

Merging

To merge branch other_branch into current one use:
$ git merge other_branch

To merge all commits from the original branch from the point of splitting up to some commit (on the original branch) into the feature branch, it is enough to state the commit id (commit hash):
$ git merge 49aec175bad17cd00733f748a2416cb46bd1706a

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).

If there are no conflicts, merge will perform git commit as well (git might open default text editor so you can confirm or edit default commit message which is "Merge...").

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)

fileE

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:
[mergetool]
prompt = false
keepBackup = false
keepTemporaries = false
[merge]
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
[diff]
tool = winmerge
[difftool "winmerge"]
name = WinMerge
trustExitCode = true
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
Merging:
fileC

Rebasing

Beside merging, rebasing is another way to incorporate changes from one into another branch. In case of rebasing, all commits on the current branch made after the splitting from the trunk are cut off, the latest trunk state is brought to the current branch and cut off part is attached on the top of the "trunk" part. There is no "merge commit" like in the merge.

To rebase current (e.g. feature) branch onto the latest development on the main trunk (e.g. develop branch) first make sure you've updated both branches and that current branch is the feature branch, then execute:
$ git rebase dev

Global

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:

If we made a commit locally but then want to change the author (name and email address), we can fix the identity used for this commit with:
$ git commit --amend --reset-author

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: