Git 使用

简介

Git 作为分布式版本控制系统,基于去中心化的设计思想,在每个分布式节点上都保存有完整的版本,降低了对中心仓库的依赖,增加了版本安全性。

Git 的使用过程中,并不是必须设置中心仓库,各个节点之间完全可以互相推送和拉取更新内容。不过考虑到相互的通信问题和团队协作,所以一般会选择一个 24 小时运行的主机作为中心仓库,以此来获取和交换更新内容,例如 GitHub 则提供了这样的托管服务。

三种状态

Git 对文件的跟踪管理存在三个阶段,工作区、暂存区和分支:

  • 工作区就是实际操作的文件目录;
  • 暂存区是一个索引文件,记录已跟踪文件的目录树,保存文件的时间戳、大小等易比较的信息;
  • 分支与暂存区类似,也保存有文件的目录树,用于记录文件系统的快照。

暂存区和分支都依赖 .git/objects 目录,该目录称为对象库,记录了真实文件系统的快照。暂存区只是一个 index 文件,存放在 .git 目录中。当工作区文件发生修改时,将工作区中文件的时间戳和大小,与 index 中记录的文件时间戳和大小进行比较,可以快速的判断工作区文件是否发生了更改,然后再具体的进行工作区文件内容与 objects 中记录文件内容进行比较。 暂存区的作用更像是工作区和分支之间的一个缓冲区域,或者称之为 “预提交文件改动到分支” 的区域。暂存区的存在,允许我们在工作区和暂存区之间方便的进行文件修改的添加与撤回,以及对修改内容的分部分提交。例如当工作中需要修改两部分内容,目前只完成了一部分的修改时,可以将完成的这部分添加到暂存区,接着在工作区继续修改另一部分,需要提交到分支上时,则提交缓存区的内容,未修改完成的部分可以继续修改。 因为分支更重要的作用是维护文件系统的版本序列,与远程仓库的通信,所以如果没有暂存区的存在,那么我们的文件修改则只能频繁的与分支打交道,届时版本序列将变得复杂且不易于维护。

Git 使用

Git 安装

下载安装 Git:| Mac OS X | Windows | Linux/Unix |

官网下载速度较慢,这里提供一个 Windows 版本的下载链接:Git for Windows


Git 配置

Git 安装之后,首先进行用户名和邮箱的配置,配置信息会记录到每次的提交记录中,并且当推送更新到 GitHub 上的项目时,会与 GitHub 账号进行匹配,在历史提交记录中会显示出用户头像,并且点亮提交次数。

通过 git config 命令进行用户名和邮箱配置时存在三种级别:

  • --system:当前机器上的配置,面向所有用户;
  • --global:当前用户的配置,面向当前用户的所有仓库;
  • --local:当前仓库的配置,只对当前仓库生效。

配置使用的优先级为:local > global > system,即范围小的配置会覆盖范围大的配置。 配置文件所在位置为: system:etc/gitconfig global:~/.gitconfig local:.git/config windows 系统中的位置为: system:git 工具安装位置的 etc/gitconfig global:当前用户主目录下的 .gitconfig local:.git/config

配置方式为:

git config --global user.name "abc"
git config --global user.email "abc@xxx.com"

查询配置方式为:

git config --global --list

一般只需要对当前用户进行配置即可,即使用 --global 级别,如果某个仓库有特殊安排,则可以在具体的仓库级别进行配置即可。不明确指定级别的话,默认设置的为 --local 级别。

对于版本号在 2.0.0 以上的 git,提供了一个简单的查询配置文件目录的命令:

git config --list --show-origin

创建仓库

创建仓库有两种方式,选择本地工作目录初始化为仓库,或者从远程仓库克隆到本地。克隆仓库的方式在下面的内容中再进行讲述,这里首先使用初始化本地工作目录为仓库的方式。

进入选定目录,执行如下命令即可:

git init

命令执行之后,在当前目录中会生成 .git 文件夹,此时当前目录即为一个“崭新”的仓库。

之所以用“崭新”来描述仓库,是因为在执行仓库初始化命令后,无论当前目录下是否存在文件,.git 目录生成后都不存在 index 文件,objects 目录下的文件夹中也没有具体的文件生成。即此时暂存区和分支都为空,只有向仓库中添加文件后,才会生成暂存区 index 文件,objects 目录下才会生成文件。


记录文件/更新

