git的相关配置

git的相关配置

全局设置

1
2
$ git config --global user.name "AtlasColin"
$ git config --global user.email atlas365@163.com

配置完成之后会在$HOME目录下生成一个.gitconfig配置文件,具体参考示例

--local 是将这些内容写入 project 下的 .git/config 文件中,每个project都可以有不同的配置。

自动补全

如果你系统上安装git之后没有自动补全功能,可以按如下操作来添加补全功能,记得需要重新登录一下。

1
$ wget -O /etc/profile.d/git-completion.sh https://raw.github.com/git/git/master/contrib/completion/git-completion.bash

开始使用

  • 创建新的git仓库
1
2
3
4
5
6
7
8
$ mkdir git_repo
$ cd git_repo
$ git init
$ echo "test" > README.mkd
$ git add README.mkd
$ git commit -m "add README.mkd file"
$ git remote add origin git@github.com:username/test.git
$ git push -u origin master
  • 使用已存在的git仓库
1
2
3
$ cd git_repo
$ git remote add origin git@github.com:username/test.git
$ git push -u origin master

注意,如果提示fatal: remote origin already exists.,那么说明该本地仓库已经有远端地址了。你可以先使用git remote rm origin删除origin,或者使用git remote add other_name git@github.com:username/test.git来添加(提交时记得使用git push -u other_name master)。

一次提交到多个远端仓库

假设现有仓库地址为: git@github.com:AtlasColin/knowledges.git

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ git clone git@github.com:AtlasColin/knowledges.git
$ cd knowledges
$ vim .git/config
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
[remote "origin"]
url = git@github.com:AtlasColin/knowledges.git
url = git@gitshell.com:AtlasColin/knowledges.git
url = git@bitbucket.org:AtlasColin/knowledges.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
remote = origin
merge = refs/heads/master

然后第一次提交时需要执行git push -u origin master,再往后就只需要执行git push就能把修改提交到上述三个远端仓库了。

注意:在 Git 2.0 将会更改默认的push动作为『只 push 当前 branch 到远端仓库』。如果想继续使用git push both命令需要手动设置一下git push的默认动作git config --global push.default matching

push.default有几个简单动作,这里介绍matchingsimple,二者意思分别是 push 本地所有的分支到远端仓库和 push 本地当前分支到上游分支。这个解释貌似还不够精确,可以man git-config来查看详细说明。

在现有仓库上创建孤儿分支

孤儿分支意思为该分支中没有任何内容,与之前创建的其他分支没有任何关联。

1
2
3
4
5
6
7
8
9
10
$ git clone git@github.com:AtlasColin/knowledges.git
$ cd knowledges
$ git checkout --orphan new_branch
Switched to a new branch 'new_branch'
$ git rm -rf . # 删除旧工作目录树中所有文件
$ rm .gitignore # 如果有该文件的话就删除
$ echo "orphan branch" > README.mkd
$ git add .
$ git commit -m "add README.mkd file"
$ git push origin new_branch

提交单个分支到远端git仓库

git push命令默认是将所有分支(branch)都提交到git仓库,有时你只想提交某个分支到远端仓库,那么就就需要使用git push origin HEAD。当然也可以使用git config --global push.default tracking命令来改变git push的默认操作,意思是执行git push时默认只提交当前分支到远端git仓库。

git常用指令

以下几个是git常用的指令,可以简单了解一下。

git config

在使用git前最好先配置一下你的个人信息及使用偏好。以下命令的意思就不用解释了吧,执行完以下命令就会在你的家目录(~)下生成一个文件~/.gitconfig

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ git config --global user.name "AtlasColin"
$ git config --global user.email atlas365@163.com
$ git config --global core.editor vim
$ git config --global merge.tool vimdiff
$ git config --global color.status auto
$ git config --global color.branch auto
$ git config --global color.interactive auto
$ git config --global color.diff auto
$ git config --global push.default simple
$ git config --global alias.co checkout
$ git config --global alias.ci commit
$ git config --global alias.st status
$ git config --global alias.last 'log -1 HEAD'
$ git config --global alias.unstage 'reset HEAD --'

