深入理解git系列

作者: IOneStar | 来源:发表于2017-11-03 18:04 被阅读90次
    title
    文章参考: http://git.oschina.net/progit/

    1,git简介

    版本控制

    简而言之,就是可以报存你所有的修改,所有的历史版本;有了它,就可以将某个文件回溯到之前的状态,甚至可以将整个项目回退到过去某个时间点的状态;你可以比较文件的变化细节,查出最后是谁修改了哪个地方,从而找出导致怪异问题出现的原因,又是谁在何时报告了某个功能缺陷等等

    类别

    集中化的版本控制系统(eg: svn)

    image

    分布式版本控制系统(eg: git)

    image

    文件的三种状态

    对于任何一个文件,在 Git 内都只有三种状态:

    • 已提交(committed),已提交表示该文件已经被安全地保存在本地数据库中了;
    • 已修改(modified,已修改表示修改了某个文件,但还没有提交保存;
    • 已暂存(staged)。已暂存表示把已修改的文件放在下次提交时要保存的清单中。
      git管理项目时,文件流转的三个工作区域:git的工作目录,暂存区域,本地仓库


      image
    • 每个项目都有一个Git目录(如果 git clone 出来的话,就是其中 .git 的目录)
    • 从项目中取出某个版本的所有文件和目录,用以开始后续工作的叫做工作目录
    • 所谓的暂存区域只不过是个简单的文件,一般都放在 Git 目录中


      image

    2,git基础

    取得项目的Git仓库

    有两种方法:1,在现存的目录下,通过导入所有文件来创建新的Git仓库;2,从已有的Git仓库克隆出一个新的镜像仓库

    • 在工作目录中初始化新仓库
    git init // 初始化后,在当前目录下会出现一个名为 .git 的目录,所有 Git 需要的数据和资源都存放在这个目录中
    git add README // 如果当前目录下有几个文件想要纳入版本控制,需要先用`git add`命令告诉git开始对这些文件进行跟踪,并进行提交
    git commit -m 'initial project version'
    
    • 从现有仓库克隆
      克隆仓库的命令格式为 git clone [url]。比如,要克隆 Ruby 语言的 Git 代码仓库 Grit,可以用下面的命令:
    git clone git://github.com/schacon/grit.git
    

    当前目录下创建一个名为grit的目录,其中包含一个.git的目录用于保存下载下来的所有版本记录,然后从中取出最新版本的文件拷贝
    如果希望在git clone的时候,自己定义要新建的项目目录的名称,可以再上面的命令的末尾指定新的名字

    git clone git://github.com/schacon/grit.git mygrit
    

    现在新建的目录就成了mygrit

    文件状态

    git status 可以查看文件目前处于什么状态
    git add xx 这是一个多功能命,根据目标文件的状态不同,此命令的效果也不同;可以用它开始跟踪新文件,或者把已跟踪的文件放到暂存区,还能用于合并时把有冲突的文件标记为已解决状态

    忽略某些文件

    我们可以创建一个.gitignore的文件,列出要忽略的文件模式
    .gitignore的格式规范如下:

    • 所有空行或者以注释符号#开头的行都会被Git忽略
    • 可以使用标准的glob模式匹配(shell所使用的简化了的正则表达式)
    • 匹配模式最后跟反斜杠(/)说明要忽略的是目录
    • 要忽略指定模式以外的文件或目录,可以再模式前加上(!)取反
    # 此为注释 – 将被 Git 忽略
        # 忽略所有 .a 结尾的文件
        *.a
        # 但 lib.a 除外
        !lib.a
        # 仅仅忽略项目根目录下的 TODO 文件,不包括 subdir/TODO
        /TODO
        # 忽略 build/ 目录下的所有文件
        build/
        # 会忽略 doc/notes.txt 但不包括 doc/server/arch.txt
        doc/*.txt
    

    查看已暂存和未暂存的更新

    git diff
    git diff --cached
    

    提交更新

    git commit
    git commit -m'docs: change readme' // -m参数后跟提交的方式
    

    git commit 规范参考

    跳过使用暂存区域 git commit -a -m'feat: add new tasks'

    git 提供了一个跳过使用暂存区域的方式,只要在提交的时候给git commit加上-a选项,git就会自动把所有已经跟踪过的文件暂存起来一并提交,从而跳过 git add步骤

    git commit -a -m'feat: add new tasks'
    

    移除文件 git rm

    从git中移除某个文件,必须要从已跟踪文件清单移除(从暂存区域移除),然后提交,git rm命令完成此项工作,并连带从工作目录中删除制定的文件,这样以后就不会出现在未跟踪文件清单了

    git rm .test
    

    如果是简单从工作目录中手工删除文件,仅删除了工作目录中的,仍在追踪名单中
    然后再运行 git rm记录此次移除文件的操作
    最后提交就不会被跟踪了。但是如果删除文件之前修改过且已经放到暂存区,则必须要加-f(即force的首字母)
    在实际项目中,经常会遇到下面的情况需要删除文件
    想把文件从git仓库中删除,但是仍希望保留在工作目录中,就是仅从跟踪清单中删除,比如一些大型日志或一堆.a的编译文件,不小心纳入仓库,但是要移除追踪但不删除文件,以便稍后在.gitignore文件中补上,加参数--cached

     git rm --cached readme.txt
    
    

    后面可以列出文件或者目录的名字,也可以使用 glob 模式。
    注意到星号 * 之前的反斜杠 \,因为 Git 有它自己的文件模式扩展匹配方式,

    git rm log/\*.log    // 此命令删除所有 log/ 目录下扩展名为 .log 的文件
    git rm \*~           //会递归删除当前目录及其子目录中所有 ~ 结尾的文件。必须加反斜杠
    
    

    移动文件git mv

    git mv file_from file_to
    

    相当于运行

    mv README.txt README
    git rm README.txt
    git add README
    

    查看提交历史 git log

    git log -p -2 // -p选项展开每次提交的内容差异, -2则仅显示最近两次更新, 做代码审查,或者快速浏览其他写作者提交的更新都做了哪些
    git log --stat // 仅显示简要的增改行数
    git log --pretty // 指定使用完全不同于默认风格的方式展示提交历史,比如`git log --pretty=oneline`将每个提示放在一行显示,另外还有short, full和fuller
    

    format,可以定制要显示的记录格式,这样的输出便于后期编程提取分析

    git log --pretty=format:"%h - %an, %ar : %s"
    ca82a6d - Scott Chacon, 11 months ago : changed the version number
    085bb3b - Scott Chacon, 11 months ago : removed unnecessary test code
    a11bef0 - Scott Chacon, 11 months ago : first commit
    

    用 oneline 或 format 时结合 --graph 选项,可以看到开头多出一些 ASCII 字符串表示的简单图形,形象地展示了每个提交所在的分支及其分化衍合情况

    $ git log --pretty=format:"%h %s" --graph
        * 2d3acf9 ignore errors from SIGCHLD on trap
        * 5e3ee11 Merge branch 'master' of git://github.com/dustin/grit
        |\
        | * 420eac9 Added a method for getting the current branch.
        * | 30e367c timeout code and tests
        * | 5a09431 add timeout protection to grit
        * | e1193f8 support for heads with slashes in them
        |/
        * d6016bc require time for xmlschema
        * 11d191e Merge branch 'defunkt' into local
    

    列出了常用的格式占位符写法及其代表的意义。

    选项 说明
        %H 提交对象(commit)的完整哈希字串
        %h 提交对象的简短哈希字串
        %T 树对象(tree)的完整哈希字串
        %t 树对象的简短哈希字串
        %P 父对象(parent)的完整哈希字串
        %p 父对象的简短哈希字串
        %an 作者(author)的名字
        %ae 作者的电子邮件地址
        %ad 作者修订日期(可以用 -date= 选项定制格式)
        %ar 作者修订日期,按多久以前的方式显示
        %cn 提交者(committer)的名字
        %ce 提交者的电子邮件地址
        %cd 提交日期
        %cr 提交日期,按多久以前的方式显示
        %s 提交说明
    

    一些其他常用的选项及其释义。

    选项 说明
        -p 按补丁格式显示每个更新之间的差异。
        --stat 显示每次更新的文件修改统计信息。
        --shortstat 只显示 --stat 中最后的行数修改添加移除统计。
        --name-only 仅在提交信息后显示已修改的文件清单。
        --name-status 显示新增、修改、删除的文件清单。
        --abbrev-commit 仅显示 SHA-1 的前几个字符,而非所有的 40 个字符。
        --relative-date 使用较短的相对时间显示(比如,“2 weeks ago”)。
        --graph 显示 ASCII 图形表示的分支合并历史。
        --pretty 使用其他格式显示历史提交信息。可用的选项包括 oneline,short,full,fuller 和 format(后跟指定格式)。
    

    限制输入长度 --since 和 --unti

    git log --since=2.weeks // 列出所有最近两周内的提交
    选项 说明
        -(n) 仅显示最近的 n 条提交
        --since, --after 仅显示指定时间之后的提交。
        --until, --before 仅显示指定时间之前的提交。
        --author 仅显示指定作者相关的提交。
        --committer 仅显示指定提交者相关的提交。
    

    如果要查看 Git 仓库中,2017 年 10 月期间,Junio Hamano 提交的但未合并的测试脚本(位于项目的 t/ 目录下的文件),可以用下面的查询命令

    git log --pretty="%h - %s" --author=gitster --since="2008-10-01" \
    

    撤销操作

    修改最后一次提交 git commit --amend

     git commit -m 'initial commit'
     git add forgotten_file
     git commit --amend
    

    如果刚才提交时忘了暂存某些修改,可以先补上暂存操作,然后再运行 --amend 提交:上面的三条命令最终只是产生一个提交,第二个提交命令修正了第一个的提交内容。

    取消已经暂存的文件 git reset HEAD <file>...

    有两个修改过的文件,我们想要分开提交,但不小心用 git add . 全加到了暂存区域。该如何撤消暂存其中的一个文件呢

    git reset HEAD benchmarks.rb
    

    取消对文件的修改 git checkout -- <file>..

    如果觉得刚才对 benchmarks.rb 的修改完全没有必要,该如何取消修改,回到之前的状态(也就是修改之前的版本)呢

    git checkout -- benchmarks.rb
    

    任何已经提交到 Git 的都可以被恢复。即便在已经删除的分支中的提交,或者用 --amend 重新改写的提交,都可以被恢复(关于数据恢复的内容见第九章)。所以,你可能失去的数据,仅限于没有提交过的

    远程仓库的使用

    • 查看当前的远程库 git remove -v,名为 origin 的远程库,Git 默认使用这个名字来标识你所克隆的原始仓库
    • 添加远程仓库git remote add [shortname] [url]
    • 从远程仓库抓取数据git fetch [remote-name]
    • 推送数据到远程仓库 git push [remote-name] [branch-name]
    • 查看某个远程仓库信息git remote show [remote-name]
    • 远程仓库的删除和重命名 git remote rename pb paul git remote rename rm [remote-name]
    git remove -v
    git remote add pb git://github.com/paulboone/ticgit.git
    git fetch pb // 
    git push origin master  //把本地的 master 分支推送到 origin 服务器上
    git remote show origin // 要看所克隆的 origin 仓库
    
    $ git remote rename pb paul
        $ git remote
        origin
        paul
    
    git remote rm paul
        $ git remote
        origin
    

    git fetch 命令只是将远端的数据拉到本地仓库,并不自动合并到当前工作分支,git pull 命令自动抓取数据下来,然后将远端分支自动合并到本地仓库中当前分支

    打标签

    • 列显已有的标签 git tag
    • 新建标签,含附注的标签

    3,分支

    简单的分支与合并,实际工作中大体的工作流程
    1,开发某个网站
    2,为了实现某个需求,创建一个分支
    3,在这个分支上开展工作;
    假设此时,突然有个紧急的问题要修复,那么你可以按照下面的方式处理:
    1,返回原先已经发布到生产服务器上的分支;
    2,为这次紧急修补创建一个新分支,并在其中修复问题
    3,通过测试后,回到生产服务器所在的分支,将修补分支合并进来,然后再推送到生产服务器上
    4,切换到之前实现新需求的分支,继续工作

    新建分支

    • 新建分支 git branch xx,这条命令是新建了一个分支,但是当前工作分支仍在mater分支上,要想把当前工作分支切换到新建的分支上,要执行git checkout xx

    新建并切换到某分支git checkout -b xx相当与下面这两条命令

    git branch xx
    git checkout xx
    

    切换分支的时候要确保你当前分支不存在没有提交的修改,否则git会阻止你切换分支

    删除分支

    • 删除分支 git branch -d xx

    合并分支

    • 分支的合并,比如master分支要合并xx分支,首先切换到master分支,然后执行git merge xx,此时xx分支已经合并到master分支上,接下来删除xx分支
    git checkout master
    git merge xx
    git branch -d xx
    
    • 遇到冲突时的合并,如果在不同的分支中都修改看同一个文件,git就无法将两者合并到一起
    <<<<<<< HEAD:index.html
        <div id="footer">contact : email.support@github.com</div>
        =======
        <div id="footer">
        please contact us at support@github.com
        </div>
        >>>>>>> iss53:index.html
    

    =======隔开的上半部分,即HEAD(即master分支,在运行merge命令时所切换到的分支),下半部分是xx分支的内容
    你可以二者选其一或者整合两者到一起,然后删除<<<<<<<=======>>>>>>>这些行.解决完所有冲突后,运行git add将他们标记为已解决状态(实际就是将该文件存到暂存区,因为一旦暂存,就表示冲突已经解决)

    分支的管理

    git branch // 列出当前所有分支,注意看master分支前的 * 字符:它表示当前所在的分支
    git branch -v // 查看各个分支最后一个提交对象的信息
    git branch --merged // 筛选与当前分支合并的分支
    git branch --no-merged // 筛选与当前分支尚未合并的分支,此时如果使用`git branch -d xx`删除该分支会提示错误,因为这样会丢失数据,如果你确实想删除该分支上的改动,运行`git branch -D xx`强制删除
    

    利用分支开发的工作流程

    长期分支

    在master分支中保留完全稳定的代码,即已经发布或即将发布的代码,与此同时,还有一个名为develop或next的平行分支,专门用于后续的开发
    或仅用于稳定性测试 — 当然并不是说一定要绝对稳定,不过一旦进入某种稳定状态,便可以把它合并到 master 里。这样,在确保这些已完成的特性分支(短期分支,比如之前的 iss53 分支)能够通过所有测试,并且不会引入更多错误之后,就可以并到主干分支中,等待下一次的发布。
    你可以用这招维护不同层次的稳定性。某些大项目还会有个 proposed(建议)或 pu(proposed updates,建议更新)分支,它包含着那些可能还没有成熟到进入 next 或 master 的内容。这么做的目的是拥有不同层次的稳定性:当这些分支进入到更稳定的水平时,再把它们合并到更高层分支中去。

    特性分支

    一个特性分支是指一个短期的,用来实现单一特性或与其相关工作的分支。

    远程分支

    远程分支是对远程仓库中分支的索引。
    (远程仓库)/(分支名)表示远程分支

    推送远程分支

    git push (远程仓库名) (分支名)

     git push origin serverfix
     Git 自动把 serverfix 分支名扩展为 refs/heads/serverfix:refs/heads/serverfix,意为“取出我在本地的 serverfix 分支,推送到远程仓库的 serverfix 分支中去”。
    仓库中去,仍旧称它为 server
    git push origin serverfix:serverfix
    上传我本地的 serverfix 分支到远程仓库中去,仍旧称它为 serverfix 分支
    
    git push origin serverfix:awesomebranch
    上传我本地的 serverfix 分支到远程仓库中去,称它为 awesomebranch 分支
    

    如果要把该远程分支的内容合并到当前分支,可以运行 git merge origin/serverfix

    想要基于远程分支上新建一个新的分支 git checkout -b serverfix origin/serverfix

    跟踪远程分支

    从远程分支checkout出来的本地分支,成为跟踪分支。跟踪分支是一种和某个远程分支有直接联系的公司;
    克隆仓库时,git通常会自动创建一个名为master分支来跟踪origin/master;这正是 git push 和 git pull 一开始就能正常工作的原因

    git checkout -b serverfix origin/serverfix 可以用 --track 简化:

    git checkout --track origin/serverfix

    本地分支设定不同于远程分支的名字,只需在第一个版本的命令里换个名字:
    git checkout -b sf origin/serverfix

    删除远程分支

    git push [远程名] :[分支名]

    git push [远程名] [本地分支]:[远程分支],如果省略 [本地分支],如果省略 [本地分支]

    分支的衍合

    把一个分支整合到另一个分支的办法有两种: merge rebase
    使用衍合的目的是想要得到一个能在远程分支上干净应用的补丁,简单的说就是修改提交历史
    一旦分支中的提交对象发布到公共仓库,就千万不要对该分支进行衍合操作。

    git rebase --onto master server client
    取出 client 分支,找出 client 分支和 server 分支的共同祖先之后的变化,然后把它们在 master 上重演一遍”
    
    git rebase [主分支] [特性分支] 命令会先取出特性分支 server,然后在主分支 master 上重演:
    git rebase master server
    

    [图片上传失败...(image-e7ad90-1509703481294)]

    github
    blog

    相关文章

      网友评论

      本文标题:深入理解git系列

      本文链接:https://www.haomeiwen.com/subject/yzztmxtx.html