All notes



Command git config --global could be replaced by manually editing the global config file for Git: ~/.gitconfig.

    sslVerify = false
    sslCAinfo = /bin/curl-ca-bundle.crt
	name = myName
	email = [email protected]
	default = simple
	st = status
	co = checkout
	ci = commit -am
	cis = commit -am "Small modi." && git pori
	pori = push origin master --tags
	fori = fetch origin
	mori = merge origin/master
	br = branch
	hist = log --pretty=format:\"%h %ad | %s%d [%an]\" --graph --date=short
	type = cat-file -t
	dump = cat-file -p
	helper = store



## Generic

## Xcode
#ignore private workspace stuff added by Xcode4

# Precompiled Headers
# Compiled Dynamic libraries
# Fortran module files
# Compiled Static libraries
# Executables



SYNOPSIS: .git/info/attributes.

pattern    attr1 attr2 ...

Each attribute can be in one of these states for a given path:


Best practices

Commit with meaningful messages

What if there is new commit when you are editing codes, and git tells you "commit first before pull"?

Stash way

See SO: git commit before merge.

Use git stash when you want to record the current state of the working directory and the index, but want to go back to a clean working directory.

git stash --all
# or git stash --include-untracked
git pull origin master
git stash pop

Rebase way

One caveat with stashing is that it doesn't create an entry in the reflog. So, if you screw up and lose your stash, you can't recover it. In some ways a commit is "safer." You can also git pull --rebase after a commit rather than stashing.

With --rebase, it runs git rebase instead of git merge.

Rebase vs Merge merging vs rebasing.

Feature & Bug Branches


Environment branches: staging and production



Git add to ignore untracked files.

# Stage the modified and deleted files.
git add -u

# Commit only the modified and deleted files.
git commit -a


git config -l



# -r, remote branches
# -a, all branches
git branch -av

# Rename current local branch
git branch -m newName
# Rename local branch "oldName"
git branch -m oldName newName

# --contains, shows only the branches that contain the named commit (in other words, the branches whose tip commits are descendants of the named commit)
# --merged, only branches merged into the named commit (i.e. the branches whose tip commits are reachable from the named commit) will be listed.

# New branch
git chechout -b [name_of_new_branch]

# Delete local branch
git branch -d [name]
# Delete local branch by force
git branch -D [name]
# Delete remote branch
git push origin :[name]

# As of Git 1.8.0:
git branch -u upstream/foo
# Or, if local branch foo is not the current branch:
git branch -u upstream/foo foo

# As of Git 1.7.0:
git branch --set-upstream foo upstream/foo

Change HEAD on remote repo



# WcfNote: must be on the server:
git symbolic-ref HEAD refs/heads/published


# [--all | --mirror | --tags]
# --all:    Push all branches (i.e. refs under refs/heads/).
# --tags:    All refs under refs/tags are pushed.

########## Remove remote tags
# [-d | --delete]: All listed refs are deleted from the remote repository. This is the same as prefixing all refs with a colon.

# You just need to push an 'empty' reference to the remote tag name:
git push origin :tagname
# Or, more expressively, use the --delete option:
git push --delete origin tagname
# You also need to delete the local tag, use:
git tag --delete tagname

# --prune:  Remove remote branches that don’t have a local counterpart.


Submodules allow you to keep a Git repository as a subdirectory of another Git repository. This lets you clone another repository into your project and keep your commits separate.

### Add submodules.

# Add a new file (.gitmodules) and a directory (src/main/webapp/ui-libs)
# submodule's .git is just a file reference to the main repo's .git.
git submodule add git:// src/main/webapp/ui-libs
# To specify a branch to follow:
git submodule add -b branch repository [path]

# Usually specify the read-only URL in ".gitmodules". For your own use:
git config submodule.repository.url PRIVATE_URL

# List all submodules
git submodule

### Initialize submodules.

# Initialize the submodules, i.e. register each submodule name and url found in .gitmodules into .git/config.
git submodule init
# clone missing submodules and checkout the commit specified in the index of the containing repository.
git submodule update

# Pass --recursive to the git clone command, it will automatically initialize and update each submodule in the repository.
git clone --recursive

# Git will go into your submodules and fetch and update for you.
git submodule update --remote DbConnector

# Have the DbConnector submodule track that repository’s “stable” branch instead of "master":
# If you leave off the -f .gitmodules it will only make the change for you
git config -f .gitmodules submodule.DbConnector.branch stable

