git深入学习笔记

git文件夹探秘

  1. 当初始化仓库的时候,会创建一个.git文件夹,其中包含以下内容:
  • hooks 文件夹 (包含客户端服务端的钩子脚本,如pre-push,pre-merge)
  • info 文件夹 (包含一个全局性排除文件)
  • object 文件夹 (存储所有数据内容)
  • refs 文件夹 (存储指向分支的提交对象的指针)
  • config 文件 (包含项目特有的配置选项)
  • description 文件 (用来显示对仓库的描述信息)
  • HEAD 文件 (指示目前被检出的分支)

底层命令

git对象

git的核心部分就是一个键值对数据库,可以向里面写任意类型的数据,它会返回一个键值,可以通过键值去检索内容。

  • 写内容,返回对应键值 命令如下
echo 'test content' | git hash-object -w --stdin  ##运行此命令后objects文件夹里会多出一个目录(目录名为hash的前两位),里面有一个以一串hash(40个字符)命名的文件
$ find ./.git/objects -type f
./.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4

-w 选项提示 hash-object命令存储数据对象;若不指定此选项,则仅返回对应的键值
–stdin 表示从标准输入读取内容;若不指定此选项,则需在命令尾部给出待存储文件的路径

git hash-object -w 文件路径   ##存文件
git hash-object 文件路径   ##返回对应文件的键值
  • 根据键值查看数据
git cat-file -p 哈希值

-t 显示数据的类型 键值对在git中是blob类型
-p 指示该命令自动判断类型,并为我们显示格式有好的内容

  • 对文件进行简单的版本控制
echo "test.txt v1" > test.txt
git hash-object -w ./test.txt

返回如下

warning: LF will be replaced by CRLF in ./test.txt.
The file will have its original line endings in your working directory   ##不用管
560a3d89bf36ea10794402f6664740c284d4ae3b

根据560a3d89bf36ea10794402f6664740c284d4ae3b查看类型依旧是blob,说明不管是存文件或者文本在git里,都是一个blob对象

说明:
1.当去修改test.txt里的内容的时候,查看objects里面的内容,依旧是之前的状态,需要再次执行git hash-object -w ./test.txt,才会存进去
2.文件名并没有保存,仅仅是保存了文件的内容
3.当前的操作都是对本地数据库进行操作,不涉及暂存区
4.每一个对象只能代表一个文件,不能代表项目的快照
5.这里的操作都是在本地数据库进行操作,不涉及暂存区

树对象

数对象允许我们将多个对象组织在一起,并且可以保存文件名,一个树对象包含一条或多条记录

  • 构建树对象
    1、利用update-index命令为test.txt文件的首个版本创建一个暂存区,并通过write-tree生成树对象
echo "test.txt v1" > test.txt
git hash-object -w ./test.txt
# 返回结果:560a3d89bf36ea10794402f6664740c284d4ae3b
git update-index --add --cacheinfo 100644 560a3d89bf36ea10794402f6664740c284d4ae3b test.txt    #没有往版本库里面放数据,只是在暂存区生成一条记录
# 100644 -> 普通文件
# 100755 -> 可执行文件
# 120000 -> 符号链接
# write-tree 将暂存区做一个快照,生成一个数对象放到版本库当中
# --add: 首次添加暂存区需要加上-add
# --cacheinfo 将要添加的文件位于git数据库中,要加上--cacheinfo
# ls-files -s 查看当前暂存区的内容
git write-tree  # 生成树对象,放到版本库

通过git cat-file -t 查看哈希06e21bb0105e2de6c846725a9a7172f57dd1af96对应的类型,结果为tree
同时通过git ls-files -s查看暂存区内容还在,可以说明在将树对象写到数据库的时候也不会将暂存区的内容清空

2、新增new.txt 将new.txt和test.txt文件的第二个版本放入暂存区,并通过write-tree命令生成树对象

 echo "new v1" > new.txt
 git hash-object -w new.txt
 # 返回结果: eae614245cc5faa121ed130b4eba7f9afbcc7cd9
 find .git/objects/ -type f
 # 返回结果: .git/objects/ea/e614245cc5faa121ed130b4eba7f9afbcc7cd9
 vim test.txt # 更改文件内容
 git hash-object -w test.txt  # 改了test.txt,为其重新生成树对象
 # 返回结果: c31fb1e89d8b6b3ef34cdb5a2f999d6e29b822ba
 find .git/objects/ -type f   # 查看会发现生成了一个新的hash
