Git入门教程
这是一篇Git入门教程,开始阅读本教程之前,请先仔细阅读目录,巧用目录来快速指引你阅读,无关紧要的目录内容可以跳过。
Git简介
Git是目前世界上最先进的分布式版本控制系统。
版本控制
典型代表Word文件的编辑,你的文件夹中是不是有这样的情况:
word20160301.doc word备份的.doc word(小王).doc word-03.doc word.doc
而某一天,你可能需要以前修改过的版本(因为,经常会遇到这种抽风的上司或者客户)
而由版本控制给你带来的是:
版本 用户 说明 日期 1 张三 删除了软件服务条款5 7/12 10:38 2 张三 增加了License人数限制 7/12 18:09 3 李四 财务部门调整了合同金额 7/13 9:51 4 张三 延长了免费升级周期 7/14 15:17
而且,你想退回到哪里,就可以退回到哪里!
记住第一个关键词:(无尽的)后悔药
分布式 VS 集中式
集中式,典型的代表就是SVN,版本库是集中存放在中央服务器的,而干活的时候,用的都是自己的电脑,所以要先从中央服务器取得最新的版本,然后开始干活,干完活了,再把自己的活推送给中央服务器。
分布式,分布式版本控制系统根本没有“中央服务器”,每个人的电脑上都是一个完整的版本库,分布式版本控制系统的安全性要高很多,因为每个人电脑里都有完整的版本库,某一个人的电脑坏掉了不要紧,随便从其他人那里复制一个就可以了。而集中式版本控制系统的中央服务器要是出了问题,所有人都没法干活了。
Git不单是不必联网这么简单,Git更强大的是分支管理。后面讲到~~~~
关于更多SVN&Git的区别可以参见: [蒋鑫:为什么 Git 比 SVN 好](http://blog.jobbole.com/20069/) [SVN 和 Git 在日常使用中的明显差异](https://github.com/xirong/my-git/blob/master/why-git.md) [GIT和SVN之间的五个基本区别](http://www.vaikan.com/5-fundamental-differences-between-git-svn/)
记住第二个关键词:分布式
Git环境搭建
安装Git
* 在Linux(Debian)上安装Git:
apt-get install git
* Mac OS X上安装Git:
一是安装homebrew,然后通过homebrew安装Git,具体方法请参考homebrew的文档:[http://brew.sh/](http://brew.sh/)。
第二种方法更简单,也是推荐的方法,就是直接从AppStore安装Xcode,Xcode集成了Git,不过默认没有安装,你需要运行Xcode,选择菜单“Xcode”->“Preferences”,在弹出窗口中找到“Downloads”,选择“Command Line Tools”,点“Install”就可以完成安装了。
* 在Windows上安装Git
从这里[https://git-for-windows.github.io/](https://git-for-windows.github.io/)下载,双击安装
安装完成后,可以在右键菜单/开始菜单中找到“Git”->“Git Bash”,蹦出一个类似命令行窗口的东西,就说明Git安装成功!
全局变量设置
就像Java需要设置Path一样,Git需要设置一些全局变量。
“Git”->“Git Bash”
$ git config --global user.name "Your Name"
$ git config --global user.email "email@example.com"
设置用户与Email,相当于自报家门,让版本库有一个记录。注意:git config
命令的--global
是全局设置的意思。
任何一个命令或者参考:
git [命令] --help
来查看帮助,或者登陆官方来学习命令http://git-scm.com/doc
参考资料:Git 内部原理 - 环境变量
创建版本库
非常简单。
windows下,需要建立的版本库的地方,右键git bash->
$ git init
瞬间Git就把仓库建好了,而且告诉你是一个空的仓库(empty Git repository),细心的读者可以发现当前目录下多了一个.git的目录,这个目录是Git来跟踪管理版本库的,没事千万不要手动修改这个目录里面的文件,不然改乱了,就把Git仓库给破坏了。
PS:如果你没有看到.git目录,那是因为这个目录默认是隐藏的
Linux中:
如果,需要在learngit目录下建立一个Git仓库,可以如下操作
$ mkdir learngit
$ cd learngit
$ git init
你也可以这样:
$ git init learngit
试一试吧!
基本操作
Git工作区和暂存区:
我们看到目录为工作区(/learngit);需要进行提交到版本库的文件放在暂存区(看不到,需要使用git status
来查看)。
git status
命令:可以让我们时刻掌握仓库当前的状态。
git diff
命令:让我们查看文件与版本库中的区别。
获取远程仓库代码(前题是init
之后)
克隆仓库:
$ git clone [user@]example.com:path/to/repo.git/
或者添加远程仓库:
使用
git remote add
命令,添加一个远程仓库的链接,命令格式:git remote add [远程仓库别名] [远程仓库地址]
$ git remote add origin git@github.com:michaelliao/learngit.git
拉取代码。
如果已经被git管理的项目,则使用
git pull
和git fetch
来管理代码的拉取与更新:使用
git pull
拉取远程代码的HEAD
头标记,即最新的代码。命令格式:
$ git pull <远程主机名> <远程分支名>:<本地分支名>
$ git pull
提交代码
把所有的文件更改提交到暂存区:
$ git add -a
为所有暂存区的代码写入日志并提交到本地仓库:
$ git commit -m "(something)"
把所有本地仓库的提交,更新到远程仓库:
$ git push
Git时光机
git log
命令:查看每次修改的日志文件。
git log与git reflog的区别,记得几点:git log是顺着当前分支往前去查找提交记录,而git reflog并不像git log去遍历提交历史,它都不是仓库的一部分,它不包含推送、更新或者克隆,而是作为本地提交记录的清单。简单理解:本地后悔药。
git reset
命令:回退命令。首先,Git必须知道当前版本是哪个版本,在Git中,用
HEAD
表示当前版本,上一个版本就是HEAD^
,上上一个版本就是HEAD^^
,当然往上100个版本写100个^
比较容易数不过来,所以写成HEAD~100
。$ git reset --hard HEAD^ HEAD is now at ea34578 add distributed
回退add命令提交到缓存区的文件,并不会把文件恢复缓存区,需要区别(3)
git checkout
命令:$ git reset HEAD <file>
git checkout -- <file>
命令:丢弃缓存区文件的修改,把文件恢复到git add
之前的状态。git diff HEAD -- <file>
命令可以查看工作区和版本库里面最新版本的区别 git rm
删除文件。
标签管理
发布一个版本时,我们通常先在版本库中打一个标签,这样,就唯一确定了打标签时刻的版本。将来无论什么时候,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来。所以,标签也是版本库的一个快照。
Git的标签虽然是版本库的快照,但其实它就是指向某个commit的指针(跟分支很像对不对?但是分支可以移动,标签不能移动),所以,创建和删除标签都是瞬间完成的。
创建标签(快照)
在Git中打标签非常简单,首先,切换到需要打标签的分支上:
$ git branch * dev master $ git checkout master Switched to branch 'master'
然后,敲命令
git tag <name>
就可以打一个新标签:$ git tag v1.0
可以用命令
git tag
查看所有标签:$ git tag v1.0
默认标签是打在最新提交的commit上的。有时候,如果忘了打标签,比如,现在已经是周五了,但应该在周一打的标签没有打,怎么办?
方法是找到历史提交的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
比方说要对add merge这次提交打标签,它对应的commit id是
6224937
,敲入命令:$ git tag v0.9 6224937
再用命令
git tag
查看标签:$ git tag v0.9 v1.0
注意,标签不是按时间顺序列出,而是按字母排序的。
可以用
git show <tagname>
查看标签信息:$ git show v0.9 commit 622493706ab447b6bb37e4e2a2f276a20fed2ab4 Author: Brian <brian@toimc.com> Date: Thu Aug 22 11:22:08 2013 +0800 add merge ...
可以看到,v0.9确实打在add merge这次提交上。
还可以创建带有说明的标签,用
-a
指定标签名,-m
指定说明文字:$ git tag -a v0.1 -m "version 0.1 released" 3628164
用命令
git show <tagname>
可以看到说明文字:$ git show v0.1 tag v0.1 Tagger: Brian <brian@toimc.com> Date: Mon Aug 26 07:28:11 2013 +0800 version 0.1 released commit 3628164fb26d48395383f8f31179f24e0882e1e0 Author: Brian <brian@toimc.com> Date: Tue Aug 20 15:11:49 2013 +0800 append GPL
还可以通过
-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 tag -d v0.9 Deleted tag 'v0.9' (was 6224937)
然后,从远程删除。删除命令也是push,但是格式如下:
$ git push origin :refs/tags/v0.9 To git@github.com:michaelliao/learngit.git - [deleted] v0.9
使用.gitignore忽略文件
有些时候,你必须把某些文件放到Git工作目录中,但又不能提交它们,比如保存了数据库密码的配置文件啦,等等,每次git status都会显示Untracked files …,有强迫症的童鞋心里肯定不爽。
好在Git考虑到了大家的感受,这个问题解决起来也很简单,在Git工作区的根目录下创建一个特殊的.gitignore文件,然后把要忽略的文件名填进去,Git就会自动忽略这些文件。
不需要从头写.gitignore
文件,GitHub已经为我们准备了各种配置文件,只需要组合一下就可以使用了。所有配置文件可以直接在线浏览:https://github.com/github/gitignore
忽略文件的原则是:
- 忽略操作系统自动生成的文件,比如缩略图等;
- 忽略编译生成的中间文件、可执行文件等,也就是如果一个文件是通过另一个文件自动生成的,那自动生成的文件就没必要放进版本库,比如Java编译产生的.class文件;
- 忽略你自己的带有敏感信息的配置文件,比如存放口令的配置文件。
举个例子:
假设你在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 bash中输入以下命令:
$ touch .gitignore
$ vi .gitignore
Git忽略规则及.gitignore规则不生效的解决办法:
git rm -r --cached .
git add .
git commit -m 'update .gitignore'
PS:注意–cached后面有一个”.”,add后面也有一个“.”
完成上述操作后,再重新修改.gitnore文件,并
git add .
添加文件到缓存区
配置命令别名
有没有经常敲错命令?比如git status
?status这个单词真心不好记。
如果敲git st
就表示git status
那就简单多了,当然这种偷懒的办法我们是极力赞成的。
我们只需要敲一行命令,告诉Git
,以后st
就表示status
:
$ git config --global alias.st status
好了,现在敲git st
看看效果。
当然还有别的命令可以简写,很多人都用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 ci -m "bala bala bala..."
--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
commit adca45d317e6d8a4b23f9811c3d7b7f0f180bfe2
Merge: bd6ae48 291bea8
Author: Michael Liao <askxuefeng@gmail.com>
Date: Thu Aug 22 22:49:22 2013 +0800
merge & fix hello.py
甚至还有人丧心病狂地把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 lg的效果:
为什么不早点告诉我?别激动,咱不是为了多记几个英文单词嘛!
配置文件
配置Git的时候,加上--global
是针对当前用户起作用的,如果不加,那只针对当前的仓库起作用。
配置文件放哪了?每个仓库的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
别名就在[alias]
后面,要删除别名,直接把对应的行删掉即可。
而当前用户的Git配置文件放在用户主目录下的一个隐藏文件.gitconfig
中:
$ cat .gitconfig
[alias]
co = checkout
ci = commit
br = branch
st = status
[user]
name = Your Name
email = your@email.com
Git恢复流程
当中心仓库由于不可抗拒因素而垮了之后:
项目Git恢复流程:
方法一:恢复指定分支
1.注册账号→输入SSH keys→新建项目。
2.在原项目文件夹下,使用git remote -v
命令查看
$ git remote -v
origin git@192.168.1.222:kanlidy/HelloGit.git (fetch)
origin git@192.168.1.222:kanlidy/HelloGit.git (push)
使用git remote remove origin
删除原有仓库地址。
3.使用新的仓库地址:
git remote add origin [ssh仓库地址]
如:
git remote add origin ssh://git@github.com/kanlidy/HelloGit.git
4.添加文件,并Commit提交,最后push上远程指定分支
git add .
git commit -m "add my repo"
#这条命令会把当前分支,推送到远程的master分支
git push origin master
#如果需要把dev分支,推送到远程的dev分支
git push origin dev:dev
方法二:恢复项目所有分支:
git remote remove origin
git remote add origin [新的SSH仓库地址]
git push --mirror ssh://git@github.com/kanlidy/LearnPython.git
本地多个SSH密钥文件
有的时候,不仅github使用ssh key,工作项目或者其他云平台可能也需要使用ssh key来认证,如果每次都覆盖了原来的id_rsa文件,那么之前的认证就会失效。这个问题我们可以通过在~/.ssh目录下增加config文件来解决。
第一步依然是配置git用户名和邮箱
git config user.name "用户名" git config user.email "邮箱"
生成ssh key时同时指定保存的文件名
ssh-keygen -t rsa -f ~/.ssh/id_rsa.company -C "email"
上面的
id_rsa.company
就是我们指定的文件名,这时~/.ssh目录下会多出id_rsa.company
和id_rsa.company.pub
两个文件,id_rsa.company.pub
里保存的就是我们要使用的key。新增并配置config文件
添加config文件
如果config文件不存在,先添加;存在则直接修改
touch ~/.ssh/config
在config文件里添加如下内容(User表示你的用户名)
Host 域名或者IP IdentityFile ~/.ssh/id_rsa.company User test
如:
Host 192.168.1.222 IdentityFile ~/.ssh/id_rsa.company User kanlidy
上传key到云平台后台(省略)
测试ssh key是否配置成功 ssh -T git@域名或者IP
如:
ssh -T git@192.168.1.222 -p 8082
成功的话会显示:
Welcome to GitLab, kanlidy!
至此,本地便成功配置多个ssh key。日后如需添加,则安装上述配置生成key,并修改config文件即可。