### Edit

git diff --submodule
git config --global diff.submodule log
# Make git show you a short summary of changes to your submodules:
git config status.submodulesummary 1
git log -p --submodule

# Synchronizes submodules' remote URL configuration setting to the value specified in .gitmodules. This is useful when submodule URLs change upstream and you need to update your local repositories accordingly.
git submodule sync

Notice the "160000" mode for the newly added submodule entry. It is a special mode in Git that basically means you’re recording a commit as a directory entry rather than a subdirectory or a file.

git commit -am 'added DbConnector module'
# [master fb9093c] added DbConnector module
#  2 files changed, 4 insertions(+)
#  create mode 100644 .gitmodules
#  create mode 160000 DbConnector

Wcf use case

Suppose my project wcfProj (on company GitLab) depends on a third party lib aGoodLib on GitHub.

Here are what I will do:

  1. Git clone aGoodLib from GitHub to local. Add a GitLab local repo and sync them. Name the GitHub repo "vendor", and GitLab repo "origin".
  2. Make the branch "master" in aGoodLib point to "origin".
  3. wcfProj has a submodule pointing to aGoodLib with company branch.
  4. We may customize codes on company branch, and merge updates from remote/GitHub.
  5. We may also send a pull request to GitHub.


# 刚开始加入子项目时:
git subtree add --prefix=Vendor/AFNetworking --squash [email protected]:AFNetworking/AFNetworking.git master
# 切分出相关的提交:
git subtree split --prefix=Vendor/AFNetworking/ --branch AFNetworking
# 提交到对应的分支:
git push [email protected]:kvnsmth/AFNetworking.git AFNetworking:critical-bug-fix
# 拉取下最新的代码:
git subtree pull --prefix=Vendor/AFNetworking --squash [email protected]:AFNetworking/AFNetworking.git master


git symbolic-ref HEAD
# refs/heads/master

git symbolic-ref -q HEAD
# refs/heads/master

git symbolic-ref --short HEAD
# master



# Compare your current pom.xml to the one from master 20 revisions ago through the first parent.
# You can replace master~20, of course, with the object name (SHA1sum) of a commit
git diff master~20:pom.xml pom.xml

# git diff revision path
# For example:
git diff b0d14a4 foobar.txt

# To see what was changed in a file in the last commi:
git diff HEAD~1 path/to/file.

# Diff between two branches.
git diff master..test
# 找出master, test的共有父分支和test分支之间的差异,用3个 '.' 来取代前面的两个'.'。
git diff master...test

# Compare two commits and apply the patch to files.
git diff 0da94be 59ff30c > my.patch
git apply my.patch

# 找当前工作目录和上次提交的本地索引间的差异。
git diff
# 显示你当前的索引和上次提交间的差异,这些内容在不带"-a"参数运行 "git commit"命令时就会被提交。
git diff --cached
# 这条命令会显示你工作目录与上次提交时之间的所有差别,这条命令所显示的 内容都会在执行"git commit -a"命令时被提交。
git diff HEAD


Shallow copy

Ref1, Ref2. Use git clone --depth to do a shallow copy. Git 1.9/2.0 (Q1 2014) has removed that limitation that you cannot clone or fetch from it, nor push from nor into it.


Commit Limiting

