第二章:Git的基本使用

GIT的基本使用

1、创建仓库并初始化

//查看某个命令文档
git help <command>
git <command> -h
git <command> --help

# 1、创建仓库
mkdir /Users/linhaifeng/pro 

# 2、初始化,表示即将对当前文件夹进行版本控制
cd /Users/linhaifeng/pro 
git init 

#注意
1、
创建版本库,版本库又名仓库,英文名repository,你可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。

2、
在仓库目录下执行git init后会生成一个隐藏目录.git,该隐藏目录就是Git用来跟踪管理版本库的,没事千万不要手动修改这个目录里面的文件,不然改乱了,就把Git仓库给破坏了。

3、
如果你使用Windows系统,为了避免遇到各种莫名其妙的问题,请确保目录名(包括父目录)不包含中文。

4、
后期的git命令都需要在仓库目录下执行,在仓库目录外执行git命令是没有意义的

2、工作区与版本库

Git只能管理文本文件不能管理二进制文件

所有的版本控制系统,其实只能跟踪文本文件的改动,比如TXT文件,网页,所有的程序代码等等,Git也不例外。版本控制系统可以告诉你每次的改动,比如在第5行加了一个单词“Linux”,在第8行删了一个单词“Windows”。而图片、视频这些二进制文件,虽然也能由版本控制系统管理,但没法跟踪文件的变化,只能把二进制文件每次改动串起来,也就是只知道图片从100KB改成了120KB,但到底改了啥,版本控制系统不知道,也没法知道。

不幸的是,Microsoft的Word格式是二进制格式,因此,版本控制系统是没法跟踪Word文件的改动的,前面我们举的例子只是为了演示,如果要真正使用版本控制系统,就要以纯文本方式编写文件。

因为文本是有编码的,比如中文有常用的GBK编码,日文有Shift_JIS编码,如果没有历史遗留问题,强烈建议使用标准的UTF-8编码,所有语言使用同一种编码,既没有冲突,又被所有平台所支持。

使用Windows的童鞋要特别注意:

千万不要使用Windows自带的**记事本**编辑任何文本文件。原因是Microsoft开发记事本的团队使用了一个非常弱智的行为来保存UTF-8编码的文件,他们自作聪明地在每个文件开头添加了0xefbbbf(十六进制)的字符,你会遇到很多不可思议的问题,比如,网页第一行可能会显示一个“?”,明明正确的程序一编译就报语法错误,等等,都是由记事本的弱智行为带来的。建议你下载Notepad++代替记事本,不但功能强大,而且免费!记得把Notepad++的默认编码设置为UTF-8 without BOM即可

Git每一次提交版本保存的都是对文件内容的完整快照,快照作何解释呢?

  • 1、针对已变化的文件,那么git保存的是把该文件的完整内容拷贝一份保存下来,而不是差异变化或者文件补丁。因此你可以完全恢复到以前的任一个提交而不会发生任何区别。

  • 2、未变化的文件只保存上一个版本的指针

所以:

如果我的项目大小是10M,那Git占用的空间是不是随着提交次数的增加线性增加呢?我提交(commit)了10次,占用空间是不是100M呢?很显然不是,Git是很智能的,如果文件没有变化,它只会保存一个指向上一个版本的文件的`指针`,即,对于一个特定版本的文件,Git只会保存一个副本,但可以有多个指向该文件的`指针`。

另外注意

Git最适合保存文本文件,事实上Git就是被设计出来就是为了保存文本文件的,像各种语言的源代码,因为Git可以对文本文件进行很好的压缩和差异分析(大家都见识过了,Git的差异分析可以精确到你添加或者删除了某个字母)。而二进制文件像视频,图片等,Git也能管理,但不能取得较好的效果(压缩比率低,不能差异分析)。实验证明,一个 500k 的文本文件经Git压缩后仅 50k 左右,稍微改变内容后两次提交,会有两个 50k 左右的文件,没错的,保存的是完整快照。而对于二进制文件,像视频,图片,压缩率非常小, Git 占用空间几乎随着提交次数线性增长。

