Git不权威总结

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专家

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270