From Martin Dilger

The author tells that Git is probably the most important innovation in software development in the last 10 years.

Quick Ref

Push Branch to remote

git push --set-upstream origin <branch_name>

Delete Branch on remote

git push origin --delete <branch_name>

Squash

Use git rebase -i <after-this-commit> and replace pick on the second and subsequent commits with squash or fixup

Prune

Use git remote prune origin to remove local refs to remote branches that dont exists anymore

Basics

When looking at the files in the .git directory there is a config file:

$ cat config | grep url
# url = https://user@github.com/user/repo.git

The git log command shows the commit messages for one or all files. The parameter --oneline leaves out author and email:

$ git log --oneline _posts/irre.md
# 7ce9393 fix spelling
# d88cf88 irre

The git status command shows untracked or modified files.

"everything" is stored in the .git/objects/ database. An object is represented as a binary file named as the hash value of the original content and compressed with zlib. This SHA-1 hash can be created with git hash-object _posts/irre.md. There are four types ob objects: Commit, Tree, Blob and Tag. The objects can be retrieved via the hash value and pretty printed with git cat-file -p bf59ee.... Every commit references its parent commit or 0 in case of the initial commit or multiple parents in case of a merge commit.

Branch

Branching is the feature that makes git so popular and powerful.

The most upper commit of every branch is called the head. It’s hash value can be found in .git/refs/heads/ in files named like the branch. The currently checked out branch can be found in .git/HEAD.

Creating a branch:

$ git branch feature-4711
$ git branch 
#   feature-4711
# * master
$ git checkout feature-4711

Resetting the current branch to the status of before the last two commits:

$ git reset --hard HEAD~2

For merging a merge tool is needed:

$ sudo aptitude install meld
$ git config --global merge.tool meld
$ git merge feature-4711
$ git status
$ git diff
$ git mergetool
$ git status # forgot commit?
$ git log --graph

When there is no conflict a fast forward merge is done, just referencing the latest commit from the feature branch.

Rebase

Imagine you are working on a feature branch and now there a new commits on master which you would also like to have on your branch. Then you say to yourself: "I wish I would have created the feature branch today and not yesterday" A possible solution would be to merge master to the feature branch but that would lead to a dirty history (graph). So the best choice is to do a

$ git rebase master

on the feature branch. This rewrites the history as if the feature branch has been created after the desired commits on master have been taken place.

You can hardly undo a rebase. Be careful!

Remotes

A repo can have one or multiple remote repositories. It is a convention name the main remote repo “origin”.

Fetch

$ git fetch origin

Fetches all objects from the remote repo. The working directory remains unchanged.

To apply the fetched remote changes to the working dir use:

$ git merge origin/master

Pull Merge

To do fetch + merge in one step use:

$ git pull origin master

If a tracking branch is configure in .git/config it is enough to type:

$ git pull

image of origin history after pull (merge) and push:

origin history after pull (merge)

Pull Rebase

$ git pull --rebase

is also possible and does a fetch + rebase instead of merge. This linearises the history. The hash values of the commits are changed. Existing merge-commits disappear because of that. So it can be possible that conflicts must be resolved a second time. Then the rebase must be finished with

$ git rebase --continue

image of origin history after pull –rebase and push:

origin history after pull --rebase

Push

$ git push origin master

copies the local (commit-) objects to the remote repository and changes it’s HEAD-pointer to the latest commit. This is only possible if the latest remote commit has been pulled to the local repo before. And it can only be pushed to a bare repository.

A forced push is very dangerous. Data can be lost by setting the remote HEAD-pointer in non fast-forward way.

Reflog

Log of all local actions. Can be used to find commits that are no more part of the history-graph.

Interactive Rebase

Can be used to rewrite the local history:

$ git rebase -i HEAD~10

The following options are given per commit:

  • pick = keep commit as it is
  • reword = keep commit but edit commit message
  • edit = filed in the working copy can be edited
  • squash = keep commit, but meld it into previous one
  • fixup = like squash, but discard this commits log message
  • exec = rund shell script

Cherry-Pick

Can be used to copy only single commits from different branches to your current branch:

$ git cherry-pick fd5eb95

This should be done only in exceptional cases, espacially when there is a conflict you will get problems later, so a merge should be prefered.

To see which cherries (commits) from your feature branch have already been picked you can use git cherry. A minus indicates that the cherry has already been picked.

$ git cherry master
# + 8d1f690170db95684fe0efdbd3f009f1e5c5228c
# + 27e9ec0e8476695d8255309147bd282c699c1e54
# - fd5eb95743913a3fbcc501d02c12a9dbaf9a63de
# + fac3578fc67077da3d2c3261c4184ff7ae2dc5f0
# + 3f693235966ae84f22d5b42e7de827900d0c165e

Hooks

Are bash script located in .git/hooks which can be executed by git in case of various events.

Alias

Can be used as shorcuts for less typing of commands which are often needed.

$ git config alias.go "git checkout"
$ git go master
# switched to branch 'master'

Tags

Are used to mark a point in History.

Lightweight Tags

You choose a label which references the hash value of a commit. So it can found easily later.

$ git tag fb-4711
$ ls .git/refs/tags
# fb-4711
$ cat .git/refs/tags/fb-4711
# 79e9ec0e8476695d8255309147bd282c699c1e54

Annotated Tags

Are stored as objects in the git database. They contain the date and name and email of the tagger and they have a message. Annotated Tags are checksummed and can be signed and verified with GPG

$ git tag -a v1.4 -m "my version 1.4"

Flow

A branching model for teams and projects where releases / deployments are made regularly.

Git Flow

$ apt-get install git-flow

Link

GitHub Flow

There is only one rule: anything in the master branch is always deployable.

Link

Repository Splitting

Sometimes it is necessary to create a new repo from a sub-directory of an existing repository.

$ git clone https://github.com/dilgerma/Daily-Git-Distributed-Repositories-Example.git dilgerma-distributed-src
$ git subtree split --prefix=tools -b repo/tools
# now there is local branch which only contains files from the folder tools
# then one needs to create an empty bare repo add it as remote:
$ git remote add tools-remote ../tools-remote.git/
# then checkout and push the new subtree-branch
$ git checkout repo/tools
$ git push tools-remote repo/tools
# cd to ../tools-remote.git/ and rename the branch
$ git branch -m repo/tools master
# then delete directory and branch from the original repo

Submodules vs subtree pull/push

for including external repos in your repo