美文网首页
Git不权威总结

Git不权威总结

作者: liufxlucky365 | 来源:发表于2020-05-24 19:42 被阅读0次

    Git不权威总结

    欢迎阅读

    本文仅总结使用git最基本的概念,点到为止的原理,和最常用的操作,更深入的学习可以参考我附上的延伸资料

    基本知识

    历史背景

    git是一款版本管理工具。在还没有互联网的时代,单机上就已经出现了版本管理工具(如VCS),但开发者互相之间难以协同。后来有了集中式版本管理工具(如SVN),由一个集中的服务器来维护版本,其他人不断向其提交修改,这样做的不方便之处在于一旦在没有网络的环境,便无法提交代码;另外单节点的集中服务器一旦出故障,后果不堪设想;而且在开源运动发展和互联网更加普及的时代背景下,越来越多的项目需要遍布在全球各地的开发者的协同,很难维护一个稳定的超级服务器,所以分布式版本管理工具git便应运而生

    git的作者是大名鼎鼎linus,在设计之初linus就为git提出了几个目标

    • 操作速度快
    • 设计简单
    • 强力支持非线性的开发模型(即允许上千个并行开发的分支)
    • 完全分布式
    • 能够管理超大规模的项目(如Linux内核)
      就我实际使用经验来看,这些目标基本都实现了

    整体认识

    我的技术观中,从大的层面来看,在解决同一个难题的技术中,后来者会更易用。所以我们不要把git想的很难,还没学就打退堂鼓了。这也是我觉得首先需要对git有一个整体认识的必要性,你会发现git的总体设计是很简单容易理解的

    git是一个代码版本管理工具
    每个文件的每一次修改都会被记录下来
    在整体修改完成并提交后,会在git中形成一个项目的完整快照,并且永久保存在git库中
    一个个的修改按照先后顺序形成一条分支,每个快照都是一个节点
    你可以随时将整个项目或者某一个文件恢复到某一个节点的版本
    这样的分支你可以从任何一个节点发起上千条,并随时将他们合并
    你的协作者可以克隆你的git库,与你的一模一样,可以随时将他的某一个分支与你的一个分支合并

    git切片.png

    我理解git的核心功能和用法其实就这么多,其他的都无非是对各个细节的完善,如各种区的划分、checkout、reset、log、config等

    .git

    在项目根目录中执行git init便创建了一个git库,.git文件夹维护了git库的全部信息。这里介绍几个主要概念,方便对git如何维护版本的理解

    SHA-1校验和
    git为每一次提交、每一个文件对象树、每一个修改都维护了唯一的id,整个id是文件内容和头信息的SHA-1校验和,是一个40位的字符串,如5453545dccd33565a585ffe5f53fda3e067b84d8。既能唯一定位对象,也能校验对象内容是否发生改变

    文件对象blob,树对象tree,提交对象commit
    简单说每一次提交commit,都会生成一个commit对象,它指向一个tree对象,这个tree对象指向了项目中的所有blob对象和目录对象(也是个tree),注意文件是版本的,对应了每次提交,比如某一个文件在项目整个周期中从来没修改过,那么虽然每个快照他的版本都指向了最初的blob对象。整个结构是这个样子:

    git提交结构.png

    引用
    .git除了对象外,另一些重要文件是引用,包括常见的HEAD、tag等,这些文件中指向了具体的一个commit对象,类似助记符吧

    工作区划分

    为了有序的将文件修改提交入git库,git为项目划分了三个区域

    1. 工作区,所有新建、刚修改的文件都索引在这个区。你也可以检出(checkout)某个版本的文件到工作区
    2. 暂存区,你可以将工作区中的任何变动有选择的加入暂存区,可以理解为提交前的缓存区
    3. 版本库,暂存区中修改提交后便进入了版本库,被永久记录了下来
    git工作区.png

    branch

    分支是git的杀手锏,非常轻量级,用过svn的同学肯定会惊讶于git分支操作之快捷。分支之所以好用,因为我们实际研发中确实是真实存在多个“分支”的。首先线上当前运行的代码属于一个已经发布的“分支”,你本地开发的是研发“分支”,pm可能随时要求你给当前线上打补丁或者修bug,此时你需要基于线上版本而不是你的研发版本进行处理。假如没有branch模型,这些操作就会非常麻烦而且容易出错。git便鼓励你频繁的创建、合并分支来完成各种研发工作

    一个比较良好的实践是

    • 一个release分支,即当前线上运行的分支
    • 一个镜像分支,用于合并不同待上线需求,进行发布前校验
    • 一批dev分支,用于开发者对功能进行合并调试
    • 一批feature分支,用于开发者自己功能开发
    • 临时的hot fix分支,用于紧急修复bug、打补丁

    远程库

    分布式是git的主要特点,允许分布式协作。其他人可以克隆你的git库,你也可以把其他人的git库添加到的你远程源中

    • 每个库都是完整且独立的,包含了项目的所有信息,包括历史修改
    • 库之间是可以进行分支合并操作的,以此进行代码交换
    • 为了方便协作,目前比较流行的是在github中创建一个库,然后感兴趣者可以clone你的库,做一些修改再提交你进行审查合并

    实战操作

    前面总计了这么多知识,其实都有意回避了具体的操作,因为我认为只要道理搞明白了,这些操作都只是一个熟能生巧的过程。下面我按照常用程度对一些非常实用的操作进行总结

    工作区

    # add
    git add file/dir/* # 将新建文件,或者改动加入暂存区。-p参数可以精细操作具体修改而不是整个文件
    
    # commit
    git commit # 将暂存区中修改提交入git库
    git commit -m '备注'
    git commit -a # 同时将工作区中已索引文件的修改都提交入库,注意不包括新增文件(即Untracked files)
    git commit --amend # 本次提交与上一次提交合并,最终只形成一个ci
    
    # diff
    git diff # 比较工作区中file与git库的区别
    git diff --cached/staged file # 比较暂存区中file与git库的区别
    
    # rm
    git rm file # 物理删除 + 从git中移除
    git rm --cached file # 仅从git库中移除,即不再跟踪文件
    
    # stash
    git stash # 将工作区现场(已跟踪文件)储藏起来,等以后恢复后继续工作
    git stash list # 查看保存的工作现场
    git stash apply # 恢复工作现场
    git stash drop # 删除stash内容
    git stash pop # 恢复的同时直接删除stash内容
    git stash apply stash@{0} # 恢复指定的工作现场,当你保存了不只一份工作现场时
    

    分支

    # branch
    git branch new_branch
    git branch -m old new # 重命名分支
    git branch -d new_branch # 删除分支
    git branch -D test # 强制删除test分支
    git checkout -b new_branch # 创建分支并切过去
    git checkout -b test dev # 基于dev新建test分支,并切换
    git branch # 查看分支
    git branch -r # 列出远端分支
    git branch -a # 列出所有分支
    
    # merge
    git branch --merge # 查看已经合并到当前分支的分支
    git branch --no-merge # 查看未合并到当前分支的分支
    git merge test # 将test分支合并到当前分支
    git merge --squash test # 合并压缩,将test上的commit压缩为一条
    
    # 冲突
    # git中的没有类似svn中的conflic概念,本质是“自动合并失败,无法add”,所以需要用户编辑代码后,自行add
    
    # cherry-pick
    git cherry-pick commit-id # 将本地其他分支的一个提交应用到当前分支
    

    rebase
    变基,将一个分支的修改在目标分支上重放一遍(原来的分支需要手动清除),这样可以达到合并的效果,同时分支树是线性的,更加美观、易维护

    git rebase master # 将master上超前的提交,变基到当前分支
    git rebase master feature # 将master变基到指定分支
    

    不要使用变基……
    如果是公开且与其他人共享的分支,那么重写公开的共享分支 将会搞砸团队中的其他会员
    要是提交分支的精确历史重要(因为变基将重写提交历史)
    根据上述准则,我会针对短期生命的本地分支使用变基,而对公开仓库的分支使用合并

    配置管理

    # config
    git config --[global|system|local] alias.co checkout # 创建别名
    git config --[global|system|local] alias.br branch
    git config --[global|system|local] alias.ci commit
    git config --[global|system|local] alias.st status
    git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
    git config --global alias.gpush '!f() { : push ; r=$1; [[ -z $r ]] && r=origin; b=$2; t=$(awk "{ print \$2 }" $(git rev-parse --git-dir)/HEAD); t=${t#refs/heads/}; [[ -z $b ]] && b=$t; cmd="git push $r HEAD:refs/for/$b%topic=$t"; echo $cmd; echo; $cmd; }; f'
     # 高亮
    git config --global color.status auto
    git config --global color.branch auto
    git config color.ui true
     # 配置用户名 邮箱
    git config --global user.name 'liufuxin'
    git config --global user.email 'liufuxin@baidu.com'
     # 查看配置的信息
    git config --list
    
    # .gitignore
    # 可以配置git忽略哪些文件
    - \* 通配符
    - . 无特殊意义
    - ? 单个字符
    - [a-z] 
    - ! 反模式
    

    内容跟踪

    # blame
    git blame file # 查看文件的每一行的版本和修改人信息
    
    # log
    git show commit-id [file] # 查看某次提交修改的内容,加file单看某个文件
    git log -p FILE_NAME # 查看某个文件提交记录
    # 单行显示
    git log --pretty=oneline
    git log --pretty=oneline --max-count=2
    git log --pretty=oneline --since='5 minutes ago'
    git log --pretty=oneline --until='5 minutes ago'
    git log --pretty=oneline --author=<your name>
    git log --pretty=oneline --all
    # 树形结构,更加美观
    git log --all --pretty=format:'%h %cd %s (%an)' --since='7 days ago' --author=liufuxin
    git log --graph --decorate --oneline --simplify-by-decoration --all
    
    # reflog
    git reflog # 显示最近操作的commit id,可用于误舍弃分支
    

    数据恢复

    # checkout
    git checkout -- file # 使用暂存区或者git库替换工作目录中的文件
    git checkout HEAD file # 使用git库替换工作目录
    
    # revert
    git revert commit-id # 再生成一个撤销最近一次提交的提交
    
    # reset
    # reset可以让HEAD重新指向过去的某次ci,后续分支从此重新向前
    # 旧的分支就成了不可见分支从分支,而且会在下次垃圾回收时回收
    # reset丢失的分支将只能通过commit-id获取,结合reflog可以恢复
    git reset --soft commit-id # 将HEAD移动到指定的提交对象,同时将HEAD移动过程中的修改,都恢复到stage,work保持不变
    git reset --mixed commit-id # 将HEAD移动到指定的repo,同时将HEAD移动过程中的修改,都恢复到work
    git reset --hard commit-id # 将HEAD移动到指定的repo,同时将HEAD移动过程中的修改,都抛弃,work保持commit-id
    git reset commit-id [--] file # 特殊形式,只能使用mixed模式,目标是文件或目录
    

    远程仓库

    # fetch
    git remote add origin git@github.com:yanhaijing/test.git # 添加源
    git push -u origin master # push同时设置默认跟踪分支
    git pull # 与git fetch; git merge;等价
    git clone git://github.com/schacon/grit.git mypro # 克隆到自定义文件夹
    
    # 删除远程文件
    git rm --cached filename/-r directory
    git commit "xxxx"
    git push
    

    学习资料

    Githug通过游戏学Git
    Git核心概念
    15分钟成为Gti专家

    相关文章

      网友评论

          本文标题:Git不权威总结

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