抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >
header.png

使用 git 已经挺长时间了,也在网上看过不少的学习教程。但是怎么说呢,git 的操作实在是太杂了,某一种目标可能就有好多种不同的实现方式,而且这些不同的实现方式又可能产生不同的结果。以至于,每次在网上查找到的解决方案可能都不同,然后不停地往 OneNote 里记笔记,时间久了,笔记越来越乱,再加上记忆力本就不好,原先不会的现在还是不会。于是寻思着简单的梳理一下。

认识 git

什么是 git?

它是一个分布式版本控制系统,用于项目开发中的版本控制;

  • 从本质上来讲 Git 是一个内容寻址(content-addressable)文件系统,并在此之上提供了一个版本控制系统的用户界面;
  • 它的核心其实就是键值对数据库(key-value data store)

文件状态

git 管理下的项目的文件分为:已跟踪未跟踪两种状态

  • 已跟踪的文件:是指那些被纳入了版本控制的文件,在上一次快照中有它们的记录,在工作一段时间后,它们的状态可能处于未修改,已修改或已放入暂存区;
  • 工作目录中除已跟踪文件以外的所有其它文件都属于未跟踪文件,它们既不存在于上次快照的记录中,也没有放入暂存区;
  • 初次克隆某个仓库的时候,工作目录中的所有文件都属于已跟踪文件,并处于未修改状态;

工作方式

  • Git 保存的不是文件的变化或者差异,而是一系列不同时刻的文件快照
  • 在进行提交操作时,Git 会保存一个提交对象(commit object)
  • 该提交对象会包含一个指向暂存内容快照的指针,但不仅仅是这样,该提交对象还包含了作者的姓名和邮箱、提交时输入的信息以及指向它的父对象的指针;

存储方式

gitmemory

名称 区域 解释
Workspace 工作区 当前用户操作修改的区域
Index/Stage 暂存区 add 后的区域
Repository 仓库区或本地仓库 commit 后的区域
Remote 远程仓库 push 后的区域

git 命令

写在前面

真要说起来 git 里的难点也就是分支的使用。之前在同学的 blog 里找到了一个很好的学习 git 分支的平台:learnGitBranching。与其说是学习,你更可以在无聊的时候把它当作一个 “游戏”,一边玩耍一边学习。其实最主要的,还是它能动态的帮助你理解 git 命令。

Learngitbranching

接下来的描述也会对它的一些操作进行梳理,毕竟复习或者查阅的时候,再去网站操作一遍,效率比较低。

符号说明

在正式介绍命令之前,先对 git 里常用的符号或者关键字进行说明:

  • 分支名后带有符号 *:表示当前分支
  • HEAD:通常会和当前分支绑定在一起,总是指向当前分支上最近一次提交记录;
    • 但是也可以 git checkout c1分离 HEAD(c1 是某次提交记录的 hash 值,通常会很长,可以使用 git log 查看;当然了,也可以利用 tag 实现),使其指向某次具体的提交记录;分离之后的提交将不属于任何分支,一般的做法是在此处再创建一个新的分支,然后再 commit 进行后续的操作;
    • 大多数修改提交树的 Git 命令都是从改变 HEAD 的指向开始的;
  • 相对引用 ^:向上移动一个提交记录,可叠加使用,如:HEAD^^^
    • 要注意:引用可以是分支名或者 HEAD,提交记录(如 c1)不算引用
  • 相对引用 ~<num>:向上移动 num 个提交记录,如:~3

常用命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
******************************************************
##### git 配置
$ git config --global user.name "<用户名>"
$ git config --global user.email "<电子邮件>"

## git 配置信息查看
$ git config --system --list // 查看系统config
$ git config --global --list // 查看当前用户(global)配置
$ git config --local --list // 查看当前仓库配置信息

*******************************************************
##### 初始化仓库
$ git init
$ rm -rf .git // 删除本地仓库

*******************************************************
##### 查看当前缓存区状态
$ git status

*******************************************************
##### 查看历史提交记录
$ git log
$ git log --decorate // 显示包含标签资料的历史记录;
$ git log --pretty=oneline // 只看版本号和提交的版本信息
$ git log --graph // 查看分支合并图

### 查看分支图信息
$ git log --graph --pretty=oneline --abbrev-commit
$ git log --graph --decorate --oneline --all

*******************************************************
##### 查看文件的修改
$ git diff <file_name>

