git pro学习笔记

已经开始工作20多天了,每天都面对一堆没见过不会做的东西,想要努力学,也总觉得时间不够。每次领导找我说话,我都担心会让我明天不要来上班了。其中,让我觉得最坑的就是Git。
之前也使用过git,但都是自己的小项目,不涉及到多人协作,也没什么分支的概念,所以只用master,自己push来pull去的,也没出过什么问题。但是工作之后设计到多个任务同时推进,所以需要频繁切换分支,提交给老师们review,于是闹出了许多提交代码不干净的尴尬笑话。
今天认真看了git pro,也就是git自己的官方书,类似文档。看了前面三张操作部分的内容,下周再来看原理。

Git Pro

Git 如何工作

版本控制的工具

  • 分布式版本控制系统
    • 客户端把代码仓库完整地镜像下来,如果一处协同工作的服务器发生故障,事后可以用任何一个镜像除了的本地仓库恢复
    • 每一次克隆操作,实际上都是一次对代码仓库的完整备份

原理

  • 直接记录快照

git VS 其他版本控制系统

  • 其他版本控制系统记录以文件列表的方式存储信息,将保存的信息看作是一组基本文件和每个文件随时间逐步累积的差异

    存储每个文ä"¶ä¸Žåˆå§‹ç‰ˆæœ¬çš„差异。

  • git在每次提交时,对全部文件制作一个快照,并保存这个快照的索引,如果文件没有修改,就保留一个指向之前文件的索引

    Git 存储项目随时间改变的å¿"照。

  • 所有操作都在本地执行
    • 执行速度快
    • 执行历史在本地保存,清晰
    • 无网络连接时,不影响工作
  • 所有数据在存储钱都计算校验和,以校验和来引用
    • 如果传送过程中丢失信息或损坏文件,git会发现
    • 也不会再Git不知情时更改任何文件内容或目录内容
    • 计算校验和的机制叫做SHA-1散列
  • 一般只添加数据
    • 很难执行不可逆操作或者清除数据

三种状态

  • 已提交(commited): 数据已安全地保存在本地数据库中
  • 已修改(modified):修改了文件,但还没有被保存到数据库中
  • 已暂存(staged):对一个已修改文件的当前版本做了标记,使之包含在下次提交的快照中

三个工作区域

  • git仓库(.git directory / repository):git用来保存项目的元数据和对象数据库的地方
  • 工作目录(working directory):对项目的某个版本独立提取出来的内容
  • 暂存区域(staging area):是一个文件,保存了下次要提交的文件列表信息,一般在git仓库目录中

工作目录、暂存区域ä"¥åŠ Git ä"“库。

git 基本工作流

  1. 在工作目录中修改文件
  2. 暂存文件,将文件的快照放入暂存区域
  3. 提交更新,找到暂存区域的文件,将快照永久性存储到git仓库目录

Git 如何操作

配置git config

存储位置
  1. /etc/gitconfig :包含系统上每一个用户及他们仓库的通用配置
  2. ~/.gitconfig~/.config/git/config: 针对当前用户,可以传递--global选项让Git读写此文件
  3. 当前使用仓库的git目录中的config文件:针对该仓库
用户信息

设置用户名称和邮件地址,每一个git提交都会使用这些信息,并且它会写入到每一次提交中,不可更改

1
2
git config --global user.name "xxx"
git config --global user.email xxx@xxx.com
  • 如果使用了--global选项,那么该命令只需要运行一次
  • 如果想在当前项目中使用不同的用户名称和邮件地址,可以在当前项目目录下运行没有--global选项的命令来配置
文本编辑器

配置默认的文本编辑器

1
git config --global core.editor emacs
检查配置
1
git config --list
  • 可能会看到重复的变量名,因为git会从不同的文件中读取同一个配置,这种情况下,git会找到它找到的每一个变量的最后一个配置
  • 也可以通过输入git config <key>找检查某一项配置

获取帮助

需要获取帮助时,有三种方法可以找到git命令的使用手册

1
2
3
git help <verb>
git <verb> --help
man git-<verb>

基本使用

获取git仓库

1. 在现有目录中初始化仓库
1
git init
  • 该命令创建一个名为.git的子目录

  • 如果需要添加文件来进行版本控制

    1
    2
    3
    git add *.js
    git add LICENSE
    git commit -m "initial project version"
2. 克隆现有仓库
  • 默认配置下远程git仓库中的每一个文件的每一个版本都将被拉取下来

    1
    git clone https://github.com/xxx/xxx
  • 如果想自定义本地仓库的名字,可以使用如下命令

    1
    git clone https://github.com/xxx/xxx mulibgit

记录每次更新

  • 每一个文件都只有两种状态
    • 已跟踪:被纳入了版本控制的文件,在上一次快照中有它们的记录
    • 未跟踪:既不存在于上次快照的记录中,也没有放入暂存区
  • 初次克隆某个仓库的时候,工作目录中的所有文件都属于已跟踪文件,并处于未修改状态