git update-index --add --cacheinfo 100644 c31fb1e89d8b6b3ef34cdb5a2f999d6e29b822ba test.txt    #之前存在于暂存区的test.txt这条记录会被覆盖
git ls-file -s
# 返回结果: 100644 c31fb1e89d8b6b3ef34cdb5a2f999d6e29b822ba 0       test.txt (hash被覆盖了)
git update-index --add --cacheinfo 100644 eae614245cc5faa121ed130b4eba7f9afbcc7cd9 new.txt
git ls-files -s
# 返回结果: 100644 eae614245cc5faa121ed130b4eba7f9afbcc7cd9 0       new.txt
# 100644 c31fb1e89d8b6b3ef34cdb5a2f999d6e29b822ba 0       test.txt
git write-tree # 生成树对象
# 返回结果: 9d74ec4055e0f1edc1921d749c250380ca7b5ebd

通过find .git/objects/ -type f 查看仓库会发现树对象添加了进去

3、将第一个树对象加入第二个数对象,使其成为新的树对象

git read-tree --prefix=bak 06e21bb0105e2de6c846725a9a7172f57dd1af96
git ls-files -s
# 返回结果:100644 560a3d89bf36ea10794402f6664740c284d4ae3b 0       bak/test.txt
 git write-tree
 # 返回结果:17d1ee3eac87d38448e7ff2cc92e88ed4e9aa094

问题:根据树对象不知道是谁保存了这些快照,在什么时候存的,以及为什么保存这些快照。

git cat-file -p 17d1ee3eac87d38448e7ff2cc92e88ed4e9aa094 # 查看树对象
# 返回结果:040000 tree 06e21bb0105e2de6c846725a9a7172f57dd1af96    bak
# 100644 blob eae614245cc5faa121ed130b4eba7f9afbcc7cd9    new.txt
# 100644 blob c31fb1e89d8b6b3ef34cdb5a2f999d6e29b822ba    test.txt

提交对象

可以通过commit-tree创建一个提交对象,并需要指定一个SHA-1值,以及该提交的父提交对象
1、创建提交对象

echo 'first commit' | git commit-tree 06e21bb0105e2de6c846725a9a7172f57dd1af96
git cat-file -t 43d3e591ca6f1e07c718b5eb855f2fa2379e12f4
# 返回结果:commit
git cat-file -p 43d3e591ca6f1e07c718b5eb855f2fa2379e12f4
# 返回结果:tree 06e21bb0105e2de6c846725a9a7172f57dd1af96
# author xxx <xxx@qq.com> 1704503195 +0800
# committer xxx <xxx@qq.com> 1704503195 +0800
echo 'sencond commit' | git commit-tree 9d74ec4055 -p 43d3e591ca6f1e07c718b5eb855f2fa2379e12f4
# 返回结果: 63df84c5b896a06ba827e17a7184b67a6bc20cad
git cat-file -p 63df84c5b896a06ba827e17a7184b67a6bc20cad
# 返回结果: tree 9d74ec4055e0f1edc1921d749c250380ca7b5ebd
# parent 43d3e591ca6f1e07c718b5eb855f2fa2379e12f4
# author 胡玉龙 <647855054@qq.com> 1704503619 +0800
# committer 胡玉龙 <647855054@qq.com> 1704503619 +0800

高层命令

本地操作

1、git add ./ # 将工作目录的修改生成git对象放到版本库,然后放到暂存区
包含以下底层命令:
git hash-object -w 文件名(修改了多少个工作目录中的文件 此命令就要被执行多少次)
git update-index

2、git commit -m ‘注释内容’
包含以下底层命令:
git write-tree
git commit-tree

