Jan 15, 2015 Tag: Git

Looking for Wisdom about Git

Ongoing attempt to collect knowhow about Git. Will be updated as needed.

Updated on Jan 27, 2017

Navigate this page:

git config

git config global

Find out what settings you have:

git config -l           # list all
git config -l --local   # list only local  settings
git config -l --global  # list only global settings

Set what you need:

  git config --global alias.datetag          '!git tag dt-`date "+%Y-%m-%d-%H-%M"`'
  git config --global alias.diffns           "diff --name-status"
  git config --global alias.br               "branch"
  git config --global alias.ci               "commit"
  git config --global alias.co               "checkout"
  git config --global alias.diffns           "diff --name-status"
  git config --global alias.fap              "fetch --all --prune"
  git config --global alias.last             "log -1 HEAD"
  git config --global alias.st               "status"
  git config --global branch.autosetuprebase "remote"
  git config --global color.branch           "auto"
  git config --global color.branch.current   "yellow reverse"
  git config --global color.branch.local     "yellow"
  git config --global color.branch.remote    "green"
  git config --global color.diff             "auto"
  git config --global color.diff.frag        "magenta bold"
  git config --global color.diff.meta        "yellow bold"
  git config --global color.diff.new         "green bold"
  git config --global color.diff.old         "red bold"
  git config --global color.interactive      "auto"
  git config --global color.status           "auto"
  git config --global color.status.added     "yellow"
  git config --global color.status.changed   "green"
  git config --global color.status.untracked "cyan"
  git config --global color.ui               "auto"
  git config --global color.ui               "true"

# Windows:
# git config --global core.editor       "D:/Portable/Notepad++/notepad++.exe -multiInst -notabbar -nosession -noPlugin"

  git config --global core.autocrlf               false
  git config --global credential.helper           "cache --timeout=3600"
  git config --global diff.tool                   "p4mergetool"
  git config --global difftool.p4mergetool.cmd    "p4merge \$LOCAL \$REMOTE"
  git config --global difftool.prompt             "false"
  git config --global merge.tool                  "p4mergetool"
# git config --global mergetool.keepBackup        "false"
  git config --global mergetool.keepTemporaries   "false"
  git config --global mergetool.p4mergetool.cmd   "p4merge \$PWD/\$BASE \$PWD/\$LOCAL  \$PWD/\$REMOTE \$PWD/\$MERGED"
  git config --global mergetool.p4mergetool.trustexitcode "false"
  git config --global mergetool.prompt            "false"

  git config --global pull.rebase                 "true"
  git config --global push.default                "matching"
  git config --global push.default                "simple"
  git config --global receive.denynonfastforwards "true"
  git config --global url."ssh://marble@review.typo3.org:29418.pushinsteadof git://git.typo3.org"
  git config --global user.email                  "martin@mbless.de"
  git config --global user.name                   "Martin Bless"

# Nice logs:
  git config --global alias.lognice          "log --graph --pretty=oneline --abbrev-commit"
  git config --global alias.ln \!"git lognice"

  git config --global alias.lg \!"git lg1"
  git config --global alias.lg1 \!"git lg1-specific --all"
  git config --global alias.lg2 \!"git lg2-specific --all"
  git config --global alias.lg3 \!"git lg3-specific --all"
  git config --global alias.lg1-specific "log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(bold yellow)%d%C(reset)'"
  git config --global alias.lg2-specific "log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%aD%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n''          %C(white)%s%C(reset) %C(dim white)- %an%C(reset)'"
  git config --global alias.lg3-specific "log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%aD%C(reset) %C(bold green)(%ar)%C(reset) %C(bold cyan)(committed: %cD)%C(reset) %C(bold yellow)%d%C(reset)%n''          %C(white)%s%C(reset)%n''          %C(dim white)- %an <%ae> %C(reset) %C(dim white)(committer: %cn <%ce>)%C(reset)'"

# end

