Git基础

GIT

git的基本介绍

git是一个开源的分布式版本控制系统(distributed revision control system, DRCS).

每个项目都有一个 Git 目录(译注:如果 git clone 出来的话,就是其中 .git 的目录;如果 git clone –bare 的话,新建的目录本身就是 Git 目录。),它是 Git 用来保存元数据和对象数据库的地方。该目录非常重要,每次克隆镜像仓库的时候,实际拷贝的就是这个目录里面的数据。

参考书目:GitBook

安装

使用

配置文件

git有三个不同级别的配置文件(每一个级别覆盖上一级别的配置),分别位于:

  1. system. /etc/gitconfig 文件[win:c:\ProgramData\git\config]: 包含系统上每一个用户及他们仓库的通用配置。 如果使用带有 –system 选项的 git config 时,它会从此文件读写配置变量。

  2. global. ~/.gitconfig 或 ~/.config/git/config 文件【win:c:\Users$User.gitconfig】:只针对当前用户。 可以传递 –global 选项让 Git 读写此文件。

  3. local. 当前使用仓库的 Git 目录中的 config 文件(就是 .git/config):针对该仓库。

用户配置

使用前要先表明自己的身份方便git记录你的操作:

git config --global user.name FrankZ
git config --global user.email chengqifw@gmail.com

配置默认文本编辑器

有时我们需要在编辑器中输入一些信息,比如执行git commit时,git会打开默认编辑器要求输入提交信息。

我这里使用的是vscode,配置之前要确保可以在命令行打开你的编辑器 https://code.visualstudio.com/docs/setup/mac

git config --global core.editor "code --wait"