git init 
find .git/objects/ -type f  # 无内容
echo "老付头顶青青草原" > laofu.txt
git add ./  # 将工作目录的修改生成git对象放到版本库,然后放到暂存区
git ls-files -s  # 查看暂存区内容
# 返回结果:100644 a8cac0ea749dc0521e979f498493d8a359a788f1 0       laofu.txt
find .git/objects/ -type f   # 查看版本库                                            
# 返回结果:.git/objects/a8/cac0ea749dc0521e979f498493d8a359a788f1
git cat-file -p a8cac0ea749dc0521e979f498493d8a359a788f1
# 返回结果:老付头顶青青草原
git cat-file -t a8cac0ea749dc0521e979f498493d8a359a788f1
# 返回结果:blob
git commit -m "这是项目的第一个版本 包含了一个laofu文件 实现了青青草原"
find .git/objects/ -type f
# 返回结果:.git/objects/92/7d83f7b7e6ba0eae2fe56f61879017b3876f8a
# .git/objects/a8/cac0ea749dc0521e979f498493d8a359a788f1
# .git/objects/c0/e49f255b9e7c97748a6c6a8ec6ce20d971b19b

3、git diff 查看未暂存的修改
git diff --cached 或–staged(1.6.1以上) 查看未提交的暂存

4、git commit -a -m “msg” 将所有已经跟踪过的文件暂存起来一并提交,跳过git add步骤

5、git rm 文件名
删除工作目录中对应的文件,再将修改添加到暂存区。
可以替换如下操作:
在工作区删除已提交的文件,然后git add ./

6、git log --oneline 查看提交的历史记录

7、git 原文件名 新文件名 将工作目录中中的文件进行重命名,再将修改添加到暂存区

8、git log --online --decorate --graph --all 查看项目分叉历史

9、git config --global alias.lgo “log --oneline --decorate --graph --all” 为上述命令配别名

分支操作

git checkout -b 分支名 新建分支并切换上去
git bcanch 分支名 commitHash 在指定的提交对象上创建新的分支
git branch -d 分支名 删除分支(空的分支/已经被合并的分支)
git branch -D 分支名 强制删除分支

注意:分支切换会改变工作目录中的文件,如果是切换到一个旧的分支,当前的工作目录会恢复到该分支最后一次提交时的样子,如果git不能完成这个任务,它将禁止切换分支

分支实战
git init
echo "a.txt v1" > a.txt
git add a.txt
git commit -a -m "1 commit for a.txt v1"
git lgo
#返回结果:fc0f944 (HEAD -> master) 1 commit for a.txt v1
vim a.txt  # 添加a.txt v2
git commit -a -m "2 commit for a.txt v2"
#返回结果:* fae4921 (HEAD -> master) 2 commit for a.txt v2
#        * fc0f944 1 commit for a.txt v1
git checkout -b test  # 创建test分支并切换过去
git lgo
# 返回结果:* fae4921 (HEAD -> test, master) 2 commit for a.txt v2
#         * fc0f944 1 commit for a.txt v1

此时工作目录只有一个a.txt

echo "b.txt v1" > b.txt
git add ./
git commit -m "3 commit for b.txt v1"
git lgo
# 返回结果:* 9b47191 (HEAD -> test) 3 commit for b.txt v1
#         * fae4921 (master) 2 commit for a.txt v2
#         * fc0f944 1 commit for a.txt v1

此时工作目录有a.txt和b.txt两个文件,查看暂存区内容如下:

git ls-files -s 
100644 38c7912943d1b1f3b89c966f977100f88372f993 0       a.txt
100644 0a170006b042f0456d14dd4800c007c4b5f8ea1d 0       b.txt

git checkout master 切换分支后查看暂存区内容发生了改变:

git ls-files -s
100644 38c7912943d1b1f3b89c966f977100f88372f993 0       a.txt

说明:切换分支会改变head,暂存区,工作目录

最佳实践:每次切换分支前,通过git status查看当前分支一定得是干净的(处于已提交状态)

错误举例:在test这个新分支上增加新的功能(比如新建c.txt),但是没有添加,也没有暂存,相当于没有给git管理,如果这时从test分支切换到master分支,文件就会被保留,这是git的安全机制

git chectout test
echo "c.txt v1" > c.txt   
#  c.txt 未暂存
git checkout master   # 会发现c.txt依旧存在,会污染主分支  工作目录显示a.txt和b.txt

坑(初始化的时候):在切换分支时,如果当前分支上有未暂存的修改(第一次)或有未提交的暂存(第一次),分支可以切换成功,但是这种操作可能会污染其它分支