首先要明确一点,工作目录中的文件只有两种状态,已跟踪和未跟踪,也就是已经纳入版本记录,和未纳入版本记录。使用上面的 git init 命令生成仓库时,工作目录中的所有文件都是未跟踪状态,从远程仓库克隆生成本地仓库时,工作目录中的所有文件都是已跟踪状态。

对于未跟踪文件,则无所谓文件是否发生了修改,因为不会跟踪记录该文件的状态。对于已跟踪文件,则会检测记录该文件是否发生了修改。

git add <file>

git add 命令面向两种对象,一个是将未跟踪文件纳入暂存区,进行跟踪记录;另外一个是将已跟踪文件的修改,添加到暂存区,记录文件的更新。当命令后跟着一个目录时,则递归添加目录及目录下所有文件。

git status

git status 命令用于查看文件的状态,未跟踪文件只有一种状态:文件未跟踪,或者称为未纳入暂存区,状态显示为 Untracked files。已跟踪文件有两种状态:一是纳入暂存区,等待提交到版本库,状态显示为 Changes to be committed;二是文件发生了修改,且修改部分尚未添加到暂存区,状态显示为 Changes not staged for commit


删除文件

git add 命令用于向暂存区添加文件,或记录文件的更新内容。若执行此命令后,发现该文件并不需要跟踪记录,或者已经添加到暂存区的文件更新内容需要取消,git 提供了相应的撤回操作命令。

git rm --cache <file>

git rm --cache <file> 命令用于从暂存区移除对文件的跟踪。

git rm <file>

git rm <file> 命令不仅从暂存区移除对文件的跟踪,并且从工作目录中也删除了该文件。

git rm --cache <file> 命令和 git rm <file> 命令都存在一个 -f 选项,用于强制删除。当已跟踪的文件发生了修改,并且修改未添加到暂存区时,则需要git rm --cache -f <file> 命令才能从暂存区移除对文件的跟踪;当已跟踪的文件发生了修改,并且修改已经添加到暂存区时,则需要git rm -f <file> 命令才能同时从暂存区和工作目录中删除文件。


删除更新

这里的更新有两种情况:

  1. 工作目录下已跟踪文件进行了更新,且更新内容尚未提交到暂存区;
  2. 工作目录下已跟踪文件进行了更新,且更新内容已经提交到暂存区。
git checkout -- <file>

git checkout -- <file> 命令用于撤销第一种情况下的更新内容,可以理解为拿暂存区的文件内容替换掉工作区的文件内容。

git reset HEAD <file>

git reset HEAD <file> 命令用于撤销第二种情况下的更新内容,可以理解为拿上个版本的系统快照替换掉暂存区的文件内容。

git checkout HEAD <file>

git checkout HEAD <file> 命令能够同时撤销工作区和暂存区的更新内容,可以理解为拿上个版本的系统快照替换掉工作区和暂存区的文件内容。

因为容易引起工作内容丢失,所以使用 git checkout HEAD <file> 命令时需要注意。


提交文件

工作中对每一个文件修改完成后,将修改内容依次添加到暂存区,当完成所有修改后,则提交暂存区文件到当前分支上。

git commit

git commit 命令用于提交暂存区文件到当前分支上,执行该命令后会打开文本编辑器提示输入提交信息。

可以直接执行 git commit -m 'commit message' 命令,将提交信息写入命令中。

git log

git log 命令用于查看提交历史,每个提交都会记录时间、用户信息、输入的 commit 信息及 commit 值 ,这里的 commit 值是一个 SHA1 校验和,在后续的版本回退中会使用到 。

git reflog

git reflog 命令用于查看 HEAD 变动历史,当执行提交、分支切换以及版本回退这类改变 HEAD 指向的操作时,都可以通过该命令查询出 HEAD 指向的提交值,即 SHA1 校验和。该命令更多时候用于版本回退时,若想撤销回退操作,恢复到回退之前的记录时,通过该命令可以查询到回退之前的校验和。


分支切换

分支的使用很广泛,修改 bug,或者开发新功能,都可以拉出一个新分支,等功能开发完成并测试通过后,再合并分支内容到主干分支上。

git 的分支使用中,不同的分支实际就是指向各个文件系统快照的指针,所以在诸多 VCSgit 提供了轻量级且高效的分支创建、切换操作。

HEAD 可以理解为一个指针,指向当前访问的分支。

git branch

git branch 命令用于查看当前的分支情况。

git branch <name>

git branch <name> 命令用于创建新分支。

git branch -d <name>

git branch -d <name> 命令用于删除指定分支。

git checkout <name>

git checkout <name> 命令用于切换到指定分支。

git checkout -b <name>

