$ mkdir learngit
$ cd learngit
$ pwd
/Users/michael/learngit
创建
$ git init
Initialized empty Git repository in /Users/michael/learngit/.git/
增加
$ git add readme.txt
提交
$ git commit -m "wrote a readme file"
提交
$ git add file1.txt
$ git add file2.txt file3.txt
$ git commit -m "add 3 files."
状态
$ git status
状态区别
$ git diff readme.txt
记录
$ git log
显示记录的方式
$ git log --pretty=oneline
回退到上一版本
$ git reset --hard HEAD^
回到之前的reset前的版本
$ git reset --hard 3628164
记录以前命令路程
$ git reflog
命令可以查看工作区和版本库里面最新版本的区别
git diff HEAD -- readme.txt
查看文件内容
$ cat readme.txt
命令git checkout -- readme.txt意思就是,把readme.txt文件在工作区的修改全部撤销,这里有两种情况:
$ git checkout -- readme.txt
一种是readme.txt自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;
一种是readme.txt已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。
********
git checkout -- file命令中的--很重要,没有--,就变成了“创建一个新分支”的命令
*******
git reset HEAD file可以把暂存区的修改撤销掉(unstage),重新放回工作区:
$ git reset HEAD readme.txt
删除文件 ,从文件管理中中删除
$ rm test.txt
接着,一是确实要从版本库中删除该文件,那就用命令git rm删掉,并且git commit
$ git rm test.txt
$ git commit -m "remove test.txt"
另一种情况是删错了,因为版本库里还有呢,所以可以很轻松地把误删的文件恢复到最新版本:(版本库没有被删的情况下)
$ git checkout -- test.txt
**********
…or create a new repository on the command line
*************
echo # learngit >> README.md
git init
git add README.md
git commit -m "first commit"
git remote add origin https://github.com/liunnis/learngit.git
git push -u origin master
****************
…or push an existing repository from the command line
************
git remote add origin https://github.com/liunnis/learngit.git
git push -u origin master
就可以把本地库的所有内容推送到远程库上:
$ git push -u origin master
从现在起,只要本地作了提交,就可以通过命令:
$ git push origin master
把本地master分支的最新修改推送至GitHub,现在,你就拥有了真正的分布式版本库!
****
用命令git clone克隆一个本地库:
$ git clone git@github.com:michaelliao/gitskills.git
**************************
在版本回退里,你已经知道,每次提交,Git都把它们串成一条时间线,这条时间线就是一个分支。
截止到目前,只有一条时间线,在Git里,这个分支叫主分支,
即master分支。HEAD严格来说不是指向提交,而是指向master,master才是指向提交的,所以,HEAD指向的就是当前分支。
**********
首先,我们创建dev分支,然后切换到dev分支:
$ git checkout -b dev
git checkout命令加上-b参数表示创建并切换,相当于以下两条命令:
$ git branch dev
$ git checkout dev
Switched to branch 'dev'
用git branch命令查看当前分支:
***********
现在,我们把dev分支的工作成果合并到master分支上:
$ git merge dev
合并完成后,就可以放心地删除dev分支了:
$ git branch -d dev
用带参数的git log也可以看到分支的合并情况:
$ git log --graph --pretty=oneline --abbrev-commit
远程库别一个方法
$ git remote add origin git@github.com:liunnis/learngit.git
$ git push -u origin master
准备合并dev分支,请注意--no-ff参数,表示禁用Fast forward:
$ git merge --no-ff -m "merge with no-ff" dev
工作区是干净的,刚才的工作现场存到哪去了?用git stash list命令看看:
$ git stash list
工作现场还在,Git把stash内容存在某个地方了,但是需要恢复一下,有两个办法:
一是用git stash apply恢复,但是恢复后,stash内容并不删除,你需要用git stash drop来删除;
另一种方式是用git stash pop,恢复的同时把stash内容也删了:
****************
你可以多次stash,恢复的时候,先用git stash list查看,然后恢复指定的stash,用命令:
$ git stash apply stash@{0}
现在,你终于接到了一个新任务:开发代号为Vulcan的新功能,该功能计划用于下一代星际飞船。
于是准备开发:
$ git checkout -b feature-vulcan
Switched to a new branch 'feature-vulcan'
虽然白干了,但是这个分支还是必须就地销毁:
$ git branch -d feature-vulcan
现在我们强行删除:
$ git branch -D feature-vulcan
当你从远程仓库克隆时,实际上Git自动把本地的master分支和远程的master分支对应起来了,并且,远程仓库的默认名称是origin。
要查看远程库的信息,用git remote:
$ git remote
origin
或者,用git remote -v显示更详细的信息:
$ git remote -v
推送分支
推送分支,就是把该分支上的所有本地提交推送到远程库。推送时,要指定本地分支,这样,Git就会把该分支推送到远程库对应的远程分支上:
$ git push origin master
如果要推送其他分支,比如dev,就改成:
$ git push origin dev
但是,并不是一定要把本地分支往远程推送,那么,哪些分支需要推送,哪些不需要呢?
master分支是主分支,因此要时刻与远程同步;
dev分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步;
bug分支只用于在本地修复bug,就没必要推到远程了,除非老板要看看你每周到底修复了几个bug;
feature分支是否推到远程,取决于你是否和你的小伙伴合作在上面开发。
总之,就是在Git中,分支完全可以在本地自己藏着玩,是否推送,视你的心情而定!
现在,模拟一个你的小伙伴,可以在另一台电脑(注意要把SSH Key添加到GitHub)或者同一台电脑的另一个目录下克隆:
$ git clone git@github.com:michaelliao/learngit.git
Cloning into 'learngit'...
remote: Counting objects: 46, done.
remote: Compressing objects: 100% (26/26), done.
remote: Total 46 (delta 16), reused 45 (delta 15)
Receiving objects: 100% (46/46), 15.69 KiB | 6 KiB/s, done.
Resolving deltas: 100% (16/16), done.
当你的小伙伴从远程库clone时,默认情况下,你的小伙伴只能看到本地的master分支。不信可以用git branch命令看看:
$ git branch
* master
现在,你的小伙伴要在dev分支上开发,就必须创建远程origin的dev分支到本地,于是他用这个命令创建本地dev分支:
$ git checkout -b dev origin/dev
现在,他就可以在dev上继续修改,然后,时不时地把dev分支push到远程:
$ git commit -m "add /usr/bin/env"
推送
$ git push origin dev
推送失败,因为你的小伙伴的最新提交和你试图推送的提交有冲突,解决办法也很简单,Git已经提示我们,先用git pull把最新的提交从origin/dev抓下来,然后,在本地合并,解决冲突,再推送:
$ git pull
git pull也失败了,原因是没有指定本地dev分支与远程origin/dev分支的链接,根据提示,设置dev和origin/dev的链接:
$ git branch --set-upstream dev origin/dev
这回git pull成功,但是合并有冲突,需要手动解决,解决的方法和分支管理中的解决冲突完全一样。解决后,提交,再push:
$ git commit -m "merge & fix hello.py"
[dev adca45d] merge & fix hello.py
$ git push origin dev
然后,敲命令git tag <name>就可以打一个新标签:
$ git tag v1.0
可以用命令git tag查看所有标签:
$ git tag
比方说要对add merge这次提交打标签,它对应的commit> $ git tag v0.9 6224937
注意,标签不是按时间顺序列出,而是按字母排序的。可以用git show <tagname>查看标签信息:
$ git show v0.9
还可以创建带有说明的标签,用-a指定标签名,-m指定说明文字:
$ git tag -a v0.1 -m "version 0.1> 还可以通过-s用私钥签名一个标签:
$ git tag -s v0.2 -m "signed version 0.2> 签名采用PGP签名,因此,必须首先安装gpg(GnuPG),如果没有找到gpg,或者没有gpg密钥对,
就会报错:签名采用PGP签名,因此,必须首先安装gpg(GnuPG),如果没有找到gpg,或者没有gpg密钥对,就会报错:
如果标签打错了,也可以删除:
$ git tag -d v0.1
Deleted tag 'v0.1' (was e078af9)
如果要推送某个标签到远程,使用命令git push origin <tagname>:
$ git push origin v1.0
或者,一次性推送全部尚未推送到远程的本地标签:
$ git push origin --tags
如果标签已经推送到远程,要删除远程标签就麻烦一点,先从本地删除:
$ git tag -d v0.9
Deleted tag 'v0.9' (was 6224937)
然后,从远程删除。删除命令也是push,但是格式如下:
$ git push origin :refs/tags/v0.9
比如,让Git显示颜色,会让命令输出看起来更醒目:
$ git config --global color.ui true
有些时候,你必须把某些文件放到Git工作目录中,但又不能提交它们,
比如保存了数据库密码的配置文件啦,等等,
每次git status都会显示Untracked files ...,
有强迫症的童鞋心里肯定不爽。
好在Git考虑到了大家的感受,这个问题解决起来也很简单,
在Git工作区的根目录下创建一个特殊的.gitignore文件,
然后把要忽略的文件名填进去,Git就会自动忽略这些文件。
假设你在Windows下进行Python开发,Windows会自动在有图片的目录下生成隐藏的缩略图文件,
如果有自定义目录,目录下就会有Desktop.ini文件,
因此你需要忽略Windows自动生成的垃圾文件:
# Windows:
Thumbs.db
ehthumbs.db
Desktop.ini
然后,继续忽略Python编译产生的.pyc、.pyo、dist等文件或目录:
# Python:
*.py[cod]
*.so
*.egg
*.egg-info
dist
build
加上你自己定义的文件,最终得到一个完整的.gitignore文件,内容如下:
# Windows:
Thumbs.db
ehthumbs.db
Desktop.ini
# Python:
*.py[cod]
*.so
*.egg
*.egg-info
dist
build
# My configurations:
db.ini
deploy_key_rsa
最后一步就是把.gitignore也提交到Git,
就完成了!当然检验.gitignore的标准
是git status命令是不是说working directory clean。
使用Windows的童鞋注意了,如果你在资源管理器里新建一个.gitignore文件,
它会非常弱智地提示你必须输入文件名,但是在文本编辑器里“保存”或者“另存为”就可以把文件保存为.gitignore了。
************************
有没有经常敲错命令?比如git status?status这个单词真心不好记。
如果敲git st就表示git status那就简单多了,当然这种偷懒的办法我们是极力赞成的。
我们只需要敲一行命令,告诉Git,以后st就表示status:
$ 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
--global参数是全局参数,也就是这些命令在这台电脑的所有Git仓库下都有用。
在撤销修改一节中,我们知道,命令git reset HEAD file可以把暂存区的修改撤销掉(unstage),重新放回工作区。既然是一个unstage操作,就可以配置一个unstage别名:
$ git config --global alias.unstage 'reset HEAD'
当你敲入命令:
$ git unstage test.py
实际上Git执行的是:
$ git reset HEAD test.py
配置一个git last,让其显示最后一次提交信息:
$ git config --global alias.last 'log -1'
这样,用git last就能显示最近一次的提交:
$ git last
甚至还有人丧心病狂地把lg配置成了:
git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
配置Git的时候,加上--global是针对当前用户起作用的,如果不加,那只针对当前的仓库起作用。
配置文件放哪了?每个仓库的Git配置文件都放在.git/config文件中:
配置文件放哪了?每个仓库的Git配置文件都放在.git/config文件中:
$ cat .git/config
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
precomposeunicode = true
[remote "origin"]
url = git@github.com:michaelliao/learngit.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
remote = origin
merge = refs/heads/master
[alias]
last = log -1
而当前用户的Git配置文件放在用户主目录下的一个隐藏文件.gitconfig中:
$ cat .gitconfig
[alias]
co = checkout
ci = commit
br = branch
st = status
[user]
name = Your Name
email = your@email.com |