Git把管理的文本文件分为两个区域、四种状态。

  • 1、工作区:即仓库目录

    # 当前开发程序所在目录称为工作区,即:工作开发都是在该目录。在我们提交一个版本到版本库后,git会自动检测自该版本之后我们对仓库目录下文件的改动(增、删、改),并标记为修改过的内容,我们可以使用 【git status】命令查看,如下所示
    
    $ cd /Users/linhaifeng/pro  # 必须确保已经在仓库目录下执行git命令
    
    $ git status # 查看当前git状态,未检测到任何变化
    
    $ echo "hello egon" >> readme.txt # 在仓库目录下或仓库的子目录下新增文件
    
    $ git status # git会自动检测到工作区的变化:新增了文件readme.txt,显示内容略
  • 2、版本库:即仓库目录下的.git目录,.git不属于工作区

    # 如果我们想将git检测到的修改过的内容提交为一个新的版本,需要
    # 1、先将git检测到的修改过的内容添加到暂存区,用到【git add】命令
    git add 文件1  # 可以添加单个文件
    git add 文件1 文件2  # 也可以添加多个文件
    git add . # 也可以直接添加整个当前目录
          #当然,也可以add多次
    
    # 2、然后再执行【git commit -m '又一个版本'】提交到版本库的分支即可
    git commit -m "第一次提交"
    
    # 注意:执行git commit 命令时,可能会提示进行用户和邮箱的配置,该配置用于记录当前版本由那个用户提交
    git config --local user.name 'egon'
    git config --local user.email 'egon@example.com'
    配置级别
    –local(默认,高级优先):只影响本地仓库
    –global(中优先级):只影响所有当前用户的git仓库
    –system(低优先级):影响到全系统的git仓库
    
    # 3、之后可以使用【git log】命令查看版本记录。
    git log
    git log --pretty=oneline  # 如果嫌输出信息太多,可以加上--pretty=oneline参数
    git log --color --graph
    查看reflog,用于找到回滚后的日志
    git reflog

3、命令小结

目前已使用命令如下,使用下述命令已经可以代替本地多个文件保存版本的方式

# 一:创建并初始化仓库
mkdir /Users/linhaifeng/pro  
cd /Users/linhaifeng/pro 
git init 

# 二:设置用户与邮箱
git config --local user.name 'Egon'
git config --local user.email 'egon@example.com'

# 三:查看Git当前状态,如:哪些文件被修改过、哪些文件还在暂存区里尚未被提交到版本库等。
git status 

# 四:将检测到修改的文件添加到暂存区
git add 文件名 

# 五:将暂存区的文件提交到版本库的分支。
git commit -m '提交信息' 

# 六:查看提交记录,即:历史版本记录
git log 
git log --pretty=oneline 

git reflog

4、版本回退与前进

我们创建Git版本库时,Git自动为我们创建了唯一一个master分支,所以,目前为止,我们执行的git commit就是往master分支上提交更改。

Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEADHEAD指针指向的就是当前在用的版本

Git的版本回退速度非常快,因为当你回退版本的时候,Git仅仅是把HEAD指向了一个指定的版本,然后顺便把工作区的文件更新了。

从当前版本,回到过去的版本,按图所示是向左回退

当前版本为版本3,回退到版本1,命令如下

# 1、查看版本信息
$ git log --pretty=oneline 
87e199e0a766ecb10028ab93fe57fb4b326445fa (HEAD -> master) 版本3
353b5afb8784f0e19c8dab83be1cb97a93b13bd4 版本2
b740905aaf2753572a714ccdf3bd58a1d437148a 版本1

# 2、回滚到上一个版本
# 2.1 方式1:HEAD指向当前版本,HEAD^代表指向当前版本的上一个,HEAD^^代表指向当前版本的上上个,依次类推,HEAD~n代表指向当前版本的上上上...n个
$ git reset --hard HEAD^  # 如果执行的是git resert --hard HEAD~2 往后数两个版本,就会回到版本1
HEAD is now at 353b5af 版本2

# 2.1 方式2:回到某个指定的版本用git log查询出的commit id号
$ git reset --hard 353b5afb8784f0e19c8dab83be1cb97a93b13bd4

从当前版本,回到未来的版本,按图所示是向右前进

当前版本为版本1,前进到版本3,命令如下

 # 1、用git log查看会发现最新的版本“版本3”不见了!!!
$ git log --pretty=oneline
353b5afb8784f0e19c8dab83be1cb97a93b13bd4 (HEAD -> master) 版本2
b740905aaf2753572a714ccdf3bd58a1d437148a 版本1

# 2、我们当然可以在命令终端中往上翻阅查找当初版本3还在时,我们用git log查出的commit id进行操作,但是这种做法毕竟不靠谱。我们可以用更靠谱的命令
$ git reflog
......
87e199e HEAD@{6}: commit: 版本3
353b5af HEAD@{7}: commit: 版本2
b740905 (HEAD -> master) HEAD@{8}: commit (initial): 版本1

# 3、前进到版本3
$ git reset --hard 87e199e
HEAD is now at 87e199e 版本3