Git 下文ä"¶ç”Ÿå‘½å‘¨æœŸå›¾ã€‚

检查当前文件状态
  • git status查看哪些文件处于什么状态,显示内容包:
    • 所有文件是否都被跟踪
    • 文件是否有修改
    • 当前分支
跟踪新文件
1
git add <file>
暂存已修改文件
1
git add <file>
  • git add可以理解成「添加内容到下一次提交中」
提示语
  • changes to be commited
    • 文件是已暂存状态,如果此时提交,那么该文件此时的版本将被留存在历史记录中
    • 如果参数是目录的路径,该命令将递归地跟踪该目录下的所有文件
  • changes not staged for commit
    • 已跟踪文件的内容发生了变化,但还没有放到暂存区
    • 要暂存这次更新,需要运行git add命令
状态简览
  • git status -s / git status --short 可以更为紧凑地输出状态
  • 文件标记
    • ?? :未跟踪文件
    • A :新增加到暂存区的文件
    • 出现在右边的M :表示该文件被修改了,但是还没放入暂存区
    • 出现在左边的M :文件被修改了,并放入了暂存区
忽略文件
  • .gitignore文件
  • 无需纳入git管理的文件,通常是一些自动生成的文件
  • 要养成一开始就设置好.gitignore文件的习惯,以免将来误提交这类无用的文件
查看已暂存和未暂存的修改
  • git diff : 比较工作目录中当前文件和暂存区域快照直接的差异,也就是修改之后还没有暂存起来的变化内容

  • git diff --cached / git diff --staged:查看已暂存的将要添加到下次提交里的内容

    image-20181117162037399

提交更新

正确顺序:

  • git status 查看文件是否都暂存起来了
  • git commit 提交

git commit -m "xxx" 提交+提交内容的信息

跳过使用暂存区域

git commit -a 自动把所有已经跟踪过的文件暂存起来一并提交,跳过git add步骤

移除文件
  • git rm 从已跟踪文件清单中移除制定的文件,下一次提交时,该文件就不再纳入版本管理了
  • git rm xxx -f 删除之前修改过并且已经放到暂存区的文件,这样的数据不能被git恢复
  • git rm --cached xxx 把文件从git仓库中删除,但仍保留在当前的工作目录中
移动文件

git mv file_from file_to 将文件从一个文件夹移动到另一个文件夹

git mv README.md README实际执行的是:

  • mv README.md README
  • git rm README.md
  • git add README

查看提交历史

  • git log 会按提交时间列出所有的更新,最新的更新排在最上面,内容包括

    • 每次提交的SHA-1校验和
    • 作者名字
    • 电子邮件地址
    • 提交时间
    • 提交说明
  • git log -n 最近n次提交

  • git log -p显示每次提交的内容差异

  • git log --stat 查看每次提交的简略的统计信息

  • git log --pretty 可以指定使用不同于默认格式的方式展示提交历史

    • git log --pretty=oneline 每个提交显示一行

    • git log --pretty=short 有commit信息

    • git log --pretty=full 详细信息,包括author,commit

    • git log --pretty=fuller 详细信息,包括具体author,authordate,commit,commitdate

    • git log --pretty=format: "xxx" 定制要显示的记录格式(可以自己规定中间的分隔符)

      image-20181117164212429

  • git log --graph 图形显示分支、合并历史

image-20181117164745734

限制输出长度
  • git log -<n> 只输出n条提交
  • git log --since=2.weeks 最近两周的提交
    • 可以是weeks, years, months
    • 可以是具体的某一个天2008-01-15
    • 可以是相对多久以前 2years 1day 3minutes ago
  • git log --until= 截止到什么时候
  • git log --author 指定作者的提交
  • git log --grep 搜索提交说明中的关键字
    • git log --all-match 同时满足两个选项搜索条件
  • git log -S 列出添加或溢出了某些字符串的提交
  • git log path 只关心某些文件或者目录的历史提交

image-20181117170724901

撤销操作

  • git commit --amend 重新提交上一次提交(在漏掉文件或提交信息写错的情况下使用)

    • 会将暂存区的文件提交,如果上次提交后未做修改,那么快照不变,只修改提交信息
  • 取消暂存的文件: git reset HEAD <file>

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

远程仓库的使用

查看远程仓库
  • git remote: 列出你指定的每一个远程服务器的简写
  • git remote -v 远程服务器简写 + 对于的URL
添加远程仓库
  • git remote add <shrotname> <url>
  • git fetch xx 拉取远程仓库中有单你没有的信息
