基本概念
1. 什么是版本控制系统
简单来说,有这么个东西它能帮你记录文件的变动的历史记录。支持这种功能的工具就叫版本控制系统( Verson Controll System )。
这一类工具能将什么时候、谁、对什么文件做了怎样的修改这样的信息以版本的形式记录在案,以便支持你未来翻旧账。
Git 并非唯一的版本控制系统,Subversion 是它的前辈,2014 年 Git 的市场占有率首次超过 Subversion 。
项目经理操作
2. 创建本地仓库Git 可以管理任何一个文件夹( 及其中内容 ),只要在该文件夹中执行 git init
命令,就可以让 Git 完成管理前的准备工作。
$ git init
执行成功后,你会看到类似如下信息:
Initialized empty Git repository in ...
从你执行 git init
命令这一刻开始 Git 就开始监控、监管这个文件夹下的文件的变动。这个文件夹( 它可以是一系列文件夹的根文件夹 )自此就成为了 Git 的一个 Repository 。
Git Repository下会被 Git 创建一个名为 .git
的子文件夹,这个文件夹也就是逻辑上的本地仓库。它里面会存放被 Git 所管理的文件的相关信息( 例如,历史版本 )。
警告
你不要、不要、不要自己去动 .git
目录下的任何东西,更不要随意将 .git
目录删除。这个目录下的内容是 Git 来使用和操作的。
Git Repository 中的文件的变动( 新创建的、被删除的、内容有更新的 )都会被 Git 察觉。
提示
git init 命令让一个普通的文件夹变为了 Git 的一个 Repository ,而这种身份的变化之会发生一次,因此,毫无疑问对于一个项目而言,git init 命令只需要执行一次。
在 Gitkraken 中打开这个刚刚初始化的 Git 仓库,GitKraken 会要求你做一次初始化的提交:
提交之后效果如下:
3. Git 中的文件状态
提前说明
在 Git 中,严谨地来说,有一个专门的状态用来描述刚刚被新建出来的文件 untracked 未被追踪。即,所有被新建出来的文件都是 untracked 状态。
但是在日常使用中,这种状态和 unstanged 状态并没有太大区别,因此有些书、工具、文章为了便于初学者更快速理解、掌握 Git ,就将这两种状态合二为一,进行简化,都称为 unstaged 状态。
文件的状态变化(核心三态):
3.4 已提交( commited )状态
用单机游戏存档作类比的话,一个文件处于「已提交」状态类似于,你的角色刚刚存完档,正站在存档点。
此时此刻,你的人物的状态( 他在地图上的位置、他的经验值、他的红蓝条、他身上的装备、他背包里的金币数等等 )和最近的一次存档是完全一样的。
这种状态下,你和你的数据有 2 个特点:
此时此刻,你应该是最踏实、最放心的时刻,你并不害怕突然断电这样会导致数据丢失的事故,因为你刚刚存完档。
你最踏实最放心的第二个原因:此时此刻你还没有做任何「多」的事情,就算因为事故导致你取重新读档,你也没有任何「损失」。
「已提交」状态既是一轮轮操作的终点,又是下一轮操作的起点。
注意,如下图,git commit
「只会」将暂存区的文件( 即,staged / uncommited 文件 )的内容提交至本地仓库进行保存,以形成一个新的版本。
提交后,staged / uncommited 状态的文件会再一次变为 commited 状态。
未提交状态:未暂存( Unstage )和已暂存( Staged )
还是以游戏的人物存档为例,「未提交」状态表示的是你的人物自上一次存档之后,他的状态发生了变化( 吃了个血包回血了、打了怪涨经验了、卡了个宝箱人品爆发出了个小极品、甚至就是往前走了两步导致在地图位置变化了),而你还没有进行新的、下一次存档。
本来文件的状态的变化本应是 未提交
-> 已提交
这样的 A -> B
型的变化。因为某些原因,Git 将 未提交状态又细分为 2 个阶段型状态:「未暂存」和「已暂存」。
这样文件的状态的变化就被设计成 未暂存
-> 已暂存
-> 已提交
这样的 A -> B -> C
型的变化。
未暂存( unstaged )状态
表示自上次提交之后有文件被「动过」。并且,顾名思义,Git 在提醒你:你应该暂存它。
所谓的「动了」包括:新增文件、修改原有文件内容、删除已有文件等。
对于 Unstaged 状态的文件,在 GitKraken 中你可以观察到它们:
已暂存( staged )状态
在 GitKraken 的图形化界面操作中,将 unstaged 状态的文件变为 staged / uncommited 状态的对应操作是:
项目经理操作
特殊状态:已忽略( ignored )状态Git Repository( 也就是上面所说的被 Git 管理的文件夹 )根目录下的 .gitignore 文件就是一个「黑名单」,在其中列举的文件如上所说,都不会被 Git 进行监管:Git 不会跟踪、记录这些文件的变动,跟不会将它们 push 到远程仓库。
java 项目的 .class 文件、maven 项目的 target 目录、nodejs 的 node_modules 目录都是应该加入到这个黑名单中的文件/目录。
.gitignore 文件必须叫 .gitignore ,一定不能错 。
提示
在 window 系统中,windows 不允许直接新建文件名以 .
开头的文件( Linux 不存在这个问题 )。因为,Windows 会误以为 .gitignore 是文件的后缀,而你的文件是没有名字的。Windows 不允许创建无名文件!
所以这种情况下,你需要「动脑子」创建。你可以在 git bash 中通过 touch 命令创建,也可以从别的项目中拷贝一个过来,还可以借助 vscode 在 vscode 中创建。
.gitignore 文件的基本语法
# 表示注释
/ 目录层级
* 通配符
示例:
# 忽略所有后缀名为 log 的文件,无所谓文件名。无论它位于什么层次结构。
*.log
# 忽略 Git Repository「根目录」下的 target 文件夹
# 这里最后的 / 非必须。不过个人建议还是加上,因为可以暗示出它是一个文件夹。
/target/
# 忽略所有名为 target 的文件夹。无论它位于什么层次结构中。
target/
补充 .gitignore 文件中有一个 !
表示的「非」的规则,对于它的使用相较而言比较复杂,暂时不要求掌握。
模板
### maven ###
target/
*.class
### nodejs ###
node_modules/
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### VS Code ###
.vscode/
### Other ###
HELP.md
*.log
# virtual machine crash logs see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
注意事项
.gitignore
配置文件的根目录就是当前 Git 工程目录。.gitignore
配置只对当前 Git 工程有效。在配置语句的前后面添加空格、Tab、注释等,会导致当前行的配置语句失效。所以,不要添加非必要的空白符。
配置语句对已经提交过的文件无效,即,它只能影响未来,不能影响过去。
4. 提交
git add
+ git commit
的作用简单来说,就是将一个文件的变动提交给 Git 。
git add
命令可以将 unstaged 文件变为 staged 文件;git commit
命令可以将 staged 文件变为 commited 文件,从而完成了「存档」这个操作。
unstaged
└──> staged
└──> commited
注意
注意,没有办法将 unstaged 状态的文件直接变为 commited ,staged 是存档操作中文件状态变化的必经之路。
对于一次「提交」而言,提交消息(message)是必须的 。否则,Git 会拒绝你的这次提交。你存档时必须要说点啥
在 GitKraken 的图形化界面中,git commit
提交操作的功能在这个区域:
注意
一个完整的提交信息包括 header、body、footer 三部分,你至少要保证提供 header ,否则,你无法提交。
要新增「一次提交」之所以要同时使用 git add 和 git commit 是因为在将文件当前的内容添加成至本地仓库之前,要 先 将其添加至 暂存区 。
5. 翻旧账:读档
从本地版本库( .git )中取出文件只需要一个指令:
git checkout [ 版本标识 | 标签 ] <文件1>, <文件2>, ...
需要特别提醒的是,磁盘文件夹中的文件会被取出的文件「覆盖」(覆盖、覆盖),因此你对该文件作出的修改会丢失。
例如,本地版本库中的文件是 80 行的,你本地的文件被你改成 100 行(但未提交),执行 git checkout 之后,你的本地文件会变成 80 行。
git checkout
命令就是在「翻旧账」!
HEAD
标签标注的就是你现在正在「历史长河」中的那个位置。也就是你当前看到的、「读」出来的是「哪个档」。