Author : Jike Song jike.song@intel.com Last Update : 05/04/2016
* The 1st DVCS: Sun WorkShop TeamWare
	- 1990's
	- Larry McVoy
* BitKeeper
	- Born 1998
	- Larry McVoy
	- Used to maintain Linux Kernel during 2002~2005
* The 2005 Storm
	- Challenge from Richard Stallman et al.
	- Andrew Tridgell's Reverse Engineering
	- Larry: BitKeeper became unavailable
	- People tried to develop alternatives:
		1) Git. By Linus Torvalds, 7 April 2005
		2) Mercurial. By Matt Mackall, 19 April 2005
* Initial GIT
	* taken ~10 days to take shape
	* the name explanation from README:
		GIT - the stupid content tracker
	  "git" can mean anything, depending on your mood.
	   - random three-letter combination that is pronounceable, and not
	     actually used by any common UNIX command.  The fact that it is a
	     mispronounciation of "get" may or may not be relevant.
	   - stupid. contemptible and despicable. simple. Take your pick from the
	     dictionary of slang.
	   - "global information tracker": you're in a good mood, and it actually
	     works for you. Angels sing, and a light suddenly fills the room.
	   - "goddamn idiotic truckload of sh*t": when it breaks
- Git is a DVCS(Distributed Version Control System)
- All copies of a repo are *exactly* the same
- Git is highly integrated with a lot of utilities in shell environment
- Always install the all-in-one package:
	# apt-get install git-all
	# yum install git-all
- Unfriendly for beginners
	"You can do things so many ways." - Linus Torvalds on Git
	"His latest cruel act is to create a revision control system
	which is expressly designed to make you feel less intelligent
	than you thought you were."  - Andrew Morton on Linus
FYI: man 7 gitglossary
- working tree
	Dirs & Files you actually see in the filesystem.
- DAG (commit object database)
	The metadata of your git repository. All objects are linked
	together in a DAG (Directed Acyclic Graph).
- INDEX
	The cache between your working tree and DAG.
- HEAD
	The newest commit of *current* branch.
To illustrate:
		+----------+
		| working  |
		| tree     |----------+
		+----------+          |
		     |                |
		     | add            |
		     |                |
		     v                |
		+----------+          |
		|  INDEX   |          | commit -a
		+----------+          |
		     |                |
		     | commit         |
		     |                |
		     v                |
		+----------+          |
		| commit   |          |
		| object   |<---------+
		| database |
		+----------+
	Figure 1: How your "add/commit" works
	"git add"	-  add your changes from working tree, to index
	"git commit"	- commit your changes in index, to DAG, thereby form a new HEAD
	"git commit -a"	- commit your changes in both working tree and index
		+----------+
		| working  |
		| tree     |----------+
		+----------+          |
		     |                |
		     | diff           |
		     |                |
		+----------+          |
		| INDEX    |          | diff HEAD
		+----------+          |
		     |                |
		     | diff --cached  |
		     |                |
		+----------+          |
		| commit   |          |
		| object   |----------+
		| database |
		+----------+
	Figure 2: How your "diff" works
	"git diff"		- diff your working tree against index
	"git diff --cached"	- diff your index with HEAD
	"git diff HEAD"		- diff your working tree with HEAD
To illustrate, let's assume that there are 2 machines:
	* The machine "server", with a git repository: "warehouse",
              with a branch: "twig";
	* The machine "client", on which we cloned "warehouse";
              +---------------+
              | local branch  |<---.
              | "twig"        |---. \
              +---------------+    \ \
                        |           \ \
                        |            \ \
                        |             \ \
"warehouse" on server   |              \ \
------------------------|---------------\-\------------------------
"warehouse" on client   |                \ \ push
                        | fetch      pull \ \
                        |          (fetch+ \ \
                        v           merge)  \ \    +--------------+
             +---------------+               \ *---| local branch |
             | remote branch |   merge        *--->| "twig"       |
             | "origin/twig" |-------------------->|              |
             +---------------+                     +--------------+
              remote "origin"
		Figure 3: Basic remote tracking workflow
	* "remote" is a git keyword, a "remote" stands for a remote
	  git repo (an URL);
	* "origin" is not a keyword: it's simply the default
	  "remote" (determined at "git clone");
	* "origin/twig" of client, is the mirror of "twig" of server;
	* on client, "git pull" ==
		git fetch + git merge origin/twig	//by default
		git fetch + git rebase origin/twig	//pull --rebase
fast-forward
	Your local branch "twig", is a proper subset of the remote branch "origin/twig".
	Merging "twig" with "origin/twig" will be called "fast-forward": it simply
	update "twig" to "origin/twig", not generating a merge commit.
refspec
	You want to push "twig" of client, to "twig" of server:
		$ git push origin twig:twig
	However, if you want to push it to generate a new branch "new_twig" on server:
		$ git push origin twig:new_twig
	Add if you want to push a particular commit to generate a new branch:
		$ git push origin master~10:new_twig
	Here "origin" specifies which remote the target is;
	"foo:bar" is the refspec: "foo" identifies the source revision of the client;
	"bar" identifies the target branch name oof the server.
	To delete the "twig" branch from server:
		$ git push origin :twig
