git筑基篇
【一】基础知识
1、版本控制系统发展史
版本控制工具的历史可以分为三代
第一代版本控制系统被称为本地版本控制系统。通过加锁将并发执行转换成顺序执行。 一次只能有一个人处理文件。如 RCS、SCCS(1972年发布)和 DSEE(被认为是 Atria ClearCase 的前身)
第二代版本控制系统被称为集中式版本控制系统(Centralized Version Control Systems,CVCS),其对同步修改更加宽容,但有一个明显的限制,用户必须在允许提交之前将当前修订合并到他们的工作中。第二代版本控制系统主要有 SVN/CVS(CVS有设计的问题,会造成提交文件不完整,版本库莫名其妙损坏的情况,SVN修正了CVS的一些稳定性问题,是目前用得最多的集中式版本库控制系统)、SourceSafe、Subversion、Team Foundation Server、SVK.
第三代版本控制系统被称为分布式式版本控制系统(Distributed Version Control Systems,DVCS),其允许合并和提交分开。在每个使用者电脑上就有一个完整的数据仓库,没有网络依然可以使用
第三代版本控制系统主要有 Bazaar、Git、Mercurial、BitKeeper、Monotone.
2、git简介
Git是一种分布式版本控制系统。在 Linux 开源的初期,linux社区使用的是BitMover 授权免费使用的BitKeeper,但免费使用有很多限制,后因一大佬破解了BitKeeper,被 BitMover 公司发现,收回了免费使用权。迫不得已,Linus 与2005年4月3日,用C开始开发一个分布式版本控制工具Git以替代 BitKeeper。在 2005 年7月26日,Linus 功成身退,将 Git 的维护交给另外一个 Git 的主要贡献者 Junio C Hamano。Git迅速成为最流行的分布式版本控制系统,尤其是2008年,GitHub网站上线了,它为开源项目免费提供Git存储,无数开源项目开始迁移至GitHub,包括jQuery,PHP,Ruby等等。
所有的版本控制系统,其实只能跟踪文本文件的改动,Git也不例外。而图片、word、视频这些二进制文件,是没法跟踪文件的变化的,只能把二进制文件每次改动串起来,也就是只知道图片从100KB改成了120KB,但到底改了啥,版本控制系统不知道,也没法知道。如果要真正使用版本控制系统,就要以纯文本方式编写文件。因为文本是有编码的,强烈建议使用标准的UTF-8编码,所有语言使用同一种编码,既没有冲突,又被所有平台所支持。
3、集中式与分布式区别
集中式版本控制系统版本库是集中存放在中央服务器的,多人协作时,要先从中央服务器取得最新的版本,再把自己的代码推送给中央服务器。缺点是中间服务器宕机会影响到所有开发者,而且必须联网的中央服务器才能工作,如果在局域网内还好,带宽够大,速度够快,可如果在互联网上,遇到网速慢的话会严重影响彼此协作。
分布式版本控制系统根本没有“中央服务器”,每个人的电脑上都是一个完整的版本库,本地工作完全不需要考虑远程库的存在,也就是有没有联网都可以正常工作,多人协作时只需把各自的修改推送给对方,就可以互相看到对方的修改了。除此之外Git还有极其强大的分支管理功能。
【二】git环境搭建
1、安装git与配置
Ubuntu 安装命令:
sudo apt-get install git
安装完后要进行全局配置
git config --global user.name "你的github或gitlab等git存储的用户名"
git config --global user.email "你的github或gitlab等git存储的邮箱地址"
2、自建代码托管平台gitlab
GitLab是一个利用 Ruby on Rails 开发的开源应用程序,实现一个自托管的Git项目仓库,可通过Web界面进行访问公开的或者私人项目。
它拥有与Github类似的功能,能够浏览源代码,管理缺陷和注释。可以管理团队对仓库的访问,它非常易于浏览提交过的版本并提供一个文件历史库。它还提供一个代码片段收集功能可以轻松实现代码复用,便于日后有需要的时候进行查找
详见:
https://www.cnblogs.com/chendf/p/13040447.html
3、git协议
Git支持多种协议,默认的git://使用ssh,但也可以使用https等其他协议。
使用https除了速度慢以外,还有个最大的麻烦是每次推送都必须输入口令,但是在某些只开放http端口的公司内部就无法使用ssh协议而只能用https。
【三】命令讲解
1、创建版本库
版本库又名仓库,英文名repository,你可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。
通过git init命令把这个目录变成Git可以管理的仓库
$ mkdir learngit
$ cd learngit
$ git init
创建好后,当前目录下多了一个.git的目录,这个目录是Git来跟踪管理版本库的。以后对代码所做的很多git操作都会导致.git目录里文件的实时变化,以便实现追踪。
2、添加到暂存区
git add将工作区文件的修改添加到暂存区
git add -u .(-u == --update),将已跟踪文件中的修改(modified)和删除(deleted)的文件添加到暂存区,不包括新文件(new)。
git add . ,将修改(modified)操作的文件和未跟踪新添加的文件(new)添加到git系统的暂存区,不包括被删除(deleted)文件
git add -A (-A == --all),是上面2个功能的合集,提交所有变化
3、提交到本地版本库
git commit 将暂存区里的改动给提交到本地版本库
git commit -m “massage”,添加注释git commit -a -m “massage” ,-a参数可以将所有已跟踪文件中的修改或删除操作的文件都提交到本地仓库,即使它们没有经过git add添加到暂存区,注意,新加的文件是不能被提交到本地仓库的
git commit --amend ,追加提交,它可以在不增加一个新的commit-id的情况下将新修改的代码追加到前一次的commit-id中,但该操作会改变你原来的commit id