-n <number>
    Limit the number of commits to output.

    Show commits more recent than a specific date.
    Show commits older than a specific date.

    Limit the commits output to ones with author/committer header lines that match the specified pattern (regular expression). With more than one --author=<pattern>, commits whose author matches any of the given patterns are chosen (similarly for multiple --committer=<pattern>).

    Pretend as if all the refs in refs/heads are listed on the command line as <commit>. If <pattern> is given, limit branches to ones matching given shell glob. If pattern lacks ?, *, or [, /* at the end is implied.
    Pretend as if all the refs in refs/tags are listed on the command line as <commit>. If <pattern> is given, limit tags to ones matching given shell glob. If pattern lacks ?, *, or [, /* at the end is implied.
    Pretend as if all the refs in refs/remotes are listed on the command line as <commit>. If <pattern> is given, limit remote-tracking branches to ones matching given shell glob. If pattern lacks ?, *, or [, /* at the end is implied.
    Pretend as if all the refs matching shell glob <glob-pattern> are listed on the command line as <commit>. Leading refs/, is automatically prepended if missing. If pattern lacks ?, *, or [, /* at the end is implied.

    Limit the commits output to ones with reflog entries that match the specified pattern (regular expression). It is an error to use this option unless --walk-reflogs is in use.
    Instead of walking the commit ancestry chain, walk reflog entries from the most recent one to older ones. When this option is used you cannot specify commits to exclude (that is, ^commit, commit1..commit2, and commit1...commit2 notations cannot be used).

    Limit the commits output to ones with log message that matches the specified pattern (regular expression). With more than one --grep=<pattern>, commits whose message matches any of the given patterns are chosen (but see --all-match).
    When --show-notes is in effect, the message from the notes is matched as if it were part of the log message.
    Limit the commits output to ones that match all given --grep, instead of ones that match at least one.
    Limit the commits output to ones with log message that do not match the pattern specified with --grep.
    Match the regular expression limiting patterns without regard to letter case.
    Consider the limiting patterns to be basic regular expressions; this is the default.
    Consider the limiting patterns to be extended regular expressions instead of the default basic regular expressions.
    Consider the limiting patterns to be fixed strings (don’t interpret pattern as a regular expression).

    Print only merge commits. This is exactly the same as --min-parents=2.
    Do not print commits with more than one parent. This is exactly the same as --max-parents=1.
    Show only commits which have at least (or at most) that many parent commits. In particular, --max-parents=1 is the same as --no-merges, --min-parents=2 is the same as --merges. --max-parents=0 gives all root commits and --min-parents=3 all octopus merges.
    --no-min-parents and --no-max-parents reset these limits (to no limit) again. Equivalent forms are --min-parents=0 (any commit has 0 or more parents) and --max-parents=-1 (negative numbers denote no upper limit).
    Follow only the first parent commit upon seeing a merge commit. This option can give a better overview when viewing the evolution of a particular topic branch, because merges into a topic branch tend to be only about adjusting to updated upstream from time to time, and this option allows you to ignore the individual commits brought in to your history by such a merge. Cannot be combined with --bisect.
    After a failed merge, show refs that touch files having a conflict and don’t exist on all heads to merge.
    Output excluded boundary commits. Boundary commits are prefixed with -.


git log v2.6.12.. include/scsi drivers/scsi
    Show all commits since version v2.6.12 that changed any file in the include/scsi or drivers/scsi subdirectories

git log --since="2 weeks ago" -- gitk
    Show the changes during the last two weeks to the file gitk. The “--” is necessary to avoid confusion with the branch named gitk

git log --name-status release..test
    Show the commits that are in the "test" branch but not yet in the "release" branch, along with the list of paths each commit modifies.

git log --follow builtin/rev-list.c
    Shows the commits that changed builtin/rev-list.c, including those commits that occurred before the file was given its present name.

git log --branches --not --remotes=origin
    Shows all commits that are in any of local branches but not in any of remote-tracking branches for origin (what you have that origin doesn’t).

git log master --not --remotes=*/master
    Shows all commits that are in local master but not in any remote repository master branches.

git log -p -m --first-parent
    Shows the history including change diffs, but only from the “main branch” perspective, skipping commits that come from merged branches, and showing full diffs of changes introduced by the merges. This makes sense only when following a strict policy of merging all topic branches when staying on a single integration branch.

git log -L '/int main/',/^}/:main.c
    Shows how the function main() in the file main.c evolved over time.

git log -3
    Limits the number of commits to show to 3.



Reference logs, or "reflogs", record when the tips of branches and other references were updated in the local repository. Reflogs are useful in various Git commands, to specify the old value of a reference. For example, [email protected]{2} means "where HEAD used to be two moves ago", [email protected]{one.week.ago} means "where master used to point to one week ago in this local repository", and so on.

"git reflog show" is an alias for "git log -g --abbrev-commit --pretty=oneline".

The "exists" subcommand checks whether a ref has a reflog. It exits with zero status if the reflog exists, and non-zero status if it does not.


# List all tags.
git tag
# List tags with pattern.
git tag -l "v1.*"

# Make a lightweight tag.
git tag v1.4
# Make an unsigned, annotated tag.
git tag -a v1.5 -m "Message"
# Make a GPG-signed tag, using the default e-mail address's key.
git tag -s v1.6 -m "Message"
# Make a GPG-signed tag, using the given key.
git tag -u keyID v1.7 -m "Message"
# Take the tag message from the given file. Use - to read the message from the standard input. -a is implied.
git tag -F file v1.8