git checkout test
git add ./
git ls-files -s
# 返回结果:100644 38c7912943d1b1f3b89c966f977100f88372f993 0       a.txt
#         100644 0a170006b042f0456d14dd4800c007c4b5f8ea1d 0       b.txt
#         100644 512ff49d382961b3157260f6e6688013904caf5c 0       c.txt
$ git checkout master
# 返回结果:Switched to branch 'master'
#         A       c.txt
git ls-files -s
# 返回结果:100644 38c7912943d1b1f3b89c966f977100f88372f993 0       a.txt
#         100644 512ff49d382961b3157260f6e6688013904caf5c 0       c.txt

这时如果切到test分支然后提交再回master就没问题

git checkout test
git lgo
# 返回结果: * 9b47191 (HEAD -> test) 3 commit for b.txt v1
#          * fae4921 (master) 2 commit for a.txt v2
#          * fc0f944 1 commit for a.txt v1
git commit -m "4 commit for c.txt v1"
git status
#返回结果: On branch test
#         nothing to commit, working tree clean
$ git checkout master  # 这时会发现工作目录只有a.txt

如果是提交过的,再切换,git会报错不让切换,必须提交完再切换(当切换到test分支修改c.txt中的内容后,没有添加到暂存区,然后切换到master分支会报错):

git checkout test
vim c.txt # 增加c.txt v2
$ git status
#返回结果:On branch test
#        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:   c.txt
git checkout master
# 返回结果:error: Your local changes to the following files would be overwritten by    checkout:
#              c.txt
#        Please commit your changes or stash them before you switch branches.
#        Aborting
实际案例

工作流:
1、开发某个网站
2、为实现某个新的需求,创建一个分支
3、在这个分支上开展工作
正在此时,你突然接到一个电话说有一个很严重的问题需要紧急修补,最后将改动添加到线上分支
4、切换回最初工作的分支上,继续工作

假设你正在项目上工作,并有一些提交

git commit -a -m "5 commit for c.txt v2"
git lgo 
# * 7ce26eb (HEAD -> test) 5 commit for c.txt v2
# * 61d8a81 4 commit for c.txt v1
# * 9b47191 3 commit for b.txt v1
# * fae4921 (master) 2 commit for a.txt v2
# * fc0f944 1 commit for a.txt v1
git checkout master
git branch -D test
git lgo
# * fae4921 (HEAD -> master) 2 commit for a.txt v2
# * fc0f944 1 commit for a.txt v1

创建新分支,去解决bug

git checkout -b "#53"
git checkout -b iss53
echo "iss53 50%" > iss53.txt
git add ./
git commit -m "6 commit iss53 50%"
git lgo
# * b7525c8 (HEAD -> iss53) 6 commit iss53 50%
# * fae4921 (master) 2 commit for a.txt v2
# * fc0f944 1 commit for a.txt v1
git reflog
# b7525c8 (HEAD -> iss53) HEAD@{0}: commit: 6 commit iss53 50%
# fae4921 (master) HEAD@{1}: checkout: moving from master to iss53
# fae4921 (master) HEAD@{2}: checkout: moving from #53 to master
# fae4921 (master) HEAD@{3}: checkout: moving from master to #53
# fae4921 (master) HEAD@{4}: checkout: moving from test to master
# 7ce26eb HEAD@{5}: commit: 5 commit for c.txt v2
# 61d8a81 HEAD@{6}: checkout: moving from master to test
# fae4921 (master) HEAD@{7}: checkout: moving from test to master
# 61d8a81 HEAD@{8}: commit: 4 commit for c.txt v1
# 9b47191 HEAD@{9}: checkout: moving from master to test
# fae4921 (master) HEAD@{10}: checkout: moving from test to master
# 9b47191 HEAD@{11}: checkout: moving from master to test
# fae4921 (master) HEAD@{12}: checkout: moving from test to master
# 9b47191 HEAD@{13}: checkout: moving from master to test
# fae4921 (master) HEAD@{14}: checkout: moving from test to master
# 9b47191 HEAD@{15}: commit: 3 commit for b.txt v1
# fae4921 (master) HEAD@{16}: checkout: moving from master to test
# fae4921 (master) HEAD@{17}: commit: 2 commit for a.txt v2
# fc0f944 HEAD@{18}: commit (initial): 1 commit for a.txt v1
git checkout master
git lgo
# * b7525c8 (iss53) 6 commit iss53 50%
# * fae4921 (HEAD -> master) 2 commit for a.txt v2
# * fc0f944 1 commit for a.txt v1
git checkout -b hotbug
git lgo
# * b7525c8 (iss53) 6 commit iss53 50%
# * fae4921 (HEAD -> hotbug, master) 2 commit for a.txt v2
# * fc0f944 1 commit for a.txt v1
vim a.txt  # 添加a.txt v3模拟修复了bug
git add ./
git commit -m "7 commit for a.txt v3 to fix hotbug"
git lgo
# * 15ae85f (HEAD -> hotbug) 7 commit for a.txt v3 to fix hotbug
# | * b7525c8 (iss53) 6 commit iss53 50%
# |/
# * fae4921 (master) 2 commit for a.txt v2
# * fc0f944 1 commit for a.txt v1

