Git notes

From Noah.org
Revision as of 10:36, 4 April 2016 by Root (talk | contribs) (→‎show ahead of origin)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search


Contents

git notes

Kernel.org git QuickStart

Show what changed when printing the log (diff/patch view)

You want to see the actual lines of code changed with the log. This is useful for searching for code that may no longer exist in the current revision.

git log -p

show previous revisions of a file

This shows the current version of a given file in the current directory.

git show HEAD~0:./FILENAME

This shows the previous version of a given file in the current directory.

git show HEAD~1:./FILENAME

diff version before last commit

If you already did a commit, this will show you what that commit changed.

git diff HEAD~1 FILENAME

High level view of all changes, including merges

git log --oneline --graph --all

pretty printing upstream tracked branches

# git for-each-ref --format='%(refname:short) -up-> %(upstream:short)' refs/heads | column -t
develop           -up->  origin/develop
master            -up->
release-tag1      -up->  origin/release-tag1
release-tag2      -up->  origin/release-tag2

checkout remote tracked branch

git fetch -a
git checkout develop 

set upstream branch for local branch that has no tracking

You ran git branch release-tag2, but didn't specify an upstream tracking branch. To fix this, first list your branches and the associated upstream branch to see where you are, then use git branch again to set the upstream tracking branch; finally, list your branches again to see that it is now tracking upstream.

# git for-each-ref --format='%(refname:short): %(upstream:short)' refs/heads
develop: origin/develop
master:
release-tag1: origin/release-tag1
release-tag2:

# git branch -u origin/release-tag2 release-tag2
Branch release-tag2 set up to track remote branch release-tag2 from origin by rebasing.

# git for-each-ref --format='%(refname:short): %(upstream:short)' refs/heads
develop: origin/develop
master:
release-tag1: origin/release-sprint49
release-tag2: origin/release-tag2

pull and push errors when working in a clone of an empty repository

If you are getting errors like No refs in common and none specified, failed to push some refs, and Your configuration specifies to merge with the ref 'master' from the remote, but no such ref was fetched. then the fix is easy (run git push origin master). The reason this happens is because your cloned repository is so new that is doesn't even have branch definitions.

$ git pull
Your configuration specifies to merge with the ref 'master'
from the remote, but no such ref was fetched.
$ git push
No refs in common and none specified; doing nothing.
Perhaps you should specify a branch such as 'master'.
fatal: The remote end hung up unexpectedly
error: failed to push some refs to 'git@git.noah.org:dotfiles'

The solution is to simply run this command:

$ git push origin master

Search for deleted files in version history (search for all the times the file was changed)

A long time ago someone removed or moved a file. You want to go back to that old version to research the code.

git log -- rootfs/etc/skel/.bashrc

You can also search by the leading directory path even though git doesn't think about directories. For example, search for when anything from rootfs/etc/skel was deleted:

git log -- rootfs/etc/skel/.bashrc

git checkout old revision by refid or date.

This will show you the refids of revisions in a date range. Then you can pick a revision and check it out.

git log --since='2013-12-01' --until='2013-12-25'
git checkout ff009a rootfs/etc/skel/.bashrc

It is also possible to checkout by date. Note that in this example the file target is just a . (period). This tells git to checkout the entire tree at the given version (or the given age, in this case).

git checkout master@{1 month 2 weeks 3 days 1 hour 1 second ago} .

Show how local refs map to remote

git for-each-ref --format='%(refname:short): %(upstream:short)' refs/heads

Can also be done for a single local branch using config:

git config branch.${BRANCH_LOCAL}.remote


delete local and remote branches

Delete a local branch.

git branch -d branch_name

Delete a remote branch. Note the cryptic syntax with the :. Remember, this is dangerous.

git push origin :branch_name

git pruning remote branches

If a remote branch has been pulled into your local repository and then subsequently removed from the remote then your local copy of the branch will remain until you prune it. The git remote prune command can be used to clean up stale branches. Use the --dry-run option to list the stale branches that would be deleted.

git remote prune origin --dry-run
# then
git remote prune origin

git push a bundle

Sometimes you cannot directly push to a remote and the remote cannot pull from you. This can also happen if you clone from a repository that has a branch checked out (the remote is non-bare). The solution is to create a bundle. This is what would have been pushed to the remote. You can then transfer this bundle to the remote somehow (email, scp, etc.) and have the remote pull the bundle.

