git 学习笔记 2
start at 2022/12/25.

开始使用Git

新增、初始Repository

  • 从头开始
$ cd /tmp
$ mkdir git-practice
$ cd git-practice
$ git init

上面三条指令都是系统自带的指令,只有最后一条是属于git的,实际上它的作用就是在当前目录创建一个.git文件夹,这个文件夹就是git的精髓了,后面再讲这个文件夹里面的内容

  • 从已存在的目录开始

    直接输入 git init 即可

  • 如果不想让当前目录再被git控制

    git的本质就是靠.git文件夹,你只需要删除.git文件夹即可

  • /tmp文件夹是什么

    看作者的话应该是macOS系统下临时文件夹,每次重启都会被清空,没用过mac,没想到mac还能这么随便。linux的/tmp好像是用来缓存的,看了下里面还有一些文件夹,应该不会每次重启自动清理,不过linux想实现那种功能倒也只是在autostart里一行rm的事

把文件交给Git管控

  • 创建文件后交给Git

    $ git status
    On branch main
    
    No commits yet
    
    nothing to commit (create/copy files and use "git add" to track)
    

    因为当前文件夹除了.git文件夹之外什么都没有,所以提示我们nothing to commit
    顺带提一下,上面的输出我是用输出流重定向到文件里复制过来的,第一次我重定向到仓库的文件夹里,发现status提示我新增了一个文件,这说明流重定向到文件时是先创建文件再输入输出,和我预想的不一样

    让我们继续,照着书上在当前文件夹创建一个helloworld,echo "hello, git" > welcome.html
    然后我们再来看git status

    $ git status
    On branch main
    
    No commits yet
    
    Untracked files:
      (use "git add <file>..." to include in what will be committed)
        welcome.html
    
    nothing added to commit but untracked files present (use "git add" to track)
    

    现在的情况和之前就有所不同的,这个文件当前处于的状态是Untracked files

  • 把文件交给Git

    $ git add welcome.html
    

    这条命令并不会有输出,但是它把welcome.html交给了Git,把Untracked变成tracked状态

    让我们再来看看status

    $ git status
    On branch main
    
    No commits yet
    
    Changes to be committed:
      (use "git rm --cached <file>..." to unstage)
        new file:   welcome.html
    

    我们发现我们的welcome.htmlUntracked变成了new file,这样我们的文件就被安置到暂存区了,可以被我们存储到存储库中去

    你一定会觉得每次只add一个文件很低效,别着急,有快的

    $ git add *.html
    

    这样就能把所有后缀为html的文件都添加到暂存区,如果想要一口气把全部文件都加入到暂存区,可以直接使用--add参数

    $ git add --all
    
  • 修改已经被git add的文件后怎么办?

    $ touch abc.txt
    $ git add abc.txt
    $ echo 1>abc.txt
    $ git status
    On branch main
    
    No commits yet
    
    Changes to be committed:
      (use "git rm --cached <file>..." to unstage)
        new file:   abc.txt
    
    Changes not staged for commit:
      (use "git add <file>..." to update what will be committed)
      (use "git restore <file>..." to discard changes in working directory)
        modified:   abc.txt
    

    我们发现有两个abc.txt,其实只有一个abc.txt,第二行里确实把abc.txt放到了暂存区里,但是在第三行我们修改了这个文件,对Git来说,此时暂存区是修改前的abc.txt,而修改后的文件没有加入暂存区,如果你确实修改是你想要的,可以再git add abc.txt来存入暂存区

  • --all.参数有什么不一样
    你可能知道 git add . 也可以把所有文件加入暂存区,但其实这句话不完全正确

    • Git版本

      在旧版本的Git(1.x)中,git add .--all 的区别在于前者不会处理删除文件的行为

      • 旧版本
      使用参数 新增文件 改动文件 删除文件
      –all O O O
      . O O X
      • 新版本
      使用参数 新增文件 改动文件 删除文件
      –all O O O
      . O O O

      也就是说,Git 2.x 之后两个就一样了

    • 执行命令时的目录位置

      git add . 只会把当前目录的所有子目录改动都加入暂存区,但不会把父文件夹以及同项目中其他位置的文件加入暂存区, 而git add --all就会把整个项目的所有变动都加入暂存区,即使当前没有处于项目的根目录

  • 把暂存区的内容提交到存储库里存档

    git add 只是将更改加入暂存区,顾名思义只是暂存,如果要把暂存给保存下来,就要commit了,使用 git commit -m "xxx"

    $ git commit -m "init commit"
    [main (root-commit) 8c2de2b] init commit
     1 file changed, 1 insertion(+)
     create mode 100644 welcome.html
    

    -m 后面是提交说明,要说明这次做了什么事情,英文中文都行,要做到简单易懂

    • commit了啥

      Git每次commit只会处理暂存区里的内容,如果你有文件没有git add 他是不会处理那些文件的

    • 输入的信息

      每次commit必须输入信息

      • 不要用过于情绪化的字眼
      • 简单明了
      • 不要用类似bug fixed的描述,每人知道你修复了什么bug,除非有bug提前被标记了
    • 什么都没有改变不能提交吗?

      可以通过git commit --allow-empty -m "XXX" 提交空的commit,这个操作没有什么意义,但是方便练习后面的合并

