Notes and Tips for Git
Table of Contents
1 Very helpful documents
- The official document is very well written and an invaluable source.
- Especially, understanding the work flows really helps.
- A very good blog which explains how to use git
- Branching model
- An article illustrates how two-stage commit and reset work.
2 Configuring git
2.1 Global configure
$HOME/.gitconfig
my global .gitconfig
2.2 Repository-wise configuration
- Run
git config
WITHOUT--global
, or - Edit
path/to/git_repo/.git/config
instead of$HOME/.gitconfig
. - You may want to set the global ones to the most conservative values (or
leave them empty), for example:
# global/default git config --global user.name "lgfang" git config --global user.email "no-spam@lungang.cn" # project specific/private git config user.name "myhandle" git config user.email "mymail@mycompany.com"
2.3 Command alias
In $HOME/.gitcofig
, add lines in the "alias" section. For example:
[alias] topo = log --graph --pretty=format:"%d" --simplify-by-decoration --all
2.4 Remember remote username and password
For example:
git remote set-url origin https://username@github.com/...
git config --global credential.helper "cache --timeout=3600"
2.5 Ignore files
Put file name globs (one per line) into path/to/git_repo/.gitignore
, for
instance:
*~ *.pyc
2.6 Git after proxy
To push/fetch a project after a proxy server.
# Examples of setting proxy git config http.proxy http://proxyuser:proxypwd@proxy.server.com:8080 git config http.proxy localhost:8888 # To clear git config http.proxy ""
I defined two aliases ("hp" and "nohp") for the commands, refer to my configure file.
3 Clone & sync
3.1 About "pull"
- "pull" is basically a combination of "fetch" and "merge". It will download all, but only merge current branch.
- "pull" is NOT recommended, use "fetch" + "rebase" (or the equivalent
command
pull --rebase
) instead.
3.2 Push all branches, tags
All branches, tags are NOT pushed by default.
- For tags
# push tag "mytag" git push origin mytag # push all tags git push --tags
- For branches
- "fetch" always retrieve all stuff (both branches and tags) from remote.
- All "tracking branches" are pushed by default.
- "fetched" branches are all tracking branches.
- Locally created branches become tracked ones (and are pushed) by the
following commands.
git push -u origin branch_name # Or git push -u origin --all
3.3 Set up a "centralized" git repository
http://git-scm.com/book/en/Git-on-the-Server-Getting-Git-on-a-Server
If a handful of people are working on the same project, chances are that you want a git repository on a server which everyone can pull and push.
The major characteristic of this kind of respositorise is they contain no working directory.
To set up this, just setup a "normal" repository and then clone it with 'bare'.
cd ~/tmp/autoit && git init && cd ~/.repo git clone --bare ~/tmp/autoit auto.git # later on, others can on the same machine git clone file:///lgfang/.repo/auto.git # or, on other machines with ssh to the_host git clone login@the_host:///lgfang/.repo/auto.git
3.4 Work with a peer server on which git is privately installed
It complains "bash: git-upload-pack: command not found" because There is less "env" when running commands remotely using ssh non-interactive session.
Solution given in above link as well.
3.5 Clone part of the history
Sometimes, we don't care the past of a project. Since each commit creates new
copies of corresponding files, we want to clone only commits we want so that
we not only get a cleaner history but also save a little bit disk space. This
is achieved by --depath N
.
git clone --depth 1 <remote repository>
3.6 Clone a single branch only
git clone -b branch_name --single-branch <remote repo> <local dir>
3.7 Archive current branch
git archive -o archive.zip HEAD
This one makes a zip file content of which does not contain ".git" directory. Another way is to clone a single branch without history. I.e.
git clone -b branch-name --single-branch --depth 1 <remote repo> <local dir>
4 Referring certain commit
- Use the hash code, e.g.
git checkout 31cbd89
NOTE: you need not enter the full hash string, just enough number of leading characters to unambiguously locate the version.
- Use relative position
git checkout HEAD~3
Above command checkout the snapshot 3 commits ahead of current HEAD.
5 Branch
5.1 Delete
Example:
git branch -d foo git push origin --delete foo
5.2 Rename
Example:
git branch -m foo bar
To rename current branch, simply:
git branch -m bar
5.3 Branch topology
You may want to create an alias for it.
git log --graph --pretty=format:"%d:%h" --simplify-by-decoration --all
5.4 Switch to another branch without commit current one
In short, use git stash
.
git stash
git co another_branch
- do some work there
git co master
git stash pop
Or, as a more complex scenario, if both branches use stash, specify stash explicitly.
git stash list git stash pop stash@{1}
Note that, stashing increases size of ".git" as well until a garbage collection run (either automatically or manually).
6 Commit
NOTE: If the commits already pushed to other repositories, you have to run
"push" with -f
, which is risky. Hence, be really cautious and double check
before "push".
6.1 To commit changes
- "add" and "commit"
git add file1 file2 git add file3 git commit
- Changes made after
git add
are NOT committedHence you usually "add" right before "commit".
- Commit without "add"
In fact, For files already being tracked, you can do "add" and "commit" in one step. Just run the following command.
git commit file1 file2 ... # Or, use the brave "commit -a"
6.2 Discard local changes
Simply checkout the file again, i.e.
git checkout -- file_name
If you already run "git add", then you have to "reset" first.
git reset file_name # Or just "git reset"
6.3 Rollback latest commits
I.e. delete/undo the latest commits.
git reset --hard HEAD~1
6.4 Revert a commit
I.e. undo a previous commit but keep commits newer than it.
git revert HEAD~1 git revert e0c0698
6.5 Stage your changes
With two-stage commit (git add
), you can stage your changes without having
to commit them.
- You are working on a complicated problem.
- You make some progress, then you
git add
to stage your code. - You continue and make more changes.
- You find the changes are inappropriate.
- You
git checkout
to discard the inappropriate changes and restart from where staged with another try. - After several rounds, all done.
- You commit your code.
6.6 Conflict
When a conflict happened during pulling, there are some "tricky" things to manually fix the conflict and check-in.
- You cannot
git commit a_file_with_conflicts
, you have togit add all_files_with_conflicts
and thengit commit
. The rational is that, in this case, you should commit all or none in this case. - Alternatively,
git commit -a
should combine those two steps (add and commit) for you.
6.7 Stage (and commit) only part of a change
git add -p file_name
Refer to tip 6 of http://www.sitepoint.com/10-tips-git-next-level/
6.8 Keep commit history clean
6.8.1 Edit commit history
- To edit the last commit:
git commit --amend -m 'new message' git commit --amend --author="lgfang <lgfang@xxx.com>"
- To edit previous commits
For example, to edit the "author" of previous commits:
git rebase -i HEAD~5 # Go 5 commits back. # In the editor, change "pick" to "edit" for designated commits. # Continue to submit git rebase --continue
Other useful actions when of rebase includes:
- r, reword = use commit, but edit the commit message
- s, squash = use commit, but meld into previous commit
6.8.2 Rebase and squash
Based on this.
Here is an example:
- Find target to rebase
$ git log --graph --pretty=format:"%d:%h" --all * (HEAD, master):8112e7a * :e19ea56 * :7786ded | * (emacs23):1f98b87 |/ * :ff42d6a * :eb32bff * :0b4df9f * :b54c413 | * (legacy-emacs):32897c9 |/ * :5e53df9
- Rebase to "combine" serveral commits into one.
The git rebase fires an editor with the following content
$ git rebase -i 5e53df9 pick b54c413 commit log ... pick 0b4df9f ... pick eb32bff ... pick ff42d6a ... pick 7786ded ... pick e19ea56 ... pick 8112e7a ...
Edit it, replacing "pick" with "squash" for commits we don't want.
NOTE: at least the first line should be leaved as "pick".
- After rebase, we got the new topology
$ git log --graph --pretty=format:"%d:%h" --all * (HEAD, master):87b59a0 | * (emacs23):1f98b87 | * :ff42d6a | * :eb32bff | * :0b4df9f | * :b54c413 |/ | * (legacy-emacs):32897c9 |/ * :5e53df9
6.8.3 Merge and squash
This applicable to picking up commits (merge) from other branches.
Exerpt from: http://alpha-blog.wanglianghome.org/2010/08/05/git-merge-squash/
判断是否使用 squash 选项最根本的标准是 :待合并分支上的历史是否有意义。
如果在开发分支上提交非常随意,甚至写成微博体,那么一定要使用
--squash
选项。版本历史记录的应该是代码的发展,而不是开发者在编码时的
活动。
--squash
选项的含义是:本地文件内容与不使用该选项的合并结果相同,但是
不提交、不移动 HEAD,因此需要一条额外的 commit 命令。其效果相当于将
another 分支上的多个 commit 合并成一个,放在当前分支上,原来的 commit
历史则没有拿过来。
git merge --squash another
git commit -m "message here"
7 History
7.1 Show log selectively
git log -3 git log origin..HEAD # show commits not push yet git log --author=lgfang git log --grep='string in commit message' git log --since=2.weeks.ago --until=2.days.ago
7.2 Show summary of changes made
git log --name-status git log --name-status -3 git log --name-status -1 05d6deb
7.3 Show detailed changes made by certain commits
You can specify multiple commits at a time.
git show b64dd26 git show HEAD~3 git show HEAD~1 HEAD~2
7.4 View files without checkout
This works for either another version or another branch.
git show hash#:path/to/that/file/from/root/of/git/repo git show branch:path/to/that/file/from/root/of/git/repo
7.5 Show differences between two commits
or between certain commits and current status
git diff HEAD~2 git diff HEAD~1..HEAD~3 git diff d151d9d..9a72743 git diff branch1..branch2 [path/to/afile]
7.6 Show what revision and author last modified each line of a file
Like cvs annotate
git blame file_name
8 Clean up disk space
NOTE:
- Re-think if the size is really an issue.
- Be careful, backup first.
- Do this before pushing commits to other repositories.
Git will run garbage collection once for a while automatically. However, if you cannot wait for that, do it manually this way:
rm -rf .git/refs/original/ git reflog expire --expire=now --all git gc --aggressive --prune=now
9 Github
- download zip instead of clone
For instance, the url for repository of the software "git" is https://github.com/git/git, to download the source of v1.8.5.4 as a zip file, just https://github.com/git/git/zipball/v1.8.5.4
10 Store and distribute configure files using git
- Set up:
- All hosts can be visited via SSH
- On one host, say "mylaptop", put configure files (say, .vimrc .bashrc)
into
~/.dotfiles
. cd ~/.dotfiles && git init
- On other hosts
git clone mylogin@mylaptop:.dotfiles
.- If mylaptop does not turn on SSH service, scp the directory to other hosts.
- Sync: on other hosts, run
git fetch mylogin@mylaptop:.dotfiles
.- If mylaptop disabled SSH service, we can push the changes to other hosts
on mylaptop instead:
git push mylogin@server1:.dotfiles branch
- NOTE: you may want to save the URL for remote repository using
git remote add server1 mylogin@server1:./dotfiles
- NOTE: you may want to save the URL for remote repository using
- If mylaptop disabled SSH service, we can push the changes to other hosts
on mylaptop instead: