Git Notes

Git Tutorials
Git for dummies
Git in Eclipse (EGit)
Git mini howto
Git workshop
Git Conflicts
Git topic branches
Git Notes
Git reflogs
Git submodule tutorial
Pinpoint regressions with Git
How to publish a Git repository
How to extract a subproject


Here are some common git operations for which we often find ourselves searching.

Contents

Workflow

Checkout a remote branch 'develop' and keep it linked to the origin

git checkout -t origin/develop

It should report: "Branch develop set up to track remote branch develop from origin."


List all branches (both local and remote)

git branch -a

List local branches and their corresponding upstream remote branches

git branch -vv

Revert local changes to a file (prior to commit)

git checkout file

Revert all local changes to the current subtree (prior to commit)

git checkout .

Cute hack to revert all local changes (prior to commit)

git stash git stash drop

Undo a commit

git reset --soft HEAD^

Undo multiple commits

git reset --soft HEAD@{2}

Where 2 is the number of commits to undo.


Update to latest HEAD, preserving local changes and local commits on top

git stash
git pull --rebase
git stash pop

Push changes on master to origin

git push origin master

Delete untracked files and directories

git clean -df

Interactively stage patches from changed file(s)

git add -p <path>

Roll back the last commit's changes to a particular file

git checkout HEAD@{1} -- file

Branches

Branch master to a new local branch "new_branch"

git checkout -b new_branch master

Push local branch to remote

git push -u origin new_branch

Make the current local branch start tracking a corresponding remote branch

git branch --set-upstream-to origin/new_branch

This is not necessary if you used git push -u as suggested above.

List the local branches that have already been merged to this one

git branch --merged

Diff a file between two branches

git diff branch1 branch2 -- file

Delete a branch both locally and remotely

git branch -rd origin/branch_to_kill
git branch -d branch_to_kill
git push origin :branch_to_kill

Move a commit from bad_branch to good_branch

# First cherry-pick the commit onto the correct branch:
git checkout good_branch
git cherry-pick deadbeef

# Then remove the commit from the bad branch:
git checkout bad_branch
git rebase -i
# Change the undesirable commit to "noop"

For more on branching, see Git topic branches.


Rename the current branch

git branch -m <new branch name>

Git + SVN

Clone an SVN repository to a local Git repository

git svn clone -s http://svn.code.sf.net/p/jhotdraw/svn/

Commit and push changes, even with local changes in the working copy

git commit git stash git svn dcommit git stash pop

Update to latest trunk, preserving local changes and local commits on top

git stash git svn rebase git stash pop

Searching

Recursively search for HelloWorld.file (and display the most recent commit modifying it)

git ls-tree -r HEAD | grep HelloWorld.file

Recursively search for all files containing the phrase 'import HelloWorld'

git grep 'import HelloWorld'

Recursively search for all files in any topic branch containing the phrase 'import HelloWorld'

git grep 'import HelloWorld' $(git rev-list --all --no-walk)

History

Display a log with colored word diffs

git log -p --color-words

Add -S to less to virtually wrap long lines.


Display a diff with colored words between a file in one commit and a file in another commit

git diff <commitA>:<file> <commitB>:<file> --color-words

Add -S to less to virtually wrap long lines.


Display all contributing authors of a project including their e-mail

git log --format='%aN <%ae&>' | sort -u

Respects .mailmap.


Viewing the history for a single file

git log --follow HelloWorld.file

This history is algorithmically calculated and must be carefully preserved.

Simultaneous (within a single commit) significant changes + file renaming (including relocation) can prevent the algorithm from successfully tracing the file's history, or cause it to begin tracing the wrong file.

Keeping code changes separate from renames should prevent this confusion, but it is good practice to check log --follow before pushing to a remote repository.


See commits in branch B not present in branch A

There are two main options. The first:

git log A..B

will display the different commits in full git log format. NB: the .. between commits is important to sure only the difference in commits is considered.

The second:

git cherry -v A B

will display a simple list of the different commits, one per line, with commit message and hash.


Scripts

There are some Git-related scripts available in the scijava-scripts project.


List information about all remote branches including last author, commit date and unmerged commit count

$SCIJAVA/bin/remote-branch-info.sh

Advanced and/or dangerous

Create a repository with g+w permissions

git init --shared=group

Or for a bare repository:

git init --bare --shared=group

(Bare repositories are meant for a remote server repository that all your coworkers push into and pull/fetch from.)


Push all remote branches from one remote (e.g., "origin") to another (e.g., "github")

git push github $(git for-each-ref refs/remotes/origin | \
  grep -v HEAD | \
  while read sha1 type ref
  do
    echo $ref:refs/heads/${ref#refs/remotes/origin/}
  done)

Another way to push all remote branches between remotes

eval git push github $(git for-each-ref | \
  sed -n 's/.*\t\(refs\/remotes\/origin\/\(.*\)\)$/\1:refs\/heads\/\2/p')

Fully garbage collect and compact the repository (deletes all orphaned refs!)

git reset --hard git for-each-ref --format="%(refname)" refs/original/ | \
  xargs -n 1 git update-ref -d git reflog expire --expire=now --all git gc --aggressive --prune=now

Rewriting history

Split a subdirectory into a separate git repository

See these posts on Stack Overflow:


Throw away git-svn-id metadata

git filter-branch --msg-filter ' sed -e "/^git-svn-id:/d" '

Combine the first two commits of a Git repository

See this post on Stack Overflow:


Change the author of a commit

git commit --amend --author="Author Name"

Change the author of many commits

See this post on Stack Overflow:


Merge multiple repositories

See these posts on Stack Overflow:


Tutorials

Creating a shared remote repository

ssh you@server
mkdir repos/remote.git
cd repos/remote.git
git --bare init --shared=group
logout

cd ~/local
git remote add origin ssh://you@server/home/you/remote.git
git push origin master
git config branch.master.remote origin
git config branch.master.merge refs/heads/master

Creates a bare remote repository at ssh://server/home/you/remote.git that tracks your local repository in /home/you/local. Adopted from Tim Lucas.

Displaying a filtered set of commits

Assume you want to see commits in branch stephan, but only those that are not part of the history of branch saalfeld:

git log stephan ^saalfeld

More realistically, if you want to see all the commits which are in a topic branch, but not yet merged into master:

git log --all ^master

If you want to see the changes which come from a topic branch which was merged in commit deadbeef, use this command line:

git log deadbeef^..deadbeef^2

Explanation: deadbeef is a merge commit, so its first parent (deadbeef^, can also be written as deadbeef^1) was the current HEAD when the merge was performed, and the second parent (deadbeef^2) is the tip of the branch which was merged. The argument A..B is short form of ^A B, i.e. all commits reachable from B excluding those which are also reachable from A.