• git


    git

    git是一个分布式版本控制系统。分布式是相对于集中式来说的,对于集中式版本控制(如SVN),所有的代码都放在集中的服务器上,大家都从这个服务器下载代码,然后在本地开发,然后再上传。而分布式版本控制没有中央服务器,每个人的本地电脑都是一个完整的版本库,可以在本地创建分支,在本地提交代码,还可以提交到远程分支;

    git创建

    git的仓库就是一个文件夹目录(又叫repository),里面的所有文件都被git进行管理;

    所以首先创建一个空目录

    $ mkdir myrep    //linux创建文件夹命令
    $ cd myrep    

    然后使用 git init 把这个普通目录变成git仓库

    $ git init

    目录下会生成一个 .git 文件夹,里面是管理git仓库相关文件;

    可以不必在空文件夹下git init, 也可以直接在现有文件目录下git init;

    版本控制系统只追踪文本文件的改动,对于二进制文件则无法追踪其内容变化,只能知道大小变了;

    其它linux相关命令:

    $ ls -al    //查看当前目录下所有文件,包括隐藏文件
    $ cd mydir    //打开文件夹
    $ touch abc.txt    //创建文件
    $ echo "12345" >> abc.txt    //向abc.txt写入字符串
    $ cat abc.txt    //查看abc.txt的文本内容

     时光机穿梭

    git时光机

    git status 命令,用于随时掌握仓库的当前状态:

    $ git status
    On branch master    //显示当前在那个分支
    Changes not staged for commit:    //变动了的文件,但还没有add到staged区
      (use "git add <file>..." to update what will be committed)
      (use "git checkout -- <file>..." to discard changes in working directory)
    
        modified:   readme.txt      //具体是哪个文件被改变了
    
    no changes added to commit (use "git add" and/or "git commit -a")

    git status 一共有3种:   

    untracked files 从未被追踪过的文件,即从来没有被add过的文件;

    changes not staged for commit  文本发生了变动,但本次变动没有被add到staged区;

    changes to be commited  文本的变动已经add到了staged区,就等着被commit啦;

    git diff 命令,就是看difference

    $ git diff readme.txt     //diff命令,用于查看对比分析区别
    diff --git a/readme.txt b/readme.txt    //目前进行比较的是a版本的readme.txt和b版本的readme.txt
    index 46d49bf..9247db6 100644      //前两个数是两个版本的git的哈希值,最后一个数先不管
    --- a/readme.txt    //---表示变动前的文件
    +++ b/readme.txt    //+++表示变动后的文件
     //下面是合并格式的首部;首部用@@分隔,前两个数-1和2,-表示第一个文件,1表示从第一行开始,2表示一共2行; +1和2用同样的方法表示第二个文件
    @@ -1,2 +1,2 @@  
    //下面是合并格式的正文内容
    -Git is a version control system.    //-表示第一个文件,所以这是第一个文件的第1行  
    +Git is a distributed version control system.    //这是第二个文件的第2行
     Git is free software.    //这是两个文件共有的部分,所以是第一个文件和第二个文件的第2行

     版本回退

    每一次commit都会产生一个版本,所以版本回退就是回退到某次commit的结果

    使用 git reset --hard HEAD^ 可以会退到上一次的版本;  注:--hard参数暂时忽略

    //在git中,HEAD表示当前版本,HEAD^表示上一个版本,同理HEAD^^表示上上个版本
    //HEAD实质上是一个指针,改变指针的指向就会切换到不同的版本
    $ git reset --hard HEAD^ HEAD is now at e475afc add distributed

    使用   git reset --hard 某版本号     回退到指定版本号的版本

    $ git reset --hard 1094a    //1094a为某个版本号的前几位,版本号没有必要写全,只要系统能识别就行
    HEAD is now at 83b0afe append GPL

    使用git log来查看历史提交的commit

    $ git log
    commit 1094adb7b9b3807259d8cb349e7df1d4d6477073 (HEAD -> master)
    Author: Michael Liao <askxuefeng@gmail.com>
    Date:   Fri May 18 21:06:15 2018 +0800
    
        append GPL
    
    commit e475afc93c209a690c39c13a46716e8fa000c366
    Author: Michael Liao <askxuefeng@gmail.com>
    Date:   Fri May 18 21:03:36 2018 +0800
    
        add distributed
    
    commit eaadf4e385e865d25c48e7ca9c8395c3f7dfaef0
    Author: Michael Liao <askxuefeng@gmail.com>
    Date:   Fri May 18 20:59:18 2018 +0800
    
        wrote a readme file

    当回退到旧版本后,又想前进到新版本(回到未来),这时是无法找到新版本的commit id的,这时就需要使用 git reflog 来找出以前的命令:

    $ git reflog
    e475afc HEAD@{1}: reset: moving to HEAD^
    1094adb (HEAD -> master) HEAD@{2}: commit: append GPL
    e475afc HEAD@{3}: commit: add distributed
    eaadf4e HEAD@{4}: commit (initial): wrote a readme file

     工作区和暂存区

     工作区:就是电脑里面能看到的仓库的目录,即最早初始化git,使用git init 的地方。

     版本库:是工作区文件目录里的隐藏的 .git 目录,这就是git的版本库;工作区和版本库的关系如下:

    你平时写的所有代码只有一份,存储在工作区中,平时写代码也是对工作区的代码文件进行编辑;

    而使用 git add 命令就会把代码的变动情况存储到stage区,也叫索引区、暂存区(注意是把代码的变化情况存入stage,而非把整个工作区代码存入stage);

    使用 git commit 命令就可将stage区的缓存一次性提交到当前HEAD所指向的分支;

     git管理的是修改而非整个文件

    举例来说,如果有操作序列: 第一次修改 -> git add -> 第二次修改 -> git commit;则会发现第二次的修改没有被提交,执行 commit 后git会提示 changes not staged for commit,这就是说第二次的修改没有被commit,即说明git管理的是文件的变动,而非整个文件(可以把修改当成一个对象实体,git管理的就是这样的对象)

    改为 第一次修改 -> git add -> 第二次修改 -> git add -> git commit,则顺利将第二次的修改也提交了。

    撤销修改

    要和版本回退相区分;

    场景一:修改了某文件,但还没有add到暂存区,想撤销修改时,用命令 git checkout -- fileName;

                  注:git checkout -- fileName 命令,当做了修改但没有add时,使用该命令后撤回到修改前的原始状态;当add过后又做了修改时,使用该命令撤回到刚add后的状态;

    场景二:修改了文件,并add到了暂存区,想要撤销修改,分两步走

                   先使用 git reset HEAD fileName, 可以将暂存区的修改撤销掉,使之变成 changes not staged for commit 状态

                   然后再用场景一中的 git checkout -- fileName 进行撤销修改

    场景三:实在不行就版本回退吧;

     删除文件

    //先正常删除文件
    $ re test.txt
    //这时若使用 git status 查看状态,会发现处于 changes not staged for commit状态
    
    //如果确实需要删除文件,则用git rm 从版本库删除文件,并commit
    $ git rm test.txt
    $ git commit -m "remove test.txt"
    
    //如果是误删,想恢复,则参照上一节的撤销修改操作,使用 git checkout -- fileName
    $ git checkout -- test.txt                        

     远程仓库

    用github做远程服务器

    第一步:创建ssh key。 在用户主目录下(C盘user目录)查看是否有id_rsa和id_rsa.pub文件,如果没有则需要生成。用bash或shell创建ssh密钥:

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

    然后一路默认直到完成。之后会在主目录里发现 .ssh目录, 里面有上述两个文件,其中 id_rsa.pub 是公钥,id_rsa是私钥。(原理是数字签名)

    第二步,登录github,在ssh的key设置中添加公钥。

    之后就可以使用ssh协议将本地的git和远程的GitHub关联了

    添加远程仓库

    第一步:在github上新建一个repository,随便起名比如myrepo

    第二步:在本地仓库运行 git remote add,将本地仓库与远程仓库相关联

    //添加后远程库的名字就是origin,也可以起别的名字
    $ git remote add origin git@github.com:yourGitHubID/myrepo.git
    
    //将本地内容推送到远程库, origin是远程库的名字,master是当前本地分支
    //实质是将本地库的当前分支推送到远程
    $git push -u origin master

    由于在push前远程库是空的,所以第一次push时,加上-u参数,git不仅会将本地的master分支内容推送到远程的此时新建的master分支,还会把本地master分支和远程master分支关联起来。

    以后push就只需要使用 git push origin master 推送新的修改了

    远程库克隆至本地

    // git@github...等一串字符是远程仓库地址
    $ git clone git@github.com:yourGitHubID/yourRepo.git

     分支管理

    创建与合并分支,及其原理

    开始的时候,master分支是一条线,git用mater指向最新的提交,再用HEAD指向master,就能确定当前分支和分支的提交点。

     

    每次提交,master都会向前移动一步,因此HEAD即当前分支始终指向最新。

    当创建新的分支,如dev时,git上新建一个指针叫dev,指向与master相同的提交,再将HEAD指向dev,表示当前在dev分支

    现在开始,修改和提交都是针对dev分支了,如果再在dev分支提交一次,会出现master指针不变,而dev指针向前移动了一步

    如果在dev上的开发工作完成了,需要把dev的工作合并到master分支,git会直接把master指针指向dev当前的指向,完成合并

    合并完成后,可以删除dev分支了

    相关指令:

    $ git branch     //查看分支
    $ git branch Name    //创建分支
    $ git checkout Name    //切换分支
    $ git checkout -b Name    //创建+切换分支
    $ git merge Name    //合并Name分支到当前分支,【注意一定是合并到当前分支,而非合并到Name分支】
    $ git branch -d Name    //删除分支

     解决冲突

    当两个不同分支修改了同一个文件时,再试图合并这两个分支时,就会出现冲突;如下master和feature1分支都修改了readme.txt,并且都进行了提交,若试图合并则会导致冲突

    $ git merge feature1    //尝试合并, git提示冲突,冲突文件为readme.txt
    Auto-merging readme.txt
    CONFLICT (content): Merge conflict in readme.txt
    Automatic merge failed; fix conflicts and then commit the result

    这时需要解决冲突,可以打开 readme.txt, 发现git已经将冲突部分标识出来了

    // <<<<<< 标记冲突开始,后面跟的是当前分支的代码
    //  ====== 用于分隔
    //  >>>>>> 与等号之间的部分是需要合并过来的分支的冲突代码
    
    Git is a distributed version control system.
    Git is free software distributed under the GPL.
    Git has a mutable index called stage.
    Git tracks changes of files.
    <<<<<<< HEAD
    Creating a new branch is quick & simple.
    =======
    Creating a new branch is quick AND simple.
    >>>>>>> feature1

    这时只需要手动修改冲突部分,可以将当前分支(master)的代码改成带合并过来的代码,然后在当前分支commit;然后再进行合并;

    上图就是将master分支的代码进行了修改,与feature保持一致,然后将feature合并到master

     分支管理策略

    团队开发时的分支策略如上图

    master分支:应该是非常稳定的,仅仅用来发布新版本

    dev:dev分支非常不稳定,用来在上面开发

    每个人各自的分支:用于c克隆dev的代码,并在上面开发

    另【个人理解】:master分支和dev分支应该是在本地和远程都有

    Bug分支

    场景如下:

    master上上线的1.0版本;

    你在自己的zqw分支上开发2.0版本,但只开发到一半;此时用户反映1.0版本有Bug,你需要紧急修复1.0中的Bug

    你想直接切换到master分支,再在master分支的基础上创建Bug分支修复Bug,修复完再切回zqw分支继续开发2.0,但这样会留下一个不怎么好的没有意义的commit记录,还很麻烦;这么做可以但没必要;

    或者你一想,干脆别commit了,直接切回master分支,再在master分支下创建Bug分支,再做修复等等操作....   【这样不可行】,理由是未经add 和 commit 的内容不属于任何一个分支,也就是对所有分支而言,工作区和stage区是公共的,你没commit就切换分支,之前工作区的一些编辑操作仍会保留

    此时就需要用stash功能了,它可以把2.0的开发工作不经过add 和 commit 就保存下来;然后你就可以放心切换到master分支修复Bug,然后完成后再切换回2.0的zqw分支继续开发;

    步骤如下

    $git stash
    
    然后切到master分支,创建bug分支改bug,合并会master分支
    
    $git checkout dev    //切回开发分支
    $git stash pop    //恢复现场

     多人协作

    常用指令

    $ git remote -v    //查看远程库信息
    
    //本地新建的分支,如果不推送到远程,则对他人不可见;
    //若是本地新建分支推送到远程,则会在远程新建同名的分支,但不会自动生成本地分支到远程对应分支的关联
    
    $ git push origin branch-name    //从本地将branch-name分支推送到远程origin
    
    $ git pull  <远程主机名> <远程分支名>:<本地分支名>    //从远程分支取回代码,并和本地分支做合并; <>内容都可省略,省略后则默认为当前本地分支,和其对应关联的远程分支
    
    //git pull 等价于 git fetch + git merge,实际最好使用fetch+merge
    $git fetch origin master:temp    //从远程master分支获取代码,并在本地建立temp分支
    $git merge temp    //将temp分支合并到当前分支
    
    $ git checkout -b branch-name origin/branch-name;    //在本地创建新分支,该分支和远程某分支对应
    
    $ git branch --set-upstream-to branch-name origin/branch-name;    //建立本地分支和远程分支的关联
    
    $git branch -vv    //查看本地分支与远程分支的关联情况

    多人协作的模式:

    首先用 git push origin your_branch 推送自己的修改;

    如果推送失败,则说明远程分支比你的当前本地分支更新,你需要先将远程分支pull到本地做合并

    如果合并有冲突,则手动修改解决冲突,并在本地提交;

    然后再push到远程

  • 相关阅读:
    calc, support, media各自的含义及用法?
    vuex有哪几种属性
    vue-router实现路由懒加载( 动态加载路由 )
    vue生命周期的理解
    vue初始化页面闪动问题
    .params和query的区别
    实现布局数据渲染以列为单位
    一. async函数
    一. includes
    十五. 对象的扩展
  • 原文地址:https://www.cnblogs.com/zhuqiwei-blog/p/10724950.html
Copyright © 2020-2023  润新知