Git
Install
_$: apt-get install git
Configure
_$: git config --global user.name "John Doe"
_$: git config --global user.email john@example.com
Set your editor to vim
_$: git config --global core.editor "vim"
Create a new repository
_$: cd /srv/git
_$: mkdir repo
_$: git init --shared=true --bare ./repo
_$: chown --recursive root:gitgroup ./repo/
_$: chmod --recursive 2775 ./repo/		# Alternatively: g+ws
Clone a repository
Regular repository as root
#                 <user>@<server>       <path to repository>
_$: git clone ssh://root@git.example.com/srv/git/repo
If we run this command in the /a/b directory it will create the repository in /a/b/repo.
Regular repository as non-root
(root@_)_$: mkdir /srv/git/repo
(root@_)_$: chown user:user ./repo
(root@_)_$: su - user
(user@_)_$: cd /srv/git/repo
(user@_)_$: git clone ssh://user@git.example.com/srv/git/repo ./
If we run this command, it will also create the repository as /a/b/repo, but the permissions in that directory will be for the user user, which is the one with whom we have cloned the repository.
Mirror repository
Create a mirror repository:
_$: git clone --mirror ssh://root@git.example.com/srv/git/repo
_$: chown --recursive root:gitgroup /srv/git/repo
_$: chmod 2775 /srv/git/repo      # Set SGID
Update a mirror repository:
_$: git remote update
Users and groups
_$: adduser user
_$: addgroup gitgroup
_$: usermod user -aG gitgroup
Permissions
/srv/git:       root:gitgroup    0770
/srv/git/repo:  root:gitgroup    0770
SSH access
Generate key:
(user@workstation)_$: ssh-keygen    # no passphrase only if you now what you are doing
Copy the key to the git server:
(user@workstation)_$: ssh-copy-id .ssh/id_rsa.pub user@gitserver
Remove access with password to the user:
(root@gitserver)_$: passwd -l user
Check it is possible to connect with the key:
(user@workstation)_$: ssh user@gitserver
Remove ssh access but allow the user to work with git:
(root@gitserver)_$: mkdir /home/user/git-shell-commands
(root@gitserver)_$: cp /usr/share/doc/git/contrib/git-shell-commands/list /home/user/git-shell-commands/
(root@gitserver)_$: cp /usr/share/doc/git/contrib/git-shell-commands/help /home/user/git-shell-commands/
(root@gitserver)_$: chown -R user /home/user/git-shell-commands
(root@gitserver)_$: chmod -R u+x  /home/user/git-shell-commands
(root@gitserver)_$: which git-shell
/usr/bin/git-shell
(root@gitserver)_$: vipw
user:x:...:/usr/bin/git-shell
Migrate a repository
We will migrate a repository from the src host to the dst host:
(user@src)_$: git clone --mirror repo repo.bak
(user@src)_$: tar -cvf repo.tar repo.bak
(user@src)_$: scp repo.tar root@dst/srv/git
(user@dst)_$: tar -xvf repo.tar
(user@dst)_$: mv repo.bak repo ; rm repo.tar
(user@dst)_$: chown root:gitgroup /srv/git/repo
(user@dst)_$: chmod 0770 /srv/git
(user@dst)_$: chmod 2775 /srv/git/repo
(user@dst)_$: chmod --recursive g+w /srv/git/repo
Alternatively, we can do:
(user@dst)_$: git init --shared=true --bare repo
(user@dst)_$: ...
# See 'Create a new repository' for all steps
(user@src)_$: git remote add new_origin ssh://user@dst/srv/git/repo
(user@src)_$: git push --all new_origin
(user@src)_$: git push --tags new_origin
(user@src)_$: git remote rm origin
(user@src)_$: git remote rename new_origin origin
Change the origin path in the development host
/.../repo/.git/config:
----------------------
[core]
	repositoryformatversion = 0
	filemode = true
	bare = false
	logallrefupdates = true