工作区,暂存区,存储库

通过上面的内容已经知道使用git的过程种会遇到这三个区域了,这三个区域的关系和联系就这么简单

202212261501

工作区,暂存区,存储库
  • 通过上面的图,你会发现从工作区可以直接到存储库,通过 git commit -a -m "xxx" 就可以直接将所有已跟踪的文件的修改直接提交到存储库里,但是注意,新添加的文件(Untracked files)是没法被提交的

  • 为什么一定要用二段式那么麻烦呢?

    先add再commit,这样的二段式可能会让你觉得有点烦琐,但这样做是有一定的好处的,当你完成一个文件的修改时,可以先把它git add 进暂存区,等暂存区的文件到一定的数量时再 git commit ,这样就方便记录下这些文件的作用。如果你想要每完成一个文件就 commit 会导致commit太琐碎,让其他人查看代码的时候会觉得很麻烦

  • 什么时候可以commit?

    • 完成一个任务
    • 下班的时候
    • 想Commit的时候
    • 没有标准答案,取决于coder的心情(?

查看记录

使用 git log 就可以查看之前的commit了

$ git log
commit ed0fe3b7753ba49d0923d85100786bdba693ef1d (HEAD -> master)
Author: lol <233@qq.com>
Date:   Mon Dec 26 23:26:59 2022 +0800

    add c.vim

commit aaa37137a002593fc26ffe1a5366ed4a54db2c67
Author: lol <233@qq.com>
Date:   Mon Dec 26 22:47:35 2022 +0800

    b

commit 2bcd045a50439781c124e33ce9b7caea0bf5c8c3
Author: lol <233@qq.com>
Date:   Mon Dec 26 22:47:16 2022 +0800

    add a.vim

越新的commit在越上面,通过输出的信息,大致可以知道三个信息

  • Commit的作者是谁
  • 在什么时候Commit的
  • 这次Commit大概做了什么事情

那堆乱码其实是通过SHA-1(Secure Hash Algorithm 1)计算来的,计算方式在后面会讲,它的作用类似于每个commit的身份证,因为碰撞率很低

如果在git log 后面加上参数,可以看到不同的结果 git log --online --graph

$ git log --oneline
ed0fe3b (HEAD -> master) add c.vim
aaa3713 b
2bcd045 add a.vim
$ git log --graph
* commit ed0fe3b7753ba49d0923d85100786bdba693ef1d (HEAD -> master)
| Author: lol <233@qq.com>
| Date:   Mon Dec 26 23:26:59 2022 +0800
|
|     add c.vim
|
* commit aaa37137a002593fc26ffe1a5366ed4a54db2c67
| Author: lol <233@qq.com>
| Date:   Mon Dec 26 22:47:35 2022 +0800
|
|     b
|
* commit 2bcd045a50439781c124e33ce9b7caea0bf5c8c3
  Author: lol <233@qq.com>
  Date:   Mon Dec 26 22:47:16 2022 +0800

      add a.vim
$ git log --oneline --graph
* ed0fe3b (HEAD -> master) add c.vim
* aaa3713 b
* 2bcd045 add a.vim

和在命令行里查看提交历史比起来,在图形界面里看提交历史其实更方便一点,但功能都是相似的

Git查询历史记录时的常见问题

  • 想要查找某人的commit

    git log --author="xxx"

  • 想要通过commit信息中的关键字检索

    git log --grep="xxx"

  • 想在Commit文件里面找到Ruby

    git log -S "Ruby"

  • 想要查找某一段时间段内的Commit

    今天早上9点-12点

    git log --since="9am" --until="12am"

    从2017年1月以后的每个早上9点-12点

    git log --since="9am" --until="12am" --after="2017-01"

在Git中删除文件或者变更文件名

在Git中,无论是删除文件还是变更文件名的本质都是一样的,都是“改动”

删除文件

我们可以直接手动删除,然后我们看一下git status

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

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

可以看到a.vim的状态是deleted,如果你想要删除就可以git add a.vim

$ git add a.vim
$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        deleted:    a.vim

现在这个改动被添加到暂存区了,只需要commit就行了

你也可以让Git帮你删除 git rm a.vim

$ git rm a.vim
rm 'a.vim'
[paradox@windows git]$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        deleted:    a.vim

相当于帮你做好了删除和 git add 这两步,后面还是需要 commit

无论是 rm 还是 git rm 都会真的把这个文件从工作目录中删除,如果你不算真的想把这个文件删除,只是不想让Git再跟踪这个文件了,可以使用 git rm a.vim --cached

$ git rm a.vim --cached
rm 'a.vim'
$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        deleted:    a.vim

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        a.vim

$ ls
a.vim  c.vim

我们可以看到,只是从Git上删除了a.vim,但是它还是存在在我们的工作区里

变更文件名

$ mv c.vim d.vim #把c.vim改名成d.vim
$ git status
On branch master
Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        deleted:    c.vim

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        d.vim

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

我们可以看到,git把这步操作看成两步,删除了c.vim再添加了一个d.vim

然后我们来 git add 一下

$ git add d.vim
$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   d.vim

Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        deleted:    c.vim

$ git add c.vim
$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        renamed:    c.vim -> d.vim

发现把d.vim和c.vim都 git add 了,git就识别出是 renamed 了,这是因为文件的内容没有改变,git判断出这只是单纯的改名

如果我们再往d.vim里添加一些内容

$ echo 6 > d.vim
$ git add d.vim
$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        deleted:    c.vim
        new file:   d.vim

git并没有识别成 renamed 再加上 modified

你也可以让git帮你改名 git mv c.vim d.vim

$ git mv c.vim d.vim
$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        renamed:    c.vim -> d.vim

事实上,文件的名称并不重要,Git其实是根据文件的内容来计算SHA-1的值的,重要的是文件的内容。当更改文件名的时候,Git并不会为此做出一个新的Blob对象,只是指向原来的Blob对象,但是因为文件名变了,所以Git会为此做出一个新的Tree对象,后面会解释Git对象是干什么用的

虽然书上是这么说的,但是我的本地环境下却会改变,有可能是git版本不一样了,待我探索一番,虽然这个变化没什么太大的关系

经过我的一番探索,发现这个SHA-1的值还和commit的时间有关系,我们继续往后探索,看看那个计算公式是什么样的

2022/12/26
> CLICK TO back <