切换到主分支

git checkout master
git merge hotbug
# Updating fae4921..15ae85f
# Fast-forward   快进合并不会产生冲突
#  a.txt | 1 +
#  1 file changed, 1 insertion(+)

解释:fast-forward 由于当前master分支所指向的提交是你当前提交的直接上游,所以git只是简单的将指针向前移动。换句话说,当你试图合并两个分支时,如果顺着一个分支走下去能够到达另一个分支,那么在合并的时候,只会简单的将指针向前推进(指针右移),因为这种情况下的合并操作没有需要解决的分歧,这就叫做快进。

当修改了a.txt和iss53.txt中的内容:

git branch -d hotbug
git checkout iss5
vim iss53 # 添加iss53 100%
git commit -a -m "8 commit for iss53.txt 100%"
git lgo
# * 1ee6edf (HEAD -> iss53) 8 commit for iss53.txt 100%
# * b7525c8 6 commit iss53 50%
# | * 15ae85f (master) 7 commit for a.txt v3 to fix hotbug
# |/
# * fae4921 2 commit for a.txt v2
# * fc0f944 1 commit for a.txt v1
vim a.txt # 添加a.txt v3 for issue53
git commit -a -m "9 commit for iss53.txt to patch a.txt v3 to real 100%"
git lgo
# * d6474b1 (HEAD -> iss53) 9 commit for iss53.txt to patch a.txt v3 to real 100%
# * 1ee6edf 8 commit for iss53.txt 100%
# * b7525c8 6 commit iss53 50%
# | * 15ae85f (master) 7 commit for a.txt v3 to fix hotbug
# |/
# * fae4921 2 commit for a.txt v2
# * fc0f944 1 commit for a.txt v1

切换到主分支,进行合并,会产生冲突:

git checkout master
git merge iss53
# Auto-merging a.txt
# CONFLICT (content): Merge conflict in a.txt
# Automatic merge failed; fix conflicts and then commit the result.
vim a.txt
# a.txt v1
# a.txt v2
# <<<<<<< HEAD
# a.txt v3
# =======
# a.txt v3 for issue53
# >>>>>>> iss53
git add ./
git commit -m "10 commit for fix ct"
git branch -d iss53
git lgo
# *   38b5b43 (HEAD -> master) 10 commit for fix ct
# |\
# | * d6474b1 9 commit for iss53.txt to patch a.txt v3 to real 100%
# | * 1ee6edf 8 commit for iss53.txt 100%
# | * b7525c8 6 commit iss53 50%
# * | 15ae85f 7 commit for a.txt v3 to fix hotbug
# |/
# * fae4921 2 commit for a.txt v2
# * fc0f944 1 commit for a.txt v1

分支原理

HEAD引用:当运行类似于git branch这样的命令时,git会通过head文件(HEAD文件是一个符号引用,指向目前所在的分支)取得当前所在分支最新提交对应的SHA-1值,并将其加入你想要创建的任何新分支中。
换句话说分支就是一个没有后缀名的文件,里面存着一个hash

git存储

使用场景:有时在项目的某个模块上开发了一段时间后,想要切换到另一个分支做点别的事情,但我不想为这做了一半的工作创建一次提交

git stash命令:将未完成的修改保存到一个栈上,后面可以应用这些改动(git stash apply)
git stash list 查看存储
git stash apply stash@{2} 应用指定的储存
git stash pop 来应用储存然后立即从栈上移除
git stash drop 加上将要移除的储存的名字来移除它