The main concern is specifying the range of commits that you want to bundle because git has no way of knowing how far back in time it was when your copy and the remote were last identical. If you don't specify how far back in history to bundle then the default is to bundle the entire history. This is equivalent to making an archive of the entire repository. Luckily, the bundle command allows you to specify a range of history by number of commits or by time.

This would bundle the last commit:

git bundle create noahs_changes.bundle --max-count=1

This bundles the last commit:

git bundle create noahs_changes.bundle HEAD^..

This bundle all commits since a given commit ID. Note that this would be every commit after the given commit ID. If you want to include the given commit ID you need to add a ^.

git bundle create noahs_changes.bundle 531a17dacdf23b9c0ebfd6b0fd60b7c41b8798ab^..

Now email or scp this bundle file to the remote. On the remote side do something like the following with the bundle. Note that FETCH_HEAD is the special location where git stores fetched objects. Notice that git log is used to examine the contents of FETCH_HEAD before it is merged.

git ls-remote .
git ls-remote noahs_changes.bundle
git fetch noahs_changes.bundle
git log -p ..FETCH_HEAD
git merge FETCH_HEAD

Or, if you trust the bundle simply do this:

git pull noahs_changes.bundle

After merging you should see that a git log on the local and remote repositories should give identical results. Note especially that the commit IDs match on both sides.

Note that git format-patch can be used for similar purposes, but it does not preserve history, so if the remote were to apply your patch you would end up with identical contents of files in the repository but with different commit IDs and history.

detached

A deteched HEAD state happens when your local working copy is not associated with any branch. This means you are looking at code that you cannot commit to any branch. This happens when you checkout a tag, or during some situations where you have a merge conflict to resolve. You can see this condition by running the following:

git checkout master^0
# or
git checkout HEAD^0

To get back to normal simply checkout the branch you were previously working on:

git checkout master

show untracked files

git ls-files --other --exclude-standard

show staged files (show added files, show cached files)

The term cached is less used now. It seems that staged is preferred. For example, compare the operation of git ls-files --cache to git diff --cached --name-only.

