Contents
See also: CodingStyle/Git
Workflow for gitorious and github
Initial checkout:
See Configuring a remote for a fork
When needing to merge upstream changes back into master:
Cookbook
Delete remote branch
git push origin :name-of-remote-branch
# OR
git push origin --delete name-of-remote-branch
Reverting changes
Amend the previous commit that has not been propogated (i.e. undo it, then start a new one with the pending changes in the index):
git commit --amend -a -m "New commit message"
Undo a commit that has not been propagated:
git reset --soft HEAD^
just changes the repository without changing the files you've edited on disk. However:
git reset --hard HEAD^
will reset both repository and revert files.
Once a commit that has been propagated, there is no way to undo. However, the following will create a new commit undoing the previous commit's changes:
git revert HEAD
To only change a commit message for a commit that has not been propogated:
git commit --amend
Pull with rebase instead of merge
git pull --rebase
Configure a branch to always do a rebase instead of a merge:
git config branch.$BRANCH_NAME.rebase true
Enforce .gitignore
Remove files from the repository that should have been ignored by .gitignore:
git rm -r --cached . git add . git status git commit -m ".gitignore is now working"
Search
# Search commit log (i.e. messages) for given needle in all branches
git log --all --grep='needle'
# As above, but search reflog (much slower)
git log -g --grep='needle'
# Search contents of commits
git grep -F 'needle' $(git rev-list --all)
# Search contents of commit in a large repository
git rev-list --all | parallel -j4 -k -X git grep --color=always -F 'needle'
# Search branches (has problems)
git branch -a | tr -d \* | parallel -k git grep --color=always -iF 'needle'
Ignore whitespace bullshit
# Ignore white space when pulling or merging git pull -Xignore-space-change git merge -Xignore-space-change git merge -Xignore-all-space # Ignore white space changes when diff'ing git diff --ignore-space-change
Rebase a branch
# Without having branch-you-want-to-rebase checked out
git rebase branch-you-want-to-rebase branch-to-rebase-from
# With having branch-you-want-to-rebase checked out
git checkout branch-you-want-to-rebase
git rebase branch-to-rebase-from
Rebase off a branch that itself had been rebased (keep the un-rebased branch around as old-branch-to-rebase-from):
git rebase --onto branch-to-rebase-from old-branch-to-rebase-from branch-you-want-to-rebase
If you want to rebase but get updated stamps (do this independently of reordering/merging commits with git rebase -i:
git rebase --ignore-date
Interactive rebase
Interactive rebase for only certain commits:
# Rebase only the last 2 commits
git rebase -i HEAD~2
# All commits that are on feature branch, but not on trunk branch
git rebase -i trunk
Retroactively sign all previous commits
Uses rebase, so this will invalidate other checkouts.
git rebase --exec 'git commit --amend --no-edit --no-verify -S' -i --root
git rebase --committer-date-is-author-date -i --root
# check
git log --pretty=fuller
Source: Git sign previous commits keeping dates by Peter Babič
Problems
Cannot lock ref error
error: cannot lock ref 'refs/remotes/origin/bugfix/SPL-178301-lookups-cache-results-incorrectly':
is caused by your local repository's copy of the origin repository's branches getting corrupted. To fix:
git remote prune origin
It will not touch any of your local branches with your edits, or anything remote, just your local repo's knowledge of remote branches.
Per-repository user settings
git config user.name 'Samat K Jain'
git config user.email 'nobody@example.com'
Cleaning
# Discard all unstaged changes in CWD
git checkout -- .
# Remove untracked files and directories, dry run. `-n` for dry run.
git clean -df -n
GPG Signing
Submodules
In the below, TARGET_DIR is something like vendor/some-package.
Cloning a project w/ submodules
First clone:
git clone --recurse-submodules …
If you forgot --recurse-submodules, can run:
git submodule update --init --recursive
Adding submodules to a project
git submodule add $REPOSITORY_URL $TARGET_DIRECTORY
You need to start tracking the new .gitmodules file (just like .gitignore), as well as a "file" representing the submodule. git status will show it as $TARGET_DIRECTORY.
git add .gitmodules $TARGET_DIRECTORY
git commit -m 'Started tracking $REPOSITORY_URL as submodule'
Update submodules
Go to each submodule, fetch, and update:
git submodule update --remote --recursive
# git commit
Remove submodules
Go to each submodule, fetch, and update:
git submodule rm $TARGET_DIR
# git commit
# Completely remove submodule (will need to be init again if you go backwards in history) to save disk space
rm -Rf .git/modules/$TARGET_DIR
Will be done with a git pull automatically if submodule.recurse option is True.
Misc
Tell git to track a specific branch of a submodule, e.g. "master":
git config -f .gitmodules submodule.${TARGET_DIR}.branch master
# commit .gitmodules
-f is specified so that .gitmodule can be updated and other people using the repository can track the same branch. Omit this if you don't care.
Settings
# `--recursive` for everything but `git clone`
git config --global submodule.recurse true
# Show summary of submodule changes in `git status`
git config --global status.submodulesummary true
# Prettier diff for submodules
git config --global diff.submodule log
Interesting reading
The Git Parable: Describes building a system like git, from the ground-up
CIA's git tips & tricks sheet is interesting, and oddly similar to this one.
git-email-based workflow
An e-mail-based workflow is preferred by many projects, including the Linux kernel.
git-send-email.io helps you get up and running w/ git-email