*******************************************************
##### 将修改添加到缓存区
$ git add -A // 所有文件都添加,也可以使用 $ git add .
$ git rm --cached <file> // 删除缓存,撤销 git add 的操作

*******************************************************
##### 提交变更
$ git commit -m "version 1.2" // 引号内是本次提交的命名

*******************************************************
##### 克隆远程数据库
$ git clone <repository> <directory>
// 在<repository>指定远程数据库的URL;
// 在<directory>指定新目录的名称,省略时默认为当前目录;

*******************************************************
##### 从远程数据库拉取更新至本地
$ git pull <repository> <refspec>...
// <repository> 处输入远程数据库地址;
// <refspec> 处指定远程数据库的分支;
$ git pull // github 上常用的抓取最新提交的方式
$ git pull origin develop // 从远程 origin 数据库的 develop 分支抓到本地的当前分支


##### 将本地数据推送至远程数据库
$ git push <repository> <refspec>...
$ git push origin master // 将本地的当前分支推送至远程 origin 数据库的 master 分支
$ git push -u origin master
// 第一次推送 master 分支时,远程库是空的,加上了-u 参数,
// Git 不但会把本地 master 分支内容推送至远程新的 master
// 分支,还会把本地 master 分支和远程 master 分支关联起来,
// 以后就可以直接 git pull / git push 简化命令
$ git push --set -upstream <远程仓库名称> <远程仓库中分支名称>
// 手动将本地当前分支与远程仓库的分支关联
$ git push -f origin master // 强制推送

*******************************************************
##### 添加远程数据库
$ git remote add <name> <url>
// 添加的同时,给远程数据库命名,以后不用再输入URL;
// 默认为:origin
$ git remote set-url <name> <url> // 修改 git 的 remote url
$ git config -e // 从配置里修改 git 的 remote url

*******************************************************
#### 分支的创建/查看/修改
$ git branch // 显示分支列表(带*的为当前分支);
$ git branch <branchname> // 创建分支并命名;
$ git branch -d <branchname> // 删除本地分支;
$ git push origin --delete <branchname> // 删除远程分支;
$ git branch -f master HEAD~3 // 将 master 分支强制指向 HEAD 的第 3 级父提交;

*******************************************************
#### 分支的退出/切换
$ git checkout <branchname> // 退出当前分支并切换到其他分支;
$ git checkout -b <branchname> // 创建分支并进行切换;
$ git checkout commit_id/tag // 分离 HEAD 至 commit_id/tag 的提交处

*******************************************************
#### 分支合并 merge
$ git merge <branch> // 将指定分支合并到当前分支
$ git merge --squash <branch> // 将目标分支的所有提交压缩为一个,并添加到当前分支;
$ git merge --abort // 取消当前合并,重建合并前状态

*******************************************************
#### 分支重定向 rebase(也可用来分支合并)
// Rebase 实际上就是取出一系列的提交记录,“复制”它们,然后在另外一个地方逐个的放下去;
// 若用在分支合并,相比于 merge,可以创造更线性的提交历史
$ git rebase <branch> // 把当前分支重定向到目标分支;
$ git rebase --abort // 取消 rebase;
$ git rebase -i HEAD~2 // 编辑模式修改分支基准(修改pick,实现压缩squash/修改edit等)

*******************************************************
#### 选择重构 cherry-pick
$ git cherry-pick <commit>... // 取出选择的提交并添加到当前分支

*******************************************************
#### 还原 revert
// 版本回退
$ git revert HEAD // 取消某次提交(会新增否定的历史记录来实现)

*******************************************************
#### 重置 reset
// 版本回退
$ git reset --hard HEAD^ // 重置结构 /(删除)提交等(历史记录会消失)
$ git reset --hard commit_id
// 如果想让服务器也回退到该版本的话:$ git push origin HEAD --force

*******************************************************
#### 标签 tag
$ git tag // 显示标签列表;
$ git tag -n // 显示标签列表及注解;
$ git tag <tagname> <commit_id> // 新建一个轻标签,默认为 HEAD,也可以指定commit id
$ git tag -am <注释> <tagname> // HEAD 指向的提交里打上注释标签;
$ git tag -d <tagname> // 删除本地标签;
$ git checkout <tagname> // 切换到对应标签的提交点,会分离 HEAD
$ git push origin <tagname> // 想远程仓库推送一个 tag
$ git push origin --tags // 推送全部未推送过的本地 tag
$ git push origin :refs/tags/<tagname> // 删除一个远程标签