# Show the tag status.
git show v1.5

# Delete tag.
git tag -d v1.4

# Verify GPG signature.
git tag -v v1.6

# Replace an existing tag.
git tag -f/--force v1.7

# Remember to share your tags.
git push origin --tags

# Switched to a new branch 'version2', with content of tag v2.0.0.
git checkout -b version2 v2.0.0

附注标签,实际上是存储在仓库中的一个独立对象,它有自身的校验和信息,包含着标签的名字,电子邮件地址和日期,以及标签说明,标签本身也允许使用 GNU Privacy Guard (GPG) 来签署或验证。

To tag previous commit:

git log --pretty=oneline
# Shows: 9fceb02d0ae598e95dc970b74767f19372d61af8 updated rakefile

# Tag the commit with SHA starting with 9fceb02.
git tag -a v1.2 9fceb02


# Shows you the URLs that Git has stored for the shortname to be used when reading and writing to that remote
git remote -v

git remote rename old new

Reset, checkout, revert


Commit-level Operation

File-level Operations

### Commit-level

# Suppose we are on branch hotfix now
git reset HEAD~2
# The two commits on the end of hotfix branch are dangling now.

# Unstaging all changes, but leaves them in the working directory:
git reset --mixed HEAD
# Completely throw away all your uncommitted changes:
git reset --hard HEAD

### File-level

# Fetch the version of in the 2nd-to-last commit and stage it for the next commit:
git reset HEAD~2
# Unstage The changes it contains will still be present in the working directory.
git reset HEAD

# Discard unstaged changes to
git checkout HEAD

gc, garbage collection

StackOverflow. one of the housekeeping tasks that git-gc performs is packing and repacking of loose objects. Even if you never have any dangling objects in your bare repository, you will -- over time -- accumulate lots of loose objects. These loose objects should periodically get packed, for efficiency. Similarly, if a large number of packs accumulate, they should periodically get repacked into larger (fewer) packs.

# Count unpacked number of objects and their disk consumption, to help you decide when it is a good time to repack.
# -H, --human-readable
git count-objects -H
# 4315 objects, 11483 kilobytes

git count-objects -v
# count: 4315
# size: 11483
# in-pack: 9778
# packs: 20
# size-pack: 15726
# prune-packable: 1395
# garbage: 0
# count: the number of loose objects
# size: disk space consumed by loose objects, in KiB (unless -H is specified)
# in-pack: the number of in-pack objects
# size-pack: disk space consumed by the packs, in KiB (unless -H is specified)
# prune-packable: the number of loose objects that are also present in the packs. These objects could be pruned using git prune-packed.
# garbage: the number of files in object database that are neither valid loose objects nor valid packs
# size-garbage: disk space consumed by garbage files, in KiB (unless -H is specified)

# --aggressive: this option only needs to be used occasionally.
git gc --aggressive
# Counting objects: 8548, done.
# Delta compression using up to 4 threads.
# Compressing objects: 100% (8468/8468), done.
# Writing objects: 100% (8548/8548), done.
# Total 8548 (delta 7007), reused 0 (delta 0)
# Removing duplicate objects: 100% (256/256), done.

git count-objects -v
# count: 0
# size: 0
# in-pack: 8548
# packs: 1
# size-pack: 8937
# prune-packable: 0
# garbage: 0

git count-objects
# 0 objects, 0 kilobytes

# Setting the value of to 0 disables automatic packing of loose objects.
git config --global 0


Bare repo?

git gc should be called automatically called during "normal" use of a bare repository.




Git Objects


# -w: write into the object database.
# --stdin: read the content from stdin instead of a file.
# The output is a 40-character SHA-1 hash.
echo 'test content' | git hash-object -w --stdin
# d670460b4b4aece5915caf5c68d12f560a9fe3e4

git cat-file -p d670460b4b4aece5915caf5c68d12f560a9fe3e4
# test content

echo 'version 1' > test.txt
git hash-object -w test.txt
# 83baae61804e65cc73a7201a7252750c76066a30

git cat-file -p 83baae61804e65cc73a7201a7252750c76066a30 > test.txt
cat test.txt
# version 1

git cat-file -t 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a
# blob

