13th July 2020

Git Reference

Initial setup

git config --global user.name "John Doe"
git config --global user.email john.doe@example.com
git config --global color.ui auto
# git config --global color.status auto
# git config --global color.branch auto
git config --global push.default matching

Committing

Adding partial modifications to index:

git add --patch [foo/bar]

Committing with showing patches:

git commit -v

Committing with auto-adding all unstaged changes:

git commit -a

Committing in the past:

GIT_AUTHOR_DATE='Fri Jul 26 19:32:10 2013 +0200' GIT_COMMITTER_DATE='Fri Jul 26 19:32:10 2013 +0200' git commit

Undoing

Reset working directory and index to last committed state (last head):

git reset --hard

Reset a single file to the version in the index:

git checkout -- foo/bar.rb

Reset a single file to the last committed version:

git checkout HEAD foo/bar.rb

Remove a change from the index (undoing a previous git add):

git rm --cached foo/bar.rb

Undo a commit (e.g. HEAD^, i.e. the one before HEAD) by committing an undoing changeset:

git revert HEAD^

Rewriting unpublished history

Amending the last commit (HEAD):

git commit --amend

Interactive editing of last 10 commits:

git rebase -i HEAD~10

Merging using rebase – move history to different branch:

git checkout featurex
git rebase master
vim foo/conflicted.rb
git add foo/conflicted.rb
git rebase --continue

Removing subtrees from the history, removing empty commits:

git filter-branch -f --tree-filter 'rm -rf foo/bar baz/bat' --prune-empty -- --all
git filter-branch -f --tree-filter 'find . -type f \( ! -name "foo*" \) -exec rm {} \;' --prune-empty -- --all
git filter-branch -f --tag-name-filter cat --prune-empty -- --all

Fixing things

Force current branch to point to specific commit:

git reset --hard <commit>

Force other branch to point to specific commit:

git branch -f <branch> <commit>

Force push branch with safety belt:

git push --force-with-lease

Patching

Generate file-based patch-set:

git format-patch <base-ref>

Apply file-based patch-set with 3-way merging:

cat *.patch | git am -3

Stashing

Stash away working directory changes and index state:

git stash

List stashes:

git stash list

Restore from stash:

git stash apply

Branching

List local/remote branches:

git branch
git branch -r

Show branches in relation to each other:

git show-branch

Switch to branch:

git checkout featurex

Create and switch to branch:

git checkout -b featurey

Delete branch after merging it to master or some other branch:

git branch -D featurey

Branching Workflow

Create new topic branch based on master or commit sha1:

git checkout -b topic/foo master|<commit>

Push to somewhere:

git push origin topic/foo

Alternatively, merge back into master:

git checkout master
git merge topic/foo

Alternatively, for private branches containing checkpoint commits, merge as a single changeset back into master:

git checkout master
git merge --squash topic/foo
git commit -v

Replace master with other branch based on commit sha1:

git branch -m master oldmaster
git checkout -b master <commit>
git push -f origin master

Merging

Merge featurex into master:

git checkout master
git merge featurex
vim foo/conflicted.rb
git add foo/conflicted.rb
git commit

Remote repositories

Clone existing remote repository:

git clone git://whatever/foo.git [foo-bar]

Clone only a single branch (master):

git clone git://whatever/foo.git --branch master --single-branch [foo-bar]

List remotes:

git remote [-v]

Add new remote:

git remote add otherdev http://example.com/~otherdev/foo.git

Set remote branch of local master to remote origin, allowing git pull to know what to fetch and merge without explicitly specifying:

git config branch.master.remote origin
git config branch.master.merge refs/heads/master

Fetch from remote without merging:

git fetch otherdev

Fetch from remote and merge:

git pull otherdev

Merge changes from remote fork, complete workflow (using detached HEAD mode):

git remote add otherdev http://example.com/~otherdev/foo.git
git fetch otherdev
git checkout otherdev/master
# test fork before merge
git checkout master
git merge otherdev/master
# test merged result
git push origin master

Creating new repositories

Creating an empty group-shared SSH-based repository:

mkdir foo
chmod 2775 foo
cd foo
git init --bare --shared=group

Creating a HTTP repository

mkdir webroot/foo.git
cd webroot/foo.git
git init --bare
git --bare update-server-info
cp hooks/post-update.sample hooks/post-update
chmod a+x hooks/post-update

Importing from Subversion to GitHub

With standard Subversion layout (trunk, branches, tags directories):

echo 'jdoe = John Doe <john.doe@example.com>' >> /tmp/foo.authors
svn2git https://svn.example.com/foo --authors /tmp/foo.authors
git remote add origin git@github.com:jdoe/foo.git
git config branch.master.remote origin
git config branch.master.merge refs/heads/master
git push

Tagging

List tags:

git tag -l

Add tag and push tags to origin:

git tag -a foo-1.6.234
git push origin --tags

Remove tag and remove from origin:

git tag -d foo-1.6.234
git push :foo-1.6.234

Vendor branch pattern

Updating the vendor branch to a new snapshot:

git checkout vendor
rm -r *
# unpack new snapshot of foobar-1.2.3 into $PWD
git add .
git commit -m 'Import foobar-1.2.3'
git tag foobar-1.2.3
git push --tags

Updating modified master to new vendor snapshot:

git checkout master
git merge vendor
git push

Switching master to non-descendent branch

git checkout better_branch
git merge --strategy=ours master
git checkout master
git merge better_branch

Back to Knowledge Base.