Usual local settings:

git config --local core.autocrlf                  input
# git config --local core.bare                    false
git config --local core.filemode                  false
# git config --local core.logallrefupdates        true
# git config --local core.repositoryformatversion 0

Pretty git branch graphs

See stackoverflow.com:

git config alias.lg1 "log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(bold yellow)%d%C(reset)' --all"
git config alias.lg2 "log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%aD%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n''          %C(white)%s%C(reset) %C(dim white)- %an%C(reset)' --all"
git config alias.lg \!"git lg1"

Pretty git branch graphs (improved)

See stackoverflow.com:

lg = !"git lg1"
lg1 = !"git lg1-specific --all"
lg2 = !"git lg2-specific --all"
lg3 = !"git lg3-specific --all"

lg1-specific = log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(bold yellow)%d%C(reset)'
lg2-specific = log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%aD%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n''          %C(white)%s%C(reset) %C(dim white)- %an%C(reset)'
lg3-specific = log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%aD%C(reset) %C(bold green)(%ar)%C(reset) %C(bold cyan)(committed: %cD)%C(reset) %C(bold yellow)%d%C(reset)%n''          %C(white)%s%C(reset)%n''          %C(dim white)- %an <%ae> %C(reset) %C(dim white)(committer: %cn <%ce>)%C(reset)'


Add, Undo Add


git add path/to/file
git add .

Undo add:

git reset HEAD -- path/to/file
git reset HEAD -- .

Just like git add, you can unstage files recursively by directory and so forth, so to unstage everything at once, run this from the root directory of your repository:

git reset HEAD -- .

Checkout another but do not touch the workdir

The following recipe works in Git guis as well.

Create a temporary branch:

git checkout -b temp

Make temp point to the same as the branch that you want to switch to. Don’t touch workdir:

git reset --soft TARGETBRANCH

Now branches temp and TARGETBRANCH point to the same commit. So you can just switch to the desired branch. And that’s the trick: Files in the workdir are not affected:

git checkout TARGETBRANCH

The temp branch isn’t needed any more and can be removed:

git branch -d temp

Search: https://www.google.de/search?q=git+switch+branch+keep+files

Rebase, Squash

  • http://stackoverflow.com/questions/5189560/squash-my-last-x-commits-together-using-git

    If you want to write the new commit message from scratch, this suffices:

    git reset --soft HEAD~3 && git commit

    If you want to start editing the new commit message with a concatenation of the existing commit messages (i.e. similar to what a pick/squash/squash/…/squash git rebase -i instruction list would start you with), then you need to extract those messages and pass them to git commit:

    # --soft   reset pointer, but not files
    # --edit   additionally open commit msg in editor
    git reset --soft HEAD~3 && \
    git commit --edit -m"$(git log --format=%B --reverse HEAD..HEAD@{1})"
    # or, if mybranch has an upstream set:
    git reset --soft HEAD~3 && \
    git commit --edit -m"$(git log --format=%B --reverse HEAD..mybranch@{upstream})"
    # like in
    git commit --edit -m"$(git log --format=%B --reverse HEAD..devmarble@{upstream})"

During rebase:

git rebase --abort
git rebase --continue
git rebase --skip

Remove untracked files

Do a dry-run:

git clean -f -n


git clean -f

Learn more at stackoverflow.

Revert changes

git checkout -- <filename>

git fetch origin
git reset --hard origin/master

Revert to a previous commit

Rewrite history if your commits are not pushed yet:

➜  git status
On branch master
Your branch is ahead of 'origin/master' by 7 commits.

➜  git reset --hard HEAD~7
HEAD ist jetzt at 4f0f998 [BUGFIX] Commit message

To revert already published commits: Leave them in the history. Create a new commit that exactly restores the former state. For example:

# Let's be in sync with origin
git pull

# Go back to a specific former commit and
# adjust the files accordingly
git reset --hard f414f31