# master^{tree} specifies the tree object that is pointed to by the last commit on your master branch.
git cat-file -p master^{tree}
# 100644 blob a906cb2a4a904a152e80877d4088654daad0c859      README
# 100644 blob 8f94139338f9404f26296befa88755fc2598c289      Rakefile
# 040000 tree 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0      lib

Git normally creates a tree by taking the state of your staging area or index and writing a series of tree objects from it.

# --add: add a specified file into the index. Default behaviour is to ignore new files.
echo 'new file' > new.txt
git update-index test.txt
git update-index --add new.txt

# --cacheinfo mode,object,path, --cacheinfo mode object path: Directly insert the specified info into the index.
# 100644: normal file.
# 100755: executable.
# 120000: symbolic link.
git update-index --add --cacheinfo 100644 83baae61804e65cc73a7201a7252750c76066a30 test.txt

# Automatically creates a tree object from the state of the index if that tree doesn’t yet exist.
git write-tree
# d8329fc1cc938780ffdd9f94e0d364e0ea74f579
git cat-file -p d8329fc1cc938780ffdd9f94e0d364e0ea74f579
# 100644 blob 83baae61804e65cc73a7201a7252750c76066a30      test.txt
git cat-file -t d8329fc1cc938780ffdd9f94e0d364e0ea74f579
# tree


Trees specify the different snapshots of your project

echo 'first commit' | git commit-tree treeSHA
# commit SHA: fdf4fc3344e67ab068f836878b6c4951e3b15f3d

git cat-file -p fdf4fc3
# tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579
# author Scott Chacon <[email protected]> 1243040974 -0700
# committer Scott Chacon <[email protected]> 1243040974 -0700
# first commit

Object Storage

Git annex



sudo yum -y install haskell-platform

# Arch.
sudo pacman -S cabal-install ghc
cabal update
cabal install git-annex --bind=$HOME/bin

Good references


# Creating a repo.
mkdir ~/annex
cd ~/annex
git init
git annex init "my laptop"

# Adding a remote on a USB drive.
sudo mount /media/usb
cd /media/usb
git clone ~/annex
cd annex
git annex init "portable USB drive"
git remote add laptop ~/annex
cd ~/annex
git remote add usbdrive /media/usb/annex

# Add files
cd ~/annex
cp /tmp/big_file .
cp /tmp/debian.iso .
git annex add .
	# add big_file (checksum...) ok
	# add debian.iso (checksum...) ok
git commit -a -m added

# renaming files
cd ~/annex
git mv big_file my_cool_big_file
mkdir iso
git mv debian.iso iso/
git commit -m moved

# Getting file content.
cd /media/usb/annex
# let git-annex know what has changed in the other repositories like the laptop.
git annex sync laptop
git annex get .
	# get my_cool_big_file (from laptop...) ok
	# get iso/debian.iso (from laptop...) ok

Direct mode


git-annex direct
git-annex indirect

# Undo
git-annex undo file

# Workflow.
git annex add file
git annex sync
git annex copy file --to otherrepo

Removing files


SSH remote

Fix broken

Branchable: move file. Branchable: removing files.

# To fix up broken symlinks, you can either run "git annex fix", or just commit the move. The pre-commit hook fixes up links automatically.
git-annex fix fileName

# Remove the content of a file from your local repository to save space.
git-annex drop iso/debian.iso

Special remotes

export AWS_ACCESS_KEY_ID="somethingotherthanthis"
export AWS_SECRET_ACCESS_KEY="s3kr1t"
git annex initremote mys3 type=S3 chunk=1MiB encryption=shared
	# initremote mys3 (shared encryption) (checking bucket) (creating bucket in US) ok
# Now you can store files on the newly initialized special remote.
git annex copy my_cool_big_file --to mys3
	# copy my_cool_big_file (to mys3...) ok

# First get git-annex in sync (so it knows about the special remote that was added in the other repository)
git annex sync
export AWS_ACCESS_KEY_ID="somethingotherthanthis"
export AWS_SECRET_ACCESS_KEY="s3kr1t"
git annex enableremote mys3
	# enableremote mys3 (checking bucket) ok
# And now you can download files from the special remote:
git annex get my_cool_big_file --from mys3
	# get my_cool_big_file (from mys3...) ok

Moving file content between repositories

Unused data

