为什么要学Git?因为别人都会你还不长点心吗?
精简自:廖雪峰官方网
我个人比较喜欢倒序说东西,也就是先把结果告诉你,然后再告诉你细节,所以先po出来多人协作的时候比较常用的语句吧。我就用码云做例子哈。我们跳过下载Git还有配置远程库ssh加密这一块(下文都有可以自己看的)。还有些东西要更新慢慢来吧 。
![](https://img.haomeiwen.com/i2270027/29e11881203a3d24.jpg)
首先是从远程库下载资源并建立链接,com后面个的是自己的远程库地址
git clone git@gitee.com:iSuAbner/BeamtechTest.git
如果是添加一个新的文件,然后上传的话
git add 文件名
git commit -m '解释'
从指定远程分支下载
git clone -b dev_Aber git@gitee.com:iSuAbner/BeamtechTest.git
当你没有新建和远程同名的本地分支的时候就能新建一个分支然后直接下载这个远程分支这种
git checkout -b dev_Abner origin
这个命令拆开来的话算是三个语句-b 本地新建一个分支 checkout 指针转向这个分支 最后面的origin链接到远程库的一个分支 如果是其他分支的话应该是origin/分支名字 ,其实这个和后期向那个远程库分支push本地分支是没关系,只是第一次获取数据的时候想要clone的远程库分支数据。也就是:
git branch -b dev_Abner
git checkout dev_Abner
如果本地新建的一个分支还没有指定传递到哪一个远程库分支的话
git branch --set-upstream-to origin/dev_Abner
如果想要log的时候有版本记录,就需要merge的时候不适用快速合并
git merge --no-ff -m '我们需要版本记录' dev_Abner
推送这个方法在远程库上会生成一个origin/同名分支的分支。要不就是传向其他分支git push --set-upstream origin dev_Abner
git push origin 同名分支
一、Git简介
Git是目前世界上最先进的分布式版本控制系统(没有之一)
Git 可以跟踪所有的文本文件的更改,比如你在几行几行添加或者删除更改了某个单词,但没有办法跟踪文件的变化,比如二进制的文件只能通过观察文件的大小来知道是否有更改。直接开始~
![](https://img.haomeiwen.com/i2270027/9a22d59f6406abb4.png)
1.仓库
首先创建一个文件夹当做Git仓库的位置
mkdir iSuAbner
cd iSuAbner
pwd 这个命令能打印出现在文件路径
2.初始化
在上文中创建的文件夹中初始化Git仓库
git init
3.添加文件
把需要上传的文件放到这个文件夹下面,然后
git add 文件名
这个add操作可以反复使用,添加多个文件,一定要记得写文件类型后缀。
然后就是上传
git commit -m "这次上传的说明"
问题:为什么需要add和commit两次操作呢?
答:因为commit是一次性操作,add是可重复性操作。
4.Git日志
当我们在文件夹中修改了之前已经commit的文件,git会做出什么记录呢?
git status
status 能告诉我们那个文件发生了变化,但是变化的细节我们不得而知。那么如何查找细节呢?
git diff “上面提示的那个文件名字”
diff是difference的缩写也就是能看到有什么不同,接下来在运行add 和commit两个方法。
5.历史版本
当你修改文件然后在添加提交这样的重复操作之后,就像游戏存档一样在Git中都会有相应的保留版本,也就是你上面commit的时候后续添加的-m字符串。我们想要看新的代码和上一次的代码有什么区别的时候就可以log出来:
git log
log方法最多显示最近三次的提交记录,如果改动比较多看log比较眼花缭乱可以git log --pretty=online
有的时候我们不仅想要看到早先版本和现在版本的差别,更想回到之前版本,这个时候就用到了reset:
git reset --hard HEAD^
这个HEAD^
是指上一个版本,HEAD
是指当前版本,HEAD^^
是指上上个版本,那么前第100个版本呢?HEAD^^^^^^^^.....
想多了,我们这样表示HEAD-100
。
当我们执行上面的那个回退操作的之后我们打印log就会发现之前的最新的版本已经没有了,千万别吓得把命令行观点冷静下,我们可以翻阅之前的命令行数据找到之前的最新版本的那一串commit id,然后我们
git reset --head 巴拉巴拉一串id
我们就会找到之前的最新版本。Git的回退版本速度很快,因为这个HEAD是一个指针,我们回退版本的时候Git只是把HEAD的指向位置改掉了。
当然如果不幸你真的是不敢相信自己的眼睛把命令行关掉冷静了下之后发现之前的commit id已经找不见了,那么如何找回commit id呢?
git reflog
reflog会记录你的每一次命令,然后找到当时的说明 找到前面的commit id再跳回来吧骚年~
二、关于缓存区和工作区
工作区就是指你的你在本地新建的那个文件夹,暂存区是Git生成的一种当你执行add命令的时候,文件存在的地方,就跟车站进车Git add就相当于把你放在了候车室,commit就给你撵上车了。当Git生成缓存区的时候同时给了我们生成了一个master分支,也就是我们commit过去的对象,也就是那个车。
Git相对于其他版本控制器的优势
1.对于修改文件
Git跟踪并管理的是修改,而不是文件,在说明了这个缓存区和工作区和master分支后,我们要明白我们commit操作的对象是缓存区的数据,比如我们add一个文件,commit之后,修改这个文件,再commit,会发现这个文件在master中并没有发生改变,这是因为虽然我们修改了文件但是我们没有把修改后的文件放在缓存区中,而上一条commit操作已经清空了我们的缓存区,那后一条commit就是对空的缓存区操作,master中的文件就不会更改。
2.关于撤销修改
我们仍然从工作区,缓存区和master分支三块来说。
第一个 是在工作区的修改撤销,因为就是你拖进本地文件夹中的代码你当然可以直接删除掉之前新加的操作,这个时候你status就会提示你你可以通过checkout --
命令无痕退到之前操作。
git checkout -- 文件名
工作区的修改撤销
分为两种情况
- 工作区修改文件后还没有添加到缓存区,这个时候你checkout就会把工作区所有的修改去掉。
- 文件已经添加到了缓存区再做了修改,撤销修改就会回到添加到暂存区后的状态。
总之就是让文件回到最近一次git commit或git add的状态。
缓存区的修改撤销
这个时候git status就会发现Git提示你git reset Head 文件名
可以把缓存区的修改撤销,重新放回工作区。
还记得我们要怎么删除工作区的修改吗 git checkout --文件名
。
这边吧 我刚开始的时候总是混掉,认为reset Head文件名和checkout --文件名
对添加进缓存区的文件操作是一样。其实在工作区修改之后加到缓存区,reset Head是删除缓存区的操作但是工作区的操作没有修改,而checkout是撤销修改工作区的内容。
3.删除文件
正常的删除文件就是rm文件名然后commit一次
git rm 文件名
git commit -m "删除文件说明"
这个是你想要删除某一个文件,但也有情况是你误删了一个文件,那么不要着急版本库里面还有完整版本,撤销工作区操作checkout --文件名
就可以重新获得文件,就想一键还原一样。
三、远程仓库
GitHub
因为GitHub仓库和本地工作区仓库之间的传输是SSH
加密的。所以我们需要获取SSH的公钥私钥,打开用户主目录,看看有没有.ssh文件夹如果有这个文件夹打开文件夹目录下面的id_rsa
和id_rsa.pub
就是私钥和公钥,如果没有.ssh文件夹:
$ ssh-keygen -t rsa -C "youremail@example.com"
上面的邮箱换上自己的邮箱号,创建SSH Key,一路回车就可以了。
在GitHub上Add SSHKey里面添加上公钥 id_rsa.pub
,为什么要使用SSH呢就是为了让GitHub知道你传过来的文件是你传过来的不是别人传过来的
。
添加远程库
在GitHub上新建一个repo,然后在本地工作区文件夹下面运行
![](https://img.haomeiwen.com/i2270027/977e7f4cdecf0a7a.png)
$ git remote add origin git@github.com:iSuAbner/learngit.git
上面的iSuAbner要换成自己的Github账户名,否则你关联的就是我的远程库,关联没问题,但是你的公钥没有在我的SSH Key里面所以你推不上来的。添加后远程库的名字就叫做origin
。
接下来就是推的过程了:
git push -u origin master
push就是把工作区的master分支上传到origin上,由于第一次上传的时候origin是空的所以用-u
可以把工作区的master分支和远程的master分支相关联起来。以后推送或者拉取的时候就可以简化命令了。
这之后只要工作区有了修改就
git push origin master
从远程库克隆
也就是从远端下载一份代码自己编写
git clone 地址(例如:git@github.com:iSuAbner/BeamtechTest.git)
分支管理
创建和合并分支
我们知道git log
可以把我们的提交记录打印出来 也就是活Git把我们的每一次操作都做了记录就像是一个时间线。在Git中这一条时间线叫做master
,Head
也就是调换版本的指针其实不是直接指向提交的,而是指向master
的,master
才是指向提交的。
![](https://img.haomeiwen.com/i2270027/84b53f69099646cd.png)
当你新建一个分支,比如
dev
那么Git就会生成一个dev
指针,这个指针和master
一样指向提交,再把HEAD
指向dev
,这样就创建了一个新的分支![](https://img.haomeiwen.com/i2270027/0e0f7193c9e24e07.png)
然后我们就把工作区的修改都提交到
dev
中,最后合并master
和dev
,删除dev
分支就大功告成了。![](https://img.haomeiwen.com/i2270027/451415594c5b9f38.png)
下面来看实际操作:
git checkout -b dev
checkout
是不是看的非常熟悉呢,上面的那个工作区撤销操作是checkout --
哦是有差别的。-b
是什么意思呢 checkout
是切换分支的命令,-b
就是创建分支的简写,这一句就代替了新建dev
,Head
再指向dev
两步。我们可以通过branch来看现在的分支情况:
git branch
前面有星号的就是当前
HEAD
指针指向的分支。确认是
dev
分支之后,就可以添加修改之类的了git add 文件名
git commit -m "说明"
上面就是我们在
dev
分支中所要做的东西,做完这些之后就需要再把HEAD指回来git checkout master
最后我们合并
dev
和master
git merge dev
然后删除
dev
分支git branch -d dev
删除之后我们
branch
的时候就能看见master
分支了。需要注意的时候我们的合并是快速合并,不是所有的合并都是快速合并的,以后会给您说明下。
解决冲突
像上面那样您修改的部分别人没有做任何事情那还是很友好的,可如果有一天你提交的文件和别人的文件发生相同位置的不同修改的时候怎么办?
比如你新建了一个branch -b featurel
然后添加提交了一些东西这个时候你想要把featurel
和master
合并,但是git
提示你您现在的master
是前一个版本的。
![](https://img.haomeiwen.com/i2270027/19d6a563f6b79c6d.png)
而这个最新的
master
同样更改了你的feature
分支更改的一些地方,这个时候就会发生冲突,我们可以通过status来查看冲突的文件,然后在工作区点开文件我们就会发现Git用<<<<<<<,=======,>>>>>>>
标记出不同分支的内容==>>
中间的就是我们feature
分支的操作和master
的冲突,删除他然后add 再commit就会像下图一样:![](https://img.haomeiwen.com/i2270027/f458e84832c9ee3c.png)
我们可以通过
git log --graph
来查看分支合并的状态。
分支管理策略
在使用Fast forward
然后合并分支,删除分支之后我们就不会保有分支的信息,如果我们想要保留这个延伸的分支点,我们就不能使用Fast forward
也就是上面的那种解决冲突的办法:
![](https://img.haomeiwen.com/i2270027/552f521f8d3c97c7.png)
这样我们就能看到我们的分支点了。
下面来看实际操作
git add readme.txt
git commit -m "增加文件"
git checkout master
git merge --no-ff -m "merge with not fast forward" dev
--no-ff
也就是不适用快速合并 -m
是为了做注释。
我们可以log看一下分支情况,所有的分支都能一目了然。
Bug分支
Bug对于程序员就像吃的饭一样,就算你吃了很多还是有那么多,正在你在一个branch
上狂写代码的时候突然上面说有一个BUG需要你马上解决,但是现在这个branch
上的代码还没有弄完啊,预计还要很长时间现在不能commit
,而bug又是需要马上解决的那我们怎么做呢?
git stash
stash方法保存当前工作区的操作并清空工作区。
当你搞定完bug回来的时候,你又要继续在之前的那个branch
上奋笔疾书了怎么回到上一个branch
呢?
git stash pop
stash pop
不仅回到之前的branch
还把stash list
中的这个stash
删除。你也可以多次stash
然后stash list
找到stash id
来回到那个工作区内容。
Feature分支
有的时候当你在一个分支上加了一堆的功能之后,最后产品经理跑过来告诉你,嗨呀好气啊 这些功能不需要了,在你用40M长刀问候完产品经理之后是时候去删除这个分支了
git branch -d feature
有的时候这样删除是删除不掉的,Git认为你写了代码为什么不合并呢,你可以帮Git@你的产品经理,然后
git branch -D feature-vulcan
删除完成,顺便看一眼躲在墙角里瑟瑟发抖的产品。
四、多人协作
之前我们说过当我们从远程库clone的时候就已经把远程库的master分支和本地的master分支关联起来,远程库的默认名字是origin,如果想要看远程库的信息可以remote。
![](https://img.haomeiwen.com/i2270027/43ec0296781228be.png)
git remote或者git remote -v
推送分支
就是把所有该分支的数据推送到远程库,推送的时候要指定分支。
git push origin 你要推送的branch name
当然也不是所有的分支都需要推送的。
master是主分支,必须要时刻与远程同步
dev是开发分支,团队里都会在上面操作,需要和远程同步
bug 和 feature就因人而异了。
模拟一个情景:
你和你的小基友们开发同一个项目,你的小基友clone远程库
git clone git@github.com:项目链接
你们约定一起在dev分支上做开发,所以你的小基友在本地创建一个分支并checkout
这个branch
,并且链接远程库origin/dev
。
git checkout -b dev origin/dev
然后他就时不时的向这个brance 提交一些内容
got commit -m "你的小基友又提交修改了,你还能写点代码不"
在你收到一万点嘲讽之后你终于提交了一份代码,但是你的小基友已经手快在同一个位置做了不同的修改并已经上传上去了,这个时候就会有冲突。
GitHub通知我们我们可以pull最新版本的origin/dev在本地解决冲突然后再上传。
git pull
然后突然发现git pull也失败了 才发现没有指定本地的dev和远程库的链接
![](https://img.haomeiwen.com/i2270027/04b0a8c3d3829db3.png)
git branch --set-upstream dev origin/dev
然后在pull,成功~,在本地修改冲突然后在commit吧。
五、标签管理
创建标签
标签就像是版本号一样,可是我们不是可以reflog出commit id吗为什么还需要标签呢?因为我相信你一定不想commit id。
创建标签很简单git checkout 到你想创建标签的branch。
git tag v1.0
我们也可以通过tag查看所有的标签
git tag
如果想给自己以前的某个操作打一个标签,那应该怎么做呢?
$ git log --pretty=oneline --abbrev-commit
找到commit id
git tag 标签名 commit id
我们也可以查看标签的内容
git show 标签名
还可以创建有说明的标签
git tag -a 标签名 -m "说明" commit id
私钥加密标签
git tag -s v0.2 -m "signed version 0.2 released" fec145a
签名采用PGP签名,因此首先安装pgp
操作标签
如果标签弄错了,可以选择删除标签
git tag -d 标签名
标签一般只是会存在本地不会上传去远程库的,但是如果想要标签一样上传到远程库:
git push origin 标签名
或者一次性全部上传上去
git push origin --tage
如果放在远程库的标签除了错误,就要分两步删除了。先删除本地的
git tag -d 标签名
然后删除远端的
git push origin :refs/tags/v0.9 To git@github.com:项目地址
在Github上做验证吧 ~
六、GitHub
大概的时候使用方法在上文中基本都说完了,这边呢说下对GitHub上其他开源项目怎么提交自己的修改分支,看到一些强大的框架的时候你是不是也想着自己能不能为这个框架做些优化呢?如果有能力你可以先Fork,然后Github就会在你的仓库下面创建一个相同的框架,然后clone自己profile的这个框架,注意一定是自己仓库下面的因为如果你直接clone原始仓库因为你没有私钥你是push不上原始仓库的。在本地修改之后push上自己的仓库然后点击pull request。
七、请问为什么我每次写文章总感觉每次都没写全?
后增加的点:
嗯 Git Clone 的时候下来的基本就是远程库master分支,想要clone其他的远程库分支就需要git pull origin dev_cfp(分支的名字)。
网友评论