Here are some common git operations for which we often find ourselves searching.
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 main to origin
git push origin main 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 main to a new local branch “new_branch”
git checkout -b new_branch main 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:
- Detach subdirectory into separate Git repository
- Detach subdirectory (that was renamed!) into a new repo
- Split large Git repository into many smaller ones
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 main git config branch.main.remote origin git config branch.main.merge refs/heads/main 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 main:
git log --all ^main 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.