bare repo
	A git repo without working tree or INDEX, only metadata.
	If a repo is to be shared by multiple users, it should be bare.
	git init --bare
	git clone --bare
To illustrate:
	origin/twig	A1--A2--A3-|-B1--B2--B3
				   |
	twig		A1--A2--A3-|-[X]
		[X] If you do a "git merge" here, it's a fast-forward.
	origin/twig	A1--A2--A3-|-B1--B2--B3
				   |           \
				   |            \
	twig		A1--A2--A3-|-C1--C2--C3--[X]--M1--
		[X] If you do a "git merge" here, it's a merge, will generate
		    a "merge commit" M1, with 2 parents: B3 and C3.
	origin/twig	A1--A2--A3-|-B1--B2--B3
				   |           \
				   |            \
	twig		A1--A2--A3-|-C1--C2--C3--[X]--
				   |-B1--B2--B3--(C1)--(C2)--(C3)
		[X] if you do a "git rebase" here, by default it will get
		    B1-B2-B3 at first, then take it as the new "base", and
		    place C1-C2-C3 upon that.
			Figure 4: fast-forward, merge, rebase
FYI WIP == Work In Progress
//to save the changes
$ git stash [save]
//to list your stashes
$ git stash list
//show a particular stash
$ git stash show -p stash@{2}
//apply a particular stash
$ git stash apply stash@{2}
//drop a particular stash
$ git stash drop stash@{2}
//pop from the stash stack
//== git stash apply stash@{0} + git stash drop stash@{0}
$ git stash pop
//drop all stashes
$ git stash clear
"git bundle" backups your repository *with* metadata:
	//backup your repo into a single file
	$ git bundle create /tmp/warehouse.bundle --all
	//restore your repo from a single file
	$ git clone /tmp/warehouse.bundle
"git archive" exports your repository *without* metadata:
	//archive your code as a bzipped tarball
	$ git archive --format=tar --prefix=linux-4.5/ v4.5 | bzip2 > /tmp/linux-4.5.tar.bz2
	//archive your code to a directory
	$ mkdir /tmp/linux-4.5
	$ git archive v4.5 | tar -xf - -C /tmp/linux-4.5
	NOTE: Use "HEAD" instead of the tag to archive current branch.
$ cat .git/COMMIT_TEMPLATE
FIX BUG: PLACEHOLDER(remove this line if this is *NOT* a bugfix)
$ grep template .git/config
template = .git/COMMIT_TEMPLATE
With configurations above, whenever you run "git commit -e", the editor
will have the template file read in.
Git tracks regular files only. To track an empty directory, you need to do
something like:
	$ mkdir emptydir
	$ echo "!.gitignore" > emptydir/.gitignore
	$ git add emptydir
That is, tell git to track a ".gitignore" file, which tells git to ignore
everything but itself.
FYI	".gitignore" is a regular file tracked by git; ".git/info/exclude"
	is a git configuration file without being tracked.
//before removal, backup your files
$ mkdir /tmp/backup
$ git ls-files --others --exclude-stardard -z |cpio -pmd0 /tmp/backup
//remove untracked files
$ git clean -d -f
//diff a particular file between 2 branches
$ git diff master staging fs/ext4/inode.c
//diff two branches
	$ git diff master staging
or:
	$ git diff master..staging
//diff what's in staging since it divorced from master
$ git diff master...staging
Adding the following function to your ~/.bashrc:
	parse_git_branch()
	{
		git branch 2>/dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/(\1) /'
	}
	export PS1="\$(parse_git_branch)$PS1"
If you enter a dir or subdir of a git repo, bash will show:
		(staging) [user@host dir]$
FYI $HOME/.gitconfig is global, while “.git/config” is repository wide.
$ cat ~/.gitconfig
[user]
	name = Jike Song
	email = jike.song@intel.com
[core]
	filemode = true
	bare = false
	pager = less -NFL
	editor = vim -c 'set ft=diff' -c 'set spell'
	gitproxy = none for intel.com
	gitproxy = /usr/bin/socks-gw
	quotepath = false
[color]
	diff = true
	status = true
	interactive = true
	branch = true
	grep = true
[daemon]
	receivepack = false
[gc]
	auto = true
[alias]
	co = checkout
	br = branch
	st = status
	df = diff
	desc = describe
	changelog = log ORIG_HEAD.. --no-merges
	outgoing = log origin/master..HEAD
	shrink = gc --aggressive --prune=all
	ignored = ls-files --others -i --exclude-standard
[push]
	default = current
[sendemail]
	smtpserver = smtp.intel.com
	smtpport = 25
	thread = true
	chainreplyto = false
git rebase
git reset
git reflog
git am, git cherry-pick
git send-email
git grep
git ls-files
git merge-base
git submodule
Wikipedia:
	https://en.wikipedia.org/wiki/Git_(software)
10 years git interview:
	https://www.linux.com/blog/10-years-git-interview-git-creator-linus-torvalds
Google Tech Talk: Linus Torvalds on Git:
	https://www.youtube.com/watch?v=4XpnKHJAok8
Pro Git:
	https://git-scm.com/book/en/v2
RTFM
	man git
	{git source}/Documentation
rypress
http://rypress.com/tutorials/git/index