总结:

  • 1、HEAD指向的版本就是当前版本,因此,Git允许我们在版本的历史之间穿梭,使用命令git reset --hard commit_id
  • 2、穿梭前,用git log可以查看提交历史,以便确定要回退到哪个版本。
  • 3、要重返未来,用git reflog查看命令历史,以便确定要回到未来的哪个版本。

5、撤销修改

场景1:已经提交了不合适的修改到版本库时,想要撤销本次提交,参考上一小节版本回退,不过前提是没有推送到远程库。

场景2:

​ 前提:如果当前文件的内容已经被提交到版本库

​ 操作:之后又修改了该文件,并且git add添加到了暂存区,后续又修改了文件

​ 撤销:

先执行git reset HEAD `将文件从暂存区拿回工作区

再执行git checkout — `将工作区的修改还原到原来的状态(即上一次git commit的状态)

场景3:

​ 前提:如果当前文件的内容从未被提交到版本库

​ 操作:修改了该文件,并且git add添加到了暂存区,后续又修改了文件

​ 撤销:

此时无法执行git reset HEAD `

应该执行git checkout — `将工作区的修改还原到git add时文件的内容

总之,git checkout — 就是让这个文件回到最近一次git commitgit add`时的状态。

file

注意,

git checkout -- file命令中的--很重要,没有--,就变成了“切换到另一个分支”的命令,我们在后面的分支管理中会再次遇到git checkout命令。

6、管理修改

Git比其他版本控制系统优秀的一个重要原因就是:Git跟踪并管理的是修改,而非文件。每次修改都需要先add到暂存区,才能提交到版本库,如果每次修改后,不用add添加到暂存区,就不会被commit提交到版本库

$ echo "hello" > a.txt # 第一次修改
$ git add a.txt 
$ echo "world" >> a.txt  # 第二次修改,本次修改并没有add到暂存区,暂存区的a.txt内容为“hello”
$ git commit -m "版本1" # 把暂存区的内容提交到版本库

$ git status  # 查看到第二次修改仍然存在于工作区,并未提交
$ git diff HEAD -- a.txt # 可以用命令查看版本库最新版本与工作区的区别
diff --git a/a.txt b/a.txt
index ce01362..94954ab 100644
--- a/a.txt
+++ b/a.txt
@@ -1 +1,2 @@
 hello
+world

上述情况,我们可以在版本1的基础上继续操作:将第二次修改也add到暂存区,然后再commit一个“版本2”到版本库,也可以在当初的时候先别着急将第一次的修改commit提交成”版本1“,先将第二次修改的内容也add到暂存区,然后与第一次的修改合并到一起提交成一个版本

7、删除文件

在Git中,删除也是一个修改操作,我们实战一下,先添加一个新文件test.txt到Git并且提交:

$ git add test.txt

$ git commit -m "v1"

一般情况下,你通常直接在文件管理器中把没用的文件删了,或者用rm命令删了:

$ rm test.txt

这个时候,Git知道你删除了文件,因此,工作区和版本库就不一致了,git status命令会立刻告诉你哪些文件被删除了:

$ git status
On branch master
Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    deleted:    test.txt

no changes added to commit (use "git add" and/or "git commit -a")

现在你有两个选择,一是确实要从版本库中删除该文件,那就用命令git rm删掉,并且git commit

$ git rm -f test.txt
rm 'test.txt'

$ git commit -m "remove test.txt"
[master d46f35e] remove test.txt
 1 file changed, 1 deletion(-)
 delete mode 100644 test.txt

现在,文件就从版本库中被删除了。

补充:

可以配置.gitignore配置忽略文件,这些文件不被git追踪

git rm --cached :仅从暂存区删除
git rm :从暂存区与工作目录同时删除
git rm $(git ls-files --deleted):删除所有被跟踪,但是在工作目录被删除的文件

小提示:先手动删除文件,然后使用git rm 和git add效果是一样的,都会从版本库中删除掉文件。

另一种情况是删错了,因为版本库里还有呢,所以可以很轻松地把误删的文件恢复到最新版本:

$ git checkout -- test.txt

git checkout其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。

注意:从来没有被添加到版本库就被删除的文件,是无法恢复的!

小结

命令git rm用于删除一个文件。如果一个文件已经被提交到版本库,那么你永远不用担心误删,但是要小心,你只能恢复文件到最新版本,你会丢失最近一次提交后你修改的内容

上一篇
下一篇
Copyright © 2022 Egon的技术星球 egonlin.com 版权所有 帮助IT小伙伴学到真正的技术