• Git学习笔记


    链接:http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000

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

      Linus一直痛恨的CVS及SVN都是集中式的版本控制系统,这些集中式的版本控制系统不但速度慢,而且必须联网才能使用(弊端)。(BitKeeper的东家BitMover公司出于人道主义精神,授权Linux社区免费使用这个版本控制系统。开发Samba的Andrew试图破解BitKeeper的协议,被BitMover公司发现了,于是BitMover公司怒了,要收回Linux社区的免费使用权。Linus花了两周时间自己用C写了一个分布式版本控制系统,这就是Git!)而Git是分布式版本控制系统,集中式和分布式版本控制系统有什么区别呢?

    集中式vs分布式

      集中式版本控制系统,版本库是集中存放在中央服务器的,而干活的时候,用的都是自己的电脑,所以要先从中央服务器取得最新的版本,然后开始干活,干完活了,再把自己的活推送给中央服务器。

      分布式版本控制系统根本没有“中央服务器”,每个人的电脑上都是一个完整的版本库,这样,你工作的时候,就不需要联网了,因为版本库就在你自己的电脑上。例如对于文件A而言,修改文件A的双方只需把各自的修改推送给对方,就可以互相看到对方的修改了。

      分布式版本控制系统的安全性要高很多,因为每个人电脑里都有完整的版本库,而集中式版本控制系统的中央服务器要是出了问题,所有人都没法干活了。

    Linux安装Git

      Debian或Ubuntu Linux:sudo apt-get install git。

      其他版本,从Git官网下载源码进行安装:解压,一次输入:./config->make->sudo make install。

    完成设置:

    $ git config --global user.name "Your Name"
    $ git config --global user.email "email@example.com"

    注:git config命令的--global参数,用了这个参数,表示你这台机器上所有的Git仓库都会使用这个配置,当然也可以对某个仓库指定不同的用户名和Email地址。

    创建版本库

    首先,选择一个合适的地方,创建一个空目录:

    $ mkdir learngit
    $ cd learngit
    $ pwd
    /data02/JFDEV/niewl/learngit

    我的仓库位置:/data02/JFDEV/niewl/learngit。

    第二步,通过git init命令把这个目录变成Git可以管理的仓库:

    $ git init
    Initialized empty Git repository in /data02/JFDEV/niewl/learngit

    一个空仓库(empty Git repository)就建好了,可以发现多了一个.git目录。这个目录是Git来跟踪管理版本库的,没事千万不要手动修改这个目录里面的文件,不然改乱了,就把Git仓库给破坏了。

    我们编写一个readme.txt文件:

    Git is a version control system.
    Git is free software.

      一定要放到learngit目录下(子目录也行),因为这是一个Git仓库,放到其他地方Git再厉害也找不到这个文件。

    第一步,用命令git add告诉Git,把文件添加到仓库:

    $ git add readme.txt

    第二步,用命令git commit告诉Git,把文件提交到仓库:

    $ git commit -m "wrote a readme file"
    [master (root-commit) cb926e7] wrote a readme file
     1 file changed, 2 insertions(+)
     create mode 100644 readme.txt

    vim readme.txt:

    Git is a distributed version control system.
    Git is free software.

    现在,运行git status命令看看结果:

    $ git status
    # On branch master
    # Changes not staged for commit:
    #   (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命令可以让我们时刻掌握仓库当前的状态,上面的命令告诉我们,readme.txt被修改过了,但还没有准备提交的修改。

    $ git diff readme.txt 
    diff --git a/readme.txt b/readme.txt
    index 46d49bf..9247db6 100644
    --- a/readme.txt
    +++ b/readme.txt
    @@ -1,2 +1,2 @@
    -Git is a version control system.
    +Git is a distributed version control system.
     Git is free software.

    如果git status告诉你有文件被修改过,用git diff可以查看修改内容。

    $ git add readme.txt
    

    在执行第二步git commit之前,我们再运行git status看看当前仓库的状态:

    $ git status
    # On branch master
    # Changes to be committed:
    #   (use "git reset HEAD <file>..." to unstage)
    #
    #       modified:   readme.txt
    #

    git status告诉我们,将要被提交的修改包括readme.txt。

    $ git commit -m "add distributed"
    [master ea34578] add distributed
     1 file changed, 1 insertion(+), 1 deletion(-)

    提交后,我们再用git status命令看看仓库的当前状态:

    $ git status
    # On branch master
    nothing to commit (working directory clean)

    Git告诉我们当前没有需要提交的修改,而且,工作目录是干净(working directory clean)的。

    版本回退

    修改readme.txt文件如下:

    Git is a distributed version control system.
    Git is free software distributed under the GPL.

    然后尝试提交:

    $ git add readme.txt
    $ git commit -m "append GPL"
    [master 3628164] append GPL
     1 file changed, 1 insertion(+), 1 deletion(-)

    在Git中,我们用git log命令查看历史记录:

    $ git log
    commit 3628164fb26d48395383f8f31179f24e0882e1e0
    Author: Michael Liao <askxuefeng@gmail.com>
    Date:   Tue Aug 20 15:11:49 2013 +0800
    
        append GPL
    
    commit ea34578d5496d7dd233c827ed32a8cd576c5ee85
    Author: Michael Liao <askxuefeng@gmail.com>
    Date:   Tue Aug 20 14:53:12 2013 +0800
    
        add distributed
    
    commit cb926e7ea50ad11b8f9e909c05226233bf755030
    Author: Michael Liao <askxuefeng@gmail.com>
    Date:   Mon Aug 19 17:51:55 2013 +0800
    
        wrote a readme file

    git log命令显示从最近到最远的提交日志,可以试试加上--pretty=oneline参数:

    $ git log --pretty=oneline
    3628164fb26d48395383f8f31179f24e0882e1e0 append GPL
    ea34578d5496d7dd233c827ed32a8cd576c5ee85 add distributed
    cb926e7ea50ad11b8f9e909c05226233bf755030 wrote a readme file

    看到的一大串类似3628164...882e1e0的是commit id(版本号),用一个SHA1计算出来的一个非常大的数字,用十六进制表示,为了避免重复带来的冲突。

      版本回退,首先,Git必须知道当前版本是哪个版本,在Git中,用HEAD表示当前版本,也就是最新的提交3628164...882e1e0(注意我的提交ID和你的肯定不一样),上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100

    要把当前版本“append GPL”回退到上一个版本“add distributed”,就可以使用git reset命令:

    $ git reset --hard HEAD^
    HEAD is now at ea34578 add distributed

    Git的版本回退速度非常快,因为Git在内部有个指向当前版本的HEAD指针,当你回退版本的时候,Git仅仅是把HEAD从指向append GPL

    改为指向add distributed

    然后顺便把工作区的文件更新了。所以你让HEAD指向哪个版本号,你就把当前版本定位在哪。

    Git提供了一个命令git reflog用来记录你的每一次命令:

    $ git reflog
    ea34578 HEAD@{0}: reset: moving to HEAD^
    3628164 HEAD@{1}: commit: append GPL
    ea34578 HEAD@{2}: commit: add distributed
    cb926e7 HEAD@{3}: commit (initial): wrote a readme file

    小结:

    • HEAD指向的版本就是当前版本,因此,Git允许我们在版本的历史之间穿梭,使用命令git reset --hard commit_id

    • 穿梭前,用git log可以查看提交历史,以便确定要回退到哪个版本。

    • 要重返未来,用git reflog查看命令历史,以便确定要回到未来的哪个版本。

    工作区和暂存区

    工作区(Working Directory)

    就是你在电脑里能看到的目录,比如我的learngit文件夹就是一个工作区。

    版本库(Repository)

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

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

    把文件往Git版本库里添加的时候,是分两步执行的:

    第一步是用git add把文件添加进去,实际上就是把文件修改添加到暂存区;

    第二步是用git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支。

    因为我们创建Git版本库时,Git自动为我们创建了唯一一个master分支,所以,现在git commit就是往master分支上提交更改。

    git add之后,git status查看一下:

    所以,git add命令实际上就是把要提交的所有修改放到暂存区(Stage),然后,执行git commit就可以一次性把暂存区的所有修改提交到分支。

    git commit之后:

    管理修改

    Git跟踪并管理的是修改,而非文件。

    第一次修改 -> git add -> 第二次修改 -> git commit。

    Git管理的是修改,当你用git add命令后,在工作区的第一次修改被放入暂存区,准备提交,但是,在工作区的第二次修改并没有放入暂存区,所以,git commit只负责把暂存区的修改提交了,也就是第一次的修改被提交了,第二次的修改不会被提交。

      每次修改,如果不add到暂存区,那就不会加入到commit中。

    撤销修改

    (1)只在工作区进行了修改。

    git checkout -- file可以丢弃工作区的修改:

    $ git checkout -- readme.txt

    (2)修改并git add到了暂存区。

    用命令git reset HEAD file可以把暂存区的修改撤销掉(unstage),重新放回工作区:

    $ git reset HEAD readme.txt
    Unstaged changes after reset:
    M       readme.txt

    git reset命令既可以回退版本,也可以把暂存区的修改回退到工作区。当我们用HEAD时,表示最新的版本。(再使用git checkout -- readme.txt丢弃工作区的修改)

    (3)假设不但改错了东西,还从暂存区提交到了版本库,可以使用“版本回退”到上一个版本。如果提交推送到远程版本库,那就没法修改了。

    删除文件

    一般情况下,你通常直接在文件管理器中把没用的文件删了,或者用rm命令删了:

    $ rm test.txt

    Git知道你删除了文件,因此,工作区和版本库就不一致了,git status命令会立刻告诉你哪些文件被删除了:

    $ git status
    # On branch master
    # Changes not staged for commit:
    #   (use "git add/rm <file>..." to update what will be committed)
    #   (use "git checkout -- <file>..." to discard changes in working directory)
    #
    #       deleted:    test.txt
    #
    no changes added to commit (use "git add" and/or "git commit -a")

    (1)“文件删除”。如果确实要从版本库中删除该文件,用命令git rm删掉,并且git commit。

    $ git rm test.txt
    rm 'test.txt'
    $ git commit -m "remove test.txt"
    [master d17efd8] remove test.txt
     1 file changed, 1 deletion(-)
     delete mode 100644 test.txt

    现在,文件就从版本库中被删除了。

    (2)“文件恢复”。如果是删错了,因为版本库里还有呢,所以可以很轻松地把误删的文件恢复到最新版本:

    $ git checkout -- test.txt

    git checkout其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。

      命令git rm用于删除一个文件。如果一个文件已经被提交到版本库,那么你永远不用担心误删,但是要小心,你只能恢复文件到最新版本,你会丢失最近一次提交后你修改的内容

    远程仓库

      首先注册GitHub账号。由于你的本地Git仓库和GitHub仓库之间的传输是通过SSH加密的,所以,需要一点设置:

    第1步:创建SSH Key。在用户主目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsaid_rsa.pub这两个文件,如果已经有了,可直接跳到下一步。如果没有,打开Shell,创建SSH Key:

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

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

    然后,点“Add SSH Key”,填上任意Title,在Key文本框里粘贴id_rsa.pub文件的内容:

    点“Add Key”,你就应该看到已经添加的Key:

    添加远程库

    首先,登陆GitHub,然后,在右上角找到“Create a new repo”按钮,创建一个新的仓库:

    在Repository name填入learngit,其他保持默认设置,点击“Create repository”按钮,就成功地创建了一个新的Git仓库:

    目前,在GitHub上的这个learngit仓库还是空的,在本地的learngit仓库下运行命令,把本地仓库的内容推送到GitHub仓库:

    $ git remote add origin git@github.com:michaelliao/learngit.git

    添加后,远程库的名字就是origin,这是Git默认的叫法,也可以改成别的,但是origin这个名字一看就知道是远程库。

    下一步,就可以把本地库的所有内容推送到远程库上:

    $ git push -u origin master
    Counting objects: 19, done.
    Delta compression using up to 4 threads.
    Compressing objects: 100% (19/19), done.
    Writing objects: 100% (19/19), 13.73 KiB, done.
    Total 23 (delta 6), reused 0 (delta 0)
    To git@github.com:michaelliao/learngit.git
     * [new branch]      master -> master
    Branch master set up to track remote branch master from origin.

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

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

    从远程库克隆

    首先,登陆GitHub,创建一个新的仓库,名字叫gitskills

    我们勾选Initialize this repository with a README,这样GitHub会自动为我们创建一个README.md文件。创建完毕后,可以看到README.md文件:

    现在,远程库已经准备好了,下一步是用命令git clone克隆一个本地库:

    $ git clone git@github.com:michaelliao/gitskills.git
    Cloning into 'gitskills'...
    remote: Counting objects: 3, done.
    remote: Total 3 (delta 0), reused 0 (delta 0)
    Receiving objects: 100% (3/3), done.
    
    $ cd gitskills
    $ ls
    README.md

    Git支持多种协议,包括https,但通过ssh支持的原生git协议速度最快。

    分支管理

    创建与合并分支

    首先,创建dev分支,然后切换到dev分支:

    $ git checkout -b dev
    Switched to a new branch 'dev'

    git checkout命令加上-b参数表示创建并切换,相当于以下两条命令:

    $ git branch dev
    $ git checkout dev
    Switched to branch 'dev'

    然后,用git branch命令查看当前分支:

    $ git branch
    * dev
      master

    git branch命令会列出所有分支,当前分支前面会标一个*号。

    修改reademe.txt然后提交:

    $ git add readme.txt 
    $ git commit -m "branch test"
    [dev fec145a] branch test
     1 file changed, 1 insertion(+)

    现在,dev分支的工作完成,我们就可以切换回master分支:

    $ git checkout master
    Switched to branch 'master'

    现在,我们把dev分支的工作成果合并到master分支上:

    $ git merge dev
    Updating d17efd8..fec145a
    Fast-forward
     readme.txt |    1 +
     1 file changed, 1 insertion(+)

    git merge命令用于合并指定分支到当前分支。合并后,再查看readme.txt的内容,就可以看到,和dev分支的最新提交是完全一样的。

    注意到上面的Fast-forward信息,Git告诉我们,这次合并是“快进模式”,也就是直接把master指向dev的当前提交,所以合并速度非常快。

    合并完成后,就可以放心地删除dev分支了:

    $ git branch -d dev
    Deleted branch dev (was fec145a)

    删除后,查看branch,就只剩下master分支了:

    $ git branch
    * master

    小结

    Git鼓励大量使用分支:

    查看分支:git branch

    创建分支:git branch <name>

    切换分支:git checkout <name>

    创建+切换分支:git checkout -b <name>

    合并某分支到当前分支:git merge <name>

    删除分支:git branch -d <name>

    解决冲突

    当Git无法自动合并分支时,就必须首先解决冲突。解决冲突后,再提交,合并完成。

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

    $ git log --graph --pretty=oneline --abbrev-commit
    *   59bc1cb conflict fixed
    |
    | * 75a857c AND simple
    * | 400b400 & simple
    |/
    * fec145a branch test
    ...
  • 相关阅读:
    Laravel模型间关系设置分表方法详解
    11个PHP程序员最常犯的MySQL错误
    教你使用swoole监听redis数据
    使用 Docker 环境来开发 PHP,Laradock 系列 1
    tp5 workerman安装不上解决方法
    一种颗粒度很小的 Laravel 路由文件划分方式
    VT 调试环境搭建
    masm32基本配置与写出第一个汇编程序
    [debug] 解决pycharm中无法import自己建立的模块问题
    《Windows内核安全与驱动开发》 7.1&7.2&7.3 串口的过滤
  • 原文地址:https://www.cnblogs.com/define-ray/p/5607148.html
Copyright © 2020-2023  润新知