git annex unused
	# unused . (checking for unused data...) 
	#   Some annexed data is no longer used by any files in the repository.
	#     NUMBER  KEY
	#     1       SHA256-s86050597--6ae2688bc533437766a48aa19f2c06be14d1bab9c70b468af445d4f07b65f41e
	#     2       SHA1-s14--f1358ec1873d57350e3dc62054dc232bc93c2bd1
	#   (To see where data was previously used, try: git log --stat -S'KEY')
	#   (To remove unwanted data: git-annex dropunused NUMBER)
	# ok

git annex dropunused 1
	# dropunused 1 ok
git annex dropunused 1-1000

#Rather than removing the data, you can instead send it to other repositories:
git annex copy --unused --to backup
git annex move --unused --to archive


git annex fsck
git annex fsck my_cool_big_file


git-annex can be configured to require more than one copy of a file exists, as a simple backup for your data. This is controlled by the numcopies setting, which defaults to 1 copy. Let's change that to require 2 copies, and send a copy of every file to a USB drive.

git annex numcopies 2
git annex copy . --to usbdrive

cd /media/usbdrive
git annex whereis
	# whereis my_cool_big_file (1 copy)
	#     0c443de8-e644-11df-acbf-f7cd7ca6210d  -- laptop
	# whereis other_file (3 copies)
	#     0c443de8-e644-11df-acbf-f7cd7ca6210d  -- laptop
	#     62b39bbe-4149-11e0-af01-bb89245a1e61  -- usb drive [here]
	#     7570b02e-15e9-11e0-adf0-9f3f94cb2eaa  -- backup drive

# Automatically reconfigure.
git annex get --auto --numcopies=2
	# get my_cool_big_file (from laptop...) ok
git annex drop --auto --numcopies=2
	# drop other_file ok

Git annex FAQ

Git-annex add hangs


I guess this is a mismatch between the version of git that git-annex was built with and the version it's using. In particular, git check-attr behavior varies between git older than 1.7.7 and newer, and git-annex picks the version at build time.


Checkout github wiki

SO: how do I clone a github wiki.

git clone [email protected]:myusername/foobar.git would be the path to clone your repository, and git clone [email protected]:myusername/ would be the path to clone its wiki.

Discard all local change


# For a specific file use:
git checkout path/to/file/to/revert

# For all unstaged files use:
git checkout -- .

# Another method
git stash save --keep-index
git stash drop

Exclude/Ignore files from commit


# This will tell git you want to start ignoring the changes to the file
git update-index --assume-unchanged path/to/file

# When you want to start keeping track again
git update-index --no-assume-unchanged path/to/file

Provide username and password when git clone

git clone https://username:[email protected]/username/repository.git

Revert to a commit


## Temporarily switch to a different commit.

# This will detach your HEAD, that is, leave you with no branch checked out:
git checkout 0d1d7fc32
# Or if you want to make commits while you're there, go ahead and make a new branch while you're at it:
git checkout -b old-state 0d1d7fc32

## Hard delete unpublished commits

# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32

# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts, if you've modified things which were
# changed since the commit you reset to.

## Undo published commits with new commits

# This will create three separate revert commits:
git revert a867b4af 25eee4ca 0766c053
# It also takes ranges. This will revert the last two commits:
git revert HEAD~2..HEAD
# Reverting a merge commit
git revert -m 1 <merge_commit_sha>
# To get just one, you could use `rebase -i` to squash them afterwards
# Or, you could do it manually (be sure to do this at top level of the repo)
# get your index and work tree into the desired state, without changing HEAD:
git checkout 0d1d7fc32 .
# Then commit. Be sure and write a good message describing what you just did
git commit

"object file is empty" and "loose object is corrupt" errors


git status
#  error: object file .git/objects/9b/b43162ab8a41594735a628e3c5cacdaa675123 is empty
#  fatal: loose object 9bb43162ab8a41594735a628e3c5cacdaa675123 (stored in .git/objects/9b/b43162ab8a41594735a628e3c5cacdaa675123) is corrupt

The easiest way to do this is to create a second clone and hope that the object exists in the clone.

# Check to see what type it is.
git cat-file -t 9bb43162ab8a41594735a628e3c5cacdaa675123
# See the content according to the type
git cat-file commit commitSHA
git cat-file blob blobSHA
# Also premit: ask for a "tree" with object being a commit object that contains it, or to ask for a "blob" with object being a tag object that points at it.

