zoukankan      html  css  js  c++  java
  • 版本控制-Git

    概述

    Git是目前世界上最先进的分布式版本控制系统(没有之一)。Linus花了两周时间自己用C写了一个分布式版本控制系统,Git迅速成为最流行的分布式版本控制系统,尤其是2008年,GitHub网站上线了,它为开源项目免费提供Git存储,无数开源项目开始迁移至GitHub,包括jQuery,PHP,Ruby等等。

    安装配置

    Mac直接从AppStore安装Xcode,Xcode集成了Git。

    设置git config

    因为Git是分布式版本控制系统,所以,每个机器都必须自报家门:你的名字和Email地址。你也许会担心,如果有人故意冒充别人怎么办?这个不必担心,首先我们相信大家都是善良无知的群众,其次,真的有冒充的也是有办法可查的。

    查看git config

    Git基础使用

    查看提交历史

    $ git log 
    $ git log --pretty=oneline
    

    Git的commit id不是1,2,3……递增的数字,而是一个SHA1计算出来的一个非常大的数字,用十六进制表示。

    版本回退

    首先,Git必须知道当前版本是哪个版本,在Git中,用HEAD表示当前版本,上一个版本就是HEAD,上上一个版本就是HEAD,当然往上100个版本写100个比较容易数不过来,所以写成HEAD~100。

    $ git reset --hard HEAD^
    

    指定回到未来的某个版本

    git reset --hard 1094a
    

    版本号没必要写全,前几位就可以了,Git会自动去找。当然也不能只写前一两位,因为Git可能会找到多个版本号,就无法确定是哪一个了。

    现在,你回退到了某个版本,关掉了电脑,第二天早上就后悔了,想恢复到新版本怎么办?找不到新版本的commit id怎么办?

    在Git中,总是有后悔药可以吃的。当你用$ git reset --hard HEAD^回退到add distributed版本时,再想恢复到append GPL,就必须找到append GPL的commit id。Git提供了一个命令git reflog用来记录你的每一次命令:

    工作区和暂存区

    Git和其他版本控制系统如SVN的一个不同之处就是有暂存区的概念。工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库。
    Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD。

    撤销修改

    撤销工作区的修改

    $ git checkout -- readme.txt
    

    丢弃工作区的修改,这里有两种情况:
    一种是readme.txt自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;
    一种是readme.txt已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。
    总之,就是让这个文件回到最近一次git commit或git add时的状态。

    撤销暂存区的修改

    git reset命令既可以回退版本,也可以把暂存区的修改回退到工作区。当我们用HEAD时,表示最新的版本。

    $ git reset HEAD readme.txt
    

    删除文件

    执行rm file删除一个文件,git把这次操作理解为一次工作区文件的修改。

    确实要从版本库中删除该文件,那就用命令git rm readme.txt 删掉,并且git commit

    远程仓库

    Git是分布式版本控制系统,同一个Git仓库,可以分布到不同的机器上。怎么分布呢?最早,肯定只有一台机器有一个原始版本库,此后,别的机器可以“克隆”这个原始版本库,而且每台机器的版本库其实都是一样的,并没有主次之分。

    GitHub是提供Git仓库托管服务的,所以,只要注册一个GitHub账号,就可以免费获得Git远程仓库。

    GitHub远程仓库的准备

    本地Git仓库和GitHub仓库之间的传输是通过SSH加密的。所以,需要一点设置:

    添加远程仓库

    在用户主目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsa和id_rsa.pub这两个文件,如果已经有了,可直接跳到下一步

    $ ssh-keygen -t rsa -C "youremail@example.com"
    

    你需要把邮件地址换成你自己的邮件地址,然后一路回车,使用默认值即可,由于这个Key也不是用于军事目的,所以也无需设置密码。

    登陆GitHub,打开“Account settings”,“SSH Keys”页面:

    为什么GitHub需要SSH Key呢?因为GitHub需要识别出你推送的提交确实是你推送的,而不是别人冒充的,而Git支持SSH协议,所以,GitHub只要知道了你的公钥,就可以确认只有你自己才能推送。

    当然,GitHub允许你添加多个Key。假定你有若干电脑,你一会儿在公司提交,一会儿在家里提交,只要把每台电脑的Key都添加到GitHub,就可以在每台电脑上往GitHub推送了。

    GitHub远程仓库克隆

    在GitHub创建了一个空的仓库GitTest

    目前,在GitHub上的这个learngit仓库还是空的,GitHub告诉我们,可以从这个仓库克隆出新的仓库,也可以把一个已有的本地仓库与之关联,然后,把本地仓库的内容推送到GitHub仓库。

    git remote add origin git@github.com:coderketao/GitTest.git
    

    请千万注意,把上面的michaelliao替换成你自己的GitHub账户名,否则,你在本地关联的就是我的远程库,关联没有问题,但是你以后推送是推不上去的,因为你的SSH Key公钥不在我的账户列表中。
    添加后,远程库的名字就是origin,这是Git默认的叫法,也可以改成别的,但是origin这个名字一看就知道是远程库。
    下一步,就可以把本地库的所有内容推送到远程库上:

    git push -u origin master
    

    把本地库的内容推送到远程,用git push命令,实际上是把当前分支master推送到远程。

    由于远程库是空的,我们第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。

    分支管理

    分支的基础使用

    每次提交,Git都把它们串成一条时间线,这条时间线就是一个分支。截止到目前,只有一条时间线,在Git里,这个分支叫主分支,即master分支。

    常见的分支管理命令

    $ git branch dev  创建分支
    $ git checkout dev 切换分支
    $ git checkout -b dev 创建分支 加上-b参数表示创建并切换
    $ git branch 查看当前分支
    $ git merge dev dev分支的工作成果合并到当前分支上
    $ git branch -d dev 删除分支
    

    有时合并分支时,Git会提示这是一次Fast-forward,意思是合并是“快进模式”,也就是直接把master指向dev的当前提交,所以合并速度非常快。

    当然,也不是每次合并都能Fast-forwardmaster分支和feature1分支各自都分别有新的提交,变成了这样:

    这种情况下,Git无法执行“快速合并”,只能试图把各自的修改合并起来,但这种合并就可能会有冲突

    合并后,master分支和feature1分支变成了下图所示:

    “快进模式”合并,用git log --graph也可以看到分支的合并情况:

    Bug分支

    软件开发中,bug就像家常便饭一样。有了bug就需要修复,在Git中,由于分支是如此的强大,所以,每个bug都可以通过一个新的临时分支来修复,修复后,合并分支,然后将临时分支删除。

    当你接到一个修复一个代号101的bug的任务时,很自然地,你想创建一个分支issue-101来修复它,但是,等等,当前正在dev上进行的工作还没有提交,并不是你不想提交,而是工作只进行到一半,还没法提交,预计完成还需1天时间。但是,必须在两个小时内修复该bug,怎么办?
    幸好,Git还提供了一个stash功能,可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作:

    $ git stash
    

    现在,用git status查看工作区,就是干净的(除非有没有被Git管理的文件),因此可以放心地创建分支来修复bug。
    工作现场还在,Git把stash内容存在某个地方了,但是需要恢复一下,有两个办法:

    • 一是用git stash apply恢复,但是恢复后,stash内容并不删除,你需要用git stash drop来删除;
    • 另一种方式是用git stash pop,恢复的同时把stash内容也删了

    Feature分支

    软件开发中,总有无穷无尽的新的功能要不断添加进来。
    添加一个新功能时,你肯定不希望因为一些实验性质的代码,把主分支搞乱了,所以,每添加一个新功能,最好新建一个feature分支,在上面开发,完成后,合并,最后,删除该feature分支。
    现在,你终于接到了一个新任务:开发代号为Vulcan的新功能,该功能计划用于下一代星际飞船。

    git checkout -b feature-vulcan
    

    5分钟后,开发完毕:切回dev,准备合并。
    一切顺利的话,feature分支和bug分支是类似的,合并,然后删除。就在此时,接到上级命令,因经费不足,新功能必须取消!
    虽然白干了,但是这个包含机密资料的分支还是必须就地销毁:

    $ git branch -d feature-vulcan
    

    销毁失败。Git友情提醒,feature-vulcan分支还没有被合并,如果删除,将丢失掉修改,如果要强行删除,需要使用大写的-D参数。

    现在我们强行删除:

    $ git branch -D feature-vulcan
    

    多人协作

    当你从远程仓库克隆时,实际上Git自动把本地的master分支和远程的master分支对应起来了,并且,远程仓库的默认名称是origin

    要查看远程库的信息

    $ git remote
    git remote -v 显示更详细的信息 可以显示抓取和推送的origin的地址。如果没有推送权限,就看不到push的地址。
    

    推送分支

    送分支,就是把该分支上的所有本地提交推送到远程库。推送时,要指定本地分支,这样,Git就会把该分支推送到远程库对应的远程分支上:

    git push origin 即将推送的本地分支
    

    但是,并不是一定要把本地分支往远程推送,那么,哪些分支需要推送,哪些不需要呢?

    • master分支是主分支,因此要时刻与远程同步;
    • dev分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步;
    • bug分支只用于在本地修复bug,就没必要推到远程了,除非老板要看看你每周到底修复了几个bug;
    • feature分支是否推到远程,取决于你是否和你的小伙伴合作在上面开发。

    抓取分支

    多人协作时,大家都会往master和dev分支上推送各自的修改。
    默认情况下,git clone只能看到本地的master分支。可以用git branch命令看看,要在dev分支上开发,就必须创建远程origin的dev分支到本地,于是可以使用这个命令创建本地dev分支

    $ git checkout -b dev origin/dev
    

    现在,他就可以在dev上继续修改,然后,时不时地把dev分支push到远程:

    $ git push origin dev
    

    标签管理

    发布一个版本时,我们通常先在版本库中打一个标签(tag),这样,就唯一确定了打标签时刻的版本。将来无论什么时候,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来。所以,标签也是版本库的一个快照。

    创建标签

    默认标签是打在最新提交的commit上的。有时候,如果忘了打标签,可以找到历史提交的commit id,然后打上就可以了。

    $ git tag v0.9 f52c633
    

    还可以创建带有说明的标签,用-a指定标签名,-m指定说明文字:

    $ git tag -a v0.1 -m "version 0.1 released" 1094adb
    

    操作标签

    如果标签打错了,也可以删除:

    $ git tag -d v0.1
    

    因为创建的标签都只存储在本地,不会自动推送到远程。所以,打错的标签可以在本地安全删除。

    如果要推送某个标签到远程,使用命令git push origin <tagname>:

    $ git push origin v1.0
    $ git push origin --tags  一次性推送全部尚未推送到远程的本地标签
    

    如果标签已经推送到远程,要删除远程标签就麻烦一点,先从本地删除:

    $ git tag -d v0.9
    

    然后,从远程删除。删除命令也是push,但是格式如下:

    $ git push origin :refs/tags/v0.9
    

    git 获取指定的tag处代码

    先 git clone 整个仓库,然后 git checkout tag_name 就可以取得 tag 对应的代码了。

    $ git checkout v0.1.0
    

    但是这时候 git 可能会提示你当前处于一个“detached HEAD" 状态,因为 tag 相当于是一个快照,是不能更改它的代码的,在切换回主线时如果没有合并,之前的修改提交基本都会丢失。如果要在 tag 代码的基础上做修改,你需要一个分支:

    git checkout -b branch_name tag_name
    

    这样会从 tag 创建一个分支,然后就和普通的 git 操作一样了。

  • 相关阅读:
    关于使用MySQL语法ON DUPLICATE KEY UPDATE单个增加更新及批量增加更新的sql
    关于ESB(企业服务总线)
    [SoapUI] 在SoapUI中通过Groovy脚本执行window命令杀掉进程
    [SoapUI] 判断工程下某个文件是否存在,存在就删除
    [OpenCV-Python] OpenCV-Python 中文教程
    [Robot Framework] Jenkins上调用Rebot命令时执行报错不往下执行其他命令
    如何让程序在开机时自动启动
    @1-5使用pandas保存豆瓣短评数据
    @1-4使用Xpath解析豆瓣短评
    @1-2初识Python爬虫
  • 原文地址:https://www.cnblogs.com/CoderHong/p/9661858.html
Copyright © 2011-2022 走看看