初始化本地 Git 仓库:
通过 git init
初始化,可以把当前目录变成了 Git 管理的本地仓库。目前仅仅是做了一个初始化仓库的操作,项目里的文件还没有被跟踪。
在当前目录下会出现一个名为
.git
的目录,这些文件是 Git 仓库的核心。
如果没有看到.git
目录,那是因为这个目录默认是隐藏的,用ls -ah
命令就可以看见。
- hooks:包含客户端或服务端的钩子脚本。
- info:包含一个全局性排除文件。
- logs:保存日志信息。
- objects:存储所有数据内容。
可以通过
find .git/objects/ -type f
可以查看 objects 目录下的文件。
- refs:存储指向数据的提交对象的指针(分支)。
- config:包含项目特有的配置选项。
- description:用来显示对仓库的描述信息。
- HEAD:指示目前被检出的分支。
- index:保存暂存区信息。
可以通过
git ls-files -s
可以查看暂存区的内容。
Git 区域:
- 工作区:就是在电脑里能看到的项目目录。用来写代码。
- 版本库:
.git
不算工作区,而是 Git 的版本库。用来实实在在存储代码及其历史版本。 - 暂存区:存放在
.git
目录下的 Index 文件。用来临时存储代码。
本地仓库的操作命令:
创建本地仓库:
- 创建一个空文件夹。
- 通过
git init
命令把这个目录变成 Git 可以管理的本地仓库。
添加文件到本地仓库:
可反复多次使用
git add
添加多个文件,通过git commit
一次提交。
-
在当前目录下新建一个文档。
-
使用
git add xxx.xx
命令,把工作区文件的新建/修改添加到暂存区。查看
.git/index
文件 和.git/objects
下的文件可以发现都有了一条记录。这说明:git add
是先将工作区的修改做成 git 对象放到版本库,然后再从版本库中拿出来放到暂存区中。
在版本库中只能跟踪和管理文本文件,比如 txt 文件、js 文件、php 文件、java 文件等,所有的程序代码都可以的。但是像视频、图片等这些二进制文件,虽然能由 git 管理,但是只能记录大小,无法跟踪具体修改了什么。
-
使用
git commit -m "xxxxx"
命令,将暂存区的内容提交到本地仓库中。-m
后面输入的是本次提交的说明。
查看状态:
git status
命令展示的是工作区和暂存区的状态。
git init
初始化之后,git status
查看一下状态,终端显示如下信息:On branch master // 当前为 master 分支 No commits yet // 本地仓库还没有任何提交 nothing to commit (create/copy files and use "git add" to track) // 暂存区没有什么可提交的
- 新建 index.txt 文件,然后
git status
查看一下状态,终端显示如下信息:On branch master // 当前为 master 分支 No commits yet // 本地仓库还没有任何提交 Untracked files: // 工作区中还没有被跟踪的文件,也就是还没有 add 的文件,add 之后将会进入暂存区 (use "git add <file>..." to include in what will be committed) index.txt nothing added to commit but untracked files present (use "git add" to track) // 暂存区没有任何提交,但是工作区存在没有被跟踪的文件
git add index.txt
将 index.txt add 到暂存区,然后git status
查看一下状态,终端显示如下信息:On branch master // 当前为 master 分支 No commits yet // 本地仓库还没有任何提交 Changes to be committed: // 暂存区将要被提交的修改,也就是已经从工作区 add 到暂存区中的文件,commit 之后将进入本地仓库 (use "git rm --cached <file>..." to unstage) // 使用 ”git rm --cached <file>“ 将从暂存区删除并取消跟踪文件,恢复到 add 之前的状态 new file: index.txt
git commit index.txt -m 'first commt: index.txt'
将index.txt
提交到本地仓库,然后git status
查看一下状态,终端显示如下信息:On branch master // 当前为 master 分支 nothing to commit, working tree clean // 暂存区没有什么可提交的,工作区的树也是干净的
- 修改 index.txt 文件的内容,然后
git status
查看一下状态,终端显示如下信息:On branch master // 当前为 master 分支 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) // 可以使用 "git restore <file>..." 丢弃在工作区的修改 modified: index.txt no changes added to commit (use "git add" and/or "git commit -a") // 暂存区没有被添加的修改,也就是这个文件在工作区、暂存区都存在,在工作区进行了一些新的修改,但是这部分修改还没 add 到暂存区
版本的前进与后退:
- 在上面
git status
查看状态的操作的基础上,将 index.txt 修改的内容也提交到本地仓库。 - 执行
git log
查看一下历史记录, 终端显示如下信息:版本回退后,git log 看不到版本回退之后的提交记录,git relog 可以看到所有的版本提交记录。
commit 7d32b404e1c71fd4ed66a4e22d70b265bee9d307 (HEAD -> master) // 7d32b404e1c71fd4ed66a4e22d70b265bee9d307 哈希值为当次提交的索引 Author: test <test@163.com> Date: Thu Sep 30 16:22:22 2021 +0800 second commit:idex.txt commit bbeac607be274343dc74099887b9cee40e50d3a3 Author: test <test@163.com> Date: Thu Sep 30 11:13:15 2021 +0800 BAN first commit:index.txt // 或者使用 git log --pretty=oneline,来让每一条日志只显示一行,更加简洁 7d32b404e1c71fd4ed66a4e22d70b265bee9d307 (HEAD -> master) second commit:idex.txt bbeac607be274343dc74099887b9cee40e50d3a3 first commit:index.txt // 或者使用 git log --oneline,不仅可以让每一条日志只显示一行,而且缩短了哈希值,更加简洁 7d32b40 (HEAD -> master) second commit:idex.txt bbeac60 first commit:index.txt // 或者使用 git reflog 7d32b40 (HEAD -> master) HEAD@{0}: commit: second commit:idex.txt bbeac60 HEAD@{1}: commit (initial): first commit:index.txt // HEAD@{1} 表示移动到当前版本需要1步
- Git 在管理历史记录的时候,有一个指针,指针的名字就叫 HEAD,版本的前进或后退就是在移动 HEAD。
git reset
命令的三个参数:--soft
:仅仅在本地库移动 HEAD 指针。--mixed
:不仅在本地库移动 HEAD 指针;而且会重置暂存区。--hard
:不仅在本地库移动 HEAD 指针;而且会重置暂存区,还会重置工作区。
// 1. 基于索引去操作(推荐):git reset --hard bbeac60 HEAD is now at bbeac60 first commit:index.txt // 此时,再 git reflog 查看一下历史记录: bbeac60 (HEAD -> master) HEAD@{0}: reset: moving to bbeac60 7d32b40 HEAD@{1}: commit: second commit:idex.txt bbeac60 (HEAD -> master) HEAD@{2}: commit (initial): first commit:index.txt // 2. 使用 ^ 符号:git reset --hard HEAD^(需要后退几步就写几个 ^ 符号。只能后退不能前进) // 3. 使用 ~ 符号:git reset --hard HEAD~1(需要后退几步就写几。只能后退不能前进)
比较文件:
git diff 【文件名】
:比较的是此文件工作区和暂存区的区别。不带文件名比较的是所有文件。
git diff 【本地仓库中的某个历史版本】 【文件名】
:比较的是此文件工作区与本地仓库中某个历史版本的区别。不带文件名比较的是所有文件。
- 新建 add.txt 文件并输入一些内容,执行
git add add.txt
。 - 修改 add.txt 文件的内容,然后执行
git diff index.txt
, 终端显示如下信息:Git 是以行为单位来管理文件的。
diff --git a/add.txt b/add.txt index a8500fc..b544c22 100644 --- a/add.txt +++ b/add.txt @@ -1,3 +1,3 @@ qqq -www // 减号代表删除的行 +wwwwww // 加号代表增加的行 eee
本地储藏:
git stash
:会把所有未提交的修改(包括暂存的和非暂存的)都保存起来,用于后续恢复当前的工作目录。
想删掉文件又担心以后需要查看它的代码,想保存它但又不想增加一个脏的提交,这时就可以考虑
git stash
。
- 实际应用中推荐给每个 stash 加一个 message,用于记录版本,使用
git stash save "xxx"
取代git stash
命令。 - 可以通过
git stash pop
命令恢复之前储藏的工作目录。
分支:
在版本控制过程中,使用多条线同时推进多个任务,这就是分支。
使用分支的好处:
- 可以同时并行推进多个功能的开发,提供开发效率。
- 各个分支之间互不影响,即使某个分支开发失败,也不会其他任何分支有影响。
Git 分支管理的本质就是创建和移动指针,创建分支其实就是创建一个新的指针,切换分支其实就是移动指针。
SVN 中创建分支是将目录和文件全部都复制一套出来。
版本库初始化之后,默认会有一条 master 主分支,HEAD 指向 master 分支;如果新建一个 testing 分支,其实就是新建一个指针指向 f30ad 这个版本。
查看分支:
使用 git branch
查看分支。
* master // 前面的 * 号表示当前正在这个分支上
创建分支:
使用 git branch hot_fix
创建 hot_fix 分支,然后使用 git branch
查看一下分支。
hot_fix
* master // 前面的 * 号表示当前正在这个分支上
切换分支:
使用 git checkout hot_fix
切换到 hot_fix 分支上,然后使用 git branch
查看一下分支。
* hot_fix
master
- 如果在 master 分支上修改了 index.txt 文件的内容,但是只在工作区做了修改,并没有 add 到暂存区和提交到本地仓库中,那么如果切换到 hot_fix 分支,index.txt 修改的内容也将被带过去。
修改的内容在哪个分支上提交,将会归属于哪个分支,另一个分支就不会再显示这部分内容了。
- 如果在 master 分支上修改了 index.txt 文件的内容,但是只在工作区做了修改和 add 到了暂存区,并没有提交到本地仓库,那么如果想要切换到 hot_fix 分支将会被 Git 阻止。
创建+切换分支:
可以使用 git checkout -b 【分支名】
直接创建并且切换分支。
删除分支:
首先当前所在的分支不能是想要删除的分支,然后使用 git branch -d 【分支名】
即可删除。
合并分支:
- 当前正在 hot_fix 分支上,修改 index.txt 文件的内容并提交到本地仓库。
- 使用
git checkout master
切换到 master 分支上,然后使用git merge hot_fix
将 hot_fix 合并到 master 分支上。Updating 373446c..b4f6025 Fast-forward // 如果顺着一个分支走下去能够到达另一个分支,那么 Git 在合并两者的时候,只会简单地将指针向前推进,这就叫做快进(fast-forward) index.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
解决冲突:
如果在两个不同的分支中,对同一个文件的同一个部分进行了不同的修改,那么对这两个分支进行合并时就会产生冲突。
- 当前在 master 分支上,对 index.txt 文件的第三行进行修改并提交到本地仓库。
- 使用
git checkout hot_fix
切换到 hot_fix 分支上,也对 index.txt 文件的第三行进行修改并提交到本次仓库。 - 此时使用
git merge master
将 master 分支合并到 hot_fix 分支上,会出现冲突,终端中显示如下:
以 VSCode 为例,在 index.txt 文件中显示如下:Auto-merging index.txt CONFLICT (content): Merge conflict in index.txt Automatic merge failed; fix conflicts and then commit the result.
删除特殊符号、留下想要的内容来解决冲突。 - 此时使用
git status
来查看一下状态:On branch hot_fix You have unmerged paths. (fix conflicts and run "git commit") (use "git merge --abort" to abort the merge) Unmerged paths: (use "git add <file>..." to mark resolution) // 使用 git add 来标记冲突的解决 both modified: index.txt no changes added to commit (use "git add" and/or "git commit -a")
- 使用
git add index.txt
来标记冲突的解决,再次使用git status
来查看一下状态:On branch hot_fix All conflicts fixed but you are still merging. (use "git commit" to conclude merge) // 使用 git commit 来结束合并 Changes to be committed: modified: index.txt
- 使用
git commit -m 'resolve conflict
来结束合并并提交。