vim damu.txt # 修改damu.txt  加上damu.txt v2
git checkout master   # 没提交切换分支直接报错
# error: Your local changes to the following files would be overwritten by checkout:
#         damu.txt
# Please commit your changes or stash them before you switch branches.
# Aborting
git stash list  # 无结果
git stash
# warning: LF will be replaced by CRLF in damu.txt.
# The file will have its original line endings in your working directory
# Saved working directory and index state WIP on damu: d7fbfa8 11 commit for damu.txt v1
git stash list
# stash@{0}: WIP on damu: d7fbfa8 11 commit for damu.txt v1
git log --oneline  # git默认做的提交是看不到的  git lgo可以看到
# d7fbfa8 (HEAD -> damu) 11 commit for damu.txt v1
# 38b5b43 (master) 10 commit for fix ct
# d6474b1 9 commit for iss53.txt to patch a.txt v3 to real 100%
# 1ee6edf 8 commit for iss53.txt 100%
# 15ae85f 7 commit for a.txt v3
# b7525c8 6 commit iss53 50%
# fae4921 2 commit for a.txt v2
# fc0f944 1 commit for a.txt v1
git checkout master # 这时可以切换成功
# Switched to branch 'master'
git checkout damu
git stash apply  # 只是应用,并不删除
# On branch damu
# 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:   damu.txt
git stash drop stash@{0}  # 应用并删除   git stash pop 也行(更直接)
# Dropped stash@{0} (36492f674de6879a3ae5537af1425b3424924f14)

后悔药

  • 工作区 撤回自己在工作目录中的修改 git checkout --filename
  • 暂存区 撤回自己的暂存 git reset HEAD filename (相当于reset三部曲第二部)
  • 版本库 撤回自己的提交 (1:内容写错就重新提交 2:修改注释)

假如要将damu.txt中的damu.txt v2撤销

cat damu.txt
# damu.txt v1
# damu.txt v2
git status
# On branch damu
# 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:   damu.txt
git checkout -- damu.txt
cat damu.txt
# damu.txt v1

vim damu.txt # 新增damu.txt v2
git add ./
git ls-files -s
# 100644 d87f264f36149d2ab8e3a8e9dbdf49ee4aaa3ba8 0       a.txt
# 100644 f8a4ded58e93c576a7a9efd9ed4e37aaff62c46a 0       damu.txt
# 100644 b84547efb8db9f66c397f834ec2ccf6039ac09ec 0       iss53.txt
git cat-file -p f8a4ded58e93c576a7a9efd9ed4e37aaff62c46a
# damu.txt v1
# damu.txt v2
git status
# On branch damu
# Changes to be committed:
#   (use "git restore --staged <file>..." to unstage)
#         modified:   damu.txt
git reset HEAD damu.txt
# Unstaged changes after reset:
# M       damu.txt
git ls-files -s
# 100644 d87f264f36149d2ab8e3a8e9dbdf49ee4aaa3ba8 0       a.txt
# 100644 167097be1530463ccbd208ad909c5ef9fc4fd892 0       damu.txt
# 100644 b84547efb8db9f66c397f834ec2ccf6039ac09ec 0       iss53.txt
git cat-file -p 167097be1530463ccbd208ad909c5ef9fc4fd892
# damu.txt v1
git status
# On branch damu
# 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:   damu.txt
git checkout -- damu.txt
git status
# On branch damu
# nothing to commit, working tree clean
cat damu.txt
# damu.txt v1