# The new clone almost certainly has its objects packed. So to get the missing file:
git cat-file 9bb43162ab8a41594735a628e3c5cacdaa675123 > b43162ab8a41594735a628e3c5cacdaa675123
cp b43162ab8a41594735a628e3c5cacdaa675123 /path/to/broken/clone/.git/objects/9b/.

git ls-tree -r HEAD | grep 9bb43162ab8a41594735a628e3c5cacdaa675123

If the new repo is shallowly cloned, there will be a "shallow" file under .git/.

git clone --depth=1 repoURL new
cd new
cd .git/objects && ls
# info pack
cd pack

# Make a temporary repo, and unpack all ojbects here.
mkdir test && cd test
git init .
git unpack-objects < ../pack-768126ea0e7b26300a081d229f3845532216f3e6.pack
cd .git/objects/ && ls
# OK, we have all objects here.
# Start copying the missing ones!

If that operation fails then the new clone does not have the file in question and you're back to trying to figure out which file that was created by work in the original clone is missing and how to recover its contents (exactly) so that the SHA matches.

# Use "git log" to find the SHA of the last commit on your branch.
git cat-file -p SHA | egrep ' tree |9bb43162ab8a41594735a628e3c5cacdaa675123'
# where "SHA" is the 40 character hex string from the output of "git log".

How to make a git repo bare


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

How to make a bare repo un-bare?


git pull fails "unable to resolve reference" "unable to update local ref"

Stackoverflow. Happened to me as well. In my case, the bad ref was master, and I did the following:

rm .git/refs/remotes/origin/master
git fetch

This made git restore the ref file. After that everything worked as expected again.

Fatal: index file smaller than expected

'git status' failed with code 128:'fatal: index file smaller than expected'. Atlassian.

rm .git/index
git reset HEAD .


error: unable to resolve reference ORIG_HEAD: Success
fatal: Cannot lock the ref 'ORIG_HEAD'.


I had this problem, and I solved it by removing the file .git/ORIG_HEAD then doing the pull again. The .git/ORIG_HEAD file was 0 bytes instead of the git reference it was supposed to contain, so I just got rid of it.

Remember password

# Store your credentials in clear text in project's .git-credentials.
git config credential.helper store
# Store in ~/.git-credentials
git config --global credential.helper store

# keep your password cached in memory for (by default) 15 minutes.
git config --global credential.helper cache
# Keep 3600s.
git config --global credential.helper "cache --timeout=3600"

# Don't remember password.
git config --unset credential.helper

Reset, revert changes

# Remove file from source control, but still keep it on disk.
git rm --cached file
# Check out file1 and overwrite uncommitted changes.
git checkout pathto/file1
# Remove uncommitted change for file1 only.
git reset HEAD file1
# Remove uncommitted changes
git reset --hard

# Remove the untracked files recursively from the working tree.
git clean # Use in caution!
git clean -nfd # -f, remove files. -d, remove dirs. -n, just try.

Ref: "git reset HEAD" to undo the "git add".

fatal: Unable to find remote helper for 'https'

Git uses curl to fetch http packages. So be sure to install curl libs before compiling git from sources:

sudo yum install -y curl-devel
./configure --prefix=/path
make -j8
make install

Reset or revert a specific file to a specific revision

If you messed up in "abbcdf" and want the version right before "abbcdf", you can do:

git checkout "abbcdf~1" path/to/file

Delete branches


# As of Git v1.7.0, you can delete a remote branch using
git push origin --delete <branchName>
# From Git v1.5.0, before v1.7.0:
git push origin :<branchName>

# Remove local branch with
git branch -d your branchname

Push to checked out branch

You can't push to the currently checked out branch of a repository. Why? If allowed, a push on the checked-out branch would change the HEAD to be inconsistent with the index and working tree on the remote repository. This would make it very easy to accidentally commit a change that undoes all of the pushed changes and also makes it very difficult to distinguish between any local changes that have not been committed and differences between the new HEAD, the index and the working tree that have been caused by push moving HEAD.

# Do your work on this branch and commit.
git checkout -b myBranch
# Then push your branch without having to destroy anything.
git push origin master:myBranch

# On server
git merge myBranch

After that, your branch in the remote repo can be merged or rebased into master.

Change tracking upstream


  1. Use git remote rename to backup "origin" and set new "origin". Note: this will also rename the remote name in upstream setting, so we need the next step.
  2. Set branch merge with git branch branchName -u newRemote/branchName. You can Check this in .git/config file.