git checkout -b <name> 命令用于创建分支,并切换到新分支。相当于 git branch <name>git checkout <name> 两条命令合并到一起。


分支合并与冲突解决

当在功能分支上完成新需求的开发任务后,需要切换回主分支,并将修改内容回合到主分支上,删除该功能分支。

git merge <name>

git merge <name> 命令用于合并指定分支的修改内容到当前分支上。

merge-1

以合并 dev 分支修改内容到 master 分支为例,若 master 分支的指向处于 dev 分支的直接上游时,如图 merge-1 所示,此时合并分支速度较快,因为只需要更改 master 分支的指向即可。

after_merge

此时的合并方式为 Fast-forward 方式,因为只需要更改分支的指向,所以速度较快,且不会产生新的提交记录。

merge-2

master 分支的指向不处于 dev 的直接上游,如图 merge-2 所示,则合并过程需要比较 C3 提交的修改内容与 C4 提交的修改内容。如果两个提交中不存在对 同一处文件内容 的修改,则此时可以顺利合并修改内容,并产生一次新的合并提交,如下图中的 C5;如果两个提交中存在对 同一处文件内容 的修改,则此时合并存在冲突,需要手动解决冲突并完成合并提交。

after_merge

merge-2 所示的合并方式为 recursive 方式,或者称之为三路合并方式。因为合并 C3C4 的提交,需要与公共上游 C2 相比较,以达到与 同一处文件内容 相比较的目的,所以该合并方式主要观察 C2C3C4三个文件系统快照,所以称为三路合并方式。因为复杂情况下公共上游并不想图中所示这么明显,可能需要进行多次迭代合并处理方可产生虚拟的公共上游,所以也称此方式为 recursive 方式。


关联远程仓库

在团队协作过程中,经常的场景就是团队的每位成员都 fork 一份项目代码到自己的个人库中,然后在自己的库里面做修改,修改完成再合入到团队的项目代码库中。所以我们的本地仓库一般关联两个远程仓库,一个是团队空间的项目代码,用于拉取最新更新内容;一个是个人库中的项目代码,用于推送个人修改内容。

git remote

git remote 命令用于展示当前仓库关联的远程仓库。

git remote add <name> <address>

git remote add <name> <address> 命令用于为当前仓库添加关联的远程仓库。

git remote remove <name>

git remote remove <name> 命令用于删除当前仓库关联的远程仓库。

git fetch <name>

git fetch <name> 命令用于从远程仓库拉取最新分支信息。

git fetch <name> 命令只会拉取分支信息,生成 <remote_name>/<branch_name> 远程分支,并不会为本地仓库生成分支。

git branch -u <remote_name>/<branch_name>

git branch -u <remote_name>/<branch_name> 命令用于将当前分支与远程分支进行关联,即建立关联关系。

git checkout --track <remote_name>/<branch_name>

git checkout --track <remote_name>/<branch_name> 命令用于在本地仓库上新建分支,并与远程分支进行关联。命令 git checkout -b <branch_name> <remote_name>/<branch_name> 提供同样建立关联分支的作用。

git push <remote_name> <branch_name>

git push <remote_name> <branch_name> 命令用于推送本地仓库的分支到远程仓库上,相当于在远程仓库上建立新分支。命令 git push <remote_name> <branch_name>:<branch_name> 提供同样推送分支的作用。

使用该命令只会在远程仓库上建立新分支,并不会自动与当前仓库上的分支进行关联,所以仍需要使用前面的命令来手动建立关联关系。

git push <remote_name> --delete <branch_name>

git push <remote_name> --delete <branch_name> 命令用于删除远程仓库上的指定分支。命令 git push <remote_name> :<branch_name> 提供同样删除远程仓库分支的作用。

当使用 git clone <remote_address> 命令来构造本地仓库时,会自动建立本地分支 master,并与远程仓库分支 origin/master 进行关联。

当本地分支已经关联到远程分支之后,拉取更新和推送更新都变得较为简单。在分支上直接执行 git push 即可推送更新到关联的远程分支上,执行 git fetch 即可拉取关联分支更新,然后执行 git merge 即可合入更新到当前分支上。此外,git 还提供有命令可以直接拉取更新并合入到当前分支上,git pull 命令相当于合并了 git fetchgit merge 两个命令的功能。


版本回退

虽然有了暂存区可以检查待提交内容的正确性,但是仍不免有错误或不恰当的内容被提交,git 提供了在分支上回退版本记录的命令。

git reset <level> <commitId>