vim damu.txt #新增错误内容
git add ./
git commit -m "12 commit for damu.txt v2"
cat damu.txt
# damu.txt v1
# sadfasfaa
git reflog # 显示了完整的操作记录
vim damu.txt # 改为正确内容
git add ./
git commit -m "13 commit for real damu.txt v2"
vim damu.txt # 添加damu.txt v3
git commit -a -m "13 commit for damu.txt v2" # 本来应该是第14次提交,但写成了13次提交
git lgo
# 81f4023 (HEAD -> damu) 13 commit for damu.txt v2
# * bfd41ad 13 commit for real damu.txt v2
# * 7f5ffef 12 commit for damu.txt v2
# * d7fbfa8 11 commit for damu.txt v1
# *   38b5b43 (master) 10 commit for fix ct
# |\
# | * d6474b1 9 commit for iss53.txt to patch a.txt v3 to real 100%
# | * 1ee6edf 8 commit for iss53.txt 100%
# | * b7525c8 6 commit iss53 50%
# * | 15ae85f 7 commit for a.txt v3 to fix hotbug
# |/
# * fae4921 2 commit for a.txt v2
# * fc0f944 1 commit for a.txt v1
git commit --amend  # 修改注释
git lgo
# 81f4023 (HEAD -> damu) 14 commit for damu.txt v3
# * bfd41ad 13 commit for real damu.txt v2
# * 7f5ffef 12 commit for damu.txt v2
# * d7fbfa8 11 commit for damu.txt v1
# *   38b5b43 (master) 10 commit for fix ct
# |\
# | * d6474b1 9 commit for iss53.txt to patch a.txt v3 to real 100%
# | * 1ee6edf 8 commit for iss53.txt 100%
# | * b7525c8 6 commit iss53 50%
# * | 15ae85f 7 commit for a.txt v3 to fix hotbug
# |/
# * fae4921 2 commit for a.txt v2
# * fc0f944 1 commit for a.txt v1

vim damu.txt  # 添加了damu.txt 漏了v4
git add ./  # 添加到暂存区之后记起来没有加上v4
vim damu.txt  # 再次编辑 加上v3
git status
# On branch damu
# Changes to be committed:
#   (use "git restore --staged <file>..." to unstage)
#         modified:   damu.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:   damu.txt

#如果这时候commit只能把第一次改的提交
git commit -m "fasdfasf"
git status # 这时候发现里面还有内容
# On branch damu
# 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:   damu.txt
git add ./  
git commit --amend # "15 commit for damu.txt v4"  

reset 三部曲

第一部:git reset --soft HEAD~ 只动HEAD(带着分支一起移动),checkout切换分支不会带着分支一起移动
本质上是撤销了上一次git commit命令,当在运行git commit时,git会创建一个新的提交,并移动HEAD所指向的分支使其指向该提交
第二部:git reset --mixed HEAD~ (等同于git reset HEAD~) 动HEAD(带着分支一起移动)和暂存区
第三部:git reset --hard HEAD~ 动HEAD(带着分支一起移动)和暂存区和工作区

git lgo
# * 9f62f86 (HEAD -> master) 3 commit for file.txt v3
# * 5fdf5b0 2 commit for file.txt v2
# * 1af1180 commit for file.txt v1
git ls-files -s
# 100644 19fc948c556147404e7a846120a6f7129d529308 0       file.txt
git cat-file -p 19fc948c556147404e7a846120a6f7129d529308
# file.txt v1
# file.txt v2
# file.txt v3
git cat-file -p HEAD
# tree ad44ab8dda512ad64d2a3ae405f42d7cd1a988a2
# parent 5fdf5b051fc3d2293cd1ab82e20a46d9f8c24e02
# author 胡玉龙 <647855054@qq.com> 1707632825 +0800
# committer 胡玉龙 <647855054@qq.com> 1707632825 +0800

# 3 commit for file.txt v3
git cat-file -p ad44ab8dda512ad64d2a3ae405f42d7cd1a988a2
# 100644 blob 19fc948c556147404e7a846120a6f7129d529308    file.txt
git cat-file -p 19fc948c556147404e7a846120a6f7129d529308
# file.txt v1
# file.txt v2
# file.txt v3
git reset --soft HEAD~
git cat-file -p HEAD
# tree 0711b613506737ae47e2d452950a48c3ff425aa1
# parent 1af1180f8f72e3ee35693ef4551c20fc6f3565d0
# author 胡玉龙 <647855054@qq.com> 1707632786 +0800
# committer 胡玉龙 <647855054@qq.com> 1707632786 +0800

# 2 commit for file.txt v2
git cat-file -p 0711b613506737ae47e2d452950a48c3ff425aa1
# 100644 blob 03359ddf64106dfb6c4bb03cbd2f71b02bd3306e    file.txt
git cat-file -p 03359ddf64106dfb6c4bb03cbd2f71b02bd3306e
# file.txt v1
# file.txt v2
cat file.txt  # 工作区file.txt没有变
# file.txt v1
# file.txt v2
# file.txt v3
git ls-files -s
# 100644 19fc948c556147404e7a846120a6f7129d529308 0       file.txt
git cat-file -p 19fc948c556147404e7a846120a6f7129d529308  # 暂存区内容没有变
# file.txt v1
# file.txt v2
# file.txt v3