Make an existing branch track a remote branch


# As of Git 1.8.0:
git branch -u upstream/foo foo
git branch --set-upstream-to=upstream/foo foo

# As of Git 1.7.0:
git branch --set-upstream foo upstream/foo

Set git server using ssh

Ref. The idea is easy: init git repo on your server, and using ssh to fetch the repo.

For example, I set ~/gitRepo on my server, and on my client, I could visit myproj repo by git clone [email protected]:~/gitRepo/myproj.git.

Ref. git clone ssh://[email protected]/project.git
或者不指明某个协议 — 这时 Git 会默认使用 SSH :
git clone [email protected]:project.git

Also do make the user "git" has no normal shell login:

# See where the git-shell is.
which git-shell
# Add git-shell here.
sudo emacs /etc/shells
# Change git's shell to git-shell.
sudo chsh git
# For more information on customizing the shell:
git help shell


git checkout --theirs/ours conflictedFile

Write commit message


Why write messages

Structure it in the format:

Short (50 chars or less) summary of changes

More detailed explanatory text, if necessary.

Further paragraphs come after blank lines.

- Bullet points are okay, too

- Typically a hyphen or asterisk is used for the bullet, preceded by a
   single space, with blank lines in between, but conventions vary here


GitLab has its config file under /etc/gitlab/gitlab.rb.

# Configure and start GitLab:
# Also run the following every time you wanna settings to take effect
sudo gitlab-ctl reconfigure
# or this does the same
sudo service gitlab reload

# You must be root to run lokkit.
# -s: Open the firewall for a service.
sudo lokkit -s http -s ssh

Add admin

Open console

Ref for openning gitlab console.

# Change to gitlab directory. Normally, /home/git/gitlab.
cd /home/git/gitlab
sudo -u git -H bundle exec rails console production

# Or, if you are running omnibus-gitlab you should run the following:
# Open-source gitlab could also use this:
sudo gitlab-rails console

OK, here is the explanation about Omnibus package:"Since a manual installation is a lot of work and error prone we strongly recommend the fast and reliable Omnibus package installation (deb/rpm)."

Set admin

Ref for setting admin.

User.find_by_email("[email protected]") do |i|
    i.admin = true

One thing. It is said [email protected] is the default administrator, but I found nil by using User.find_by_email('[email protected]'). Maybe it is because my gitlab uses LDAP. Then after I login with my own LDAP account (which is admin now), I found the default admin is actually: [email protected].

Enabling the admin group feature

You can have an LDAP group with the common name (CN) 'GitLab administrators' containing the users that should be GitLab administrators. For omnibus-gitlab, add the following to /etc/gitlab/gitlab.rb and run gitlab-ctl reconfigure.

gitlab_rails['ldap_admin_group'] = 'GitLab administrators'

NOTE: It is recommended that you keep a non-LDAP GitLab administrator user around on your GitLab instance in case you accidentally remove the admin status from your own LDAP-enabled GitLab user.

Recipe Compile Error: External URL must include a FQDN

On CentOS 6.5, after sudo gitlab-ctl reconfigure, it complained the error as the title says. This provided a good solution for me. The file /etc/gitlab/gitlab.rb has ill-formed FQDN - missing a '=' sign. After adding this, it compiled successfully.

Gitlab FAQ

Where is gitlab.yml?

Under /var/opt/gitlab/gitlab-rails/etc/. However, it says:

This file is managed by gitlab-ctl. Manual changes will be erased! To change the contents below, edit /etc/gitlab/gitlab.rb and run `sudo gitlab-ctl reconfigure`.

However, if I want to use IP addr instead of FQDN, I have to manually change it in gitlab.yml under "host" key, and then "sudo gitlab-ctl restart" (not reconfigure, otherwise it will be erased!). About how to change the URL for gitlab, see Ref.

LDAP failed

In /var/log/gitlab/gitlab-rails/production.log, it says "ArgumentError (uid or filter MUST be provided)". So I changed the "uid=sAMAccount" to "uid=cn", problem solved.

Developer can't push?

关于git developer角色无法push的问题, see Ref. gitlab为了安全考虑默认保护主干,只有master角色才能push到主干。可以考虑使用git推荐的策略:Keep stable branches secure and force developers to use Merge Requests。即开发人员在本地整合好以后,发出merge request。