4、查看修改变动
git diff将查看工作区和暂存区版本的区别
git diff -- 文件名
5、撤销提交
分几种情况:
未提交到暂存区:
使用git checkout -- 文件名(--很重要,没有--,就变成了“切换到另一个分支”的命令),把工作区的修改全部撤销
git checkout其实是用版本库里的版本替换工作区的版本
提交到暂存区:
git reset HEAD <file>,把暂存区的修改撤销掉(unstage),重新放回工作区
git reset HEAD Marketing/User.php或git reset HEAD .(把所有文件从暂存区撤回工作区)
git checkout -- .或git checkout .(把工作区的修改全部撤销)
提交到本地版本库:
这里又分2种情况:reset(回退)、revert(反做)
git reset的作用是修改HEAD的位置,即将HEAD指向的位置改变为之前存在的某个版本.如果想恢复到之前某个提交的版本,且那个版本之后提交的版本我们都不要了,就可以用这种方法。
git reset --hard HEAD #git reset --hard HEAD~1或git reset --hard 上一次commitId
git push —f #因为本地库HEAD指向的版本比远程库的要旧,所以需要强制推送到远程库,推送后,远程库的HEAD也已经指向目标版本了,此时回退成功
git revert -n "版本号"是用于“反做”某一个版本,以达到撤销该版本的修改的目的。使用场景: 如果我们想撤销之前的某一版本,但是又想保留该版本后面的版本,可使用git revert