git reset <level> <commitId> 命令用于回退版本到指定提交记录点。这里 commitIdSHA1 校验和,用于标识待回退到的提交记录点。回退的 level 有三种:

  • --soft:修改 HEAD 指向指定的提交记录点,并将指定记录到最新提交记录之间的修改回退至暂存区,工作区不受影响。
  • --mixed:修改 HEAD 指向指定的提交记录点,并将指定记录与最新提交记录之间的修改回退至工作区,暂存区会被清除。
  • --hard:修改 HEAD 指向指定的提交记录点,并将指定记录到最新提交记录之间的修改清除。

该命令不填写具体 level 时,默认级别为 --mixed。这里注意一下 --hard 的使用,该级别会清除工作区和暂存区的修改,即便撤销回退操作回到最新提交,工作区和暂存区的修改也不会恢复,所以谨慎使用。同理, --mixed 级别也会清除暂存区的修改,所以版本回退过程中,需要注意选择恰当的回退方式。

执行版本回退命令时,并不一定每次都要提供指定版本记录的校验和,也可以通过 HEAD 来指定回退到相邻的哪一个版本记录。HEAD^ 表示回退到上一个版本记录,HEAD^^ 表示回退到上两个版本记录,HEAD~n 表示回退到上 n 个版本记录。

git revert <commitId>

git revert <commitId> 命令用于回退指定提交记录。

git revert <commitId> 命令和 git reset <level> <commitId> 命令都可以用于回退版本,不同之处在于 reset 用于回退到指定提交记录,revert 用于撤销指定提交记录,并且产生一个新的提交记录。

在本地仓库的分支上执行回退操作后,有些情况下可能要同步回退远程仓库。

git push -f

git push -f 命令用于同步回退当前分支关联的远程分支,因为当前分支的版本落后于远程分支,所以需要加 -f 选项,执行强制推送。


文件异同

通过 git status 只能查看出文件的状态以及是否发生了修改,并不能具体的展示出差异内容。

git diff <file>

git diff <file> 命令为查看工作目录的文件与暂存区文件的差异,也就是查看从上次提交文件修改到暂存区后,到目前为止,工作目录的文件又做了什么修改。

git diff --cached <file>

git diff --cached <file> 命令为查看暂存区的文件与当前分支的文件差异,也就是此次准备提交到分支上的有哪些修改内容。

git diff 命令还有其他形式:

git diff <branch> <file>

git diff <branch> <file> 命令为查看当前工作目录文件与其他分支文件差异。

git diff --cached <branch> <file>

git diff --cached <branch> <file> 命令为查看当前暂存区文件与其他分支文件差异。

其实工作中这种命令的使用场景不多,这里只是举个例子,说明 git diff 的使用形式是灵活多样的,例如也可以用于比较两次 commit 的差异等。


本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Jackson0714

配置Meld为git的默认比较工具

293100
来自专栏后端技术探索

推荐!手把手教你用 Git

SVN是集中式版本控制系统,版本库是集中放在中央服务器的,而干活的时候,用的都是自己的电脑,所以首先要从中央服务器哪里得到最新的版本,然后干活,干完后,需要把自...

10020
来自专栏Java成神之路

Git之 基本常用命令

   git init          把当前的目录变成可以管理的git仓库,生成隐藏.git文件。

7140
来自专栏哲学驱动设计

版本分支管理标准

35320
来自专栏Samego开发资源

常用Git命令记录

16350
来自专栏java沉淀

git安装教程和git命令使用详解

18340
来自专栏后端技术探索

推荐!手把手教你用 Git

SVN是集中式版本控制系统,版本库是集中放在中央服务器的,而干活的时候,用的都是自己的电脑,所以首先要从中央服务器哪里得到最新的版本,然后干活,干完后,需要把自...

6420
来自专栏CodingToDie

GIT 使用(二):创建仓库并提交代码

基本操作 所用命令使用 windows 下安装 git-bash 运行 Table of Contents 先决条件 已经安装了 GIT 客户端 已经设置用户信...

44050
来自专栏玩转JavaEE

Git基本操作

上篇文章我们简单的介绍了Git的诞生和发展,然后也说了Windows环境下Git的安装和一些基本的配置,本文我们就来说一说Git中的一些基本概念和基本操作。 本...

30780
来自专栏JMCui

Git学习笔记.

Git 的工作就是创建和保存你项目的快照及与之后的快照进行对比 Git 与 SVN 区别 GIT不仅仅是个版本控制系统,它也是个内容管理系统(CMS),工作管理...

36350

扫码关注云+社区

领取腾讯云代金券