- 本地创建一个版本库:
$ mkdir learngit
$ cd learngit
$ pwd
/Users/michael/learngit
- 把目录变成Git可以管理的仓库:
$ git init
Initialized empty Git repository in /Users/michael/learngit/.git/
在此目录新建文件,并添加到git仓库:
$ git add readme.txt
- 把文件提交到仓库(可一次提交多个已add的文件):
$ git commit -m "wrote a readme file"
[master (root-commit) cb926e7] wrote a readme file
1 file changed, 2 insertions(+)
create mode 100644 readme.txt
- git status 查看仓库当前的状态:
$ git status
# On branch master
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: readme.txt
#
no changes added to commit (use "git add" and/or "git commit -a")
- git diff 查看修改内容:
$ git diff readme.txt
diff --git a/readme.txt b/readme.txt
index 46d49bf..9247db6 100644
--- a/readme.txt
+++ b/readme.txt
@@ -1,2 +1,2 @@
-Git is a version control system.
+Git is a distributed version control system.
Git is free software.
- 用git log可以查看提交历史:
$ git log
commit 3628164fb26d48395383f8f31179f24e0882e1e0
Author: Michael Liao <askxuefeng@gmail.com>
Date: Tue Aug 20 15:11:49 2013 +0800
append GPL
commit ea34578d5496d7dd233c827ed32a8cd576c5ee85
Author: Michael Liao <askxuefeng@gmail.com>
Date: Tue Aug 20 14:53:12 2013 +0800
add distributed
commit cb926e7ea50ad11b8f9e909c05226233bf755030
Author: Michael Liao <askxuefeng@gmail.com>
Date: Mon Aug 19 17:51:55 2013 +0800
wrote a readme file
或者
$ git log --pretty=oneline
3628164fb26d48395383f8f31179f24e0882e1e0 append GPL
ea34578d5496d7dd233c827ed32a8cd576c5ee85 add distributed
cb926e7ea50ad11b8f9e909c05226233bf755030 wrote a readme file
- 用git reflog查看命令历史:
$ git reflog
ea34578 HEAD@{0}: reset: moving to HEAD^
3628164 HEAD@{1}: commit: append GPL
ea34578 HEAD@{2}: commit: add distributed
cb926e7 HEAD@{3}: commit (initial): wrote a readme file
- 使用命令
git reset --hard commit_id
滚回历史版本:
(上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100)
$ git reset --hard HEAD^
HEAD is now at ea34578 add distributed
撤销修改
场景1:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令git checkout -- file
。
场景2:当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令git reset HEAD file
,就回到了场景1,第二步按场景1操作。
场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,参考版本回退(git reset --hard commit_id
),不过前提是没有推送到远程库。删除文件
Git知道你删除了文件,因此,工作区和版本库就不一致了,git status命令会立刻告诉你哪些文件被删除了。
有两个选择:
一是确实要从版本库中删除该文件,那就用命令git rm file
删掉,并且git commit;
二是删错了,因为版本库里还有呢,所以可以很轻松地把误删的文件恢复到最新版本,git checkout -- file
;但如果修改后没commit的文件删除了,所做修改也就丢失了(discard changes in working directory)。
注:git checkout其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。添加远程库
先新建一个 远程库repo-name
要关联一个远程库,使用命令
git remote add origin git@server-name:path/repo-name.git;
关联后,使用命令git push -u origin master
第一次推送master分支的所有内容;
此后,每次本地提交后,只要有必要,就可以使用命令git push origin master
推送最新修改;从远程库克隆
首先cd进入目录,git clone git@github.com:michaelliao/gitskills.git
GitHub给出的地址不止一个,还可以用https://github.com/michaelliao/gitskills.git
这样的地址。创建与合并分支
Git鼓励大量使用分支:
查看分支:git branch
创建分支:git branch <name>
切换分支:git checkout <name>
创建+切换分支:git checkout -b <name>
合并某分支到当前分支:git merge <name>
删除分支:git branch -d <name>
请注意–no-ff参数,表示禁用Fast forward:加上–no-ff参数就可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并,而fast forward合并就看不出来曾经做过合并。
$ git merge --no-ff -m "merge with no-ff" dev
Merge made by the 'recursive' strategy.
readme.txt | 1 +
1 file changed, 1 insertion(+)
- 解决冲突
当Git无法自动合并分支时,就必须首先解决冲突。解决冲突后,再提交,合并完成。
用git log –graph命令可以看到分支合并图。
$ git log --graph --pretty=oneline --abbrev-commit
* 59bc1cb conflict fixed
|\
| * 75a857c AND simple
* | 400b400 & simple
|/
* fec145a branch test
...
- 分支管理策略
- Bug分支
Git还提供了一个stash功能,可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作
$ git stash
Saved working directory and index state WIP on dev: 6224937 add merge
HEAD is now at 6224937 add merge
此时,工作区是干净(clean)的,首先确定要在哪个分支上修复bug,假定需要在master分支上修复,就从master创建临时分支:
$ git checkout master
$ git checkout -b issue-101
现在修复bug,然后提交:
$ git add readme.txt
$ git commit -m "fix bug 101"
修复完成后,切换到master分支,并完成合并,最后删除issue-101分支:
$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 2 commits.
$ git merge --no-ff -m "merged bug fix 101" issue-101
Merge made by the 'recursive' strategy.
readme.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
$ git branch -d issue-101
Deleted branch issue-101 (was cc17032).
接着回到dev分支干活
$ git checkout dev
$ git status
用git stash list命令看看:工作现场存到哪去了
$ git stash list
stash@{0}: WIP on dev: 6224937 add merge
需要恢复一下stash ,有两个办法:
一是用git stash apply恢复,但是恢复后,stash内容并不删除,你需要用git stash drop来删除;
另一种方式是用git stash pop,恢复的同时把stash内容也删了:
$ git stash pop
# On branch dev
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# new file: hello.py
#
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: readme.txt
#
Dropped refs/stash@{0} (f624f8e5f082f2df2bed8a4e09c12fd2943bdd40)
可以多次stash,恢复的时候,先用git stash list查看,然后恢复指定的stash,用命令:
$ git stash apply stash@{0}
- Feature分支
软件开发中,总有无穷无尽的新的功能要不断添加进来。
添加一个新功能时,你肯定不希望因为一些实验性质的代码,把主分支搞乱了,所以,每添加一个新功能,最好新建一个feature分支,在上面开发,完成后,合并,最后,删除该feature分支。
如果要丢弃一个 没有被合并过 的分支,可以通过git branch -D <name>
强行删除。 多人协作
1.查看远程库信息,使用git remote -v;
2.本地新建的分支如果不推送到远程,对其他人就是不可见的;
3.从本地推送分支,使用git push origin branch-name,如果推送失败,先用git pull抓取远程的新提交;
4.在本地创建和远程分支对应的分支,使用git checkout -b branch-name origin/branch-name,本地和远程分支的名称最好一致;
5.建立本地分支和远程分支的关联,使用git branch –set-upstream branch-name origin/branch-name;
6.从远程抓取分支,使用git pull,如果有冲突,要先处理冲突。标签管理
为了简化commit号,发布一个版本时,我们通常先在版本库中打一个标签(tag),这样,就唯一确定了打标签时刻的版本。
在master当前版本上打标签:
$ git branch
* dev
master
$ git checkout master
$ git tag v1.0
可以用命令git tag查看所有标签:
$ git tag
v1.0
对于历史版本,方法是找到历史提交的commit id,然后打上就可以了:
$ git log --pretty=oneline --abbrev-commit
6a5819e merged bug fix 101
cc17032 fix bug 101
7825a50 merge with no-ff
6224937 add merge
59bc1cb conflict fixed
400b400 & simple
75a857c AND simple
fec145a branch test
d17efd8 remove test.txt
...
然后
$ git tag v0.9 6224937
此时就有两个标签了,可`git tag` 查看
注意,标签不是按时间顺序列出,而是按字母排序的。可以用git show <tagname>
查看标签信息:
$ git show v0.9
commit 622493706ab447b6bb37e4e2a2f276a20fed2ab4
Author: Michael Liao <askxuefeng@gmail.com>
Date: Thu Aug 22 11:22:08 2013 +0800
add merge
...
还可以创建带有说明的标签,用-a指定标签名,-m指定说明文字:
$ git tag -a v0.1 -m "version 0.1 released" 3628164
还可以通过-s用私钥签名一个标签:
$ git tag -s v0.2 -m "signed version 0.2 released" fec145a
命令git push origin <tagname>
可以推送一个本地标签;
命令git push origin --tags
可以推送全部未推送过的本地标签;
命令git tag -d <tagname>
可以删除一个本地标签;
命令git push origin :refs/tags/<tagname>
可以删除一个远程标签。
自定义Git
等待补充忽略文件
忽略文件合集A collection of .gitignore templates
在Git工作区的根目录下创建一个特殊的.gitignore文件,然后把要忽略的文件名填进去,Git就会自动忽略这些文件。
.gitignore文件本身要放到版本库里,并且可以对.gitignore做版本管理!
举个例子:
假设你在Windows下进行Python开发,Windows会自动在有图片的目录下生成隐藏的缩略图文件,如果有自定义目录,目录下就会有Desktop.ini文件,因此你需要忽略Windows自动生成的垃圾文件:
# Windows:
Thumbs.db
ehthumbs.db
Desktop.ini
有些时候,你想添加一个文件到Git,但发现添加不了,原因是这个文件被.gitignore忽略了,试着修改忽略规则,或者强制添加:
$ git add -f App.class
- 配置指令别名
用st表示status,–global参数是全局参数,也就是这些命令在当前用户的所有Git仓库下都有用。
$ git config --global alias.st status
很多人都用co表示checkout,ci表示commit,br表示branch:
$ git config --global alias.co checkout
$ git config --global alias.ci commit
$ git config --global alias.br branch
- 搭建Git服务器
待补充