Git terminology can be confusing. There are synonyms for many terms. When you add a file you are adding it to the cache, which is also called stage. Some git commands even have synonyms. For example, the following two commands are identical in function. This lists the names of files that have been staged. In other words, this lists the names of files that have been added to the cache. Remember, this is what you do just prior to a commit ('git add hello_world.c).

git diff --cached --name-only
git diff --staged --name-only

I wish there was a more plumbing way to do this. This example uses the porcelain interface.

How to use git diff

git diff
shows diff between the working directory and the index. This show your working copy changes that have not been added to the index.
git diff --cached
shows diff between index and the HEAD. The HEAD is the last commit. This show what would be added by the next commit.
git diff HEAD
shows a diff between the working directory and the HEAD (the last commit).
git diff HEAD~1
If you already did a commit, this will show you what that commit changed.
git diff origin
(or git diff origin/HEAD) shows a diff between what is committed locally and the remote origin. Note that you must run git fetch or git remote update to fetch the index of the remotes. Otherwise you will only see the diff since the last time you ran a command to download the remote index. Don't use git pull in this situation because, while it will download the remote index, it will also merge and commit the diffs to your index, so then there would be no diffs to see. You can get similar information using git rev-list origin..HEAD, which will show you rev IDs (see #show ahead of origin).
git diff HEAD^ some_file.txt
shows diff of a file with a previous version.
git diff HEAD^^ some_file.txt
shows diff of a file with two versions in the past.
git diff HEAD@{3} some_file.txt
shows diff of a file three versions in the past.

If you just want to see the names of the files with diffs instead of the delta itself then add the --name-only option to git diff.

git diff --name-only origin

show the current branch and remote origin

This shows your branch while gracefully handling the case when your local is detached. This doesn't tell you anything about the origin. If you are detached then you are not tracking any remote. For testing this you can use git checkout HEAD^0 to put your working directory in a detached state. The symbolic-ref command shows which branch the given symbolic ref refers to. The HEAD symbolic ref is the working directory, so this shows which branch that the working directory is on.

( git symbolic-ref HEAD 2>/dev/null || git rev-parse HEAD 2>/dev/null ) | sed "s/refs\/heads\///"

Here are some other ways to get the branch:

git describe --contains --all HEAD
git branch 2>/dev/null | sed -e '/^[^*]/d' -e 's/\* \(.*\)/\1/'

This shows both the remote and branch you are on.

git for-each-ref --format='%(upstream:short)' $(git symbolic-ref -q HEAD)

Another way to do this is to use a combination of two commands.

REMOTE=$(git remote)
REMOTE_BRANCH="${REMOTE}/$(git rev-parse --abbrev-ref HEAD)"

Also note that if your working code is detached then the following will show HEAD instead of a remote branch:

$(git rev-parse --abbrev-ref HEAD)

Putting this all together in a script snippet:

REMOTE_BRANCH=$(git rev-parse --abbrev-ref HEAD)
BRANCH=$(git symbolic-ref HEAD 2>/dev/null | sed "s/refs\/heads\///")
if [ -z "${BRANCH}" ]; then
    BRANCH="Detached: $(git rev-parse HEAD 2>/dev/null)"
fi

Git is simple, no?

show ahead of origin

See #show the current branch and remote origin for finding REMOTE_BRANCH.

git rev-list ${REMOTE_BRANCH}..HEAD

That will list each commit ID you are ahead of the remote branch. Pipe through wc to get a count

git rev-list ${REMOTE_BRANCH}..HEAD | wc

show contents of a file at a given revision

git show ${COMMIT_ID}:${FILE_PATH}

Use git log to find a commit ID that you are interested in viewing. The use git show with the commit ID, a colon, and the filename. You may truncate the commit ID as desired.

git log ./maze.py
git show a25bc6d73d55529d26294cea96b5d740302f2130:./maze.py
git show a25bc6d7:./maze.py

If you only ask git to show the commit ID then it will display the diff of the entire commit, which may include other files.

git show a25bc6d73d55529d26294cea96b5d740302f2130

List the file names in a given commit ID

This lists the files in commit ID a25bc6d73d55529d26294cea96b5d740302f2130.

git diff-tree --no-commit-id --name-only -r a25bc6d

See what would change before a 'git pull'

The git pull command is a combination of a fetch and a merge. It is best to avoid git pull because it hides important details. Instead use git fetch, then see what changes have been made before you run a git merge into your local branch. Fetch can never mess up your local copy since it simply makes a local mirror of what is on the remote. After doing a git fetch you can use any of the following commands to examine the remote changes.

git fetch
git log HEAD..origin
git log -p HEAD..origin # shows each patch
git diff HEAD...origin # with three dots shows a single diff of all changes.
git cherry-pick

error: failed to push some refs

   33c7f02..d82b08f  dev -> dev
 ! [rejected]        release -> release (non-fast-forward)
error: failed to push some refs to 'username@git.example.com:engineering.git'
To prevent you from losing history, non-fast-forward updates were rejected
Merge the remote changes (e.g. 'git pull') before pushing again.  See the
'Note about fast-forwards' section of 'git push --help' for details.

The important thing to notice is that the dev branch succeeded, but the release branch was rejected. This can be confusing if you have the dev branch checked out. If you didn't read the message carefully you might think that your dev push was rejected. You might then do all the things you are told to do to fix the problem (git pull) on the dev branch. This, of course, will have no effect. The solution is to switch to the release branch and bring your copy up to date before pushing again.

git checkout release
git pull
git push
git checkout dev

What makes this confusing is that git pull seems to update the branch you have checked out; whereas git push will push all the branches you have edited.

git checkout

The following creates a branch, checks it out, and tracks it to a remote origin all in one step.

git checkout -b <BRANCH_NAME> origin/<BRANCH_NAME>

create from tag

git checkout <TAG_NAME) -b <NEW_BRANCH_NAME>
git push origin <NEW_BRANCH_NAME>

Push only a single branch to a remote

By default, git will push all of your local branches to remote branches. You can push only the checked-out branch with the following:

git push HEAD
# older style
git push origin release

You can set this behavior as the default with the following configuration:

git config push.default simple
# older style
git config push.default upstream

git remote

When using git-remote over ssh it seems that you have to use the full path on the remote server, and not the path relative to the user you are connecting as. Also, you must put a trailing slash on the path. For example:

git ls-remote ssh://username@git.example.org/home/username/repositorium/engineering/

find which branch has a commit ID

Sometimes I have a commit ID, but I don't know what branch it's in. The following will show which branch contains the given commit ID.

git branch --contains <HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH>

find available branches on remote

