前言
看了很多教程,发现还是很多东西记不住,如果不写写的话两天就忘了,所以记一下笔记。为了让别人有教程的感觉,对笔记进行了由浅入深的排序,可以帮你们快速入门。
git由来
linux在后期的开发过程中开发人员和代码量巨大,急需版本控制工具,刚开始有公司赞助给他们用,后来他们试图破解这个工具(确实很作死),人家不给他用了,这些linux coder一气之下用C开发了初代的git,后来火了之后又在2008年做了github网站托管全球代码,从此git走入千家万户。
git是分布式的,但是我们普通人用起来和集中式没有区别。所以不用管这个概念。
安装git
linux : sudo apt-get install git
mac: 安装homebrew - > 安装git 安装xcode - > preferences->downloads->Command Line Tools->install
window: 官方安装程序链接,推荐安装setup版而不是portable版
安装完以后需要你进行设置标记下是谁的github :
1 | $ git config --global user.name "name or nick name" |
版本库
版本库就是一个小小的仓库,这个仓库由git管理,里面任何东西的变动它都知道,在电脑上它就是一个文件夹。
我们来创建一个仓库(文件)
1 | mkdir testforgit |
初始完以后我们需要尝试写一个文件,比如readme.txt 写完放入git管控的目录下,这样git才能找到它,然后我们两步提交此文件到服务器:
1 | $ git add readme.txt |
基础命令
修改文件
我们修改readme文件,然后通过以下命令来查看区别:
1 | $ git status |
版本回退
修改完文件后我们后悔了,或者说我们修改完的代码崩溃了 调不过来了,我们想回退到以前能正常运行的版本。好,这在git是非常方便的:
1 | #我们首先看下现在的reamde文件内容 |
撤销修改
有一天你在写代码,本来没啥事,结果等你第二天起来的时候发现昨晚写的工作区代码有很多bug,bug多到懒得调试,此时你可以一行一行的查找删除修改,也可以直接回滚版本,但是你发现出问题的代码仅存在在 login.php中,于是你想有没有一种办法回滚单个文件?嘿嘿 确实有
1 | $ git checkout -- login.php |
上次逃过一劫,然后你就放松警惕了,某天晚上你又在login.php写了一堆漏洞,然后还git add到了暂存区,但是你还没有commit,这时候如果用上面的命令是没用的,因为上面的命令同样只能恢复到提交到暂存区的状态,于是你晚上大哭大闹,觉得自己真是stupid,不过git 可以帮你:
1 | git reset HEAD <file> |
嘿嘿,晚上终于可以早点睡觉了!
删除文件
当你删除本地库的readme.txt文件时 git status 会显示和版本库的文件不一致 会显示你删除了那个文件。
这个时候我们可以直接删除版本库的文件 git rm readme.txt 然后再次commit 一下,这样版本库和本地库就同步了。文件就删除完成。
如果你是不小心删除的,那就是恢复功能了,直接用上面的git checkout – readme.txt
git核心功能远程仓库来了
我们掌握了git的基础命令后发现git和svn也确实没啥大区别,但是为啥那么多人用git呢?接下来就是git方便的地方了,同时通过这个也可以知道为啥github那么受欢迎。
git远程仓库可以搭建在任意一台电脑上,大家都以它为仓库来拉取和提交代码,但是对于小公司来说没有必要自己去搭建一个git服务器,我们只需要把github当作一个云端电脑即可。(省时省力省钱)
免费的git仓库
我们只需要注册一个github就获得了一个免费的github仓库,下面我们需要配置这个仓库使得我们本地和云端github仓库安全传输代码和数据。
1、首先我们创建SSH key,在用户主目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsa和id_rsa.pub这两个文件,如果已经有了,可直接跳到下一步。如果没有,打开Shell(Windows下打开Git Bash),创建SSH Key:
1 | $ ssh-keygen -t rsa -C "yourmail@mail.com" |
剩下的一路回车选择默认值即可,当然如果你想给你的key设置密码也可以(过程中直接输入密码),不过我这里就不设置了。
然后我们就创建成功了,这时候你的用户主目录下有.ssh文件夹,里面分别是id_rsa和id_rsa.pub。这两个就是SSH Key的秘钥对,id_rsa是私钥,不能泄露出去,id_rsa.pub是公钥,可以放心地告诉任何人。
2、登录github添加公钥。登录后点击头向下拉菜单找到settings,然后点击SSH and GPG keys。然后new一个新的SSH keys:
为什么GitHub需要SSH Key呢?因为GitHub需要识别出你推送的提交确实是你推送的,而不是别人冒充的,而Git支持SSH协议,所以,GitHub只要知道了你的公钥,就可以确认只有你自己才能推送。
当然,GitHub允许你添加多个Key。假定你有若干电脑,你一会儿在公司提交,一会儿在家里提交,只要把每台电脑的Key都添加到GitHub,就可以在每台电脑上往GitHub推送了。
最后友情提示,在GitHub上免费托管的Git仓库,任何人都可以看到喔(但只有你自己才能改)。所以,不要把敏感信息放进去。
如果你不想让别人看到Git库,有两个办法,一个是交点保护费,让GitHub把公开的仓库变成私有的,这样别人就看不见了(不可读更不可写)。另一个办法是自己动手,搭一个Git服务器,因为是你自己的Git服务器,所以别人也是看不见的。这个方法我们后面会讲到的,相当简单,公司内部开发必备。
确保你拥有一个GitHub账号后,我们就即将开始远程仓库的学习。
添加远程库
现在你需要登录自己的github在右上角找到“Create a new repo“ 创建一个仓库,创建完成后复制仓库的地址,回到本地的lear-git文件夹(就是你本地仓库的文件夹),把这两个仓库关联并把本地的文件push上去:
1 | # 关联两个仓库 |
从远程库克隆
生活中大多数情况是我们从零开始就已经准备使用github仓库,这时候我们肯定先创建远程仓库,然后拉取到本地,而不是从本地仓库再上传到远程仓库。
创建的github仓库的步骤和上面是一样的,我们最后仅仅需要找个合适的地方:
1 | git clone 地址 |
如果有多个人协作开发,那么每个人各自从远程克隆一份就可以了。
此外我们还发现了git也支持https 但是https速度慢,而且必须要每次推送输入口令,这种就很麻烦,除非再公司内部只开放http的情况下使用,其他情况下我们更多的用 ssh
分支管理
为什么会有分支?
我们上线了一个版本,然后我们现在要开发下一个版本,这时候我们创建一个分支进行开发,然后忽然客户说上线的环境有bug,那我们可以在上线版本上再搞一个分支出来去修复bug,这样互不耽误,改bug、开放新版本、添加新需求可以同步进行,最后上线的时候再根据需要统一合并。
为什么git创建、删除、切换分支都能在一秒内完成?
因为git的分支是通过改变指针的指向来完成,无论你的分支有多少文件,对git来说,它只是把指向其他分支的指针重新指向master分支。
创建和合并分支
git里主分支是master,head指向master,切换分支时head指向对应分支,我们的工作分支就是head所指向的分支。
创建分支:
1 | $ git checkout -b dev #创建并切换到dev分支,功能等同于下面两条命令 |
查看当前分支
1 | $ git branch |
合并分支
1 | $ git merge 分支名称 |
删除废弃的分支
1 | $ git branch -d dev |
解决冲突
如果两个文件名相同内容不同且都在当前节点提交,就会变成这样:
这时候我们进行 git merge+分支名称 会提示冲突因为相同文件有不同的内容,这个时候需要我们手动修改对应文件 并再次 git add git commit 然后才可以合并成功
分支管理
git merge 命令 默认使用的是fast-forward模式,此模式下删掉分支后,会丢掉分支的信息。有时候我们需要合并后保留分支中的信息方便我们做代码变动的审查,于是就有了强制关闭Fast forward模式的合并
1 | $git checkout -b dev |
我们在实际开发中应该这样合理分配利用分支。
1、首先master分支是非常稳定的,仅仅用来发布新版本。
2、干活儿在dev分支上,等测试没问题了再合并到master分支。
3、每个人都有自己的分支,是不是的往dev分支上合并就可以了。
借用廖老师的一张图,真正的开发应该是这样
BUG分支
bug永远存在,无论你的组大佬有多少,bug永远存在。git分支让bug修复更方便。
我是bob现在我正在bob分支上开发,但是领导突然通知有bug马上让我去修复,但是我的本地的工作还没有搞完,只写了一半,也无法提交(commit)。所以我只能先把当前工作区存储起来:
1 | $git status #查看当前工作区是否有未提交的,如果没有就不用保存当前工作区了 |
这里会有人问,为什么我创建的比如3.txt没有加入版本控制器,它就无法被保存,那此时的git stash并不是完全保存了我现在的工作区,他有什么作用?
是这样的,比如我们修改了一个已经存在 在 git版本控制的文件比如readme.txt 但此时我们还未提交,如果此时我们切换到master,那么修改内容也会在master分支的reandme出现,而如果我们git stash 暂存当前的工作区,那么我们就会回到上一次commit的点上,再切换到master后,我们的工作区的内容不会对master分支的工作去造成任何影响。我们就可以更方便的进行master的操作。结束后 我们回到自己的分只进行 git stash pop 恢复 所有的git版本控制中的修改就都会还原,至于那些不在git版本控制中的文件,他永远都在工作区,既存在于master分支也存在与我们自己的开发分支,只有有人把他git add 进行提交时,它才归入版本控制库,独属于某一分支。
所以git stash在修复bug、切换分支时还是很有必要的。
然后我们切换到master分支去修bug
1 | $git checkout master |
这样我们就完成了一次bug修复。
Feature分支
某天客户心血来潮,说要加一个可以自动识别是人在玩儿手机还是狗在玩儿手机的功能。虽然你觉得很不靠谱且功能都开发的差不多了,但是客户就是上帝,你还是需要增加一个需求。
为了不让新功能把我们已经开发好的代码打乱,我们从当前的dev分支新建一个feature分支:
1 | $git checkout -b feature-person-or-dog |
多人协作
当你从远程仓库克隆时,实际上git自动把本地的master分支和远程的master分支对应起来了,并且远程仓库默认名称就是origin。
要查看远程仓库的信息: $git remote
或者使用 ·$git remote -v
查看更详细信息。
1 | $ git remote -v |
上面显示了可以抓取和推送的origin地址。如果没有推送权限,就看不到push的地址。
我们有时候建立了自己的分支,而这个分支远程库没有,这时候我们就需要自己推送分支到远程仓库。
1 | $git push origin dev |
什么分支是适合推送的呢:
master分支是主分支,因此要时刻与远程同步;
dev分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步;
bug分支只用于在本地修复bug,就没必要推到远程了,除非老板要看看你每周到底修复了几个bug;
feature分支是否推到远程,取决于你是否和你的小伙伴合作在上面开发。
新加入的小伙伴怎么开发:
1 | $git clone git@github.com:geeeez/git_test.git |
你的小伙盘推送完他的提交到origin/dev 碰巧你也要改该分支同样的文件并试图推送。这时候就会推送失败,git会提示你先git pull 最新的 origin/dev,然后本地合并解决冲突后再推送。
当然如果你此时的dev与远程的dev还没有关联起来,git pull会报错,那你首先应该关联再pull
1 | $git branch --set-upstream-to=origin/dev dev |
因此,多人协作的工作模式通常是这样:
首先,可以试图用
git push origin <branch-name>
推送自己的修改;如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并;
如果合并有冲突,则解决冲突,并在本地提交;
没有冲突或者解决掉冲突后,再用
git push origin <branch-name>
推送就能成功!如果git pull提示no tracking information,则说明本地分支和远程分支的链接关系没有创建,用命令
git branch --set-upstream-to <branch-name> origin/<branch-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
,如果有冲突,要先处理冲突。
标签管理
git中打标签非常简单
1 | $git branch |
默认标签打在最新提交的commit上,有时候你想往上次的提交中打上一个标签:
1 | #查看看提交的commit id |
如果标签打错了也可以删除
1 | $git tag -d v0.1 |
因为标签只存储在本地,不会推送到远程。所以,打错的标签可以在本地安全删除。
如果需要推送某个标签到远程,可以使用命令:bash git push origin <tagname>
或者,一次性推送全部未推送的标签:bash $ git push origin --tags
如果推送到远程再想删除就稍微有点麻烦了:
1 | #先从本地删除 |
拯救强迫症
密码配置文件肯定不能上github但是每次提交时都会提醒你有一个文件未提交,这样强迫症患者很有压力,所以git解决了这个,你只需要创建一个.gitignore文件,然后编辑它,格式官方已经给出:
https://github.com/github/gitignore
比如,在windows:
1 |
|
然后把.gitignore文件提交给版本库即可:
1 | $git add .gitignore |
有时候我们已经提交了一个文件,但是我们希望以后不要再追踪这个文件了,我们就可以:
1 | $git rm --catch 文件名 |