配置喜欢的对比工具

  1. 打开配置文件 git config --global -e
  2. 新增字段: ``` [diff] tool = default-difftool [difftool “default-difftool”] cmd = code –wait –diff $LOCAL $REMOTE


#### 检查配置信息
你可能会看到重复的变量名(他们来自不同配置文件),Git 会使用它找到的每一个变量的最后一个配置。

git config –list

详细命令自行查看帮助`git help cinfig`(其实敲错了就会弹出帮助文档...)


## 获取git仓库
### 方式一、在本地初始化一个仓库
在本地项目目录中执行:

git init

初始化命令会在当前目录创建 .git 子目录,这个子目录含有你初始化的 Git 仓库中所有的必须文件,这些文件是 Git 仓库的骨干。 但是,在这个时候,我们仅仅是做了一个初始化的操作,你的项目里的文件还没有被跟踪。

### 方式二、从远程服务器clone一个仓库
克隆仓库的命令格式是 git clone [url]。比如我们想拉取vue的源码学习(clone到本地vueSource文件夹):

git clone https://github.com/vuejs/vue.git vueSource

Git 克隆的是该 Git 仓库服务器上的几乎所有数据,而不是仅仅复制完成你的工作所需要文件。 当你执行 git clone 命令的时候,默认配置下远程 Git 仓库中的每一个文件的每一个版本都将被拉取下来。 事实上,如果你的服务器的磁盘坏掉了,你通常可以使用任何一个克隆下来的用户端来重建服务器上的仓库(虽然可能会丢失某些服务器端的挂钩设置,但是所有版本的数据仍在)

## 忽略文件
一些我们不想纳入版本管理的文件却每次都出现在未跟踪列表是很烦的,要养成一开始就设置好 .gitignore 文件的习惯,也可以避免将来提交一些无用的文件。我们可以创建一个名为 .gitignore 的文件,列出要忽略的文件模式:

*.tmp /node_modules/

> 文件 .gitignore 的格式规范如下:
> * 所有空行或者以 # 开头的行都会被 Git 忽略。
> * 可以使用标准的 glob 模式匹配。
> * 匹配模式可以以(/)开头防止递归。
> * 匹配模式可以以(/)结尾指定目录。
> * 要忽略指定模式以外的文件或目录,可以在模式前加上惊叹号(!)取反。
> 
> 所谓的 glob 模式是指 shell 所使用的简化了的正则表达式。 星号(*)匹配零个或多个任意字符;[abc] 匹配任何一个列在方括号中的字符(这个例子要么匹配一个 a,要么匹配一个 b,要么匹配一个 c);问号(?)只匹配一个任意字符;如果在方括号中使用短划线分隔两个字符,表示所有在这两个字符范围内的都可以匹配(比如 [0-9] 表示匹配所有 0 到 9 的数字)。 使用两个星号(*) 表示匹配任意中间目录,比如`a/**/z` 可以匹配 a/z, a/b/z 或 `a/b/c/z`等。

>GitHub 有一个十分详细的针对数十种项目及语言的 .gitignore 文件列表,你可以在 [https://github.com/github/gitignore](https://github.com/github/gitignore) 找到它.

## 下班的征兆——提交更新
#### 命令介绍:
> `git add` 将未跟踪文件或已修改文件放入暂存区;

> `git diff` 比较文件,查看修改内容

> `git commit` 提交更新,记录暂存区的快照

我们工作目录下的文件分为两种:已跟踪或未跟踪(不需要进行版本控制或还没有将其加入版本控制)。

已跟踪的文件又有以下几种状态:未修改、已修改、已暂存;

要查看哪些文件处于什么状态,可以用:

git status

下图描述了工作目录下文件各种状态的转变

![图片来自gitbook](http://upload-images.jianshu.io/upload_images/3331727-2e148723650e2723?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

我们每完成一个功能以及下班前要做的就是立即将所有新增的需要版本控制的文件、所有修改的文件add到暂存区(没错,都用add命令)。
此处有一点要注意,如果我们在commit之前又修改了一次某个已进入暂存区的文件,那么这是使用`status`命令会发现这个文件同时出现在已修改和暂存区的列表中。若此时执行commit只会提交先前add进暂存区的内容,因为提交是对暂存区做快照。所有我们每次修改都需要先add进暂存区再提交

![image](http://upload-images.jianshu.io/upload_images/3331727-c5126dfaf3ca6286?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


#### 差异对比
想知道具体修改了什么地方,可以用 git diff 命令(简单瞄一眼还可以,大量的比较还是用图形化的对比工具比较舒服:超喜欢在webstorm中用)

要查看尚未暂存的文件更新了哪些部分,不加参数直接输入 `git diff`:
![image](http://upload-images.jianshu.io/upload_images/3331727-2c5f6b3202bfc077?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

此命令比较的是工作目录中当前文件和暂存区域快照之间的差异, 也就是修改之后还没有暂存起来的变化内容。

若要查看已暂存的将要添加到下次提交里的内容,可以用 `git diff --cached` 命令。(Git 1.6.1 及更高版本还允许使用 git diff --staged,效果是相同的,但更好记些。)

![fileA尚未提交过](http://upload-images.jianshu.io/upload_images/3331727-ff39fa317d8c50ca?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

配置了difftool就可以用`git difftool` 和 `git difftool --staged`


#### 提交更新
执行`git commit`会启动文本编辑器以便输入本次提交的说明。 (默认会启用 shell 的环境变量 $EDITOR 所指定的软件,一般都是 vim 或 emacs。当然也可以按照 起步 介绍的方式,使用 git config --global core.editor 命令设定你喜欢的编辑软件。)

编辑器会显示类似下面的文本信息:

![image](http://upload-images.jianshu.io/upload_images/3331727-76dfb843e5030ee7?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
另外,你也可以在 commit 命令后添加 -m 选项,将提交信息与命令放在同一行;`git commit -a`可以自动将已修改的文件加入暂存区并提交

## 移除文件
1. 我们先把工作空间的文件删掉,然后看看`git status`会显示什么:

    ![image](http://upload-images.jianshu.io/upload_images/3331727-6f655ec3e03749f1?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

    可以看到,git已经给了足够多的建议:

    * `git reset HEAD fileA`:将fileA从暂存区移除
    * `git add fileA`或`git rm fileA`:将删除fileA的操作提交到暂存区
    * `git checkout HEAD fileA`:从当前版本恢复被删掉的fileA到工作区

    真心想删除fileA那就将删除操作add/rm到暂存区然后commit,新版本中将木有fileA了

2. 直接执行`git rm fileA`:
    
    ![image](http://upload-images.jianshu.io/upload_images/3331727-7da9e9401ed96764?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

    就是相当于先在工作区删掉fileA,然后执行add操作加入暂存区嘛。
    
如果删除之前修改过并且已经放到暂存区域的话,则必须要用强制删除选项 -f(译注:即 force 的首字母)。 这是一种安全特性,用于防止误删还没有添加到快照的数据,这样的数据不能被 Git 恢复。

另外一种情况是,我们想把文件从 Git 仓库中删除(亦即从暂存区域移除),但仍然希望保留在当前工作目录中。 换句话说,你想让文件保留在磁盘,但是并不想让 Git 继续跟踪。 当你忘记添加 .gitignore 文件,不小心把一个很大的日志文件或一堆 .a 这样的编译生成文件添加到暂存区时,这一做法尤其有用。 为达到这一目的,使用 --cached 选项:

git rm –cached README

git rm 命令后面可以列出文件或者目录的名字,也可以使用 glob 模式。 比方说:

$ git rm log/\*.log
注意到星号 * 之前的反斜杠 \, 因为 Git 有它自己的文件模式扩展匹配方式,所以我们不用 shell 来帮忙展开。 此命令删除 log/ 目录下扩展名为 .log 的所有文件。 类似的比如:

git rm *~

该命令为删除以 ~ 结尾的所有文件。

## 移动文件
不像其它的 VCS 系统,Git 并不显式跟踪文件移动操作。 如果在 Git 中重命名了某个文件,仓库中存储的元数据并不会体现出这是一次改名操作。 不过 Git 非常聪明,它会推断出究竟发生了什么,至于具体是如何做到的,我们稍后再谈。

既然如此,当你看到 Git 的 mv 命令时一定会困惑不已。 要在 Git 中对文件改名,可以这么做:

git mv file_from file_to


它会恰如预期般正常工作。其实,运行 `git mv` 就相当于运行了下面三条命令:

mv README.md README git rm README.md git add README ``` 如此分开操作,Git 也会意识到这是一次改名,所以不管何种方式结果都一样。 两者唯一的区别是,mv 是一条命令而另一种方式需要三条命令,直接用 git mv 轻便得多。 不过有时候用其他工具批处理改名的话,要记得在提交前删除老的文件名,再添加新的文件名。


推荐一个学习Git分支的网页,挺有意思 https://learngitbranching.js.org/

<=to be continued

jungle