This will show which branches are available on a remote server. It will also show the latest commit ID for each branch.

git ls-remote origin

convert clean repository to 'bare'

Bare repositories on a remote can take two forms. Both of these will behave the same if you clone with git clone user@example.com:repo.

~/repo/.git/
~/repo.git/
cd repo
git config --bool core.bare true

or

mv repo/.git repo.git
git --git-dir=repo.git config core.bare true
rm -rf repo

Or do this:

git reset --hard HEAD

When pushing to a remote repository that you have cloned from you might get an error like this:

remote: error: refusing to update checked out branch: refs/heads/master
remote: error: By default, updating the current branch in a non-bare repository
remote: error: is denied, because it will make the index and work tree inconsistent
remote: error: with what you pushed, and will require 'git reset --hard' to match
remote: error: the work tree to HEAD.

Converting the remote repository to a bare repository will fix this.

git clone

git clone
git fetch
git pull

git merge

Checkout the branch that you want to merge into. In this example, I want to merge a branch named feature-pxe-boot back into master.

git checkout master

Then just merge feature-pxe-boot

git merge feature-pxe-boot

The merged files are automatically committed. All you have to do is push if you want other people to see the merged commits.

git push

git log

The default format for git log does not show the files that were modified in a commit. The following adds the list of modified files to the log output.

git log --name-status

See also #config for the alias git ll which does the same thing.

git show

git show <object>

Example, after finding the refid of a commit using git log you can show what changes were actually part of that commit.

$ git show 263fe4ca6744757f596f12750cd4a8b1412d69e8
commit 263fe4ca6744757f596f12750cd4a8b1412d69e8
Author: Noah Spurrier <noah@noah.org>
Date:   Tue Feb 19 12:19:41 2013 -0800

    Documented this feature because I forgot where I put it.

diff --git a/XenResources/config/xm4.tmpl b/XenResources/config/xm4.tmpl
index 8e949d3..d476222 100644
--- a/XenResources/config/xm4.tmpl
+++ b/XenResources/config/xm4.tmpl
@@ -17,6 +17,9 @@
   }
 }
 memory      = '{$memory}'
+# This allows you to get the name of the Xen host while inside the guest.
+# Do something like this to get the vmhost name:
+#     VMHOST=$(sed -e 's/^.*vmhost=\([^[:space:]]*\)$/\1/' /proc/cmdline)
 extra = "vmhost="+os.popen('hostname -f').read().strip()
 
 #

config

The git config command will update ~/.gitconfig.

git config --global user.name "Noah Spurrier"
git config --global user.email noah@noah.org
git config --global core.editor vim
git config --global color.ui auto
git config --global merge.tool vimdiff
git config --global push.default simple

You can also edit the ~/.gitconfig file directly. The following also contains a few simple aliases that I like to use.

[user]
    name = Noah Spurrier
    email = noah@noah.org
[core]
    editor = vim
[color]
    ui = auto
[merge]
    tool = vimdiff
[push]
    default = simple
[alias]
    # See also https://git.wiki.kernel.org/index.php/Aliases
    retrack = "!retrack() { git config \"branch.$1.remote\" $(dirname \"$2\"); git config \"branch.$1.merge\" \"refs/heads/$(basename \"$2\")\"; }; retrack"
####graph = log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative
    graph = log --graph --pretty='format:%h,%ci,%d, %s <%ae>'
    ll = log --name-status

git archive

This is like an export. It retrieves a remote git repository without the .git metadata (history).

git archive --remote=ssh://username@www.example.org/home/username/repositorium/engineering/ HEAD > git_archive.tar

You can also use this to retrieve subdirectories of repositories. The follow retrieves only the subdirectory "dotfiles". Note that the selection of subdirectory is made after HEAD::

git archive --remote=ssh://username@www.example.org/home/username/repositorium/engineering/ --prefix=dotfiles/ HEAD:dotfiles > dotfiles_archive.tar

fix commits with the wrong committer/author name or email address

This basically completely rewrites your history. All of your git ref hashes will change.

git filter-branch --env-filter 'GIT_AUTHOR_NAME="Noah Spurrier";GIT_AUTHOR_EMAIL="noah@noah.org";GIT_COMMITTER_NAME="Noah Spurrier";GIT_COMMITTER_EMAIL="noah@noah.org";' HEAD

Git Commit: git/svn commit differences are confusing to newbies