# Go back in history 1 step to where we just came from
# Don't adjust files.
git reset --soft HEAD@{1}

# Make a commit with the former state of files.
git commit -m "Reverting to the state of the project at f414f31`

See also:

Check the history:

git reflog

Switch branch but keep local files

You cannot do this directly. In GIT terms you have to look at it from a different perspective. You should conceive the process as: (1) save files, (2) switch branch, (3) checkout only the files.

It can be done like this:

# create a temporary branch
git branch temp

# commit all files to temp
git add .
git commit -am "commit everything to branch temp"

# checkout the desired branch
git checkout master

# checkout ONLY the files from branch temp
git checkout temp -- .

# delete the temp branch
git branch -D temp

# end


Documentation: https://git-scm.com/docs/git-submodule

Add local submodule (from Stackoverflow:

git rm --cached one two three
git submodule add `pwd`/one
git submodule add `pwd`/two
git submodule add `pwd`/three

Example of ‘foreach’:

git reset --hard
git submodule foreach --recursive "git reset --hard"

Useful “tricks”

git add -i            # add interactively
git commit --amend    # change commit message
git commit -m "[BUGFIX] Start multiline commit message

...continue with message
...continue with message
"                        <- finish message and start commit.

git pull --ff-only     # yes, fast forward only
git pull --rebase      # ?

git branch -va         # show all branches

git diff ABC BCD --name-only  # just list the name of different files

Which commits affect this file?

git log --follow FILESPEC

To be sorted

Training, Tutorial

Working with Remotes

Add a remote source:

git remote add marble https://github.com/marble/typo3-upgradereport.git

Remove a remote source:

git remote remove marble

Pull from a foreign repo:

git remote -v
git remote add marble https://github.com/marble/typo3-upgradereport.git
git fetch marble
git checkout -b marble/marble-patch-1 --track marble/marble-patch-1
git remote -v

Create and check out branch from origin with tracking:

# Examples:
git checkout -t      origin/feature
git checkout --track origin/feature
git checkout --track origin/feature -b feature

Copy a clone to Non-Git version

cd /path/to/TYPO3.CMS
git checkout TYPO3_6-2
git pull
rsync -r --exclude="/.git" /path/to/TYPO3.CMS/  ~/htdocs/project/public_html/typo3_src-6.2dev

Which files and folders are currently in the cache?

What’s under version control?:

git ls-files

Which files and folders are currently being ignored?

Ignored files


git ls-files --others   #!!!

Run both! One is not sufficient!:

echo "" >temp.log.txt
git ls-files --others --ignored --exclude-standard --directory  >>temp.log.txt
git ls-files --others --ignored --exclude-standard >>temp.log.txt


git config --local -l | grep branch


# Add any remote repositories you want to compare:
git remote add foobar git://github.com/user/foobar.git

# Update your local copy of a remote:
# Fetch won't change your working copy.
git fetch foobar

# Compare any branch from your local repository to any remote you've added:
git diff [--name-status --name-only]  master foobar/master

# Delete remote branch
git push origin --delete <branchName>

Dmitry Dulepov writes:

If you work in a team, create many git branches and push them to the server, you may end up with many local branches that were merged and removed on the server. The following simple command will clean up your repository from local branches that track missing remote branches:

git fetch --all -p

Check your working tree

# Changes in the working tree not yet staged for the next co
# Changes between the index and your last commit;
# what you would be committing if you run "git commit" without "-a" option.
git diff --cached

# Changes in the working tree since your last commit; what you would be
# committing if you run "git commit -a"
git diff HEAD

Comparing with arbitrary commits


# Instead of the top of the current branch, compare with the top of “test” branch $ git diff test

# Instead of comparing with the top of “test” branch, compare with the top of the # current branch, but limit the comparison to the file “test”. $ git diff HEAD – ./test

# Compare the version before the last commit with the last commit. $ git diff HEAD^ HEAD

Comparing branches

# Changes between the tips of the topic and the master branches.
$ git diff topic master

# Same: Changes between the tips of the topic and the master branches.
$ git diff topic..master

# Changes that occurred on the master branch since when the topic branch was started off it.
$ git diff topic...master

Limit the diff output

# Show only modification, rename and copy, but not addition nor deletion.
$ git diff --diff-filter=MRC

# Show only names and the nature of change, but not actual diff output.
$ git diff --name-status

# Limit diff output to named subtrees.
$ git diff arch/i386 include/asm-i386

Munge the diff output

# Spend extra cycles to find renames, copies and complete rewrites (very expensive).
$ git diff --find-copies-harder -B -C

# Output diff in reverse.
$ git diff -R

git submodule

As an example, git submodule foreach 'echo $path $(git rev-parse HEAD)' will show the path and currently checked out commit for each submodule http://stackoverflow.com/questions/658885/how-do-you-get-git-to-always-pull-from-a-specific-branch

cd /path/to/repository
echo '' >temp-submodule-info.txt
git submodule foreach --recursive 'echo $path `git rev-parse HEAD`' >>temp-submodule-info.txt
git submodule foreach --recursive 'echo $path `git remote -v`'      >>temp-submodule-info.txt

Git log nice


git config --global alias.ln "log --graph --pretty=oneline --abbrev-commit"

Hashcode of last commit

echo $(git log -1 HEAD --format=format:%H)

echo $(git log -n 1    --format=format:%H)

echo $(git log -n1     --format=format:%H)

git log --pretty=format:"%h - %an, %ar : %s"
ca82a6d - Scott Chacon, 11 months ago : changed the version number
085bb3b - Scott Chacon, 11 months ago : removed unnecessary test code
a11bef0 - Scott Chacon, 11 months ago : first commit

Formatting options

Option Description of Output
%H Commit hash
%h Abbreviated commit hash
%T Tree hash
%t Abbreviated tree hash
%P Parent hashes
%p Abbreviated parent hashes
%an Author name
%ae Author e-mail
%ad Author date (format respects the –date= option)
%ar Author date, relative
%cn Committer name
%ce Committer email
%cd Committer date
%cr Committer date, relative
%s Subject

Git create a patch file

If you want to create a patch file via git diff that can be applied using patch -p0 < patchfile use the following command:

git diff --no-prefix > patchfile

To apply the patch:

patch -p0 < patchfile

If you have an existing git diff patch file that was created without the --no-prefix option, you can apply that patch via:

patch -p1 < patchfile

This will ignore the default a/ b/ source prefixes.

p4merge - visual diff tool

Download and install p4merge

Setup p4merge as a visual mergetool

git config --global merge.tool                p4mergetool
git config --global mergetool.p4mergetool.cmd "/Applications/p4merge.app/Contents/Resources/launchp4merge \$PWD/\$BASE \$PWD/\$LOCAL  \$PWD/\$REMOTE \$PWD/\$MERGED"
git config --global mergetool.p4mergetool.trustExitCode false
git config --global mergetool.keepBackup      false

Setup p4merge as a visual diff tool

git config --global diff.tool p4mergetool
git config --global difftool.p4mergetool.cmd "/Applications/p4merge.app/Contents/Resources/launchp4merge \$LOCAL \$REMOTE"

Using p4merge to resolve conflicts

When you run into a conflict when merging simply run:

git mergetool
  1. You will be prompted to run “p4mergetool”, hit enter and the visual merge editor will launch.
  2. Using the merge tool you can resolve the conflict and then save the file.
  3. After you exit the merge tool take a look back at your terminal. You will be asked if the merge was successful, choose yes if all is well or no if you need to start over.
  4. This prompting is happening because the “trustExitCode” option is turned off. Personally I always like to be asked, but you can have git just trust the exit code from the merge tool.

How to keep git log and less output on the screen

From Boris Serebrov:

When git uses less as pager the output of commands like git log disappears from the console screen when you exit from less. This is not convenient in many cases so here is how to fix this.

Just for git commands:

git config --global --replace-all core.pager "less -iXFR"

For less globally (including git) - add to .bashrc or .zshrc and so on:

export LESS=-iXFR

The options we set for less are:

-i ignore case when searching (but respect case if search
term contains uppercase letters)

-X do not clear screen on exit

-F exit if text is less then one screen long

-R was on by default on my system, something related to colors

The list of Git-aliases that Oh-My-Zsh defines


Aliases (sorted alphabetically):

alias g='git'

alias ga='git add'
alias gaa='git add --all'
alias gapa='git add --patch'

alias gb='git branch'
alias gba='git branch -a'
alias gbda='git branch --merged | command grep -vE "^(\*|\s*master\s*$)" | command xargs -n 1 git branch -d'
alias gbl='git blame -b -w'
alias gbnm='git branch --no-merged'
alias gbr='git branch --remote'
alias gbs='git bisect'
alias gbsb='git bisect bad'
alias gbsg='git bisect good'
alias gbsr='git bisect reset'
alias gbss='git bisect start'

alias gc='git commit -v'
alias gc!='git commit -v --amend'
alias gca='git commit -v -a'
alias gca!='git commit -v -a --amend'
alias gcan!='git commit -v -a -s --no-edit --amend'
alias gcam='git commit -a -m'
alias gcb='git checkout -b'
alias gcf='git config --list'
alias gcl='git clone --recursive'
alias gclean='git clean -fd'
alias gpristine='git reset --hard && git clean -dfx'
alias gcm='git checkout master'
alias gcmsg='git commit -m'
alias gco='git checkout'
alias gcount='git shortlog -sn'

compdef gcount=git

alias gcp='git cherry-pick'
alias gcs='git commit -S'

alias gd='git diff'
alias gdca='git diff --cached'
alias gdct='git describe --tags `git rev-list --tags --max-count=1`'
alias gdt='git diff-tree --no-commit-id --name-only -r'

gdv() { git diff -w "$@" | view - }
compdef _git gdv=git-diff

alias gdw='git diff --word-diff'
alias gf='git fetch'
alias gfa='git fetch --all --prune'

function gfg() { git ls-files | grep $@ }
compdef gfg=grep

alias gfo='git fetch origin'
alias gg='git gui citool'
alias gga='git gui citool --amend'

ggf() {
   [[ "$#" != 1 ]] && local b="$(git_current_branch)"
      git push --force origin "${b:=$1}"

compdef _git ggf=git-checkout
ggl() {
   if [[ "$#" != 0 ]] && [[ "$#" != 1 ]]; then
      git pull origin "${*}"
   [[ "$#" == 0 ]] && local b="$(git_current_branch)"
      git pull origin "${b:=$1}"
compdef _git ggl=git-checkout
alias ggpull='git pull origin $(git_current_branch)'
compdef _git ggpull=git-checkout
ggp() {
   if [[ "$#" != 0 ]] && [[ "$#" != 1 ]]; then
      git push origin "${*}"
   [[ "$#" == 0 ]] && local b="$(git_current_branch)"
      git push origin "${b:=$1}"
compdef _git ggp=git-checkout
alias ggpush='git push origin $(git_current_branch)'
compdef _git ggpush=git-checkout
ggpnp() {
   if [[ "$#" == 0 ]]; then
      ggl && ggp
      ggl "${*}" && ggp "${*}"
compdef _git ggpnp=git-checkout
alias ggsup='git branch --set-upstream-to=origin/$(git_current_branch)'
ggu() {
   [[ "$#" != 1 ]] && local b="$(git_current_branch)"
      git pull --rebase origin "${b:=$1}"
compdef _git ggu=git-checkout
alias ggpur='ggu'
compdef _git ggpur=git-checkout

alias gignore='git update-index --assume-unchanged'
alias gignored='git ls-files -v | grep "^[[:lower:]]"'
alias git-svn-dcommit-push='git svn dcommit && git push github master:svntrunk'
compdef git-svn-dcommit-push=git

alias gk='\gitk --all --branches'
compdef _git gk='gitk'
alias gke='\gitk --all $(git log -g --pretty=format:%h)'
compdef _git gke='gitk'

alias gl='git pull'
alias glg='git log --stat --color'
alias glgp='git log --stat --color -p'
alias glgg='git log --graph --color'
alias glgga='git log --graph --decorate --all'
alias glgm='git log --graph --max-count=10'
alias glo='git log --oneline --decorate --color'
alias glol="git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
alias glola="git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --all"
alias glog='git log --oneline --decorate --color --graph'
alias glp="_git_log_prettily"
compdef _git glp=git-log

alias gm='git merge'
alias gmom='git merge origin/master'
alias gmt='git mergetool --no-prompt'
alias gmtvim='git mergetool --no-prompt --tool=vimdiff'
alias gmum='git merge upstream/master'

alias gp='git push'
alias gpd='git push --dry-run'
alias gpoat='git push origin --all && git push origin --tags'
compdef _git gpoat=git-push
alias gpu='git push upstream'
alias gpv='git push -v'

alias gr='git remote'
alias gra='git remote add'
alias grb='git rebase'
alias grba='git rebase --abort'
alias grbc='git rebase --continue'
alias grbi='git rebase -i'
alias grbm='git rebase master'
alias grbs='git rebase --skip'
alias grh='git reset HEAD'
alias grhh='git reset HEAD --hard'
alias grmv='git remote rename'
alias grrm='git remote remove'
alias grset='git remote set-url'
alias grt='cd $(git rev-parse --show-toplevel || echo ".")'
alias gru='git reset --'
alias grup='git remote update'
alias grv='git remote -v'

alias gsb='git status -sb'
alias gsd='git svn dcommit'
alias gsi='git submodule init'
alias gsps='git show --pretty=short --show-signature'
alias gsr='git svn rebase'
alias gss='git status -s'
alias gst='git status'
alias gsta='git stash'
alias gstaa='git stash apply'
alias gstd='git stash drop'
alias gstl='git stash list'
alias gstp='git stash pop'
alias gsts='git stash show --text'
alias gsu='git submodule update'

alias gts='git tag -s'
alias gtv='git tag | sort -V'

alias gunignore='git update-index --no-assume-unchanged'
alias gunwip='git log -n 1 | grep -q -c "\-\-wip\-\-" && git reset HEAD~1'
alias gup='git pull --rebase'
alias gupv='git pull --rebase -v'
alias glum='git pull upstream master'

alias gwch='git whatchanged -p --abbrev-commit --pretty=medium'
alias gwip='git add -A; git rm $(git ls-files --deleted) 2> /dev/null; git commit -m "--wip--"'


Add global .gitignore file

See https://help.github.com/articles/ignoring-files/


touch   ~/.gitignore_global
echo >> ~/.gitignore_global
echo "*NOT_VERSIONED*" >> ~/.gitignore_global
git config --global core.excludesfile ~/.gitignore_global
git config --global -l
cat ~/.gitignore_global

Copy a folder of a repo and keep the history

From: Extract a folder from a git repo into its own repo

  1. Clone the repo:

    git clone oldrepo newrep

  2. Remove every commit except those of the subfolder:

    git filter-branch –prune-empty –subdirectory-filter MYFOLDERNAME master


Rebase when pulling

Remember these:

git pull --rebase
git config --global pull.rebase true
git config branch.BRANCH-NAME.rebase true

Remove all merged local branches

git checkout master
git branch --merged | grep -v "\*" | xargs -n 1 git branch -d



comments powered by Disqus

Previous topic

Looking for Wisdom about Fluid

Next topic

Looking for Wisdom about JQuery




Recent Posts

This Page