Daily Git
From Martin Dilger
The author tells that Git is probably the most important innovation in software development in the last 10 years.
- Quick Ref
- Basics
- Branch
- Rebase
- Remotes
- Reflog
- Interactive Rebase
- Cherry-Pick
- Hooks
- Alias
- Tags
- Flow
- Repository Splitting
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:
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:
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
GitHub Flow
There is only one rule: anything in the master branch is always deployable.
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