@(前端开发)[Git|工具]
以前也看过一些关于git的视频,可是觉得自己一直都没有真的理解和掌握git,花了一天半的时间,看完了廖雪峰老师的Git教程,并动手实践了一下,才觉得自己是真的对git入门了,看的过程中也做了一些笔记,也就是下文啦。
Git实践
Git简介
历史
功能:
Git是目前世界上最先进的分布式版本控制系统(没有之一)。
历史:
- 1991 Linux创建Linux,需要管理
- 2002年以前,Linux手动合并开发者提供的代码
- 2002~2005:BitMover公司的BitKeeper免费给Linux使用
- 2005开发Samba的Andrew试图破解BitKeeper的协议,被BitMover公司发现了,要收回Linux社区的免费使用权。
- Linus花了两周时间自己用C写了一个分布式版本控制系统-Git,一个月之后Linux源码由此代理
- 2008年Github上线,为开源项目提供免费Git存储
集中式VS分布式
集中式的版本控制系统:CVS,SVN
运行方式:版本库是集中存放在中央服务器的,而干活的时候,用的都是自己的电脑,所以要先从中央服务器取得最新的版本,然后开始干活,干完活了,再把自己的活推送给中央服务器。
缺点:集中式版本控制系统最大的毛病就是必须联网才能工作
分布式:Git
分布式版本控制系统运行方式:每个人的电脑上都是一个完整的版本库,你在自己电脑上改了文件A,你的同事也在他的电脑上改了文件A,这时,你们俩之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。
分布式版本控制系统通常也有一台充当“中央服务器”的电脑,但这个服务器的作用仅仅是用来方便“交换”大家的修改,没有它大家也一样干活,只是交换修改不方便而已。
安装Git
在Linux上安装Git
- 输入
git
,看看系统有没有安装Git: -
sudo apt-get install git
就可以直接完成Git的安装
在Mac OS X上安装Git
两种方法:
-
第一种安装
homebrew
,然后通过homebrew安装Git,具体方法请参考homebrew的文档:http://brew.sh/。 -
第二种方法更简单,也是推荐的方法,就是直接从AppStore安装Xcode,Xcode集成了Git,不过默认没有安装,你需要运行Xcode,选择菜单“Xcode”->“Preferences”,在弹出窗口中找到“Downloads”,选择“Command Line Tools”,点“Install”就可以完成安装了。
在Windows上安装Git
- msysgit是Windows版的Git,从http://msysgit.github.io/下载,然后按默认选项安装即可。
- 安装完成后,在开始菜单里找到“Git”->“Git Bash”,蹦出一个类似命令行窗口的东西,就说明Git安装成功!
$ git config --global user.name "Your Name"
$ git config --global user.email "email@example.com"
创建版本库
版本库:
版本库又名仓库,英文名repository,你可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。
$ mkdir learngit
$ cd learngit
$ pwd
/Users/michael/learngit
-
pwd
命令用于显示当前目录; -
mkdir learngit
用于创建一个空目录; - 通过
git init
命令把这个目录变成Git可以管理的仓库: - 将文件添加到版本库:
所有的版本控制系统,其实只能跟踪文本文件的改动,比如TXT文件,网页,所有的程序代码等等,Git也不例外。版本控制系统可以告诉你每次的改动,比如在第5行加了一个单词“Linux”,在第8行删了一个单词“Windows”。而图片、视频这些二进制文件,虽然也能由版本控制系统管理,但没法跟踪文件的变化,只能把二进制文件每次改动串起来,也就是只知道图片从100KB改成了120KB,但到底改了啥,版本控制系统不知道,也没法知道。
新建一个文件:一定要放到learngit目录下(子目录也行),因为这是一个Git仓库,放到其他地方Git再厉害也找不到这个文件。
-git add
:用命令git add告诉Git,把文件添加到仓库:
-git commit
:用命令git commit告诉Git,把文件提交到仓库:
$ git commit -m "wrote a readme file"
穿梭时光
- 要随时掌握工作区的状态,使用
git status
命令。 - 如果
git status
告诉你有文件被修改过,用git diff
可以查看修改内容。
版本回退
-
git log
:显示从最近到最远的提交日志; -
git log --pretty=oneline
:显示简要版的提交日志; - commit id(版本号)已
3628164...882e1e0
方式显示,是一个SHA1计算出来的一个非常大的数字,用十六进制表示,防止多人协作时产生冲突; -
git reset --hard HEAD^
:返回上一个版本,HEAD
表示当前版本,HEAD^^表示上上个版本
,也可以用类似于HEAD~3
来表示要回退到哪一个版本。 -
$ git reset --hard 3628164
:后面的数字是版本号,此方法可以随意跳转 - Git的版本回退速度非常快,因为Git在内部有个指向当前版本的HEAD指针,当你回退版本的时候,Git仅仅是把HEAD从指向另一个版本
-
git reflog
:记录所有的操作,可以通过此查询版本号;
工作区和暂存区
工作区(Working Directory):
就是你在电脑里能看到的目录,比如我的learngit文件夹就是一个工作区:
版本库(Repository)
工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库。
Git的版本库里存了很多东西,其中最重要的就是称为stage
(或者叫index
)的暂存区,还有Git为我们自动创建的第一个分支master
,以及指向master
的一个指针叫HEAD
。
提交变更的两个步骤:
- 第一步是用git add把文件添加进去,实际上就是把文件修改添加到暂存区;
- 第二步是用git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支。
- 你可以简单理解为,需要提交的文件修改通通放到暂存区,然后,一次性提交暂存区的所有修改。
理解缓存区的意思
git add
命令实际上就是把要提交的所有修改放到暂存区(Stage),然后,执行git commit
就可以一次性把暂存区的所有修改提交到分支。
管理修改
如果同一个文件有多次修改,需要每次都add到缓存库,不然提交无效
每次修改,如果不add到暂存区,那就不会加入到commit中。
撤销修改
场景1:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令git checkout -- file。
场景2:当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令git reset HEAD file,就回到了场景1,第二步按场景1操作。
场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,参考版本回退一节,不过前提是没有推送到远程库。
删除文件
- 删除文件的两种方法:
- 直接从本地删除
- 使用
rm test.txt
- 删除之后会出现两种情况:
- 从版本库恢复:
git checkout -- test.txt
- 从版本库也删除:
git rm test.txt
然后git commit
- 从版本库恢复:
总结“checkout”:
git checkout
其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。
命令git rm
用于删除一个文件。如果一个文件已经被提交到版本库,那么你永远不用担心误删,但是要小心,你只能恢复文件到最新版本,你会丢失最近一次提交后你修改的内容。
远程仓库
- Git的杀手功能之一
- 实际情况往往是这样,找一台电脑充当服务器的角色,每天24小时开机,其他每个人都从这个“服务器”仓库克隆一份到自己的电脑上,并且各自把各自的提交推送到服务器仓库里,也从服务器仓库中拉取别人的提交。
创建本地git仓库与Github之间的传输
- 在用户主目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsa和id_rsa.pub这两个文件,如果已经有了,可直接跳到下一步。如果没有,打开Shell(Windows下打开Git Bash),创建SSH Key:
$ ssh-keygen -t rsa -C "youremail@example.com"
Your identification has been saved in /Users/zhangwang/.ssh/id_rsa.
Your public key has been saved in /Users/zhangwang/.ssh/id_rsa.pub.
如果一切顺利的话,可以在用户主目录里找到.ssh目录,里面有id_rsa和id_rsa.pub两个文件,这两个就是SSH Key的秘钥对,id_rsa是私钥,不能泄露出去,id_rsa.pub是公钥,可以放心地告诉任何人。
- 登陆GitHub,打开“Account settings”,“SSH Keys”页面:
然后,点“Add SSH Key”,填上任意Title,在Key文本框里粘贴id_rsa.pub文件的内容:
为什么GitHub需要SSH Key呢?
因为GitHub需要识别出你推送的提交确实是你推送的,而不是别人冒充的,而Git支持SSH协议,所以,GitHub只要知道了你的公钥,就可以确认只有你自己才能推送。
在GitHub上免费托管的Git仓库,任何人都可以看到喔(但只有你自己才能改)。所以,不要把敏感信息放进去。
如果你不想让别人看到Git库,有两个办法,一个是交点保护费,让GitHub把公开的仓库变成私有的,这样别人就看不见了(不可读更不可写)。另一个办法是自己动手,搭一个Git服务器,因为是你自己的Git服务器,所以别人也是看不见的。这个方法我们后面会讲到的,相当简单,公司内部开发必备。
添加远程库
- 要关联一个远程库,使用命令
git remote add origin git@server-name:path/repo-name.git
; - 关联后,使用命令
git push -u origin master
第一次推送master分支的所有内容; - 此后,每次本地提交后,只要有必要,就可以使用命令
git push origin master
推送最新修改; - 分布式版本系统的最大好处之一是在本地工作完全不需要考虑远程库的存在,也就是有没有联网都可以正常工作,而SVN在没有联网的时候是拒绝干活的!当有网络的时候,再把本地提交推送一下就完成了同步,真是太方便了!
从远程库中克隆
1.克隆一个远程库:$ git clone git@github.com:servername/gitskills.git
- 如果有多个人协作开发,那么每个人各自从远程克隆一份就可以了。
- GitHub给出的地址不止一个,还可用https://github.com/michaelliao/gitskills.git这样的地址。实际上,Git支持多种协议,默认的git://使用ssh,但也可以使用https等其他协议。
- 使用https除了速度慢以外,还有个最大的麻烦是每次推送都必须输入口令,但是在某些只开放http端口的公司内部就无法使用ssh协议而只能用https。
小结:
- 要克隆一个仓库,首先必须知道仓库的地址,然后使用git clone命令克隆。
- Git支持多种协议,包括https,但通过ssh支持的原生git协议速度最快。
分支管理
什么是分支咧?
分支就是科幻电影里面的平行宇宙,当你正在电脑前努力学习Git的时候,另一个你正在另一个平行宇宙里努力学习SVN。
如果两个平行宇宙互不干扰,那对现在的你也没啥影响。不过,在某个时间点,两个平行宇宙合并了,结果,你既学会了Git又学会了SVN!
分支有啥作用咧?
- 你创建了一个属于你自己的分支,别人看不到,还继续在原来的分支上正常工作,而你在自己的分支上干活,想提交就提交,直到开发完毕后,再一次性合并到原来的分支上,这样,既安全,又不影响别人工作。
- Git的分支是与众不同,无论创建、切换和删除分支,Git在1秒钟之内就能完成!无论你的版本库是1个文件还是1万个文件。
创建和合并分支
- 查看分支:
git branch
- 创建分支:
git branch <name>
- 切换分支:
git checkout <name>
- 创建+切换分支:
git checkout -b <name>
相当于以下两步:$ git branch dev
$ git checkout dev
- 合并某分支到当前分支:
git merge <name>
- 删除分支:
git branch -d <name>
Git鼓励大量使用分支:这样更安全
Fast-forward
信息,Git告诉我们,这次合并是“快进模式”
模式图:
- 原来只有master分支
- 使用
git checkout -b dev
创建并转移至新分支dev
- 在新分支上更改内容
- 使用:
git merge dev
合并dev分支到master分支
- 使用
git branch -d dev
删除已经完成了使命的dev分支
解决冲突
人生不如意之事十之八九,合并分支往往也不是一帆风顺的。
当在两个分支上对同一个文件进行修改时,如果合并这两个分支就会产生冲突,这时候需要手动修改。
git log --graph --pretty=oneline --abbrev-commit
用git log --graph
命令可以看到分支合并图。
分支管理策略
在实际开发中,我们应该按照几个基本原则进行分支管理:
- master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;
- 那在哪干活呢?干活都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本;
- 你和你的小伙伴们每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了。
所以,团队合作的分支看起来就像这样:
合并分支时,加上--no-ff参数就可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并,而fast forward合并就看不出来曾经做过合并。
Bug分支
软件开发中,bug就像家常便饭一样。有了bug就需要修复,在Git中,由于分支是如此的强大,所以,每个bug都可以通过一个新的临时分支来修复,修复后,合并分支,然后将临时分支删除。
-
git stash
功能:可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作: - 然后从master上面创建新的分支,修复bug合并
-
git stash list
:用于查看被储藏起来的那部分项目, - 恢复被储藏项目的两种方法:
- 用·
it stash apply
恢复,但是恢复后,stash内容并不删除,你需要用git stash drop来删除; - 用
git stash pop
,恢复的同时把stash内容也删了:
- 用·
Feature分支
软件开发中,总有无穷无尽的新的功能要不断添加进来。
添加一个新功能时,你肯定不希望因为一些实验性质的代码,把主分支搞乱了,所以,每添加一个新功能,最好新建一个feature分支,在上面开发,完成后,合并,最后,删除该feature分支。
开发一个新feature,最好新建一个分支;
如果要丢弃一个没有被合并过的分支,可以通过git branch -D <name>
强行删除。
当要删除一个没被合并的分支时,系统会提醒,如果要删除需要强制删除,需要执行命令:git branch -D <name>
多人协作
- 查看远程库信息,使用
git remote -v
; - 本地新建的分支如果不推送到远程,对其他人就是不可见的;
- 从本地推送分支,使用
git push origin branch-name
,如果推送失败,先用git pull抓取远程的新提交; - 在本地创建和远程分支对应的分支,使用
git checkout -b branch-name origin/branch-name
,本地和远程分支的名称最好一致; - 建立本地分支和远程分支的关联,使用
git branch --set-upstream branch-name origin/branch-name
; - 从远程抓取分支,使用
git pull
,如果有冲突,要先处理冲突。
那些分支需要及时推送?
- master分支是主分支,因此要时刻与远程同步;
- dev分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步;
- bug分支只用于在本地修复bug,就没必要推到远程了,除非老板要看看你每周到底修复了几个bug;
- feature分支是否推到远程,取决于你是否和你的小伙伴合作在上面开发。
标签管理
啥是标签呢?
Git的标签就像是版本库的快照,实质上它就是指向某个commit的指针(跟分支很像对不对?但是分支可以移动,标签不能移动),所以,创建和删除标签都是瞬间完成的。
作用在于将来无论什么时候,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来。
创建标签
-
git tag <name>
:创建一个新标签 -
git tag
查看所有标签 - 标签不是按时间顺序列出,而是按字母排序的。可以用
git show <tagname>
查看标签信息 - 还可以创建带有说明的标签,用
-a
指定标签名,-m
指定说明文字: - 还可以通过
-s
用私钥签名一个标签 - 命令
git tag <name>
用于新建一个标签,默认为HEAD,也可以指定一个commit id; -
git tag -a <tagname> -m "blablabla..."
可以指定标签信息; -
git tag -s <tagname> -m "blablabla..."
可以用PGP签名标签;
操作标签
- 命令
git push origin <tagname>
可以推送一个本地标签; - 命令
git push origin --tags
可以推送全部未推送过的本地标签; - 命令
git tag -d <tagname>
可以删除一个本地标签; - 命令
git push origin :refs/tags/<tagname>
可以删除一个远程标签。
使用GitHub
- 在GitHub上,可以任意Fork开源仓库;
- 自己拥有Fork后的仓库的读写权限;
- 可以推送pull request给官方仓库来贡献代码。
- 在GitHub出现以前,开源项目开源容易,但让广大人民群众参与进来比较困难,因为要参与,就要提交代码,而给每个想提交代码的群众都开一个账号那是不现实的,因此,群众也仅限于报个bug,即使能改掉bug,也只能把diff文件用邮件发过去,很不方便。
- 但是在GitHub上,利用Git极其强大的克隆和分支功能,广大人民群众真正可以第一次自由参与各种开源项目了。
- 如何参与一个开源项目呢?比如人气极高的bootstrap项目,这是一个非常强大的CSS框架,你可以访问它的项目主页https://github.com/twbs/bootstrap,点“Fork”就在自己的账号下克隆了一个bootstrap仓库,然后,从自己的账号下clone:
自定义git
-
git config --global color.ui true
:让git显示颜色;
忽略特殊文件
在Git工作区的根目录下创建一个特殊的.gitignore文件,然后把要忽略的文件名填进去,Git就会自动忽略这些文件。
不需要从头写.gitignore文件,GitHub已经为我们准备了各种配置文件,只需要组合一下就可以使用了。所有配置文件可以直接在线浏览:https://github.com/github/gitignore
忽略文件的原则是:
- 忽略操作系统自动生成的文件,比如缩略图等;
- 忽略编译生成的中间文件、可执行文件等,也就是如果一个文件是通过另一个文件自动生成的,那自动生成的文件就没必要放进版本库,比如Java编译产生的.class文件;
- 忽略你自己的带有敏感信息的配置文件,比如存放口令的配置文件。
使用Windows的童鞋注意了,如果你在资源管理器里新建一个.gitignore
文件,它会非常弱智地提示你必须输入文件名,但是在文本编辑器里“保存”或者“另存为”就可以把文件保存为.gitignore
了。
配置别名
给Git配置好别名,就可以输入命令时偷个懒。
配置方法:
$git config --global alias.st status
$ git config --global alias.co checkout
$ git config --global alias.ci commit
$ git config --global alias.br branch
--global参数是全局参数,也就是这些命令在这台电脑的所有Git仓库下都有用。
每个仓库的Git配置文件都放在.git/config文件中
而当前用户的Git配置文件放在用户主目录下的一个隐藏文件.gitconfig中:
$ cat .gitconfig
[alias]
co = checkout
ci = commit
br = branch
st = status
[user]
name = Your Name
email = your@email.com
别名就在[alias]后面,要删除别名,直接把对应的行删掉即可。
配置别名也可以直接修改这个文件,如果改错了,可以删掉文件重新通过命令配置。
搭建Git服务器
- 第一步,安装git:
$ sudo apt-get install git
- 第二步,创建一个git用户,用来运行git服务:
$ sudo adduser git
- 第三步,创建证书登录:
收集所有需要登录的用户的公钥,就是他们自己的id_rsa.pub文件,把所有公钥导入到/home/git/.ssh/authorized_keys文件里,一行一个。 - 第四步,初始化Git仓库:
先选定一个目录作为Git仓库,假定是/srv/sample.git,在/srv目录下输入命令:
$ sudo git init --bare sample.git
Git就会创建一个裸仓库,裸仓库没有工作区,因为服务器上的Git仓库纯粹是为了共享,所以不让用户直接登录到服务器上去改工作区,并且服务器上的Git仓库通常都以.git结尾。然后,把owner改为git:
$ sudo chown -R git:git sample.git
- 第五步,禁用shell登录:
出于安全考虑,第二步创建的git用户不允许登录shell,这可以通过编辑/etc/passwd文件完成。找到类似下面的一行:
git:x:1001:1001:,,,:/home/git:/bin/bash
改为:
git:x:1001:1001:,,,:/home/git:/usr/bin/git-shell
这样,git用户可以正常通过ssh使用git,但无法登录shell,因为我们为git用户指定的git-shell每次一登录就自动退出。 - 第六步,克隆远程仓库:
现在,可以通过git clone命令克隆远程仓库了,在各自的电脑上运行:
$ git clone git@server:/srv/sample.git Cloning into 'sample'... warning: You appear to have cloned an empty repository.
剩下的推送就简单了。
网友评论