比如我想撤销31e14f28aad提交,执行命令
git revert -n 31e14f28aad git cmomit -m 'revert b3' git push
6、关联远程库
如果先有本地库,后有远程库
如初始项目时,使用git init命令把本地目录变成Git仓库,需要使用git remote add origin 远程库地址url(如git@github.com:cdf/learn.git),来把已有的本地仓库关联到远程库。
这样远程库既可以作为备份,又可以让其他人通过该仓库来协作了。
7、推送本地库到远程库
git push,把本地库的内容推送到远程。
git push -u origin master,如果远程库是空的(在先有本地库,后有远程库的情况),第一次推送master分支时,要加上-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。
以后直接诶使用git push(或git push origin master)即可把本地仓库推送到远程仓库
8、从远程库克隆
如果先有本地库,后有远程库的时候,则需要使用git remote add origin 远程库url关联远程库。
若是先创建远程库,则使用使用git clone把远程库url克隆到本地库。
要克隆一个仓库,首先必须知道仓库的地址,然后使用git clone命令克隆。Git支持多种协议,包括https,但ssh协议速度最快。
当你从远程仓库克隆时,实际上Git自动把本地的master分支和远程的master分支对应起来了,并且,远程仓库的默认名称是origin
git clone git@github.com:cdf/hello.git
9、分支操作
因为创建、合并和删除分支非常快,所以Git鼓励你使用分支完成某个任务。
git branch branch_name,创建分支
git checkout branch_name,切换到某分支
git branch -b branch_name,加-b参数代表创建并切换到某分支(相当于上面2个命令)
因为切换分支使用git checkout <branch>,撤销修改则是git checkout -- <file>,同一个命令,有两种作用容易让人迷惑,因此,最新版本的Git提供了新的git switch命令来切换分支
git switch branch_name,切换分支(推荐使用git switch)
git switch -c branch_name,创建并切换分支(--change)
git branch 查本地分支
git merge other_branch_name,把其它分支代码合并到当前分支
git branch -d other_branch_name,删除其它分支(-D,d大写代表强制删除)
分支合并策略
使用git merge合并分支时,Git默认使用Fast forward模式,但这种模式下,删除被合并分支后,会丢掉分支信息。
如果加上参数--no-ff禁用Fast forward模式,就可以用普通模式合并,Git就会在merge时生成一个新的commitId,这样,从分支历史上就可以看出分支信息。
git merge --no-ff -m "merge with no-ff" dev
加-m进行注释是因为合并会生成新的commitId,就行执行git commit会生成commitId需要注释一样

10、冲突解决
常见冲突情况,2个或多个人修改了同一行的代码,然后分支合并产生冲突,git merge other_branch_name,会提示冲突的文件名。
Git用<<<<<<<,=======,>>>>>>>标记出不同分支的内容,我们必须解决冲突后再提交。
可手动找到相应文件解决,或使用工具()
解决后使用git add/git commit提交
11、查看分支合并图
用git log --graph命令可以看到分支合并图,如
git log --graph --pretty=oneline --abbrev-commit -n 6
可看见

12、暂存修改(保存现场)
在开发项目的时候,突然来一个变更需要修改,我们除了将当前项目提交(commit)后切换(checkout) 到其他分支外,我们还可以先将当前的修改暂存(stash)起来,然后再切换(checkout)到其他分支,而不需要提交(commit),这样就可以减少一个 commit (虽然可以使用 git commit --amend 来修改最后一次提交 )
暂存修改分2种情况
文件已被git跟踪:使用git stash,如果需要加注释使用git stash save 'message'
文件未被跟踪,如新增文件,使用git stash -a或需要注释git stash save -a 'messge',或先 git add . 然后再使用 git stash 或 git stash save "注释" 来暂存修改
其它命令:
git stash list ,查看暂存列表

可以看到stash@{id}里面的id默认从0开始,最近的暂存为0,使用此特性可对暂存区进行一些操作
git show stash@{n},通过此命令可以查看stash的详情,如git show stash@{0}可看到最近一次暂存内容的修改情况
git stash apply stash@{id}, 回到曾今的工作现场(在当前分支应运指定id暂存内容),恢复后,stash内容并不删除。需使用git stash drop stash@{id}来删除
git stash pop stash@{id},恢复最新的暂存内容到工作区,不指定stash@{id}(git stash pop即git stash pop stash@{0}),会在 stash list 里面将最近一次的修改暂存记录删除掉,等同于git stash apply stash@{0}和git stash drop stash@{0}。
git stash clear,清空所有修改暂存
git stash drop stash@{id},删除指定暂存
12、git cherry-pick拣选
复制特定的提交到当前分支,可用于“重放”别的分支的bug修复过程等。
如,master分支有bug,当前分支是早期从master分支分出来的,在master分支上修复了bug后,我们只想把master分支提交所做的修改“复制”到当前分支,而不是把整个master分支merge过来,这时可使用git cherry-pick.
git cherry-pick <commit>,如git cherry-pick 4c805e2
13、git remote远程分支操作
远程仓库的默认名称是origin。使用git remote可查看远程仓库名

