[ About | Licence | Contacts ]
Written by Oleksandr Gavenko (AKA gavenkoa), compiled on 2024-04-01 from rev 052223c22317.


Setting up git


$ sudo apt-get install git


$ setup.exe -p git
$ apt-cyg install git

After install set up some options:

$ git config --global user.name "Oleksandr Gavenko"
$ git config --global user.mail "gavenkoa@gmail.com"

After that you should have:

$ cat ~/.gitconfig
name = Oleksandr Gavenko
mail = gavenkoa@gmail.com

git over proxy.

Only http:// protocol support proxy (not git://):

$ export http_proxy="http://username:password@proxy:port/"
$ git clone http://github.com/$user/$proj.git $proj

You can store proxy settings under repository local config file:

$ git config http.proxy http://$user:$passwd@$ip:$port

Start project with git

Setup proj space on fs:

$ mkdir proj
$ cd proj
$ git init
Initialized empty Git repository in /home/user/tmp/proj/.git/
$ ls -a
. .. .git

Add file, make changes, commit all:

$ emacs Makefile
... C-x C-c
$ emacs app.c
... C-x C-c
$ git add Makefile app.c
$ git status
# On branch master
# Initial commit
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#       new file: Makefile
#       new file: app.c

or just:

$ git add .

Commit newlly added file:

$ git commit
... Write message log ...
Created initial commit 2169263: My first commit massage.
 1 files changed, 4 insertions(+), 0 deletions(-)
 create mode 100644 app.c

Show difference

Show difference between index/stage and working tree:

$ git diff

Show difference between HEAD and index (what is going to be commited):

$ git diff --cached
$ git diff --staged


--cached and --staged are synonyms.

Show difference beetween HEAD and working tree (what is commited after git commit -a):

$ git diff HEAD
$ git diff HEAD -- $path

Show difference in changeset:

$ git show $hash

Show difference between revisions:

$ git diff $rev1..$rev2
$ git diff ORIG_HEAD..HEAD

For merge first parent is a tip where merge is performed, second is a tip of merged branch.


git show shows "combined diff": only files which were modified from all parents. git show --first-parent can be used to show how branch was chaged after merge.

Show differences to each parent for merge:

$ git show -m $hash
Difference between git HEAD and the current project state?
git show of a merge commit.

Undo tracking added file.

You do:

$ git add badfile
$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#       new file:   badfile

To stop tracking badfile do:

$ git rm --cached badfile
$ git status
# On branch master
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#       file
nothing added to commit but untracked files present (use "git add" to track)


$ git reset badfile

Committing changes

Individual file:

$ $EDITOR Makefile
$ git add Makefile
$ git diff --cached
$ git commit -m "..."

Commit all changed and previously manages files:

$ git commit -a -m "...."

Managing branches

Print current branch:

$ git branch

List all known branches:

$ git branch -a

List all known remote branches:

$ git branch -r

List all remote branches directly from remote:

$ git ls-remote
$ git ls-remote origin

List registered remotes:

$ git remote -v
$ git remote
$ git remote show

List remote branches from $REMOTE remote:

$ git ls-remote --heads $REMOTE
$ git remote show $REMOTE

Special case of above is origin remote, which is default remote:

$ git remote show origin
$ git ls-remote --heads origin


Look to [remote "..."] in ~/.git/config to find out names of possible remotes. Alternatively get list from:

$ git remote show

Getting branches pointers from default (origin) remote (without merging tracking branch):

$ git fetch

Getting branches pointers from $REMOTE remote:

$ git fetch $REMOTE

To get updated with default remote changes:

$ git pull

or specify concrete remote:

$ git pull $REMOTE
$ git pull origin