Do a `git commit -a` in most cases.

Git stages commits into an index before they are committed, so a commit is a two step process. The `git-status` command will show which modifications have been indexed for the next commit. The `git-add` command will index a modified or new file for the next commit.

A `git fetch` also is done as a two step process. I especially like this feature. When you do a `git fetch` files are pulled from a remote server, but they are not immediately merged into your working copy. I despise this about SVN. Instead the remote files (actually their diffs) are held in the index where you can browse them and choose which parts to merge into your working copy.

Notice that the message below from `git-status` says two things. It shows files that have been modified and it shows which of those changes have been added to the commit. Notice here that one file is modified, but no changes have actually been added to the commit.

$ git-status
# On branch master
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#
#       modified:   dotfiles/.vimrc
#
no changes added to commit (use "git add" and/or "git commit -a")

You can have git automatically index all modified files with `git commit -a`. This is usually what most SVN users expect.

git-svn

dcommit

  1. When you want to do "svn up", instead do "git svn rebase". If you have conflicts use `git mergetool` then `git rebase --continue`.
  2. When you have everything up-to-date do `git svn dcommit`.
  3. If git complains about files not being up-to-date do `git svn rebase` again.

VCS command translation

See also this table in Wikipedia: VCS commands

Rosetta table gives git and Subversion equivalent commands
git subversion notes
git clone url svn checkout url `git+ssh` works just like `svn+ssh`
git clone git+ssh://noah@www.example.org/home/noah/src
git pull svn update
git status svn status The output from git is more clear.
git -f checkout path svn revert path This deletes your local changes.
git add file svn add file
git rm file svn rm file
git mv file svn mv file
git commit -a svn commit
git log svn log
git show rev:path/to/file svn cat url
git show rev:path/to/directory svn list url
git show rev svn log -rrev url
git branch branch_name svn copy http://example.com/svn/trunk http://example.com/svn/branches/branch_name
git merge --no-commit branch_name svn merge -r 20:HEAD http://example.com/svn/branches/branch_name This is reason #1 why SVN sucks. Merge tracking is crap. As of version 1.5 they have some limited support for merge tracking, but it still blows.
git tag -a tag_name svn copy http://example.com/svn/trunk http://example.com/svn/tags/tag_name SVN doesn't really have tags. Most people just use copy. The downside is that people can commit to tags, which kind of defeats the purpose.

Cheat Sheet

Originally from http://cheat.errtheblog.com/s/git

Setup


git clone <repo>

 clone the repository specified by <repo>; this is similar to "checkout" in
 some other version control systems such as Subversion and CVS

Add colors to your ~/.gitconfig file:

  [color]
    ui = auto
  [color "branch"]
    current = yellow reverse
    local = yellow
    remote = green
  [color "diff"]
    meta = yellow bold
    frag = magenta bold
    old = red bold
    new = green bold
  [color "status"]
    added = yellow
    changed = green
    untracked = cyan

Highlight whitespace in diffs

  [color]
    ui = true
  [color "diff"]
    whitespace = red reverse
  [core]
    whitespace=fix,-indent-with-non-tab,trailing-space,cr-at-eol

Add aliases to your ~/.gitconfig file:

 [alias]
   st = status
   ci = commit
   br = branch
   co = checkout
   df = diff
   lg = log -p
   lol = log --graph --decorate --pretty=oneline --abbrev-commit
   lola = log --graph --decorate --pretty=oneline --abbrev-commit --all
   ls = ls-files

Configuration


git config -e [--global]

 edit the .git/config [or ~/.gitconfig] file in your $EDITOR

git config --global user.name 'John Doe' git config --global user.email johndoe@example.com

 sets your name and email for commit messages

git config branch.autosetupmerge true

 tells git-branch and git-checkout to setup new branches so that git-pull(1)
 will appropriately merge from that remote branch.  Recommended.  Without this,
 you will have to add --track to your branch command or manually merge remote
 tracking branches with "fetch" and then "merge".

git config core.autocrlf true

 This setting tells git to convert the newlines to the system’s standard
 when checking out files, and to LF newlines when committing in

You can add "--global" after "git config" to any of these commands to make it apply to all git repos (writes to ~/.gitconfig).


Info


git reflog

 Use this to recover from *major* fuck ups! It's basically a log of the
 last few actions and you might have luck and find old commits that
 have been lost by doing a complex merge.