更多详情:『Git 官方手册

其他操作

总结常用命令,还是免不了量越来越大,变得混乱的问题。所以,再加上一个模块,记录一些可能不那么常用的组合操作;

这一块内容以后会慢慢不断更新;

先扔一个 Git 常用操作的索引:『Git 操作索引

修改 commit 注释

1
2
3
4
5
6
$ git rebase -i HEAD~2    // 选择至所需修改的节点
// 会出现 pick: commit_id <注释>, 将要改的那行的 pick 改成 edit 然后退出
// 此时使用 $ git log,可以版本已经变成了你想改的那个
// 修改版本提交注释
$ git commit --amend // 接受,保存修改,并提交
$ git rebase --continue // 接受 rebase 的执行

取消 track 某一文件

git rm -r --cache <file_name>

  • untrack 后,使用 commit -a 时,不会将其添加到暂存区中;
  • 之后会在 .ignore 文件中将该 untrack 的文件添加进去,完成;

文件暂存(栈)

你要把现在正在工作的分支保存下来,等处理完其他的再回来接着当前分支的修改工作:

  1. 将当前分支的修改暂存起来(此处不等于 add+commit):git stash
    • 备份当前的工作区的内容,从最新的一次提交中读取相关内容,让工作区保证和上次提交的内容一致。同时,将当前的工作区修改的内容保存到 Git 栈中暂存起来。
  2. 切换到别的分支工作,完成后切换回原来的工作分支,查看暂存列表 git stash list
    • 显示 Git 栈内的所有备份,可以利用这个列表来决定从那个地方恢复
  3. 恢复暂存的修改到工作区 git stash apply <stash_name> 恢复暂存之后不删除暂存:
    • 从 Git 栈中读取最新一次保存的内容,恢复工作区的相关内容。
  4. 或者 git stash pop 恢复暂存之后删除暂存:
    • 从 Git 栈中读取最新一次保存的内容,恢复工作区的相关内容;
    • 之后 pop 会删除最新的暂存;
  5. 删除 “暂存”:git stash drop <stash_name>
    • 从 Git 栈删除最旧的一个暂存
  6. 结束

设置 git 代理

有时在客户公司办公,需要上外网,临时查一下资料,设置办法如下:

1
2
3
4
5
6
7
8
# 设置代理:
$ git config --global http.proxy http://IP:Port

# 代理设置完成后,查看设置是否生效:
$ git config -–get -–global http.proxy

# 删除代理设置
$ git config --global --unset http.proxy

使用规范

Branch 管理

推荐使用如下 5 个分支开发管理:

BranchManage

分支 名称 解释
master 分支 主分支(保护分支) 只负责管理发布的状态,在提交时使用标签记录发布版本号
develop 分支 开发分支 针对发布的日常开发分支
feature 分支 特性分支 - 这个分支是针对新功能的开发,在 bug 修正的时候从 develop 分支分叉出来的;
- 基本上不需要共享特性分支的操作,所以不需要远端控制,完成开发后,把分支合并回 develop 分支后发布;
release 分支 发布分支 - 一般的开发是在 develop 分支上进行的,到了可以发布的状态时再创建 release 分支,为 release 做最后的 bug 修正;
- 到了可以 release 的状态时,把 release 分支合并到 master 分支,并且在合并提交里添加 release 版本号的标签;
- 注意:要导入在 release 分支所作的修改,也要合并回 develop 分支;
fix 分支 bug 修复分支 需要根据实际情况对已发布的版本进行漏洞修复;

详见:『原文

Tag 管理

通常 Tag 采用三段式:v版本.里程碑.序号(v2.3.1)

  • 架构升级或架构重大调整,修改第 1 位
  • 新功能上线或者模块大的调整,修改第 2 位
  • bug 修复上线,修改第 3 位

Commit 管理

不管采用怎样的表述方式,最终目标都是:表达清楚、格式统一、方便快速阅读和定位

建议格式(type:scope:body:issue) :

  • <|新功能|修改|Bug修复|重构|测试>(影响模块)提交描述信息(#issue?)

其他问题

这个模块先仍在这,之前遇到的问题也没怎么记录,这篇文章已经把我总结的有点头大了。以后,再遇到问题再在这里更。

参考