git remote -v,可查看详细信息
git push origin local_branch_name,把本地指定分支上的所有本地提交推送到远程库。
如git push origin dev、git push origin master
推送时,通过指定本地分支,这样,Git就会把该分支推送到远程库对应的远程分支上
必须先指定本地分支与远程分支的链接,才能使用git push origin local_branch_name。
可使用git branch --set-upstream-to=origin/remote_branch_name local_branch_name来指定链接.如git branch --set-upstream-to=origin/dev dev
14、git rebase变基
负责把分叉的提交历史“整理”成一条直线,再推送到远程。
使用场景:同一分支,别人在我之前做了修改,并且提交到了远程库,那么我提交时必须先git pull获取一下最新代码,再git push到远程库。
这样有个问题:提交历史分叉了

我们可以在git pull之后,gitpush提交之前,执行
git rebase
这样再git push到远程库,提交历史就不再分叉,变的好看一些

15、git tag标签
标签是是指向某个commit的指针,是版本库的快照。
使用场景:
git commit提交多次,需要把上周的某一次打包发布,要找到对应的commit号,很麻烦,这事可以打个标签,按标签查找就行了。
还有一种场景,使用composer search、composer require等操作库文件,由于库文件是存储在github等git仓库中,它的不同版本也是通过标签向外发布供引入。
git tag tag_name [commitId],不指定commitId表示在最新节点打标签。如git tag v1.0.
可通过git log --pretty=oneline --abbrev-commit查看各commit号,指定节点打标签。如git tag v1.2 guwy543we4
参数解释
-a,指定标签名,
-m ,注释
如:git tag -a v0.1 -m "version 0.1 released" 1wewe12
git tag,查看当前所有标签
git show tag_name,查看指定标签信息
git tag -d tag_name,删除标签
git push origin tag_name,因为创建的标签都只存储在本地,不会自动推送到远程,有时需把指定标签推送到远程分支。
git push origin --tags,一次性把所有标签推送到远程分支。
如果标签推送到了远程库,要删除标签怎么办?
先使用 git tag -d tag_name删除本地分支,再使用git push origin :refs/tags/tag_name,如(git push origin :refs/tags/v1.2)从远程删除
注意:标签总是和某个commit挂钩。如果这个commit既出现在master分支,又出现在dev分支,那么在这两个分支上都可以看到这个标签
16、配置别名git alias
分对当前用户其作用还是整个仓库起作用
当前用户起作用,可使用git config --global alias.自定义别名 git名,如给git status配置别名,可使用命令git config --global alias.st status。
可对git log配置别名: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配置文件放在用户主目录下的一个隐藏文件.gitconfig中,可找到这个目录,直接修改来配置

对当前仓库起作用,git config alias.自定义别名 git名,不加--global。配置文件放在.git/config中,可对其直接修改来配置
17、忽略文件
有些文件,如:
操作系统自动生成的文件,比如缩略图等;
编译生成的中间文件、可执行文件等,也就是如果一个文件是通过另一个文件自动生成的,那自动生成的文件就没必要放进版本库;
你自己的带有敏感信息的配置文件,比如存放口令的配置文件。
需要进行忽略操作,可编写.gitignore,.gitignore文件本身要放到版本库里,并且可以对.gitignore做版本管理!
如果本地忽略已提交到远程,再次ignore忽略失败,解决方案,删除缓存:
git rm -r --cached core/library/wew/cer/.
git commit -m '忽略版本控制证书'
git push
18、清理版本库不存在的 本地分支
有时由于切换的本地分支很多,导致分支管理越来越麻烦,可以清理掉已经不用的分支,如删除本地有但在远程库已经不存在的分支
git remote prune origin
19、更改远程仓库地址
场景:某员工创建了项目,后离职了,那以前的仓库url需要进行用户名改变(http://gitlab.mkeduit.com:8888/用户名/learn.git),
方法有3种
第一种:直接修改地址
git remote set-url origin <url>
第二种:删除远程地址,再添加
git remote rm origin
添加仓库
git remote add origin http://gitlab.cdf.com:8888/xiaona/learn.git
查看仓库是否添加成功
git remote -v
配置全局用户名邮箱
git config --global user.name "cdf"
git config --global user.email cdf@gmail.com
git commit --amend --reset-author
拉取下最新的分支
git pull
关联本地分支到远程分支
git branch --set-upstream-to=origin/master master
测试推送代码是否正常
git push
git pull
浙公网安备 33010602011771号