git lgo
# 5fdf5b0 (HEAD -> master) 2 commit for file.txt v2
# 1af1180 commit for file.txt v1
git reflog   
# 5fdf5b0 (HEAD -> master) HEAD@{0}: reset: moving to HEAD~
# 9f62f86 HEAD@{1}: commit: 3 commit for file.txt v3
# 5fdf5b0 (HEAD -> master) HEAD@{2}: commit: 2 commit for file.txt v2
# 1af1180 HEAD@{3}: commit (initial): commit for file.txt v1
git reset --soft 9f62f86   #回到第三次提交上去
git reflog
# 9f62f86 (HEAD -> master) HEAD@{0}: reset: moving to 9f62f86
# 5fdf5b0 HEAD@{1}: reset: moving to HEAD~
# 9f62f86 (HEAD -> master) HEAD@{2}: commit: 3 commit for file.txt v3
# 5fdf5b0 HEAD@{3}: commit: 2 commit for file.txt v2
# 1af1180 HEAD@{4}: commit (initial): commit for file.txt v1
git lgo
# * 9f62f86 (HEAD -> master) 3 commit for file.txt v3
# * 5fdf5b0 2 commit for file.txt v2
# * 1af1180 commit for file.txt v1
git reset --mixed HEAD~
# Unstaged changes after reset:
# M       file.txt
git ls-files -s
# 100644 03359ddf64106dfb6c4bb03cbd2f71b02bd3306e 0       file.txt
git cat-file -p 03359ddf64106dfb6c4bb03cbd2f71b02bd3306e
# file.txt v1
# file.txt v2
git cat-file -p HEAD
# tree 0711b613506737ae47e2d452950a48c3ff425aa1
# parent 1af1180f8f72e3ee35693ef4551c20fc6f3565d0
# author 胡玉龙 <647855054@qq.com> 1707632786 +0800
# committer 胡玉龙 <647855054@qq.com> 1707632786 +0800

2 commit for file.txt v2
git cat-file -p 0711b613506737ae47e2d452950a48c3ff425aa1
100644 blob 03359ddf64106dfb6c4bb03cbd2f71b02bd3306e    file.txt
git cat-file -p 03359ddf64106dfb6c4bb03cbd2f71b02bd3306e  # 暂存区内容也变了
# file.txt v1
# file.txt v2
cat file.txt
# file.txt v1
# file.txt v2
# file.txt v3

git reflog
# 5fdf5b0 (HEAD -> master) HEAD@{0}: reset: moving to HEAD~
# 9f62f86 HEAD@{1}: reset: moving to 9f62f86
# 5fdf5b0 (HEAD -> master) HEAD@{2}: reset: moving to HEAD~
# 9f62f86 HEAD@{3}: commit: 3 commit for file.txt v3
# 5fdf5b0 (HEAD -> master) HEAD@{4}: commit: 2 commit for file.txt v2
# 1af1180 HEAD@{5}: commit (initial): commit for file.txt v1
git reset --mixed 9f62f86
git ls-files -s
# 100644 19fc948c556147404e7a846120a6f7129d529308 0       file.txt
git cat-file -p 19fc948c556147404e7a846120a6f7129d529308
# file.txt v1
# file.txt v2
# file.txt v3
git reset --hard HEAD~
# HEAD is now at 5fdf5b0 2 commit for file.txt v2
cat file.txt
# file.txt v1
# file.txt v2
git ls-files -s
# 100644 03359ddf64106dfb6c4bb03cbd2f71b02bd3306e 0       file.txt
git cat-file -p 03359ddf64106dfb6c4bb03cbd2f71b02bd3306e
# file.txt v1
# file.txt v2


git checkout与git reset --hard区别:
1、checkout只动HEAD,后者会动HEAD,暂存区,工作区
2、reset会移动HEAD分支的指向,checkout只会移动自身来指向另一个分支

git reset (–mixed HEAD) filename (reset将会跳过第一步) 只动暂存区

git checkout commitID 将工作目录更新到指定的提交状态,HEAD将处于游离状态,不指向任何分支
git checkout --filename 将工作区的指定文件的内容恢复到暂存区的状态
git checkout commitID 将工作区和暂存区都恢复到指定提交版本的指定文件的状态

  • 24
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值