git add

$$

$$

添加文件内容到索引中去(暂存文件),几个简单示例:

1
2
3
4
$ git add .
$ git add --all
$ git add *.txt
$ git add directory/*.sh

突然你又不想git add了,那么执行以下命令:

1
2
3
$ git reset .
$ git reset *.txt
$ git reset directory/*.sh

git rm

删除索引和当时工作目录中的文件。

1
2
3
$ git rm filename
$ git rm -f *.txt
$ git rm -r .

git commit

将当前改动记录到仓库中,即提交改动到本地仓库中。

1
$ git commit -m "add a file and remove a file"

突然你又不想git commit了,那么执行以下命令:

1
$ git reset HEAD^

commit之后发现少添加了一个文件:

1
2
3
$ git commit -m'msg'
$ git add forget_file
$ git commit --amend

你的 commit 已经 push 到远程分支(master)了,现在你想反悔了:

1
2
3
4
$ git clone git@github.com:AtlasColin/knowledges.git
$ cd knowledges
$ git reset HEAD^
$ git push -f master

git status

查看当前工作目录的状态,即修改、添加及删除了哪些文件。

1
$ git status

git checkout

检出一个分支和目录到当前工作目录中,可以简单理解为切换分支的命令。

以下命令分别为切换到分支 branch1 和创建一个新的分支 new_branch 。

1
2
$ git checkout branch1
$ git checkout -b new_branch

取消本地改动:

1
$ git checkout -- file_name

git clean

清理当前工作目录。

1
2
3
$ git clean -nd
$ git clean -fd
$ git clean -fX

git branch

  • 列出、创建和删除分支。

以下指令分别为列出本地分支、所有分支、远端分支、创建、删除、强制删除分支。

1
2
3
4
5
6
$ git branch --list
$ git branch --all
$ git branch --remotes
$ git branch new_branch
$ git branch --delete branch_name
$ git branch -D branch_name

删除remote tracking branch,就是git branch -r命令列出的分支。

1
2
$ git branch -r
$ git branch -d -r origin/develop
  • 合并分支

如果出现冲突,那么手动解决冲突就可以了。

1
2
3
$ git checkout branch_name
$ git checkout master
$ git merge branch_name
  • 删除远程分支

合并分支之后如果不再需要以前的分支了,那么可以在本地及远程删除它。

1
2
3
$ git branch -d branch_name
$ git branch -D branch_name
$ git push origin :branch_name

这条命令耐人寻味啊,其中origin是你的远程仓库名字(git remote -v可以查看到)。

git diff

查看改动内容。

1
2
3
4
$ git diff filename
$ git diff .
$ git diff revision1 revision2
$ git diff branch1 branch2

DIFF暂存(添加到索引中)的文件:

1
2
$ git add .
$ git diff --cached

View the redundant Tab or Space in your codes:

1
2
$ git diff --check
$ git diff --check --cached

只查看更改了哪些文件:

1
$ git diff --name-only

git init

git log

查看修改日志。

git log – filename

查看某个文件(包括已删除的文件)的修改历史,输出为commit info。

git log -p – filename

查看某个文件(包括已删除的文件)的修改历史,输出为commit info和diff。

git merge

git mv

git pull

git push

git rebase

你检索出代码之后(假设是master分支),创建了一个分支,然后修改了这个分支。另一个人也检索出代码(假设是master分支),然后修改了这个分支并提交到远端了。这时你需要重新从远端检索一下(master)分支的代码,然后切换到你创建的那个分支,再执行rebase命令,因为你这个分支的 base 分支已经发生变化了,你要合并到 base 分支的话需要重新 rebase 一下。

1
2
3
4
5
6
7
$ git clone -b master git@github.com:AtlasColin/knowledges.git
$ git checkout -b new_branch
$ git checkout master
$ git pull
$ git checkout new_branch
$ git rebase
$ git rebase --continue

你执行git rebase之后可能会有文件冲突,这时你需要手动解决冲突,解决之后继续rebase。

git cherry-pick

把已经提交的commit从一个分支移动到另一个分支。使用场景如下:

你有两个分支分别是master和stable,并且stable是master的一个历史commit。有一个bug存在于stable中,很明显这个bug也会存在于master中,你在stable里修复了这个bug,现在你也要在master里修复这个bug,这时你就需要使用cherry-pick把修复这个bug的commit移动到master分支里。

1
2
3
4
5
6
$ git checkout stable
$ git commit -m"fix a bug" # commit id: 2ea0234b1fa6
$ git checkout master
$ git cherry-pick 2ea0234b1fa6
$ vim xxx # solve conflicts
$ git commit -c 2ea0234b1fa6

git revert

git reset

一不小心执行了git add .,然后就可以用git reset命令来破了。

删除最近一次 commit ,但保留这次 commit 中修改的内容,即用git status来查看会显示有文件等待提交。

1
$ git reset --soft HEAD^

删除最近一次 commit ,并且不保留这次 commit 中的修改内容,即用git status来查看会显示没有改动。

git stash

暂时保存工作目录里的东东,随后可以再还原回来。

1
2
3
# git stash -a
# git stash list
# git stash pop

git submodule

git 是分布式的,每次只能将整个 repo 全部下载下来进行更改提交,这样明显不太合理,因为很多时候你只想改动一点代码,只需要将这部分代码所在的目录 clone 下来就行了。为了解决这个问题,git 引入了 submodule ,即一个 git repo 里可以包含多个 child git repo 。

一个比较大的项目,里面肯定会包含很多模块及子项目,可以将这些模块和子项目分别做成 git repo ,然后用大项目的 git repo 将其包含进来就可以了,举例如下:

一个项目(foo)包含了一个子项目(bar),主项目的 repo 是 https://github.com/AtlasColin/knowledges,子项目的 repo 地址是 https://github.com/AtlasColin/vim,需要做以下操作来完成 git submodule 的创建。

1
2
3
4
5
$ git clone https://github.com/AtlasColin/knowledges
$ cd linux
$ git submodule add https://github.com/AtlasColin/vim vim
$ git status
$ git commit -m"add a submodule vim"

git submodule add命令会生成一个.gitmodules文件,并且当前目录下也会出现vim这个 repo 。

其他人 clone 时默认是不会将vim的代码clone下来的,并且vim这个 submodule 体现在本地文件系统上是个目录,而在 git repo 里其实是一个空的文本文件。如果想将 submodule 即子项目的代码也全部 clone 下来,你需要执行以下操作:

1
2
3
4
$ git clone https://github.com/AtlasColin/knowledges.git
$ cd linux
$ git submodule init
$ git submodule update

删除 submodule

1
$ git rm -r submodule

git tag

个人感觉功能比branch强大点,因为tag里可以加注释。

1
2
3
4
5
6
7
$ git tag -a tagname -m"tag message"
$ git tag tagname -f -m"new tag message"
$ git push origin tagname
$ git push --tags origin tagname
$ git push orgin :tagname
$ git push --delete orgin tagname
$ git push orgin :refs/tags/tagname

git blame

查看某个文件当前内容的修改记录,即都在哪个commit中被谁修改的。

1
$ git blame filename

会列出filename文件中所有行都是在什么时候被添加的、被谁添加的以及被谁在哪个commit里添加的。

1
2


git ls-remote

查看远端仓库里的信息,比如tag之类的东东:

1
$ git ls-remote --tags orign

Why duplicate tag in remotes: http://stackoverflow.com/q/5346060/1536735

Sparse Checkout

意思就是只 Checkout 某个文件或某些文件。

1
2
3
4
5
6
git init linux
cd linux
git config core.sparsecheckout true
git remote add origin https://github.com/AtlasColin/knowledges.git
echo 'git' >> .git/info/sparse-checkout
git pull origin master

以上的意思就是只 Checkout 仓库 Master 分支上的根目录下的git目录里的内容,其实还是会从远端仓库拉下所有代码,只是在本地把除了git目录以外的东西都隐藏掉了。

Squash 多个 commits 为一个

git log 输出如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
commit f1f0f4629ee714533799cbad131d89e70ed53100
Author: AtlasColin <atlas365@163.com>
Date: Wed Jun 22 12:08:21 2016 +0800

New Feature: step 3

commit 2da26d85988aae5bef68498b66a2298e655b3a67
Author: AtlasColin <atlas365@163.com>
Date: Wed Jun 22 12:08:10 2016 +0800

New Feature: step 2

commit 5acf4b84a435535d679b1777bfc9fc4a7750ee11
Author: AtlasColin <atlas365@163.com>
Date: Wed Jun 22 12:08:03 2016 +0800

New Feature: step 1

commit 5b33fc2ddaa152e9ce10a4371e6cad6148eb974c
Author: AtlasColin <atlas365@163.com>
Date: Wed Jun 22 12:07:45 2016 +0800

first commit

你添加了一个New Feature,用了 3 个 Commits,现在你需要把这三个 Commits 合并成一个。

1
2
3
4
$ git rebase -i 5b33fc2ddaa152e9ce10a4371e6cad6148eb974c
pick 5acf4b8 New Feature: step 1
pick 2da26d8 New Feature: step 2
pick f1f0f46 New Feature: step 3

然后修改一下,仅保留一个pick,其他都改成squash,意思是将所有的 Commit 都压缩成保留的这一个pick Commit 上,然后保存。

1
2
3
pick 5acf4b8 New Feature: step 1
squash 2da26d8 New Feature: step 2
squash f1f0f46 New Feature: step 3

再次查看git log就会变成如下的样子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
commit b4d5a507a722d83c611108204a4100a5152f5fe5
Author: AtlasColin <atlas365@163.com>
Date: Wed Jun 22 12:08:03 2016 +0800

New Feature: step 1

New Feature: step 2

New Feature: step 3

commit 5b33fc2ddaa152e9ce10a4371e6cad6148eb974c
Author: AtlasColin <atlas365@163.com>
Date: Wed Jun 22 12:07:45 2016 +0800

first commit

从历史记录时删除大文件

1
2
3
4
5
$ git filter-branch --force --index-filter \
'git rm --cached --ignore-unmatch PATH-TO-YOUR-BIG-FILES' \
--prune-empty --tag-name-filter cat -- --all
$ git push origin --force --all
$ git push origin --force --tags

这样会导致所有和PATH-TO-YOUR-BIG-FILES相关的 commit 都会被修改,感觉压根就不应该提交大文件的。

给 Git 挂代理

对于 Git over http/https,可以这样做:

1
2
3
4
$ export all_proxy=http://1.2.3.4:3128
$ export all_proxy=socks5://1.2.3.4:1080
$ git clone http://github.com/user/repo.git
$ git clone https://github.com/user/repo.git

对于 Git over SSH,可以这样做:

1
2
3
4
vim ~/.ssh/config
Host github.com
User git
ProxyCommand nc -X 5 -x localhost:1080 %h %p

原理是给 SSH 配置代理,其中-X 5的意思是使用 socks5 协议,-x localhost:1080就是 socks5 的代理地址了,这两个都是 nc 的参数。

其他

给GIT SSH添加参数

默认情况下,使用git clone时会使用默认的ssh key连接,你现在(git 2.3)可以自定义ssh key的位置了。

1
$ GIT_SSH_COMMAND='ssh -i /path/to/ssh_private_key' git clone git@github.com:AtlasColin/knowledges.git

给自己项目在github上创建一个mirror

1
2
3
4
5
6
7
8
9
10
11
12
13
# In this example, we use an external account named extuser and
# a GitHub account named ghuser to transfer repo.git

git clone --bare https://githost.org/extuser/repo.git
# Make a bare clone of the external repository to a local directory

cd repo.git
git push --mirror https://github.com/ghuser/repo.git
# Push mirror to new GitHub repository

cd ..
rm -rf repo.git
# Remove temporary local repository