git diff

 show a diff of the changes made since your last commit
 to diff one file: "git diff -- <filename>"
 to show a diff between staging area and HEAD: `git diff --cached`

git status

 show files added to the staging area, files with changes, and untracked files

git log

 show recent commits, most recent on top. Useful options:
 --color       with color
 --graph       with an ASCII-art commit graph on the left
 --decorate    with branch and tag names on appropriate commits
 --stat        with stats (files changed, insertions, and deletions)
 -p            with full diffs
 --author=foo  only by a certain author
 --after="MMM DD YYYY" ex. ("Jun 20 2008") only commits after a certain date
 --before="MMM DD YYYY" only commits that occur before a certain date
 --merge       only the commits involved in the current merge conflicts

git log <ref>..<ref>

 show commits between the specified range. Useful for seeing changes from
 remotes:
 git log HEAD..origin/master # after git remote update

git show <rev>

 show the changeset (diff) of a commit specified by <rev>, which can be any
 SHA1 commit ID, branch name, or tag (shows the last commit (HEAD) by default)

git show --name-only <rev>

 show only the names of the files that changed, no diff information.

git blame <file>

 show who authored each line in <file>

git blame <file> <rev>

 show who authored each line in <file> as of <rev> (allows blame to go back in
 time)

git gui blame

 really nice GUI interface to git blame

git whatchanged <file>

 show only the commits which affected <file> listing the most recent first
 E.g. view all changes made to a file on a branch:
   git whatchanged <branch> <file>  | grep commit | \
        colrm 1 7 | xargs -I % git show % <file>
 this could be combined with git remote show <remote> to find all changes on
 all branches to a particular file.

git diff <commit> head path/to/fubar

 show the diff between a file on the current branch and potentially another
 branch

git diff head -- <file>

 use this form when doing git diff on cherry-pick'ed (but not committed)
 changes
 somehow changes are not shown when using just git diff.

git ls-files

 list all files in the index and under version control.

git ls-remote <remote> [HEAD]

 show the current version on the remote repo. This can be used to check whether
 a local is required by comparing the local head revision.

Adding / Deleting


git add <file1> <file2> ...

 add <file1>, <file2>, etc... to the project

git add <dir>

 add all files under directory <dir> to the project, including subdirectories

git add .

 add all files under the current directory to the project
 *WARNING*: including untracked files.

git rm <file1> <file2> ...

 remove <file1>, <file2>, etc... from the project

git rm $(git ls-files --deleted)

 remove all deleted files from the project

git rm --cached <file1> <file2> ...

 commits absence of <file1>, <file2>, etc... from the project

Ignoring


Option 1:

Edit $GIT_DIR/info/exclude. See Environment Variables below for explanation on $GIT_DIR.

Option 2:

Add a file .gitignore to the root of your project. This file will be checked in.

Either way you need to add patterns to exclude to these files.

Staging


git add <file1> <file2> ... git stage <file1> <file2> ...

 add changes in <file1>, <file2> ... to the staging area (to be included in
 the next commit

git add -p git stage --patch

 interactively walk through the current changes (hunks) in the working
 tree, and decide which changes to add to the staging area.

git add -i git stage --interactive

 interactively add files/changes to the staging area. For a simpler
 mode (no menu), try `git add --patch` (above)

Unstaging


git reset HEAD <file1> <file2> ...

 remove the specified files from the next commit


Committing


git commit <file1> <file2> ... [-m <msg>]

 commit <file1>, <file2>, etc..., optionally using commit message <msg>,
 otherwise opening your editor to let you type a commit message

git commit -a

 commit all files changed since your last commit
 (does not include new (untracked) files)

git commit -v

 commit verbosely, i.e. includes the diff of the contents being committed in
 the commit message screen

git commit --amend

 edit the commit message of the most recent commit

git commit --amend <file1> <file2> ...

 redo previous commit, including changes made to <file1>, <file2>, etc...


Branching


git branch

 list all local branches

git branch -r

 list all remote branches

git branch -a

 list all local and remote branches

git branch <branch>

 create a new branch named <branch>, referencing the same point in history as
 the current branch

git branch <branch> <start-point>

 create a new branch named <branch>, referencing <start-point>, which may be
 specified any way you like, including using a branch name or a tag name

git push <repo> <start-point>:refs/heads/<branch>

 create a new remote branch named <branch>, referencing <start-point> on the
 remote.
 Example: git push origin origin:refs/heads/branch-1
 Example: git push origin origin/branch-1:refs/heads/branch-2

git branch --track <branch> <remote-branch>

 create a tracking branch. Will push/pull changes to/from another repository.
 Example: git branch --track experimental origin/experimental

git branch -d <branch>

 delete the branch <branch>; if the branch you are deleting points to a 
 commit which is not reachable from the current branch, this command 
 will fail with a warning.

git branch -r -d <remote-branch>

 delete a remote-tracking branch.
 Example: git branch -r -d wycats/master

git branch -D <branch>

 even if the branch points to a commit not reachable from the current branch,
 you may know that that commit is still reachable from some other branch or
 tag. In that case it is safe to use this command to force git to delete the
 branch.

git checkout <branch>

 make the current branch <branch>, updating the working directory to reflect
 the version referenced by <branch>

git checkout -b <new> <start-point>

 create a new branch <new> referencing <start-point>, and check it out.

git push <repository> :<branch>

 removes a branch from a remote repository.
 Example: git push origin :old_branch_to_be_deleted

git co <branch> <path to new file>

 Checkout a file from another branch and add it to this branch. File
 will still need to be added to the git branch, but it's present.
 Eg. git co remote_at_origin__tick702_antifraud_blocking
 ..../...nt_elements_for_iframe_blocked_page.rb

git show <branch> -- <path to file that does not exist>

 Eg. git show remote_tick702 -- path/to/fubar.txt
 show the contents of a file that was created on another branch and that 
 does not exist on the current branch.

git show <rev>:<repo path to file>

 Show the contents of a file at the specific revision. Note: path has to be
 absolute within the repo.

Merging


git merge <branch>

 merge branch <branch> into the current branch; this command is idempotent
 and can be run as many times as needed to keep the current branch 
 up-to-date with changes in <branch>

git merge <branch> --no-commit

 merge branch <branch> into the current branch, but do not autocommit the
 result; allows you to make further tweaks

git merge <branch> -s ours

 merge branch <branch> into the current branch, but drops any changes in
 <branch>, using the current tree as the new tree


Cherry-Picking


git cherry-pick [--edit] [-n] [-m parent-number] [-s] [-x] <commit>

 selectively merge a single commit from another local branch
 Example: git cherry-pick 7300a6130d9447e18a931e898b64eefedea19544


Squashing


WARNING: "git rebase" changes history. Be careful. Google it.

git rebase --interactive HEAD~10

 (then change all but the first "pick" to "squash")
 squash the last 10 commits into one big commit


Conflicts


git mergetool

 work through conflicted files by opening them in your mergetool (opendiff,
 kdiff3, etc.) and choosing left/right chunks. The merged result is staged for
 commit.

For binary files or if mergetool won't do, resolve the conflict(s) manually and then do:

 git add <file1> [<file2> ...]

Once all conflicts are resolved and staged, commit the pending merge with:

 git commit


Sharing


git fetch <remote>

 update the remote-tracking branches for <remote> (defaults to "origin").
 Does not initiate a merge into the current branch (see "git pull" below).

git pull

 fetch changes from the server, and merge them into the current branch.
 Note: .git/config must have a [branch "some_name"] section for the current
 branch, to know which remote-tracking branch to merge into the current
 branch.  Git 1.5.3 and above adds this automatically.

git push

 update the server with your commits across all branches that are *COMMON*
 between your local copy and the server.  Local branches that were never 
 pushed to the server in the first place are not shared.

git push origin <branch>

 update the server with your commits made to <branch> since your last push.
 This is always *required* for new branches that you wish to share. After 
 the first explicit push, "git push" by itself is sufficient.

git push origin <branch>:refs/heads/<branch>

 E.g. git push origin twitter-experiment:refs/heads/twitter-experiment
 Which, in fact, is the same as git push origin <branch> but a little
 more obvious what is happening.
 

Reverting


git revert <rev>

 reverse commit specified by <rev> and commit the result.  This does *not* do
 the same thing as similarly named commands in other VCS's such as "svn 
 revert" or "bzr revert", see below

git checkout <file>

 re-checkout <file>, overwriting any local changes

git checkout .

 re-checkout all files, overwriting any local changes.  This is most similar 
 to "svn revert" if you're used to Subversion commands


Fix mistakes / Undo


git reset --hard

 abandon everything since your last commit; this command can be DANGEROUS.
 If merging has resulted in conflicts and you'd like to just forget about
 the merge, this command will do that.

git reset --hard ORIG_HEAD

 undo your most recent *successful* merge *and* any changes that occurred
 after.  Useful for forgetting about the merge you just did.  If there are
 conflicts (the merge was not successful), use "git reset --hard" (above)
 instead.

git reset --soft HEAD^

 forgot something in your last commit? That's easy to fix. Undo your last
 commit, but keep the changes in the staging area for editing.

git commit --amend

 redo previous commit, including changes you've staged in the meantime.
 Also used to edit commit message of previous commit.


Plumbing


test <sha1-A> = $(git merge-base <sha1-A> <sha1-B>)

 determine if merging sha1-B into sha1-A is achievable as a fast forward;
 non-zero exit status is false.


Stashing


git stash git stash save <optional-name>

 save your local modifications to a new stash (so you can for example
 "git svn rebase" or "git pull")

git stash apply

 restore the changes recorded in the stash on top of the current working tree
 state

git stash pop

 restore the changes from the most recent stash, and remove it from the stack
 of stashed changes

git stash list

 list all current stashes

git stash show <stash-name> -p

 show the contents of a stash - accepts all diff args

git stash drop [<stash-name>]

 delete the stash

git stash clear

 delete all current stashes


Remotes


git remote add <remote> <remote_URL>

 adds a remote repository to your git config.  Can be then fetched locally.
 Example:
   git remote add coreteam git://github.com/wycats/merb-plugins.git
   git fetch coreteam

git push <remote> :refs/heads/<branch>

 delete a branch in a remote repository

git push <remote> <remote>:refs/heads/<remote_branch>

 create a branch on a remote repository
 Example: git push origin origin:refs/heads/new_feature_name

git push <repository> +<remote>:<new_remote>

 replace a <remote> branch with <new_remote>
 think twice before do this
 Example: git push origin +master:my_branch

git remote prune <remote>

 prune deleted remote-tracking branches from "git branch -r" listing

git remote add -t master -m master origin git://example.com/git.git/

 add a remote and track its master

git remote show <remote>

 show information about the remote server.

git checkout -b <local branch> <remote>/<remote branch>

 Eg git checkout -b myfeature origin/myfeature
 Track a remote branch as a local branch.
 

git pull <remote> <branch> git push

 For branches that are remotely tracked (via git push) but
 that complain about non-fast forward commits when doing a 
 git push. The pull synchronizes local and remote, and if 
 all goes well, the result is pushable.

Submodules


git submodule add <remote_repository> <path/to/submodule>

 add the given repository at the given path. The addition will be part of the
 next commit.

git submodule update [--init]

 Update the registered submodules (clone missing submodules, and checkout
 the commit specified by the super-repo). --init is needed the first time.

git submodule foreach <command>

 Executes the given command within each checked out submodule.

Remove submodules

  1. Delete the relevant line from the .gitmodules file.
  2. Delete the relevant section from .git/config.
  3. Run git rm --cached path_to_submodule (no trailing slash).
  4. Commit and delete the now untracked submodule files. 

Patches


git format-patch HEAD^

 Generate the last commit as a patch that can be applied on another
 clone (or branch) using 'git am'. Format patch can also generate a
 patch for all commits using 'git format-patch HEAD^ HEAD'
 All page files will be enumerated with a prefix, e.g. 0001 is the
 first patch.

git am <patch file>

 Applies the patch file generated by format-patch.

git diff --no-prefix > patchfile

 Generates a patch file that can be applied using patch:
   patch -p0 < patchfile
 Useful for sharing changes without generating a git commit.

Git Instaweb


git instaweb --httpd=webrick [--start | --stop | --restart]


Environment Variables


GIT_AUTHOR_NAME, GIT_COMMITTER_NAME

 Your full name to be recorded in any newly created commits.  Overrides
 user.name in .git/config

GIT_AUTHOR_EMAIL, GIT_COMMITTER_EMAIL

 Your email address to be recorded in any newly created commits.  Overrides
 user.email in .git/config

GIT_DIR

 Location of the repository to use (for out of working directory repositories)

GIT_WORKING_TREE

 Location of the Working Directory - use with GIT_DIR to specifiy the working
 directory root
 or to work without being in the working directory at all.