开始使用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.html
从Untracked
变成了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的过程种会遇到这三个区域了,这三个区域的关系和联系就这么简单
通过上面的图,你会发现从工作区可以直接到存储库,通过
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对象是干什么用的
2022/12/26虽然书上是这么说的,但是我的本地环境下却会改变,有可能是git版本不一样了,待我探索一番,虽然这个变化没什么太大的关系
经过我的一番探索,发现这个SHA-1的值还和commit的时间有关系,我们继续往后探索,看看那个计算公式是什么样的