• git的基本操作


    git是做什么的?

    git是一个用于帮助用户实现版本控制的软件

    一、版本控制概述

    1.1、什么是版本控制

    版本控制(Revision control)是一种在开发的过程中用于管理我们对文件、目录或工程等内容的修改历史,方便查看更改历史记录,备份以便恢复以前的版本的软件工程技术。

    • 实现跨区域多人协同开发
    • 追踪和记载一个或者多个文件的历史记录
    • 组织和保护你的源代码和文档
    • 统计工作量
    • 并行开发、提高开发效率
    • 跟踪记录整个软件的开发过程
    • 减轻开发人员的负担,节省时间,同时降低人为错误

    简单说就是用于管理多人协同开发项目的技术。

    没有进行版本控制或者版本控制本身缺乏正确的流程管理,在软件开发过程中将会引入很多问题,如软件代码的一致性、软件内容的冗余、软件过程的事物性、软件开发过程中的并发性、软件源代码的安全性,以及软件的整合等问题。

    1.2、常用术语

    1)、仓库(Repository)
    受版本控制的所有文件修订历史的共享数据库

    2)、工作空间(Workspace) 
    本地硬盘或Unix 用户帐户上编辑的文件副本

    3)、工作树/区(Working tree)
    工作区中包含了仓库的工作文件。您可以修改的内容和提交更改作为新的提交到仓库。

    4)、暂存区(Staging area)
    暂存区是工作区用来提交更改(commit)前可以暂存工作区的变化。

    5)、索引(Index)
    索引是暂存区的另一种术语。

    6)、签入(Checkin)
    将新版本复制回仓库

    7)、签出(Checkout)
    从仓库中将文件的最新修订版本复制到工作空间

    8)、提交(Commit)
    对各自文件的工作副本做了更改,并将这些更改提交到仓库

    9)、冲突(Conflict)
    多人对同一文件的工作副本进行更改,并将这些更改提交到仓库

    10)、合并(Merge)
    将某分支上的更改联接到此主干或同为主干的另一个分支

    11)、分支(Branch)
    从主线上分离开的副本,默认分支叫master

    12)、锁(Lock)
    获得修改文件的专有权限。

    13)、头(HEAD)
    头是一个象征性的参考,最常用以指向当前选择的分支。

    14)、修订(Revision)
    表示代码的一个版本状态。Git通过用SHA1 hash算法表示的ID来标识不同的版本。

    15)、标记(Tags)
    标记指的是某个分支某个特定时间点的状态。通过标记,可以很方便的切换到标记时的状态。

    1.3、常见的版本控制器

    主流的版本控制器有如下这些:

    • Git
    • SVN(Subversion)
    • CVS(Concurrent Versions System)
    • VSS(Micorosoft Visual SourceSafe)
    • TFS(Team Foundation Server)
    • Visual Studio Online

    版本控制产品非常的多(Perforce、Rational ClearCase、RCS(GNU Revision Control System)、Serena Dimention、SVK、BitKeeper、Monotone、Bazaar、Mercurial、SourceGear Vault),现在影响力最大且使用最广泛的是Git与SV

    1.4、版本控制分类

    1.4.1、本地版本控制

    记录文件每次的更新,可以对每个版本做一个快照,或是记录补丁文件,适合个人用,如RCS。

    1.4.2、集中版本控制

    所有的版本数据都保存在服务器上,协同开发者从服务器上同步更新或上传自己的修改

    所有的版本数据都存在服务器上,用户的本地只有自己以前所同步的版本,如果不连网的话,用户就看不到历史版本,也无法切换版本验证问题,或在不同分支工作。而且,所有数据都保存在单一的服务器上,有很大的风险这个服务器会损坏,这样就会丢失所有的数据,当然可以定期备份。代表产品:SVN、CVS、VSS

    1.4.3、分布式版本控制

    所有版本信息仓库全部同步到本地的每个用户,这样就可以在本地查看所有版本历史,可以离线在本地提交,只需在连网时push到相应的服务器或其他用户那里。由于每个用户那里保存的都是所有的版本数据,只要有一个用户的设备没有问题就可以恢复所有的数据,但这增加了本地存储空间的占用。

    1.5、Git与SVN最主要区别

    SVN是集中式版本控制系统,版本库是集中放在中央服务器的,而工作的时候,用的都是自己的电脑,所以首先要从中央服务器得到最新的版本,然后工作,完成工作后,需要把自己做完的活推送到中央服务器。集中式版本控制系统是必须联网才能工作,对网络带宽要求较高。

    Git是分布式版本控制系统,没有中央服务器,每个人的电脑就是一个完整的版本库,工作的时候不需要联网了,因为版本都在自己电脑上。协同的方法是这样的:比如说自己在电脑上改了文件A,其他人也在电脑上改了文件A,这时,你们两之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。

    二、Git安装与配置

    2.1、什么是Git

    Git是目前世界上最先进的分布式版本控制系统。

    Git是免费、开源的

    最初Git是为辅助 Linux 内核开发的,来替代 BitKeeper

    作者:Linux和Git之父李纳斯·托沃兹(Linus Benedic Torvalds)1969、芬兰

    优点:

    • 适合分布式开发,强调个体。
    • 公共服务器压力和数据量都不会太大。
    • 速度快、灵活。
    • 任意两个开发者之间可以很容易的解决冲突。
    • 离线工作。

    缺点:

    • 模式上比SVN更加复杂。
    • 不符合常规思维。
    • 代码保密性差,一旦开发者把整个库克隆下来就可以完全公开所有代码和版本信息。

    官网: https://git-scm.com/

    源码: https://github.com/git/git/

    2.2、搭建Git工作环境

    2.2.1、下载Git

    打开 git官网,下载git对应操作系统的版本。

    选择版本:

    这里我选择下载64-bit Git for Windows Setup

    2.2.2、安装Git

    选择安装配置信息

    一直Next默认就好了,如果需要设置就要仔细读一下安装界面上的选项。

    2.2.3、启动Git

    安装成功后在开始菜单中会有Git项,菜单下有3个程序:

    Git Bash:Unix与Linux风格的命令行,使用最多,推荐最多

    与DOS风格的命令有些区别,不习惯可以选择Git CMD

    Git CMD:Windows风格的命令行

    Git GUI:图形界面的Git,不建议初学者使用,尽量先熟悉常用命令

    点击Create New Repository可以直接创建一个新的仓库。

    2.2.4、Linux与Mac OS安装Git

    Linux安装Git:sudo apt-get install git 命令行就可以安装了。

    Mac OS安装Git: https://git-scm.com/download/mac,下载双击.pkg安装

    2.2.5、Bash基本操作命令

    1)、cd : 改变目录。
    2)、cd . . 回退到上一个目录,直接cd进入默认目录
    3)、pwd : 显示当前所在的目录路径。
    4)、ls(ll): 都是列出当前目录中的所有文件,只不过ll(两个ll)列出的内容更为详细。
    5)、touch : 新建一个文件 如 touch index.js 就会在当前目录下新建一个index.js文件。
    6)、rm: 删除一个文件, rm index.js 就会把index.js文件删除。
    7)、mkdir: 新建一个目录,就是新建一个文件夹。
    8)、rm -r : 删除一个文件夹, rm -r src 删除src目录, 好像不能用通配符。
    9)、mv 移动文件, mv index.html src index.html 是我们要移动的文件, src 是目标文件夹,当然, 这样写,必须保证文件和目标文件夹在同一目录下。
    10)、reset 重新初始化终端/清屏。
    11)、clear 清屏。
    12)、history 查看命令历史。
    13)、help 帮助。
    14)、exit 退出。
    15)、#表示注释

    2.3、Git配置 - git config

    2.3.1、查看配置 - git config -l

    使用git config -l 可以查看现在的git环境详细配置,你的账号信息都在里面

    查看不同级别的配置文件:

    #查看系统config
    git config --system --list
      
    #查看当前用户(global)配置
    git config --global  --list
     
    #查看当前仓库配置信息
    git config --local  --list

    2.3.2、Git配置文件分类

    Windows系统中,Git在$HOME目录中查找.gitconfig文件(一般位于C:Documents and Settings$USER下)

    Git相关的配置文件有三个:

    1)、 /etc/gitconfig:包含了适用于系统所有用户和所有项目的值。(Win:C:Program FilesGitmingw64etcgitconfig) --system 系统级

    2)、~/.gitconfig:只适用于当前登录用户的配置。(Win:C:UsersAdministrator.gitconfig)  --global 全局

    3)、位于git项目目录中的.git/config:适用于特定git项目的配置。(Win:C:gitProject) --local当前项目

    注意:对于同一配置项,三个配置文件的优先级是1<2<3

    这里可以直接编辑配置文件,通过命令设置后会响应到这里。

    2.3.3、设置用户名与邮箱(用户标识,必要)

    当你安装Git后首先要做的事情是设置你的用户名称和e-mail地址。这是非常重要的,因为每次Git提交都会使用该信息。它被永远的嵌入到了你的提交中:

       $ git config --global user.name "manyqian"  #名称
       $ git config --global user.email 850928058@qq.com   #邮箱

    只需要做一次这个设置,如果你传递了--global 选项,因为Git将总是会使用该信息来处理你在系统中所做的一切操作。如果你希望在一个特定的项目中使用不同的名称或e-mail地址,你可以在该项目中运行该命令而不要--global选项。 总之--global为全局配置,不加为某个项目的特定配置。

    2.3.4、添加或删除配置项

    1)、添加配置项 
    git config [--local|--global|--system]  section.key value
    [--local|--global|--system]  #可选的,对应本地,全局,系统不同级别的设置,请看2.3.2
    section.key #区域下的键
    value #对应的值

    --local 项目级

    --global 当前用户级

    --system 系统级 

    例如我们要在student区域下添加一个名称为height值为198的配置项:

    2)、删除配置项 

    git config [--local|--global|--system] --unset section.key

     将系统级的height配置项移除

    2.3.5、更多配置项

    git config --global color.ui true   #打开所有的默认终端着色
    git config --global alias.ci commit   #别名 ci 是commit的别名
    [alias]  
    co = checkout  
    ci = commit  
    st = status  
    pl = pull  
    ps = push  
    dt = difftool  
    l = log --stat  
    cp = cherry-pick  
    ca = commit -a  
    b = branch 
    
    user.name  #用户名
    user.email  #邮箱
    core.editor  #文本编辑器  
    merge.tool  #差异分析工具  
    core.paper "less -N"  #配置显示方式  
    color.diff true  #diff颜色配置  
    alias.co checkout  #设置别名
    git config user.name  #获得用户名
    git config core.filemode false  #忽略修改权限的文件  

    所有config命令参数

    语法: git config [<options>]        
            
    文件位置        
        --global                  #use global config file 使用全局配置文件
        --system                  #use system config file 使用系统配置文件
        --local                   #use repository config file    使用存储库配置文件
        -f, --file <file>         #use given config file    使用给定的配置文件
        --blob <blob-id>          #read config from given blob object    从给定的对象中读取配置
            
    动作        
        --get                     #get value: name [value-regex]    获得值:[值]名[正则表达式]
        --get-all                 #get all values: key [value-regex]    获得所有值:[值]名[正则表达式]
        --get-regexp          #get values for regexp: name-regex [value-regex]    得到的值根据正则
        --get-urlmatch            #get value specific for the URL: section[.var] URL    为URL获取特定的值
        --replace-all             #replace all matching variables: name value [value_regex]    替换所有匹配的变量:名称值[ value_regex ]
        --add                     #add a new variable: name value    添加一个新变量:name值
        --unset                   #remove a variable: name [value-regex]    删除一个变量名[值]:正则表达式
        --unset-all               #remove all matches: name [value-regex]    删除所有匹配的正则表达式:名称[值]
        --rename-section          #rename section: old-name new-name    重命名部分:旧名称 新名称
        --remove-section          #remove a section: name    删除部分:名称
        -l, --list                #list all    列出所有
        -e, --edit            #open an editor    打开一个编辑器
        --get-color               #find the color configured: slot [default]    找到配置的颜色:插槽[默认]
        --get-colorbool           #find the color setting: slot [stdout-is-tty]    发现颜色设置:槽[ stdout是TTY ]
            
    类型        
        --bool                    #value is "true" or "false"    值是“真”或“假”。
        --int                     #value is decimal number    值是十进制数。
        --bool-or-int             #value is --bool or --int    值--布尔或int
        --path                    #value is a path (file or directory name)    值是路径(文件或目录名)
            
    其它        
        -z, --null                #terminate values with NUL byte    终止值与null字节
        --name-only               #show variable names only    只显示变量名
        --includes                #respect include directives on lookup    尊重包括查找指令
        --show-origin             #show origin of config (file, standard input, blob, command line)    显示配置(文件、标准输入、数据块、命令行)的来源

    三、Git理论基础

    3.1、工作区域

    Git本地有三个工作区域:工作目录(Working Directory)、暂存区(Stage/Index)、资源库(Repository或Git Directory)。如果在加上远程的git仓库(Remote Directory)就可以分为四个工作区域。文件在这四个区域之间的转换关系如下:

    • Workspace:工作区,就是你平时存放项目代码的地方
    • Index / Stage:暂存区,用于临时存放你的改动,事实上它只是一个文件,保存即将提交到文件列表信息
    • Repository:仓库区(或本地仓库),就是安全存放数据的位置,这里面有你提交到所有版本的数据。其中HEAD指向最新放入仓库的版本
    • Remote:远程仓库,托管代码的服务器,可以简单的认为是你项目组中的一台电脑用于远程数据交换

    本地的三个区域确切的说应该是git仓库中HEAD指向的版本

    • Directory:使用Git管理的一个目录,也就是一个仓库,包含我们的工作空间和Git的管理空间。
    • WorkSpace:需要通过Git进行版本控制的目录和文件,这些目录和文件组成了工作空间。
    • .git:存放Git管理信息的目录,初始化仓库的时候自动创建。
    • Index/Stage:暂存区,或者叫待提交更新区,在提交进入repo之前,我们可以把所有的更新放在暂存区。
    • Local Repo:本地仓库,一个存放在本地的版本库;HEAD会只是当前的开发分支(branch)。
    • Stash:隐藏,是一个工作状态保存栈,用于保存/恢复WorkSpace中的临时状态。

    3.2、工作流程

    git的工作流程一般是这样的:

    1、在工作目录中添加、修改文件;

    2、将需要进行版本管理的文件放入暂存区域;

    3、将暂存区域的文件提交到git仓库。

    因此,git管理的文件有三种状态:已修改(modified),已暂存(staged),已提交(committed)

    3.3、图解教程

    个人认为Git的原理相比别的版本控制器还是复杂一些的,有一份图解教程比较直观:

    图解教程英文原版

    图解教程中文版

    四、Git操作

    4.1、创建工作目录与常用指令

    工作目录(WorkSpace)一般就是你希望Git帮助你管理的文件夹,可以是你项目的目录,也可以是一个空目录,建议不要有中文。

    日常使用只要记住下图6个命令:

    4.2、获得GIT仓库

    创建本地仓库的方法有两种:一种是创建全新的仓库,另一种是克隆远程仓库。

    4.2.1、创建全新仓库

    需要用GIT管理的项目的根目录执行:

    # 在当前目录新建一个Git代码库
    $ git init

    执行:

    结果:

     

    执行后可以看到,仅仅在项目目录多出了一个.git目录,关于版本等的所有信息都在这个目录里面。

    当然如果使用如下命令,可以把创建目录与仓库一起完成:

    # 新建一个目录,将其初始化为Git代码库
    $ git init [project-name]

    4.2.2、克隆远程仓库

     另一种方式是克隆远程目录,由于是将远程服务器上的仓库完全镜像一份至本地,而不是取某一个特定版本,所以用clone而不是checkout,语法格式如下:

    # 克隆一个项目和它的整个代码历史(版本信息)
    $ git clone [url]

    4.3、GIT文件操作

    版本控制就是对文件的版本控制,要对文件进行修改、提交等操作,首先要知道文件当前在什么状态,不然可能会提交了现在还不想提交的文件,或者要提交的文件没提交上。GIT不关心文件两个版本之间的具体差别,而是关心文件的整体是否有改变,若文件被改变,在添加提交时就生成文件新版本的快照,而判断文件整体是否改变的方法就是用SHA-1算法计算文件的校验和。

    4.3.1、文件4种状态

    • Untracked: 未跟踪, 此文件在文件夹中, 但并没有加入到git库, 不参与版本控制. 通过git add 状态变为Staged.

    • Unmodify: 文件已经入库, 未修改, 即版本库中的文件快照内容与文件夹中完全一致. 这种类型的文件有两种去处, 如果它被修改, 而变为Modified. 如果使用git rm移出版本库, 则成为Untracked文件

    • Modified: 文件已修改, 仅仅是修改, 并没有进行其他的操作. 这个文件也有两个去处, 通过git add可进入暂存staged状态, 使用git checkout 则丢弃修改过, 返回到unmodify状态, 这个git checkout即从库中取出文件, 覆盖当前修改

    • Staged: 暂存状态. 执行git commit则将修改同步到库中, 这时库中的文件和本地文件又变为一致, 文件为Unmodify状态. 执行git reset HEAD filename取消暂存, 文件状态为Modified

    4.3.2、查看文件状态

    上面说文件有4种状态,通过如下命令可以查看到文件的状态:

    #查看指定文件状态
    git status [filename]
    
    #查看所有文件状态
    git status

    命令:

    结果:

    红色文件的状态为untracked(未跟踪),提示通过git add(文件名,.本文件夹所有的)可以暂存

    GIT在这一点做得很好,在输出每个文件状态的同时还说明了怎么操作,像上图就有怎么暂存、怎么跟踪文件、怎么取消暂存的说明。

    4.3.3、添加文件与目录

    工作区(Working Directory)就是你在电脑里能看到的目录。

    版本库(Repository)工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库。

    Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD

    将untracked状态的文件添加到暂存区,语法格式如下:

    # 添加指定文件到暂存区
    $ git add [file1] [file2] ...
    
    # 添加指定目录到暂存区,包括子目录
    $ git add [dir]
    
    # 添加当前目录的所有文件到暂存区
    $ git add .

    执行:

    4.3.4、移除文件与目录(撤销add)

    当执行如下命令时,会直接从暂存区删除文件,工作区则不做出改变

    #直接从暂存区删除文件,工作区则不做出改变
    git rm --cached <file>

    通过重写目录树移除add文件:

    #如果已经用add 命令把文件加入stage了,就先需要从stage中撤销
    git reset HEAD <file>...

    当执行 “git reset HEAD” 命令时,暂存区的目录树会被重写,被 master 分支指向的目录树所替换,但是工作区不受影响。

    移除所有未跟踪文件

    #移除所有未跟踪文件
    #一般会加上参数-df,-d表示包含目录,-f表示强制清除。
    git clean [options] 
    #只从stage中删除,保留物理文件
    git rm --cached readme.txt 
    
    #不但从stage中删除,同时删除物理文件
    git rm readme.txt 
    
    #把a.txt改名为b.txt
    git mv a.txt b.txt 

    当执行提交操作(git commit)时,暂存区的目录树写到版本库(对象库)中,master 分支会做相应的更新。即 master 指向的目录树就是提交时暂存区的目录树。

    当执行 “git reset HEAD” 命令时,暂存区的目录树会被重写,被 master 分支指向的目录树所替换,但是工作区不受影响。

    当执行 “git rm –cached <file>” 命令时,会直接从暂存区删除文件,工作区则不做出改变。

    当执行 “git checkout .” 或者 “git checkout — <file>” 命令时,会用暂存区全部或指定的文件替换工作区的文件。这个操作很危险,会清除工作区中未添加到暂存区的改动。

    当执行 “git checkout HEAD .” 或者 “git checkout HEAD <file>” 命令时,会用 HEAD 指向的 master 分支中的全部或者部分文件替换暂存区和以及工作区中的文件。这个命令也是极具危险性的,因为不但会清除工作区中未提交的改动,也会清除暂存区中未提交的改 动。

    4.3.5、查看文件修改后的差异

    git diff用于显示WorkSpace中的文件和暂存区文件的差异

    用"git status"只能查看对哪些文件做了改动,如果要看改动了什么,可以用:

    #查看文件修改后的差异
    git diff [files]

    ---a表示修改之前的文件,+++b表示修改后的文件

    #比较暂存区的文件与之前已经提交过的文件
    git diff --cached

    也可以把WorkSpace中的状态和repo中的状态进行diff,命令如下:

    #比较repo与工作空间中的文件差异
    git diff HEAD~n

    4.3.6、签出

    如果仓库中已经存在文件f4.txt,在工作区中对f4修改了,如果想撤销可以使用checkout,签出覆盖

    检出命令git checkout是git最常用的命令之一,同时也是一个很危险的命令,因为这条命令会重写工作区

    语法:

    #用法一
    git checkout [-q] [<commit>] [--] <paths>...
    #用法二
    git checkout [<branch>]
    #用法三
    git checkout [-m] [[-b]--orphan] <new_branch>] [<start_point>]

    <commit>是可选项,如果省略则相当于从暂存区(index)进行检出

    $ git checkout branch
    #检出branch分支。要完成图中的三个步骤,更新HEAD以指向branch分支,以及用branch  指向的树更新暂存区和工作区。
    
    $ git checkout
    #汇总显示工作区、暂存区与HEAD的差异。
    
    $ git checkout HEAD
    #同上
    
    $ git checkout -- filename
    #用暂存区中filename文件来覆盖工作区中的filename文件。相当于取消自上次执行git add filename以来(如果执行过)的本地修改。
    
    $ git checkout branch -- filename
    #维持HEAD的指向不变。用branch所指向的提交中filename替换暂存区和工作区中相   应的文件。注意会将暂存区和工作区中的filename文件直接覆盖。
    
    $ git checkout -- . 或写作 git checkout .
    #注意git checkout 命令后的参数为一个点(“.”)。这条命令最危险!会取消所有本地的  #修改(相对于暂存区)。相当于用暂存区的所有文件直接覆盖本地文件,不给用户任何确认的机会!
    
    $ git checkout commit_id -- file_name
    #如果不加commit_id,那么git checkout -- file_name 表示恢复文件到本地版本库中最新的状态。

    4.3.6、忽略文件

    有些时候我们不想把某些文件纳入版本控制中,比如数据库文件,临时文件,设计文件等

    在主目录下建立".gitignore"文件,此文件有如下规则:

    1. 忽略文件中的空行或以井号(#)开始的行将会被忽略。
    2. 可以使用Linux通配符。例如:星号(*)代表任意多个字符,问号(?)代表一个字符,方括号([abc])代表可选字符范围,大括号({string1,string2,...})代表可选的字符串等。
    3. 如果名称的最前面有一个感叹号(!),表示例外规则,将不被忽略。
    4. 如果名称的最前面是一个路径分隔符(/),表示要忽略的文件在此目录下,而子目录中的文件不忽略。
    5. 如果名称的最后面是一个路径分隔符(/),表示要忽略的是此目录下该名称的子目录,而非文件(默认文件或目录都忽略)。

    如:

    #为注释
    *.txt #忽略所有 .txt结尾的文件
    !lib.txt #但lib.txt除外
    /temp #仅忽略项目根目录下的TODO文件,不包括其它目录temp
    build/ #忽略build/目录下的所有文件
    doc/*.txt #会忽略 doc/notes.txt 但不包括 doc/server/arch.txt

    更多规则请点这里

    4.3.7、提交

    通过add只是将文件或目录添加到了index暂存区,使用commit可以实现将暂存区的文件提交到本地仓库。

    # 提交暂存区到仓库区
    $ git commit -m [message]
    
    # 提交暂存区的指定文件到仓库区
    $ git commit [file1] [file2] ... -m [message]
    
    # 提交工作区自上次commit之后的变化,直接到仓库区,跳过了add,对新文件无效
    $ git commit -a
    
    # 提交时显示所有diff信息
    $ git commit -v
    
    # 使用一次新的commit,替代上一次提交
    # 如果代码没有任何新变化,则用来改写上一次commit的提交信息
    $ git commit --amend -m [message]
    
    # 重做上一次commit,并包括指定文件的新变化
    $ git commit --amend [file1] [file2] ...

    修订提交

    如果我们提交过后发现有个文件改错了,或者只是想修改提交说明,这时可以对相应文件做出修改,将修改过的文件通过"git add"添加到暂存区,然后执行以下命令:

    #修订提交
    git commit --amend

    撤销提交(commit)

    原理就是放弃工作区和index的改动,同时HEAD指针指向前一个commit对象

    #撤销上一次的提交
    git reset --hard HEAD~1

     要通过git log查看提交日志,也可直接指定提交编号或序号

    撤销提交
    git revert <commit-id>
    这条命令会把指定的提交的所有修改回滚,并同时生成一个新的提交。

    4.3.8、日志与历史

    查看提交日志可以使用git log指令,语法格式如下:

    #查看提交日志
    git log [<options>] [<revision range>] [[--] <path>…​]

    几乎所有输入过的都被记录下来的,不愧是做版本控制的。

    查看所有分支日志

    "git reflog"中会记录这个仓库中所有的分支的所有更新记录,包括已经撤销的更新。

    4.3.9、查看文件列表

    使用git ls-files指令可以查看指定状态的文件列表,格式如下:

    #查看指定状态的文件
    git ls-files [-z] [-t] [-v] (--[cached|deleted|others|ignored|stage|unmerged|killed|modified])* (-[c|d|o|i|s|u|k|m])*

    4.3.10、撤销更新

    1)、撤销暂存区更新

    使用"git add"把更新提交到了暂存区。这时"git status"的输出中提示我们可以通过"git reset HEAD <file>..."把暂存区的更新移出到WorkSpace中

    2)、撤销本地仓库更新

    使用git log查看提交日志

    撤销提交有两种方式:使用HEAD指针使用commit id

    在Git中,有一个HEAD指针指向当前分支中最新的提交。当前版本,我们使用"HEAD^",那么再钱一个版本可以使用"HEAD^^",如果想回退到更早的提交,可以使用"HEAD~n"。(也就是,HEAD^=HEAD~1,HEAD^^=HEAD~2)

    git reset --hard HEAD^
    git reset --hard HEAD~1
    git reset --59cf9334cf957535cb328f22a1579b84db0911e5

    回退后

    现在又想恢复被撤销的提交可用"git reflog"查看仓库中所有的分支的所有更新记录,包括已经撤销的更新,撤销方法与前面一样。

    git reset --hard HEAD@{7}
    git reset --hard e0e79d7

    --hard:撤销并删除相应的更新

    --soft:撤销相应的更新,把这些更新的内容放到Stage中

    4.3.11、删除文件

    1)、删除未跟踪文件

    如果文件还是未跟踪状态,直接删除文件就可了,bash中使用rm可以删除文件

    2)、删除已提交文件

     -f 强制删除,物理删除了,同时删除工作区和暂存区中的文件

    撤销删除:

    #to discard changes in working directory
    git checkout -- <file>...

    3)、删除暂存区的文件,不删除工作区的文件

    使用git reset HEAD <file>...同样可以实现上面的功能

    4.3.12、文件操作小结

     Git很强大,很灵活,这是毋庸置疑的。但也正因为它的强大造成了它的复杂,因此会有很多奇奇怪怪的问题出现,多用就好了。

    4.4、GIT分支

    分支在GIT中相对较难

    分支就是科幻电影里面的平行宇宙,当你正在电脑前努力学习Git的时候,另一个你正在另一个平行宇宙里努力学习SVN。

    如果两个平行宇宙互不干扰,那对现在的你也没啥影响。不过,在某个时间点,两个平行宇宙合并了,结果,你既学会了Git又学会了SVN!

    learn-branches

    分支在实际中有什么用呢?假设你准备开发一个新功能,但是需要两周才能完成,第一周你写了50%的代码,如果立刻提交,由于代码还没写完,不完整的代码库会导致别人不能干活了。如果等代码全部写完再一次提交,又存在丢失每天进度的巨大风险。

    现在有了分支,就不用怕了。你创建了一个属于你自己的分支,别人看不到,还继续在原来的分支上正常工作,而你在自己的分支上干活,想提交就提交,直到开发完毕后,再一次性合并到原来的分支上,这样,既安全,又不影响别人工作。

    Git分支的速度非常快。

    截止到目前,只有一条时间线,在Git里,这个分支叫主分支,即master分支。HEAD严格来说不是指向提交,而是指向master,master才是指向提交的,所以,HEAD指向的就是当前分支。

    特性分支的图示

    git分支中常用指令:

    # 列出所有本地分支
    $ git branch
    
    # 列出所有远程分支
    $ git branch -r
    
    # 列出所有本地分支和远程分支
    $ git branch -a
    
    # 新建一个分支,但依然停留在当前分支
    $ git branch [branch-name]
    
    # 新建一个分支,并切换到该分支
    $ git checkout -b [branch]
    
    # 新建一个分支,指向指定commit
    $ git branch [branch] [commit]
    
    # 新建一个分支,与指定的远程分支建立追踪关系
    $ git branch --track [branch] [remote-branch]
    
    # 切换到指定分支,并更新工作区
    $ git checkout [branch-name]
    
    # 切换到上一个分支
    $ git checkout -
    
    # 建立追踪关系,在现有分支与指定的远程分支之间
    $ git branch --set-upstream [branch] [remote-branch]
    
    # 合并指定分支到当前分支
    $ git merge [branch]
    
    # 选择一个commit,合并进当前分支
    $ git cherry-pick [commit]
    
    # 删除分支
    $ git branch -d [branch-name]
    
    # 删除远程分支
    $ git push origin --delete [branch-name]
    $ git branch -dr [remote/branch]

    4.4.1、新建分支与切换分支

    默认分支是这样的,master是主分支

    git-br-initial

    1)、新建一个分支,但依然停留在当前分支,使用:$ git branch [branch-name]

    切换分支到dev1后的结果:

    当我们创建新的分支,例如dev时,Git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上:

    git-br-create

    你看,Git创建一个分支很快,因为除了增加一个dev指针,改改HEAD的指向,工作区的文件都没有任何变化!

    不过,从现在开始,对工作区的修改和提交就是针对dev分支了,比如新提交一次后,dev指针往前移动一步,而master指针不变:

    git-br-dev-fd

    假如我们在dev上的工作完成了,就可以把dev合并到master上。Git怎么合并呢?最简单的方法,就是直接把master指向dev的当前提交,就完成了合并:

    git-br-ff-merge

    所以Git合并分支也很快!就改改指针,工作区内容也不变!

    合并完分支后,甚至可以删除dev分支。删除dev分支就是把dev指针给删掉,删掉后,我们就剩下了一条master分支:

    git-br-rm

    2)、切换分支,git branch <name>,如果name为-则为上一个分支

    3)、新建一个分支,并切换到该分支,$ git checkout -b [branch]

    4)、新建一个分支,指向指定commit使用命令:$ git branch [branch] [commit]

    master上本来有两个提交记录的,此时的dev3指向的是第1次提交的位置

     5)、新建一个分支,与指定的远程分支建立追踪关系使用命令:$ git branch --track [branch] [remote-branch]

    4.4.2、查看分支

    1)、列出所有本地分支使用$ git branch

    2)、列表所有远程分支使用$ git branch -r

    3)、列出所有本地分支和远程分支使用$ git branch -a

    4.4.3、分支合并

    合并指定分支到当前分支使用指令$ git merge [branch]

    4.4.4、解决冲突

    如果同一个文件在合并分支时都被修改了则会引起冲突,

    Git用<<<<<<<,=======,>>>>>>>标记出不同分支的内容,其中<<<HEAD是指主分支修改的内容,

    解决的办法是我们可以修改冲突文件后重新提交,请注意当前的状态产master | MERGING:

    手动解决完冲突后就可以把此文件添 加到索引(index)中去,用git commit命令来提交,就像平时修改了一个文件 一样。

    git log --graph命令可以看到分支合并图。

    分支策略

    master主分支应该非常稳定,用来发布新版本,一般情况下不允许在上面工作,工作一般情况下在新建的dev分支上工作,工作完后,比如上要发布,或者说dev分支代码稳定后可以合并到主分支master上来。

    4.4.5、删除分支

    删除本地分支可以使用命令:$ git branch -d [branch-name],-D(大写)强制删除

    删除远程分支可以使用如下指令:

    $ git push origin --delete [branch-name]
    $ git branch -dr [remote/branch]

    -d表示删除分支。分支必须完全合并在其上游分支,或者在HEAD上没有设置上游

    -r表示远程的意思remotes,如果-dr则表示删除远程分支

    五、远程仓库

    Git是分布式版本控制系统,同一个Git仓库,可以分布到不同的机器上,但开发参与者必须在同一个网络中,且必须有一个项目的原始版本,通常的办法是让一台电脑充当服务器的角色,每天24小时开机,其他每个人都从这个“服务器”仓库克隆一份到自己的电脑上,并且各自把各自的提交推送到服务器仓库里,也从服务器仓库中拉取别人的提交。完全可以自己搭建一台运行Git的服务器但现在更适合的做法是使用免费的托管平台。

    同时相较于传统的代码都是管理到本机或者内网。 一旦本机或者内网机器出问题,代码可能会丢失,使用远端代码仓库将永远存在一个备份。同时也免去了搭建本地代码版本控制服务的繁琐。 云计算时代 Git 以其强大的分支和克隆功能,更加方便了开发者远程协作。

    5.1、托管平台

    Git代码托管平台,首先推荐的是GitHub,好多好的开源项目都来自GitHub,但是GitHub只能新建公开的Git仓库,私有仓库要收费,有时候访问比较卡,如果你做的是一个开源项目,可以首选GitHub。下面推荐几个比较好的Git代码托管平台:

    5.1.1、GitHub

    关于GItHub相信大家都有耳闻,我就不详细介绍了。GitHub地址: https://github.com/,其首页如图:

    5.1.2、Gitlab

    对于有些人,提到GitHub就会自然的想到Gitlab,Gitlab支持无限的公有项目和私有项目。Gitlab地址: https://about.gitlab.com/,其首页截图如图:

    5.1.3、Bitbucket

    bitbucket免费支持5个开发成员的团队创建无限私有代码托管库。bitbucket地址:

    5.1.4、开源中国代码托管

    开源中国一个账号最多可以创建1000个项目,包含公有和私有,开源中国代码托管地址: http://git.oschina.net/,其首页如图:

    5.1.5、(推荐)coding.net

    谈到coding.net,首先必须提的是速度快,功能与开源中国相似,同样一个账号最多可以创建1000个项目(5个私有),也支持任务的创建等。coding.net地址: https://coding.net/

    我个人比较推荐Coding.net、GItHub。

    当然还有许多,如CSDN,百度,阿里等,欢迎大家比较后推荐。

    选择国外的主机请考虑网速,选择国内的主机请考虑稳定与安全性。

    5.2、远程仓库操作

    申请到了Git远程仓库的帐号并创建了一个空的远程仓库现在我们就可以结合本地的仓库与远程仓库一起协同工作了,模拟多人协同开发,这里我们全部使用命令完成。

    5.2.1、常用操作指令

    # 下载远程仓库的所有变动
    $ git fetch [remote]
    
    # 显示所有远程仓库
    $ git remote -v
    
    # 显示某个远程仓库的信息
    $ git remote show [remote]
    
    # 增加一个新的远程仓库,并命名
    $ git remote add [shortname] [url]
    
    # 取回远程仓库的变化,并与本地分支合并
    $ git pull [remote] [branch]
    
    # 上传本地指定分支到远程仓库
    $ git push [remote] [branch]
    
    # 强行推送当前分支到远程仓库,即使有冲突
    $ git push [remote] --force
    
    # 推送所有分支到远程仓库
    $ git push [remote] --all
    
    #简单查看远程---所有仓库
    git remote  (只能查看远程仓库的名字)
    #查看单个仓库 git remote show [remote-branch-name] #新建远程仓库 git remote add [branchname] [url] #修改远程仓库 git remote rename [oldname] [newname] #删除远程仓库 git remote rm [remote-name] #获取远程仓库数据 git fetch [remote-name] (获取仓库所有更新,但不自动合并当前分支) git pull (获取仓库所有更新,并自动合并到当前分支) #上传数据,如git push origin master git push [remote-name] [branch]

    5.2.2、git clone 克隆

    远程操作的第一步,通常是从远程主机克隆一个版本库,这时就要用到git clone命令。

    $ git clone <版本库的网址>

    比如,克隆一个上课示例的版本库。

    $ git clone https://github.com/zhangguo5/AngularJS04_BookStore.git

    该命令会在本地主机生成一个目录,与远程主机的版本库同名。如果要指定不同的目录名,可以将目录名作为git clone命令的第二个参数。

    $ git clone <版本库的网址> <本地目录名>

    git clone支持多种协议,除了HTTP(s)以外,还支持SSH、Git、本地文件协议等,下面是一些例子。

    $ git clone http[s]://example.com/path/to/repo.git/
    $ git clone ssh://example.com/path/to/repo.git/
    $ git clone git://example.com/path/to/repo.git/
    $ git clone /opt/git/project.git 
    $ git clone file:///opt/git/project.git
    $ git clone ftp[s]://example.com/path/to/repo.git/
    $ git clone rsync://example.com/path/to/repo.git/

    SSH协议还有另一种写法。

    $ git clone [user@]example.com:path/to/repo.git/

    通常来说,Git协议下载速度最快,SSH协议用于需要用户认证的场合。各种协议优劣的详细讨论请参考 官方文档

    5.2.3、git remote

    为了便于管理,Git要求每个远程主机都必须指定一个主机名。git remote命令就用于管理主机名。

    不带选项的时候,git remote命令列出所有远程主机。

    $ git remote

    使用-v选项,可以参看远程主机的网址。

    $ git remote -v

    上面命令表示,当前只有一台远程主机,叫做origin,以及它的网址。

    克隆版本库的时候,所使用的远程主机自动被Git命名为origin。如果想用其他的主机名,需要用git clone命令的-o选项指定。

    $ git clone -o WeUI https://github.com/Tencent/weui.git
    $ git remote

    git remote show命令加上主机名,可以查看该主机的详细信息。

    $ git remote show <主机名>

    git remote add命令用于添加远程主机。

    $ git remote add <主机名> <网址>

    git remote rm命令用于删除远程主机。

    $ git remote rm <主机名>

    git remote rename命令用于远程主机的改名。

    $ git remote rename <原主机名> <新主机名>

    5.2.4、git fetch

    一旦远程主机的版本库有了更新(Git术语叫做commit),需要将这些更新取回本地,这时就要用到git fetch命令。

    $ git fetch <远程主机名>

    上面命令将某个远程主机的更新,全部取回本地。

    git fetch命令通常用来查看其他人的进程,因为它取回的代码对你本地的开发代码没有影响。

    默认情况下,git fetch取回所有分支(branch)的更新。如果只想取回特定分支的更新,可以指定分支名。

    $ git fetch <远程主机名> <分支名>

    比如,取回origin主机的master分支。

    $ git fetch origin master

    所取回的更新,在本地主机上要用"远程主机名/分支名"的形式读取。比如origin主机的master,就要用origin/master读取。

    git branch命令的-r选项,可以用来查看远程分支,-a选项查看所有分支。

    $ git branch -r
    origin/master
    
    $ git branch -a
    * master
      remotes/origin/master

    上面命令表示,本地主机的当前分支是master,远程分支是origin/master

    取回远程主机的更新以后,可以在它的基础上,使用git checkout命令创建一个新的分支。

    $ git checkout -b newBrach origin/master

    上面命令表示,在origin/master的基础上,创建一个新分支。

    此外,也可以使用git merge命令或者git rebase命令,在本地分支上合并远程分支。

    $ git merge origin/master
    # 或者
    $ git rebase origin/master

    上面命令表示在当前分支上,合并origin/master

    5.2.5、git pull

    git pull命令的作用是,取回远程主机某个分支的更新,再与本地的指定分支合并。它的完整格式稍稍有点复杂。

    $ git pull <远程主机名> <远程分支名>:<本地分支名>

    比如,取回origin主机的next分支,与本地的master分支合并,需要写成下面这样。

    $ git pull origin next:master

    如果远程分支是与当前分支合并,则冒号后面的部分可以省略。

    $ git pull origin next

    上面命令表示,取回origin/next分支,再与当前分支合并。实质上,这等同于先做git fetch,再做git merge

    $ git fetch origin
    $ git merge origin/next

    在某些场合,Git会自动在本地分支与远程分支之间,建立一种追踪关系(tracking)。比如,在git clone的时候,所有本地分支默认与远程主机的同名分支,建立追踪关系,也就是说,本地的master分支自动"追踪"origin/master分支。

    Git也允许手动建立追踪关系。

    git branch --set-upstream master origin/next

    上面命令指定master分支追踪origin/next分支。

    如果当前分支与远程分支存在追踪关系,git pull就可以省略远程分支名。

    $ git pull origin

    上面命令表示,本地的当前分支自动与对应的origin主机"追踪分支"(remote-tracking branch)进行合并。

    如果当前分支只有一个追踪分支,连远程主机名都可以省略。

    $ git pull

    上面命令表示,当前分支自动与唯一一个追踪分支进行合并。

    如果合并需要采用rebase模式,可以使用--rebase选项。

    $ git pull --rebase <远程主机名> <远程分支名>:<本地分支名>

    如果远程主机删除了某个分支,默认情况下,git pull 不会在拉取远程分支的时候,删除对应的本地分支。这是为了防止,由于其他人操作了远程主机,导致git pull不知不觉删除了本地分支。

    但是,你可以改变这个行为,加上参数 -p 就会在本地删除远程已经删除的分支。

    $ git pull -p
    # 等同于下面的命令
    $ git fetch --prune origin 
    $ git fetch -p

    5.2.6、git push

    git push命令用于将本地分支的更新,推送到远程主机。它的格式与git pull命令相仿。

    $ git push <远程主机名> <本地分支名>:<远程分支名>

    注意,分支推送顺序的写法是<来源地>:<目的地>,所以git pull是<远程分支>:<本地分支>,而git push是<本地分支>:<远程分支>。

    如果省略远程分支名,则表示将本地分支推送与之存在"追踪关系"的远程分支(通常两者同名),如果该远程分支不存在,则会被新建。

    $ git push origin master

    上面命令表示,将本地的master分支推送到origin主机的master分支。如果后者不存在,则会被新建。

    如果省略本地分支名,则表示删除指定的远程分支,因为这等同于推送一个空的本地分支到远程分支。

    $ git push origin :master
    # 等同于
    $ git push origin --delete master

    上面命令表示删除origin主机的master分支。

    如果当前分支与远程分支之间存在追踪关系,则本地分支和远程分支都可以省略。

    $ git push origin

    上面命令表示,将当前分支推送到origin主机的对应分支。

    如果是新建分支第一次push,会提示:
      fatal: The current branch dev1 has no upstream branch.
      To push the current branch and set the remote as upstream, use
      git push --set-upstream origin dev1
      输入这行命令,然后输入用户名和密码,就push成功了。

      以后的push就只需要输入git push origin

    原因是:

    #因为在git的全局配置中,有一个push.default属性,其决定了git push操作的默认行为。在Git 2.0之前,这个属性的默认被设为'matching',2.0之后则被更改为了'simple'。
    
    #我们可以通过git version确定当前的git版本(如果小于2.0,更新是个更好的选择),通过git config --global push.default 'option'改变push.default的默认行为(或者也可直接编辑~/.gitconfig文件)。
    
    push.default 有以下几个可选值:
    nothing, current, upstream, simple, matching
    
    其用途分别为:
    nothing - push操作无效,除非显式指定远程分支,例如git push origin develop(我觉得。。。可以给那些不愿学git的同事配上此项)。
    current - push当前分支到远程同名分支,如果远程同名分支不存在则自动创建同名分支。
    upstream - push当前分支到它的upstream分支上(这一项其实用于经常从本地分支push/pull到同一远程仓库的情景,这种模式叫做central workflow)。
    simple - simple和upstream是相似的,只有一点不同,simple必须保证本地分支和它的远程
    upstream分支同名,否则会拒绝push操作。
    matching - push所有本地和远程两端都存在的同名分支。
    因此如果我们使用了git2.0之前的版本,push.default = matching,git push后则会推送当前分支代码到远程分支,而2.0之后,push.default = simple,如果没有指定当前分支的upstream分支,就会收到上文的fatal提示。

    如果当前分支只有一个追踪分支,那么主机名都可以省略。

    $ git push

    如果当前分支与多个主机存在追踪关系,则可以使用-u选项指定一个默认主机,这样后面就可以不加任何参数使用git push

    $ git push -u origin master

    上面命令将本地的master分支推送到origin主机,同时指定origin为默认主机,后面就可以不加任何参数使用git push了。

    不带任何参数的git push,默认只推送当前分支,这叫做simple方式。此外,还有一种matching方式,会推送所有有对应的远程分支的本地分支。Git 2.0版本之前,默认采用matching方法,现在改为默认采用simple方式。如果要修改这个设置,可以采用git config命令。

    $ git config --global push.default matching
    # 或者
    $ git config --global push.default simple

    还有一种情况,就是不管是否存在对应的远程分支,将本地的所有分支都推送到远程主机,这时需要使用--all选项。

    $ git push --all origin

    上面命令表示,将所有本地分支都推送到origin主机。

    如果远程主机的版本比本地版本更新,推送时Git会报错,要求先在本地做git pull合并差异,然后再推送到远程主机。这时,如果你一定要推送,可以使用--force选项。

    $ git push --force origin 

    上面命令使用--force选项,结果导致远程主机上更新的版本被覆盖。除非你很确定要这样做,否则应该尽量避免使用--force选项。

    最后,git push不会推送标签(tag),除非使用--tags选项。

    $ git push origin --tags

    六、资源与资料下载

    资料链接: https://pan.baidu.com/s/1c20DVOW  密码: p9ri

    Git教程下载_王亮(大神)

  • 相关阅读:
    repo sync中遇到:contains uncommitted changes
    <kernel>/scripts/checkpatch.pl脚本可用来检查代码书写不规范和作一些简单的代码静态检查
    各国股市开盘与收盘时间
    分页数据绑定例子模板
    提升网络销售转化率的10种方法
    网络业务员
    股票入门:如何看盘
    带样式的页码代码
    看着一年一度的高考,虽然高考已经离我远去
    ajax处理函数模板代码
  • 原文地址:https://www.cnblogs.com/ManyQian/p/9481415.html
Copyright © 2020-2023  润新知