一篇入门Git基本命令[拜读廖雪峰大神Git教程]
1.Git:分布式版本控制系统
版本控制系统:记录版本改动记录(升级、删除等),可以团队协同编辑
2.Git诞生历程
迫于Linux代码日益壮大,各地维护升级Linux志愿者强烈抱怨每次通过diff方式发给Linus,
Linus不满意当时CVS、SVM这些集中式的版本控制系统,因为不仅速度慢,而且必须联网。因此,
Linus选择了出于人道主义精神的BitMover公司免费提供的商业版本控制系统BitKeeper,但在
2005年,Linux社区一些牛人试图破解BitKeeper的协议,被BitMover公司发现了撤回了免费使用权。
转折点来了,Linus花了两周时间用C写了一个分布式版本控制系统,这就是Git!并在一个月内,
Linux系统的源码已由Git开始管理了!
Git的出现迅速流行起来后,驱动了在2008年GitHub网站的上线。无数开源项目(如jQuery/PHP/
Ruby等待)开始迁移至GitHub。
3.集中式VS分布式
集中式版本控制系统:版本库放在中央服务器中,干活是需从中取出,修改后再放回去。而这一系列操作
是需要联网的(最大的毛病)
常见的版本控制系统:
1.CVS、SVN(目前用得最多的集中式版本控制系统)-->免费开源的,但存在提交文件不完整,
版本库莫名其妙损坏等一些不稳定的问题。
2.IBM的ClearCase--->收费的,特点是安装比window大,运行比蜗牛慢,哈哈
还有微软的VSS,集成在Visual Studio,因其反人类的设计,微软自己都不好意思使用
分布式版本控制系统:没有“中央服务器”,每个人电脑都是一个完整的版本库(像本地文件一样方便存取)
当多人协作编辑时,只需要把修改推送给对方即可(通常很少在两人之间推送修改,而由一台充当
“中央服务器”的电脑来交换大家的修改,这是不影响彼此在各自电脑编辑版本库的)。
此外,这种每人电脑都有完整的版本库极大提高了系统的安全性。反而集中式的出了问题,影响很大。
常见分布式版本控制:
除了Git,还有BitKeeper、类似Git的Mercurial、Bazaar等
总之,分布式除了不需联网的便利外,其强大的“分支管理”也是一重大优势。
Git是现今最快、最简单也最流行的“分布式版本控制系统”
4. Git安装
Git现在能在Windows、Mac、Linux、Unix这些平台运行
1.在Linux安装Git
直接输入git 会提示有没安装且友好的提供了安装命令
1.1在Debian/Ubuntu linux,可用“sudo apt-get install git”
老一点的Dibian或Ubuntu Linux,改为“sudo apt-get install git-core”
(历史原因,之前有个软件名为GIT(GNU Interactiv Tools),当前Git只好命名为
git-core,但由于Git名气太大,GIT改为gnuit, 而git-core顺理成章更正“git”)
1.2 其它Linux版本,可通过源码安装。官网下载源码解压后,依次输入:./config,make,
sudo make install
2.在Mac OS X上安装Git
方法1:安装homerbrew,通过gomebrew安装Git,可参考http://brew.sh/
方法2:从AppStore安装Xcode,Xcode集成了Git,不过默认没有安装,需运行Xcode,在
选择才对“Xcode->Preferences”找到Downloads下载安装
3.在Window上安装Git
官网下载安装程序(https://git-scm.com/downloads),按默认选项安装即可。
在开始菜单Git->Git Bash弹出命令行窗口则说明Git安装成功。
安装后的配置:
git config --global user.name "Your Name"
git config --global user.email "email@example.com"
注意:--global参数,指定这台机器上所有的Git仓库都会使用这个配置。当然也可不同仓库指定
不同用户名和Email地址
5.创建版本库并添加文件
5.1 创建
版本库又名“仓库(repository)”,可简单理解为一个目录,里面的所有文件都可以被Git管理,每个文件的
修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或在将来某个时刻“还原”
创建命令:
mkdir learngit(如果在window,确保目录名(包括父目录)不包含中文)
cd learngit
pwd
git init 把这个目录初始化为Git可管理的仓库,并创建了.git隐藏目录用以跟踪管理版本库的(不能随便修改)
(备注:不一定必须在空目录下创建Git仓库,已有东西的目录也可以)
5.2 添加文件到版本库
需明确一点:所有的版本控制系统,其实只能跟踪文本文件的改动。诸如图片、视频虽能管理,但不能跟踪
具体的变化,举例来说,只能知道图片大小从100KB改成120KB,不能确定所改内容。
注意:微软的word格式是二进制格式,故不能跟踪word文件的改动
一点提醒:切忌用微软记事本编辑任何文本文件,因其在每个文件开头添加0xefbbbf保存UTF-8编码的文件,
编辑保存后会造成很多莫名其妙的错误,如正确程序编译报错、网页第一行显示一个?等
建议:Notepad++代替且设置为UTF-8 without BOM默认编码
1.编写一个readme.txt(放在learngit目录下)
2.git add readme.txt
3.git commit -m "wrote a readme file"
# 告诉Git,把文件提交到仓库, -m 是本次提交的说明
备注:commit可以一次提交很多文件,而add命令还可以: git add file1.txt file2.txt...
6.修改文件并重新提交
1.修改readme.txt
2.查看工作区状态:git status(可选)
3.查看修改内容:git diff readme.txt(可选)
4.更新即将提交的修改:git add readme.txt
5.提交修改: git commit -m "modified xxx"
6.查看工作区状态:git status(可选)
7.提交日志与回退版本
1.查看提交日志
git log 显示最近到最远的提交日志
git log --pretty=oneline 每条记录以行显示查看
如1094adb7b9b3807259d8cb349e7df1d4d6477073 (HEAD -> master) append GPL
这里,1094adb...是commit id(版本号),由SHA1计算出来的一个非常大的数字,十六进制表示。
避免多人在同一版本工作时版本号的冲突
实际,Git每提交一个新版本,自动串成一条时间线
2.回退版本
HEAD表示当前版本,上一个版本是HEAD^,上上一个HEAD^^,再往上100版本为HEAD~100
git reset --hard HEAD^
撤回回退(需要对应的commit id): git reset --hard 1094a(版本号的前几位即可)
查找需回退到某一版本的id:git reflog -->记录你的每一次命令
8.工作区和暂存区
工作区:你电脑里能看到的目录,但.git目录不算工作区,而是Git的版本库
暂存区(stage或者index):在Git的版本库.git里面。此外Git自动创建第一个分支master,以及指向
master的一个HEAD指针
前面讲的git add 实际是把文件的修改添加/更新到暂存区
而git commit,把暂存区的所有内容提交到当前分支(即默认的master)
9.管理修改
目标:了解Git为什么比其它版本控制系统设计得优秀,因为Git跟踪并管理的是“修改”,而非文件
查看工作区和版本库里面最新版本的区别:git diff HEAD -- readme.txt
总结:不用git add添加修改到暂存区,那就不会加入到commit中
10.撤销修改
丢弃工作区的修改:
git checkout -- readme.txt (注意有 -- ,没有则变成切换到另一个分支的命令)
或者 git restore readme.txt
丢弃暂存区的修改:
git reset HEAD readme.txt
或者 git restore --staged readme.txt
丢弃已提交的修改:版本回退-->前提,没有把版本库推送到远程版本库
11.删除文件
先rm file 再git rm <file> git commit -m "remove <file>"
小提示:先手动删除文件,然后使用git rm <file> 和 git add <file>效果是一样的
如果从工作区误删了,但版本库里还存在。可撤销修改,从版本库“一键还原”。
注意还原时只能恢复文件到最新版本
12.远程仓库
GitHub提供Git仓库托管服务的网站,可在GitHub建个账号,即可把本地仓库推送到GitHub仓库管理
注意,本地Git仓库传输到GitHub仓库是通过SSH加密的,故需要一点设置:
1.创建SSH Key
ssh-keygen -t rsa -C "youremail@example.com" 一路回车,使用默认值即可
效果:用户主目录下能找到.ssh目录,里面有id_rsa(私钥,不能泄露)和 id_rsa.pub(公钥)两个文件
2.登录GitHub,打开“Account settings”, "SSH Keys"页面
点“Add SSH Key”填上任意Title,在Key文本里粘贴id_rsa.pub文件的内容,再点Add Key即可
GitHub使用SSH Key原因:GitHub需识别出你推送的提交确实是你推送的,而不是他人冒充的。
小提示:可添加多个Key
如果不想让别人看到你的Git仓库:
方法一:交点保护费,让GitHub把公开的仓库变成私有的
方法二:自己建一个Git服务器(公司内部开发必备)
13.添加远程库
目标:本地创建一个Git仓库,且在GitHub也创建一个Git仓库,这两个仓库需远程同步,以多人协作维护
步骤:
1.登录GitHub,在右上角找到“Create a new repo”按钮,创建一个仓库
2.在Repository name填入仓库名learngit,其它默认,点击“Create repository”即可
3.在本地learngit仓库下运行命令:-->创建关联:本地Git仓库<==>远程Git仓库
git remote add origin(远程库的名字,Git默认叫法) git@github.com:账户名/learngit.git
4.推送本地Git仓库所有内容
git push -u origin master 而-u把本地master分支内容推到远程新的master分支且两者关联起来
以后只需推送或拉取即可,不需 -u
5.以后,只有本地做了提交,就可通过以下命令把最新修改推送到GitHub
git push origin master
注意:第一次使用Git的push或clone连接GitHub的SSH警告
The authenticity of host 'github.com (xx.xx.xx.xx)' can't be established.
RSA key fingerprint is xx.xx.xx.xx.xx.
Are you sure you want to continue connecting (yes/no)?
原因:Git使用SSH连接,本地需确认GitHub的Key的指纹信息是否真的来自GitHub服务器,输入yes即可
然后,Git会输出一个警告:(只输出一次)
Warning: Permanently added 'github.com' (RSA) to the list of known hosts.
表示,把GitHub的Key添加到了本机的一个信任列表里了
总结:分布式版本系统最大的好处之一是在本地工作完全不需要考虑远程库的存在,也即有没联网都可以正常
工作,当有网时,再把本地提交推送一下就完成了同步
14.从远程克隆
1.登录GitHub,创建一个仓库“gitskills”
勾选“Initialize this repository with a REAME”
2.git clone git@github.com:账户名/gitskills.git--------->使用ssh协议
这样,多个人协作开发,每个人从远程克隆一份即可
此外,还可用:https://github.com/用户名/仓库名.git 地址克隆----->使用https协议
用https缺点:1.速度慢(ssh最快) 2.每次推送必须输入口令
优点:对某些只开放http端口的公司内部无法使用ssh,只能用https
15 分支管理
分支作用:
创建属于自己的分支(别人看不见),而原来的分支正常可供他人工作,等你在自己分支开发完成,
再一次性合并到原来的分支,即安全也不影响他人工作
相比SVN很慢的分支切换,Git的分支在1s内就能完成
16 创建并合并分支
每次提交串成的一条时间线就是一个分支。
初始化仓库默认创建一个master分支,即主分支。而“HEAD”指向“当前分支”,刚开始即指向master
master指向最新的提交,而HEAD指向master
创建分支过程:
当创建一个新分支如dev时,Git即新建一个指针叫dev指向master相同的提交,再把HEAD指向dev
此时,在工作区的修改和提交就是针对dev分支了,比如新提交一次后,dev指针往前移动一步,而master指针不变。
命令:git checkout -b dev 其中,-b 表示创建并切换分支
<==>git branch dev + git checkout dev
查看当前分支:git branch 当前分支标有一个*
切换分支:git checkout master(最新版本的Git提供git switch xxx 切换分支)
举例:git switch -c dev 创建并切换到新的dev分支,直接切换某分支:git switch xxx
合并分支过程:
在dev工作完成后,把dev合并到master上,最简单方法即把master指向dev当前的提交即可。
此时的dev可删除
命令:git merge dev 合并指定分支到当前分支(注意先切回master主分支)
(Fast-forward:快进模式,直接把master指向dev的当前提交,因此合并非常快)
删除分支:git branch -d dev
17 解决冲突:
冲突原因:两分支都修改并提交了同一文件,合并时会冲突
解决办法:重新编辑冲突的文件为我们希望的内容,再提交
另外,git log --graph 可以看到分支合并图,选项 --abbrev-commit可缩写前几位commit id
18 分支管理策略
通常,合并分支时,如果可能,Git会用Fast forward模式合并分支,但删除分支后,会丢掉分支信息
如果要强制禁用Fast forward模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息
实战:
在一个新建分支修改并提交一个文件后,切换回master
执行合并:git merge --no-ff -m "xxx" dev
查看分支合并图: git log --graph --pretty=oneline --abbrev-commit
分支策略(重点)
在实际开发中,应该按照几个基本原则进行分支管理
1.master分支应该是非常稳定的,仅用来发布新版本,平时不能在上面干活
2.干活都在dev分支上,到某个时候,比如1.0版本发布时,再把dev分支合并到master上
在master分 支发布1.0版本
总结:使用--no-ff 的普通模式合并后,历史有分支,能看出曾经做过合并
而fast forward合并就看不出来曾经做过合并
19 Bug分支
当需处理某个分支的bug时,切换到那个分支前需保存当前的工作(如果有修改的话)
保存命令:git stash
再切换到那个分支,建立一个bug分支提交处理后合并到那个分支
再返回之前的分支继续工作
查看stash: git stash list
恢复命令:git stash pop--->同时删除stash list对应的内容
或 git stash apply stash@{对应的索引号}---->不会删除list保存的内容
以上bug解决了,但是在当前分支还存在bug未修改,即分支不一致
解决办法:
把提交的修改复制到当前分支:
git cherry-pick 某个commit的id
20 Feature分支
需求:开发一个新的feature
实现:最好新建一个分支,如果完成后准备合并被中途要求废弃添加新的feature
则可通过 git branch -D <name> 强行删除
21 多人协作
当克隆远程仓库时,实际Git自动把本地master分支与远程的master分支对应起来了,
且远程仓库默认名称是origin
本地新建的分支,如果不推送到远程,对其他人是不可见的
查看远程库信息:git remote 或 git remote -v 显示更详细的信息(显示可以
抓取和推送的远程仓库的地址,若没推送权限,则看不到push的地址)
1.推送分支
git push origin master 推送本地master分支到远程仓库origin默认的master分支
要推送其它分支,比如dev,则git push origin dev
但是并不是一定要把本地所有分支往远程推送
master分支是主分支,因此时刻与远程同步
dev是开发分支,团队所有成员都需要在上面工作,也需要与远程同步
bug分支只用在本地修复bug,没必要推到远程
feature分支是否推断远程,取决于你是否和你的小伙伴合作在上面开发
2.抓取分支
当你的小伙伴把origin仓库克隆到本地时,只能看到master分支,此时还需抓取origin的
dev分支到本地:git checkout -b dev origin/dev
问题:
当你都小伙伴修改某一文件后推送dev到远程origin的dev,而恰巧你也修改了同一文件,但在
推送你的dev时会出现冲突
方法:
先用git pull把最新的提交从origin/dev抓下来,然后在本地合并,解决冲突,再推送
注意,先设置本地dev与origin/dev的链接再pull,即
git branch --set-upstream-to=origin/dev dev
git pull
合并前,先解决冲突,再合并提交push
总结:多人协作的工作模式:
1.首先,试图用git push origin <branch-name>推送自己的修改
2.如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并
3.如果合并有冲突,则解决冲突,并在本地提交
4.没有冲突或解决冲突后,再用git push origin <branch-name>推送就能成功
如果git pull提示no tracking information,则说明本地分支和远程分支的链接关系没有创建,用命令
git branch --set-upstream-to <branch-name> origin/<branch-name>
22 Rebase
目标:在多人协作时,将分叉的提交变成直线
实现:git rebase
rebase操作的特点:优点:把分叉的提交历史“整理”成一条直线,看上去更直观。
缺点:本地的分叉提交已经被修改过了。
23 标签管理
通常在发布一个版本时,在版本库打一个标签(tag),即标签是版本库的一个快照
实际,标签是指向某个commit的指针。总之,tag是跟某个commit绑在一起,不能改变,
在查找时不是6a851e这些难记的commit id,而可通过标签tag
24 创建一个标签
1.切换到需打标签的分支
2.git tag <name> 注意:默认标签是打在最新提交的commit上的,即HEAD
可指定在某个commit打标签,即 git tag <name> <commit_id>
可创建带有说明的标签,-a 指定标签名 -m指定说明文字
git tag -a v0.1 -m "version 0.1 released" <commit_id>
3.通过git tag 查看所有标签
4.查看标签信息: git show <tag_name>
注意:标签总是和某个commit挂钩,如果这个comit即出现在master分支,又出现在
dev分支,那么在两个分支都可以看到这个标签
25 操作标签
1.删除标签: git tag -d <tag_name> 安全删除在本地的标签
2.推送某个标签到远程: git push origin <tag_name>
或一次性推送全部尚未推送到远程的本地标签:git push origin --tags
3.删除远程某个标签:
1.删除本地的标签:git tag -d <tag_name>
2.删除远程的标签:git push origin :refs/tags/<tag_name>
26 使用GitHub
1.Fork刚兴趣的开源项目到自己仓库
2.git clone git@github.com:<user_name>/项目名.git 到本地
注意:一定要从自己账号下clone仓库,才能推送修改。直接clone原作者的仓库
是不能推送修改的
如果你想原作者接受你的修改,可发起一个pull request
27 使用Gitee
国内Git托管服务——Gitee(gitee.com)
Gitee特点:提高免费Git仓库、集成代码质量检测、项目演示等功能
对于团队协作开发,还提供项目管理、代码托管、文档管理的服务,
<5人小团队免费
Note:Gitee的免费版本也提供私有库功能,只是又5人的成员上限
Gitee使用:
1.添加SSH公钥,类似Github
2.关联本地仓库到Gitee远程库:
2.1创建一个项目(项目名称最好与本地库保持一致)
2.2本地库上使用命令:git remote add origin git@gitee.com:<用户名>/仓库名.git
之后,就可以正常pull和push了
如果关联时报错:fatal:remote origin already exists
可查看远程库信息:git remote -v
解决办法:删除已有的GitHub远程库:git remote rm origin再关联
此外,一个本地库既可以关联GitHub,又关联Gitee
但注意要用不同名称标识不同的远程库
git remote add <库名1> git@github.com:.....
git remote add <库名2> git@gitee.com:.....
再查看一下:git remote -v
若要推送某个仓库:git push <仓库名1/2..> master
28 自定义Git
1.让Git显示颜色: git config --global color.ui true
29 忽略特殊文件
目标:在工作目录保存特殊文件(如配置文件)但不能提交它们
实现:
1.在Git工作区的根目录创建一个特殊的.gitignore文件,然后要把忽略的文件名填进去,GIt就会自动忽略这些文件
Github已提供各种配置文件,可浏览:https://github.com/github/gitignore
忽略文件的规则
1.忽略操作系统自动生成的文件,比如缩略图等
2.忽略编译生成的中间文件,可执行文件等,也就是如果一个文件是通过另一个文件自动生成的,
那自动生成的文件就没必要放进版本库,比如java编译产生的.class文件
3.忽略你自己的带有敏感信息的配置文件,比如存放口令的配置文件
最后一步:把.gitignore提交到Git
有时,不能添加一个因为被.gitignore忽略的文件,可用-f强制添加到Git,如
git add -f App.class
或者你发现.gitignore写得有问题,可用git checkignore检查
30 配置别名
git config --global alias.st status -->用git st 取代 git status
注意: --global是全局参数,针对当前用户的所有仓库起作用,如果不加,则
只对当前仓库起作用
新命令: git log -1(是阿拉伯数字) 显示最后一次的提交
配置文件:
仓库的配置文件:.git/config
用户的配置文件:用户主目录下的 .gitconfig
31 搭建Git服务器
强烈推荐Ubuntu或Debian下搭建,因为几条简单的apt命令即可完成安装
1.安装git
sudo apt-get install git
2.创建一个git用户,用来运行git服务
sudo adduser git
3.创建证书登录
收集所有需要登录的用户的公钥,即他们的id_rsa.pub文件
把这些公钥导入到/home/git/.ssh/authorrized_keys文件里,一行一个
4.初始Git仓库
选定一个目录作为Git仓库,假定是/srv/sample.git
在/srv目录下输入命令:sudo git init --bare sample.git
这样就创建了一个没有工作区的裸仓库,因为服务器的Git仓库纯粹为了共享
不能让用户直接登录服务器去改工作区,且服务器仓库以.git结尾
然后,把owner改为git:sudo chown -R git:git sample.git
5.禁用shell登录
出于安全考虑,不能让第2步的git用户登录shell,找到/etc/passwd下的
git:x:1001:1001:,,,:/home/git:/bin/bash
改为:git:x:1001:1001:,,,:/home/git:/usr/bin/git-shell
git用户一登陆时执行git-shell会自动退出
6.克隆远程仓库
git clone git@server:/srv/sample.git
管理公钥:如果团队很大,可用Gitosis来管理公钥
管理权限:Git支持钩子(hook),可在服务器上编写一系列脚本来控制提交等操作
达到“权限控制”的目的,Gitolite就是这个工具
32 使用Source Tree
Git图形界面工具:推荐SourceTree(Atlassian开发的免费Git图形界面工具,可操作任何Git库)
从资源管理器把本地仓库文件夹拖到SourceTree即可添加一个本地Git库
也可以选择“New”-“Clone from URL”直接从远程克隆到本地
参考资料
Git官网:http://git-scm.com
国外Git学习的小本本:Git Cheat Sheet
https://gitee.com/liaoxuefeng/learn-java/raw/master/teach/git-cheatsheet.pdf
Git 中文教程:https://github.com/geeeeeeeeek/git-recipes
说明:本文参考自:
廖雪峰的 Git 教程:https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000