从远程仓库抓取和拉取
  • git fetch [remote-name]
    • 访问远程仓库,从中拉取所有你还没有的数据
    • 执行完后,你会永远那个远程仓库中所有分支的引用,可以随时合并或查看
    • 它不会自动合并或修改你当前的工作,需要手动将其合并入你的工作
  • git pull
    • 有一个分支设置为跟踪一个远程分支,可以使用git pull来自动抓鱼然后合并远程分支到当前分支
推送到远程仓库
  • git push [remote-name] [branch-name] 将内容推送到上游
  • 多人合作时,需要先将他人的工作拉取下来,合并进你的工作,然后才能推送
查看远程仓库
  • git remote show [remote-name] 查看某一个远程仓库的更多信息
远程仓库的移除与重命名
  • git remote rename 修改远程仓库的简写名
  • git remote rm xxx 移除一个远程仓库

打标签

人们会使用这个功能来标记发布节点

列出标签
  • git tag
  • git tag -l 'v1.8.5*' 列出1.8.5系列的标签
创建标签
  • 两种类型
    • 轻量标签(lightweight):特定提交的引用(像一个不会改变的分支)
    • 附注标签(annotated):存储在git数据库汇总的一个完整对象
附注标签
  • git tag -a v1.4 -m "my version 1.4"
  • git show v1.4 显示标签信息和对应的提交信息
轻量标签
  • 本质上是将提交校验和存储到到一个文件中,没有保存任何其他是信息
  • git tag v1.4-lw
  • git show v1.4-lw 不会显示额外的标签信息,只显示提交信息
后期打标签
  • git tag -a v1.2 xxxxxx 后面接校验和
共享标签
  • 默认情况下,git push不会传送标签到远程仓库服务器上
  • 所以必须显式地推送标签到共享服务器上
  • git push origin [tagname]
  • git push origin --tags 会把所有不再远程仓库服务器上的标签全部传送过去
检出标签
  • git checkout -b [branchname] v2.0.0 在特定标签上创建一个新分支

git别名

  • 可以通过git config来为每一个命令设置一个别名

Git分支

  • 分支本质上仅仅是指向提交对象的可变指针

基础操作

分支创建
  • git branch <branchname> 创建分支
  • git log --decorate 查看各个分支当前所指的对象
分支切换
  • git checkout <branchname> 切换分支(HEAD会指向切换的分支)

分支的新建与合并

  • git checkout -b <branchname> 创建并切换到新分支
  • git merge <branchname> 将其他分支的内容合并到当前分支上
  • git branch -d <branchname> 删除分支
正确工作流
  1. 做任务A时,创建A分支 (当前分支master

    1
    git checkout -b A   
  2. 需要执行任务B,先保存任务A的修改,再从master上创建新分支B

    1
    2
    3
    git stash  
    git checkout master
    git checkout -b B
  3. 在B上完成任务后,合并分支B到master,再删除分支B

    1
    2
    3
    git checkout master
    git merge B
    git branch -d B
遇到冲突时的分支合并
  • git status 可以在任何时候使用这一命令来查看因包含合并冲突而处于未合并状态的文件

  • 解决方案

    • 手动解决
    • mergetool

分支管理

  • git branch -v 查看所有分支的最后一次提交

  • git branch --merged / git branch --no-merged 查看哪些分支已经合并及未合并

分支的开发工作流

  • 不同分支可以维护不同层次的稳定性
  • 对于大型项目来说,稳定分支(master)通常会在提交历史中落后一大截
  • 分类
    • 特性分支
      • 短期分支
      • 用来实现单一特性或其相关工作

远程分支

  • 远程引用是对远程仓库的引用(指针)
  • git ls-remote 获取远程引用的完整列表
  • 远程跟踪分支: 远程分支状态的引用
    • 本地引用不能移动
    • 在做网络通信操作时,它们会自动移动
  • 推送 git push origin serverfix 后一个分支即refs/heads/serverfix:refs/heads/serverfix
    • 推送本地的serverfix分支来更新远程仓库上的serverfix分支
  • 跟踪分支:从一个远程跟踪分支检出一个本地分支会自动创建一个叫做“跟踪分支”
  • git checkout -track [remotename]/[branch] 设置跟踪分支
  • git branch -vv 查看设置的所有跟踪分支

变基

变基的基本操作
  • 变基:提取在B分支引入的补丁和修改,在A分支上再应用一次
  • rebase :将提交到某一分支上的所有修改都移至另一分支上
原理
  • 找到A、B分支最近的共同祖先
  • 对比当前分支(B)的历次提交,提取相应的修改保存为临时文件
  • 将该分支指向目标基底A,将另存为临时文件的修改依序应用
变基 VS 合并
  • 将dev分支的内容并入到master中

    1. 在master分支上执行 git merge dev

    2. 在dev分支上依次执行以下命令

      1
      2
      3
      git rebase master
      git checkout master
      git merge experiment
  • 以上两种方法的结果是一样的,只是变基会使提交历史看起来更整洁

  • 不要对在你的仓库外有副本的分支进行变基