[remote "origin"]
	fetch = +refs/heads/*:refs/remotes/origin/*
	url = ssh://<user>@<destination>/srv/git/<repository>
[branch "master"]
	remote = origin
	merge = refs/heads/master
If the repository is not bare, you can also do the following:
_$: git remote add <new_repo_name> <new_repo_url>
_$: git push <new_repo_name> master
_$: git remote rm origin
_$: git push <new_repo_name> master
Repository in the development host
_$: cd /home/user/code
_$: mkdir project
_$: cd project
_$: git clone ssh://git.example.com/srv/gitdata/project/
_$: ln -s /home/user/code/project /home/user/pyvenv/project
Deployment automation
a) Force to origin/master
_$: git fetch --all
_$: git reset --hard origin/master
b) Do not force to origin/master
_$: git fetch --all
_$: git pull origin/master
Branches
Create a branch:
_$: git branch <branch>
Create a local branch that tracks a branch in origin:
_$: git checkout --track origin/<branch>
Delete a local branch:
_$: git branch -d <local_branch>
_$: git branch -D <local_branch>    # Force removal even when the branch has not been updated
Delete a remote branch:
a) With the option --delete:
_$: git push origin --delete <remote_branch>
b) Without any option:
_$: git push origin :<remote_branch>
Check in which branch we are:
_$: git branch
Change to another branch:
_$: git checkout <branch>
Set a branch which tracks a remote branch:
_$: git branch --set-upstream <branch> origin/<branch>    # git 1.7
Upload a local branch to origin:
_$: git branch --set-upstream-to=origin/<branch> <branch>
Push
Push from one branch to another:
_$: git push origin <source_branch>:<destination_branch>
Merges
Up to a certain commit:
_$: git fetch
_$: git merge <sha1>
All the way:
_$: git fetch
_$: git merge origin/master
Differences
Differences between commits:
_$: git diff HEAD^    --numstat  # Last commit vs HEAD
_$: git diff HEAD     --numstat  # Working tree (staged + unstaged) vs HEAD
_$: git diff          --numstat  # Working tree (staged) vs HEAD
_$: git diff --cached --numstat  # Working tree (unstaged) vs HEAD
Clean a repository
_$: cd /srv/git/repo.git
_$: git gc
Update the date of the last commit
We can update the date of the last commit to the current date and time:
_$: git commit --amend --no-edit --date="$(date -R)"
If you find yourself doing this a lot, you can add it to your .bashrc file as an alias:
.bashrc:
--------
...
alias gupdate='git commit --amend --no-edit --date="$(date -R)"'
Delete a file from the commit history
Sources:
- https://help.github.com/articles/remove-sensitive-data
 - http://stackoverflow.com/questions/5563564/completely-remove-files-from-git-repo-and-remote-on-github
 - http://stackoverflow.com/questions/2164581/remove-file-from-git-repository-history
 - http://stubbisms.wordpress.com/2009/07/10/git-script-to-show-largest-pack-objects-and-trim-your-waist-line/
 
_$: git filter-branch         --index-filter 'git rm --cached --ignore-unmatch <file>' HEAD
_$: git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch <file>' --prune-empty --tag-name-filter cat -- --all
_$: git push origin master --force
In order for the push to work, the repository must have the fast forward enabled:
repo/.git/config:
-----------------
...
[receive]
	denyNonFastforwards = false
Force the rewriting of the repo to one branch
_$: git fetch origin master     # or: git fetch origin <branch>
_$: git reset --hard FETCH_HEAD
Move to a previous commit
_$: git log
...
_$: git reset ba59b4eee45e9a357e8ed26510250c40bcc5edf5  # Commit ID
Changes made
Yours (working tree) with respect to HEAD:
_$: git log  @{upstream}..HEAD
_$: git diff @{upstream}..HEAD              # Usual
_$: git diff --stat @{upstream}..HEAD       # With statistics
_$: git diff --name-only @{upstream}..HEAD  # Only filenames
HEAD with respect to yours (working tree):
_$: git log  HEAD..@{upstream}
_$: git diff HEAD..@{upstream}              # Unusual
_$: git diff --stat HEAD..@{upstream}       # With statistics
_$: git diff --name-only HEAD..@{upstream}  # Only filenames
Remember: HEAD –> index –> working tree
index with respect to HEAD:
_$: git diff --cached
working tree with respect to index:
_$: git diff
working tree with respect to HEAD:
_$: git diff HEAD
Some commit to another:
_$: git diff <oldest SHA> <newest SHA>
Some commit to another, just a file:
_$: git diff <oldest SHA> <newest SHA> -- <file>
Some commit:
_$: git show <commit SHA>
Save changes
Add a file:
_$: git add <file>
Commit changes
_$: git commit -m "Commit message explaining changes."
Push changes:
_$: git push origin master
Discard changes
Of all files in unstage state:
_$: git clean -df && git checkout -- .      # Run from the main directory
Of a file:
_$: git checkout -- </path/to/file>
Of a commit in master already pushed:
_$: git log                     # Find the previous commit's SHA -> fabc72b2
_$: git reset fabc72b2 --hard   # Reset to that commit
_$: git push origin +master     # Force push to master
History of a deleted file
_$: git log --all -- /path/to/file