Delete local branch (-D is unsafe i.e. changes aren't pushed to any remote):

$ git branch -d $NAME
$ git branch -D $NAME

Delete remote branch:

$ git push $REMOTE --delete $BRANCH_NAME
$ git push $REMOTE -d $BRANCH_NAME
$ git push origin -d $BRANCH_NAME

To locally remove pointers to deleted remotely branches:

$ git remote update --prune
$ git remote update --prune origin


Only curtain branches fetched by default:

[remote "origin"]
url = ...
fetch = +refs/heads/*:refs/remotes/origin/*

Edit fetch value to change defaults.

Move branch pointer to arbitrary hash:

$ git branch -f $NAME $HASH

Create local branch from remote with the same name:

$ git checkout --track origin/fix

Create local branch from remote with an alternative name:

$ git checkout -b myfix origin/fix

git analog of 'hg incoming'

git does not directly support such feature. You can emulate it by:

$ git fetch
$ git log master..origin/master   # or just '..origin/master'

By previous commands you grab changes from remote server! You can apply them by pull or merge or rebase command:

$ git pull
$ git merge

To detect if remote repository have new changes:

$ git ls-remote
$ git ls-remote $upstream

View git commits

Review specific commit with:

$ git show $REV
$ git diff $REV^ $REV

Review merge commit related to specific parent:

$ git diff $REV^1 $REV
$ git diff $REV^2 $REV

$ git diff HEAD^1 HEAD
$ git diff HEAD^2 HEAD


^1 is the first parent, ^2 is the second parent, and so on.

git show command for merge commits shows only changes from conflicting hunks. It is equivalent to (lines that changed as part of the conflict resolution):

$ git diff-tree --cc $REV

Review difference between commits:

$ git $REV1 $REV2
$ git $REV1..$REV2
$ git $REV1..$REV2 -- $DIR_OR_FILE

Review history with diffs:

$ git log -p
$ git log -p $FROM_REV

Review history of merges only:

$ git log --min-parents=2 -p --cc

View unpublished git commits / analog of git 'hg outgoing'

git does not directly support such feature. Recently hg start tracking changes that pushed to any other repositories (called as public versus draft which is not yet published anywhere). You can emulate it by:

$ git fetch origin
$ git log origin/master..master
$ git log origin/master..
$ git log origin/master..HEAD
$ git log @{u}..

$ git diff origin/master..

Verbose syntax:

$ git log --branches --not --remotes
Viewing unpushed Git commits.
How can I see what I am about to push with git?

git analog of 'hg glog'

$ git log --all --graph
$ git log --all --graph --oneline
$ git log --all --graph --oneline --decorate

Add alias:

glog = log --all --graph

Git analog of 'hg rollback'

To edit commit message of last commit:

$ git commit --amend -m "$MSG"

To integrate changes into last commit (-a to avoid antecedent git add ..., --no-edit if you don't like to change commit message, otherwise external editor is opened):

$ git commit -a --amend --no-edit

To edit messages of old commits starting from $REV:

$ git rebase -i $REV

To undo latest commit:

$ git reset HEAD~1

Git analog of 'hg root'

$ git rev-parse --show-toplevel

Making local branch tracking remote

$ git branch -u upstream/foo
$ git branch -u upstream/foo foo

$ git branch --set-upstream-to=upstream/foo
$ git branch --set-upstream-to=upstream/foo foo

Showing what and how local branches are tracked:

$ git branch -vv
$ cat .git/gitconfig

Showing what remote branches tracked:

$ git remote show $remote

Undo mistaken rebase

If there are no any reset, rebase or merge afterwards the easiest way to recode to pre-rebase state is one of:

$ git rebase --abort
$ git reset --hard ORIG_HEAD

Otherwise look to:

$ git reflog

and reset to necessary head:

$ git reset --hard "HEAD@{...}"
Undoing git rebase.

Undo reset --hard

git reset --hard is destructive command without backup data.

You may find your previously added data in Git garbage:

$ git fsck --lost-found

look to files inside .git/lost-found directory.

Reviewing git reflog also may help.

Undo mistaken push

$ git reset HEAD^
$ git push --force

Alternative commands may look like:

$ git reset --hard $HASH
$ git push -u origin master --force

You can delete remote branch with syntax of appended colon before branch name:

$ git reset HEAD^
$ git push origin :$NAME
$ git push origin $NAME

Git bisect

bad changes should be later in graph history then good ones. To use alternative names:

$ git start --term-old=... --term-new=...

Start bisecting with:

$ git bisect start

Mark good and bad revisions:

$ git co vBAD
$ make test
$ git bisect bad

$ git co vGOOD
$ make test
$ git bisect good

If build/test failed to complete use:

$ git bisect skip

To restore mistakenly marked revisions:

$ git bisect log >$LOG
$ git bisect reset
$ git bisect replay $LOG

Import patch

Check patch summary:

git apply --stat my.patch

Detect possible errors during patch application:

git apply --check my.patch

Apply patch to working tree without commit:

git apply my.patch

Commit patch:

git am my.patch

Commit patch by signing you as reviewer:

git am --signoff my.patch

Debug git network operation

Git uses libcurl for network operation:

$ git ...

Push new repo to remote.

$ mkdir $REPO
$ cd $REPO
$ git init
$ git add .
$ git commit -m "Initial commit"
$ git remote add origin https://$USER:$PASS@$HOST/$REPO
$ git push -u origin master

Show heads in branch.

$ git show-ref --heads -s

Search string in file

To search string in all or specific files or working copy:

$ git grep $PATT
$ git grep -i $PATT -- '*.[ch]'

To search for string in commit messages:

$ git log --grep $PATT
$ git log --grep $PATT --all

To search in all history:

$ git log -S$PATT
$ git log --pickaxe-regex=$PATT
$ git log -G$PATT
$ git grep -i PATT $(git rev-list --all) -- '*.[ch]'


-G search occurences in diff chunks, while -S detects changes in match count.

Git Tools - Searching.
How to grep Git commit diffs or contents for a certain word?
Search all of Git history for a string?
How to grep (search) committed code in the git history?

Find most recent tag for revision.

$ git describe $REV

Many projects set tags on branches rather then mainline (for example JS/CSS projects perform build and commit binary/minified files, which unnecessary for mainline history). In this case review simplifiied history by:

$ git log --graph --all --decorate --oneline --simplify-by-decoration

List tags with dates.

$ git log --tags --simplify-by-decoration --pretty="format:%ci %d"

Update to date.

$ git checkout 'master@{1979-02-26}'
$ git checkout 'master@{1979-02-26 18:30:00}'


Create a bundle (a single file with specified Git objects, --all for complete history):

$ git bundle create $REPO.bundle --all

Recreate repository from bundle:

$ git clone $REPO.bundle $REPO_DIR


git init; git bundle unbundle $BUNDLE doesn't recreate refs, you need to use git clone instead.

Or clone without checking out working directory:

$ git clone --mirror $ORIG $DEST

Bundle is a single file, clone creates .git file hierarchy.

Using git to work with SVN offline.

Prepare SVN and git utilities:

$ sudo apt-get svn git-core git-svn

Making SVN repo:

$ cd $HOME/tmp
$ svnadmin create svn-repo
$ svn co file://$HOME/tmp/svn-repo svn-devel

$ cd svn-devel
$ mkdir tags trunk branches

$ svn add *
A         branches
A         tags
A         trunk

$ cd trunk/
$ printf "all:\n  echo XXX\n" >Makefile
$ printf "int main() {return 0;}" >main.c

$ svn add *

$ cd ..

$ svn st
A      trunk
A      trunk/main.c
A      trunk/Makefile
A      branches
A      tags

$ svn ci -m init
Adding         branches
Adding         tags
Adding         trunk
Adding         trunk/Makefile
Adding         trunk/main.c
Transmitting file data ..
  $ svn cp -m v0.0 file://$HOME/tmp/svn/trunk file://$HOME/tmp/svn/tags/v0.0
  $ svn cp -m v0.1 file://$HOME/tmp/svn/trunk file://$HOME/tmp/svn/branches/v0.1

Moving SVN changset to git repo:

$ cd $HOME/tmp
$ git svn init file://$HOME/tmp/svn git-repo
$ ls -a
.  ..  .git

$ git svn fetch
    A   trunk/main.c
    A   trunk/Makefile
W: +empty_dir: branches
W: +empty_dir: tags
r1 = 52ccd9882979dd53ec198dbac108783ec660410f (git-svn)
    A   tags/v0.0/main.c
    A   tags/v0.0/Makefile
r2 = 8ec8a772bb6f37ace56b3649066dc84e481ed427 (git-svn)
    M   trunk/Makefile
r3 = 2c169ff409ed504dd6a092b1e302beb3fd94871e (git-svn)
    A   branches/v0.1/main.c
    A   branches/v0.1/Makefile
r4 = e68d76f4ba6beea4b9059c1884c1f38ce10831a7 (git-svn)
    M   trunk/Makefile
r5 = cdde63974454b13ac53f2eeb201aa76c49fd875c (git-svn)
Checked out HEAD:
  file:///home/sasha/tmp/svn r5

or (in old git version):

$ git svn clone file://$HOME/tmp/svn git-repo

Making changes in svn:

$ cd $HOME/tmp/svn-devel/trunk
$ echo ".PHONY: clean" >>Makefile
$ svn ci -m "Added clean to phony."
Sending        trunk/Makefile
Transmitting file data .
Committed revision 6.

Making committed in git:

$ cd $HOME/tmp/git-repo/trunk
$ echo ".PHONY: all" >>Makefile
$ echo "int foo(int x) {return x+x;}" >>main.c
$ git status
# On branch master
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#       modified:   Makefile
#       modified:   main.c
no changes added to commit (use "git add" and/or "git commit -a")
  $ git commit -a -m "Bug fixed."
Created commit 222d399: Bug fixed.
 2 files changed, 2 insertions(+), 0 deletions(-)

Getting changes from SVN to git:

$ git svn rebase
  M   trunk/Makefile
r6 = 8165e9bfb38e9df09a7313d19606ec227629b670 (git-svn)
First, rewinding head to replay your work on top of it...
Applying Bug fixed.
error: patch failed: trunk/Makefile:6
error: trunk/Makefile: patch does not apply
Using index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
Auto-merged trunk/Makefile
CONFLICT (content): Merge conflict in trunk/Makefile
Failed to merge in the changes.
Patch failed at 0001.

When you have resolved this problem run "git rebase --continue".
If you would prefer to skip this patch, instead run "git rebase --skip".
To restore the original branch and stop rebasing run "git rebase --abort".

rebase refs/remotes/git-svn: command returned error: 1
  $ git add Makefile
  $ git rebase --continue
Applying Bug fixed.

and return all from git to SVN:

$ git svn dcommit
Committing to file:///home/sasha/tmp/svn ...
    M   trunk/Makefile
    M   trunk/main.c
Committed r7
    M   trunk/main.c
    M   trunk/Makefile
r7 = 68e782c8d06635f2db4dd69b9ca8599f99da22e2 (git-svn)
No changes between current HEAD and refs/remotes/git-svn
Resetting to the latest refs/remotes/git-svn

See what going to SVN repo:

$ cd $HOME/tmp/svn-devel/trunk
$ svn diff -r BASE:HEAD
Index: Makefile
--- Makefile    (working copy)
+++ Makefile    (revision 7)
@@ -6,4 +6,4 @@
 .o: .c
    $(CC) $(CFLAGS) -c -o $@ $<

-.PHONY: clean
+.PHONY: all clean
Index: main.c
--- main.c  (working copy)
+++ main.c  (revision 7)
@@ -2,3 +2,4 @@
     return 0;
+int foo(int x) {return x+x;}
  $ svn up
U    Makefile
U    main.c
Updated to revision 7.

Get latest changes from SVN and update Git repo state:

$ git svn fetch
$ git svn rebase


gitk - The git repository browser. See gitk(1).


$ sudo apt-get instal gitk


$ cd /path/to/git-repo
$ gitk