git笔记
GIit
Git 是什么?
Git 是一个分布式版本控制系统
Git 是一个对项目文件管理的工具,有着版本控制等功能
git本地仓库的工作原理
sequenceDiagram participant 远程仓库 本地仓库->>本地仓库: init 本地仓库->>远程仓库: git config --global(验证账号密码) 本地仓库->>远程仓库: git remote add origin(连接远程的地址) 远程仓库-->>本地仓库: clone(克隆) 远程仓库->>本地仓库: pull or fetch 本地仓库->>本地仓库: merge 暂存区->>本地仓库: commit 工作区->>暂存区: add Note right of 工作区 : 新建文件---未跟踪(untracked) Note right of 工作区 : 修改文件---未暂存(unstaged) 暂存区->>工作区: git restore file 回退 暂存区->>暂存区: git restore --staged file 清退暂存区 本地仓库->>本地仓库: git reset 重置 本地仓库-->>远程仓库: branch(选择分支push) 本地仓库-->>远程仓库: push 远程仓库-->>远程仓库: merge(合并)
git 文件管理 会 忽略 .gitignore 文件中的文件路径
命令速查
1. 初始化本地仓库
1 | git init |
创建.git文件夹,存放修改前后的版本信息,方便回滚以及记录
.git 是隐藏文件夹,需要设置显示隐藏文件夹才可以显示
2. 提交文件到缓冲区
1 | //全部提交 |
3. 查看仓库状态
1 | git status |
4.提交暂存区文件进仓库
1 | git commit -m "本次提交修改的注释,可以任意文本" |
提交工作区的文件进仓库
1 | git commit -a -m "你的提交信息" |
不需要进入暂存区就提交工作区的文件,其中-a是-all 全部的意思
注意,这个方法不提交新的文件,只针对git 已追踪的文件,即已存在的文件,新文件提交仍然需要gitadd再git commit
5.查看提交日志(可查看提交人、分支、文件、时间)
1 | git log |
指令有其他参数git log [option]
,其中option的值有
分支名,可单独查看分支的 修改
--all
显示所有分支
--all d
提交信息为一行
--abbrev-commit
让输出的commitId简短
--graph
以图片形式显示
1 | git log --graph --all --pretty=oneline --abbrev-commit |
其余更多请参考git log命令参数详解 - 知乎 (zhihu.com)
所有日志,包括回退的日志
1 | git reflog |
6.版本回退
1 | git reset --hard commitID |
commitID
通过 git log
查看
--soft
、--mixed
以及--hard
是三个恢复等级。
- 使用
--soft
就仅仅将头指针恢复,已经add的暂存区以及工作空间的所有东西都不变。- 如果使用
--mixed
,就将头恢复掉,已经add的暂存区也会丢失掉,工作空间的代码什么的是不变的。- 如果使用
--hard
,那么一切就全都恢复了,头变,aad的暂存区消失,代码什么的也恢复到以前状态。
注意!!!
使用
git reset
只会把git已追踪的文件回退,不会把新建立的文件删除如果要清理新建立的文件有俩种方式
git add
加入追踪后回退git clean
清理未追踪的文件
7. 查看分支
1 | git branch |
8. 创建分支
1 | git branch 分支名 |
9. 切换分支
1 | git checkout 分支名 |
HEAD
指向当前分支
切换到一个不存在的分支,即创建新分支并复制当前分支内容并切换
1 | git checkout -b 分支名 |
10. 删除分支
1 | git branch -d 分支名 |
11.合并分支
首先使用git switch
或者git checkout
选择需要保留的分支上
1 | git merge 分支名 |
合并后esc
+:
+wq
退出合并文本编辑
处理分支
当是使用merge
合并分支的时候,如果有相同的文件修改了不一样的变动,即冲突
,此时git会自动合并,git并不会处理冲突,只在命令行告诉你什么地方会有冲突:
在test.txt 文件内是这样的
其中`HEAD
到=====
分割线是你所合并的主分支内容,等号分割线下到hello
是被我合并的分支(hello 是我合并的分支名)
之后手动修改需要解决的冲突内容,可以选择都保留,也可以选择留下一部分,git add
+git commit
上传本地仓库,以下是项目流程结构图
禁用Fast forward
默认的快速合并的结果:
其中新建用户是dev的commit ,快速合并中HEAD直接指向dev,导致dev的提交信息被遗失了
以下是 禁用快速合并的结果
如图所示,合并后的commit信息还在
1 | git merge --no-ff feature-branch |
squash
如果分支commit太多太乱,可以使用
1 | git merge --squash feature-branch |
这项指令会让所有的提交合并为一个提交进行合并,并且不保留合并信息
变基
1 | git rebase |
交换commit的顺序,重写commit的顺序,让提交历史更加简洁易懂
具体待续…
12. 远程仓库
先要关联远程仓库
1 | git remote add origin 远程仓库地址 |
origin
的作用是给远程仓库地址起一个别名为origin
,这是一个默认名字,可以替换,相当于c语言的typedef
以及#define
,origin作为远程仓库的地址添加到本地仓库,在之后的拉取代码,推送代码的过程中就不需要每次都打一大串的远程仓库地址
查看绑定的远程仓库地址
1 | git remote -v |
有多少个远程仓库
建议使用上面的指令查看,包含关系关系如下图
1 | git remote |
推送到远程仓库
最常用的指令
1 | git push -u origin main |
- 命令为推送文件夹的所有不被忽略的文件到origin所指的仓库地址的main分支上
-u
是--set-upstream
的缩写
用于关联远程仓库与本地仓库的指定分支,关联后不需要指定分支名就可以使用git push
以及git pull
指令
查看本地分支以及远程仓库分支的跟踪状态
1 | git branch -vv |
修改关联分支仓库
1 | git branch -u origin/new-branch old-branch-name |
完全指令
1 | git push [-f] [--set-upstream][远端名称[本地分支名][:远端分支名]] |
-f
,即--force
如果指令加入,则是不理会推送冲突(即他人的提交或者在远程仓库的修改),强制覆盖--set-upstream
也就是-u
上面有详细解释- 远端名称,即远程仓库地址,可用别名替代,也就是默认设置的
origin
- 如果远程仓库和本地仓库一致,则省略
[:远程分支]
- 推送到不同的名称的的分支示例
git push -u origin main:yuan_branch
,本地的main分支推送到了远程的yuan_branch分支
克隆 远程仓库
clone,和词意相当,也就是把远程仓库的全部文件下载到本地
1 | git clone 远程仓库地址 [本地文件夹名称] |
- 本地文件夹名称可省略,会在当前自动创建一个远程仓库名的文件夹。并把所有的文件下载到这个文件夹里面
设置了文件夹名则是在目录下创建文件夹名的文件夹,并把所有的文件下载到这个文件夹里面。
连接远程仓库
除了push时连接远程仓库外还可以通过以下方法
git checkout --track origin/dev
作用:
- 创建一个名为
dev
的本地分支(假设远程分支是origin/dev
)。 - 切换到这个新创建的本地分支。
- 配置这个本地分支以跟踪远程分支
origin/dev
或
1 | git checkout -b dev origin/dev # 创建并切换到本地分支 dev,从 origin/dev 的当前提交开始 |
将这两个步骤合并为一步
1 | git checkout -b dev --track origin/dev |
13.抓取和拉取远程仓库
抓取:fetch
,获取远程仓库的最新修改,创造一个origin/分支名的新分支,不会自动合并需要你手动合并
以下是使用方法:
- 获取所有分支
1 | git fetch origin |
- 获取远程仓库的某个分支
1 | git fetch origin main |
抓取最新变化以后,需要你手动去合并分支,更新你的本地仓库的代码
拉取:full
,获取远程仓库的修改,并且合并这个修改的代码到你的本地仓库,此时可能产生冲突,这时候就需要
也就是说,full
其实是fetch
+merge
14. 标签 tag
标签是git版本自定义文本的功能,让人更好的区分不同版本,而不是一串无规律的数字字母编号
可以理解为 给不同的 commit版本 起别名,或是一个 死指针 固定的指向那个 commit
git tag
查看所有标签
git tag <tagname>
创建一个标签,默认以当前分支的最新commit为基本
git tag <tagname> <commitID>
给指定commitId进行打标签
git show <tagname>
展示标签详细信息
git tag -a v0.1 -m "version 0.1 released" 1094adb
给标签设置详细信息
git push origin <tagname>
上传标签到远程仓库
git push origin master --tags
上传全部标签到远程仓库
git tag -d <tagname>
删除标签
git push origin --delete <tagname>
远程仓库的标签删除
git push origin :refs/tags/<tagname>
同上
15. 贮藏 stash
当我在一个分支中,已经完成了一部分的开发,但是还不能提交,这时候我需要切换到另一个分支(例如有紧急bug),这个时候切换分支未提交的文件就会一起带到另一个分支上,
这个时候我们就需要冷藏这个分支上未提交的工作区。
1 | $ git status |
这个时候工作区就干净了,可以任意切换分支了
git stash
贮藏
git stash list
查看所有的贮藏
1 | $ git stash list |
可以通过下述命令来标记此次储藏,以便后期查看
1 | git stash save [stashMessage] |
解封/恢复
1 | Yee@Yee MINGW64 ~/Desktop/gitdome (dev) |
通过git stash apply
可以解封,但是还存在在stash list中,通过git stash drop
删除,可以看出,stash是一个栈结构
1 | git stash drop |
git stash pop
通过这个可以一键删除并恢复
1 | $ git stash |
假如我有多个贮藏
1 | git stash list |
我可以选择一个git stash apply stash@{0}
指定的编号去恢复
16. 工作区回退/暂存区回退 checkout / reset/restore
checkout
工作区的文件在修改后可以执行两种操作:
git add
确认工作无误后,把文件上传到暂存区,再commit一个新版本
git checkout -- 文件名
发现工作有错误,回退到修改之前
git restore
git 2.23 版本后出现的回退指令
首先,使用git status
查看仓库状态,这是一个干净无修改的工作区
我们修改一个test.txt,添加一行字符串
1 | $ git status |
git restore是git 2.23出现的新指令,用于清晰语义,因为checkout是切换分支有歧义…
先使用git checkout -- 文件名
测试
1 | $ git checkout -- test.txt |
这样做就回退test.txt文件到了commit-->HEAD
的状态
restore
现在使用git restore
测试
1 |
|
一样可以完成结果,回复到暂存区的状态
如果想回退到HEAD-->
,那么指令是git restore --source=HEAD example.txt
在查资料的时候看见git restore --staged <file>
这个是清空暂存区中的文件(仅从暂存区移除,不影响工作区)
1 | Yee@Yee MINGW64 ~/Desktop/gitdome (main) |
我们可以看到暂存区的文件被退回了,但是工作区已经修改的文件仍然还在
reset
如果是想仅仅是把暂存区的文件放回工作区可以使用:git reset HEAD <file>
1 | Yee@Yee MINGW64 ~/Desktop/gitdome (main) |
以下是gpt的介绍
git reset
是一个非常强大的 Git 命令,用于撤销更改和移动 HEAD 指针。它可以用于重置暂存区的文件、更改当前分支的提交历史,甚至更新工作目录。以下是详细的用法和示例:
基本用法:
1 | sh |
模式:
- —soft:仅移动 HEAD 指针,不改变暂存区和工作区的内容。
- —mixed(默认模式):移动 HEAD 指针,并重置暂存区为指定的 commit,但不改变工作区的内容。
- —hard:移动 HEAD 指针,重置暂存区,并更新工作区,使其与指定的 commit 一致。
用法和示例:
--soft
模式
仅重置 HEAD 指针,不改变暂存区和工作区。这种模式适合想保留更改但移动提交历史的情况。
1 | sh复制代码# 移动 HEAD 指针到指定的提交,但保留暂存区和工作区的更改 |
示例:
1 | sh |
这个命令会把 HEAD 指针移到上一个提交,保留当前的所有更改为已暂存状态。
--mixed
模式(默认)
重置 HEAD 指针和暂存区,但保留工作区的更改。这是默认模式,适合想保留更改但从暂存区移除的情况。
1 | sh复制代码# 移动 HEAD 指针到指定的提交,并重置暂存区,但保留工作区的更改 |
示例:
1 | sh |
这个命令会把 HEAD 指针移到上一个提交,并将当前的更改从暂存区移除,但保留在工作区。
--hard
模式
重置 HEAD 指针、暂存区和工作区,使其全部与指定的 commit 一致。这会丢失所有未提交的更改。
1 | sh复制代码# 移动 HEAD 指针到指定的提交,并重置暂存区和工作区,使它们与该提交一致 |
示例:
1 | sh |
这个命令会把 HEAD 指针移到上一个提交,并丢弃所有未提交的更改。
其他示例
- 重置单个文件
如果只想重置暂存区中的某个文件,可以使用:
1 |
|
这个命令会把指定文件从暂存区移除,但保留在工作区。
- 移动到特定提交
1 | sh |
这个命令会把 HEAD、暂存区和工作区都重置到指定的提交。
- 撤销最近的提交但保留更改
1 | sh |
这个命令会撤销最近的提交,但保留所有更改为已暂存状态。
git reset
是一个功能强大且多用途的命令,可以用来修改提交历史、重置暂存区和工作区。根据不同的模式,可以选择适合当前需求的操作方式:
- —soft 保留所有更改,但移动 HEAD 指针。
- —mixed 重置暂存区,但保留工作区更改。
- —hard 丢弃所有未提交的更改,并重置到指定的提交。
ps.reset偷个懒用的gpt的介绍
总结
回退分为三种
- 回退工作区
git checkout <file>
git restore <file>
- 文件从暂存区到工作区,不影响工作区
git reset HEAD <file>
git restore --staged <file>
- commit、暂存区、工作区都变为commit一个版本
`git reset --hard commit_id
17. 删除文件
git rm <file>
暂存区和工作区都删除文件,只需要commit,相当于手动删除+git add
1 |
|
18.版本差异
git diff
是一个用于显示未提交更改的 Git 命令。它可以显示工作区和暂存区之间的差异、暂存区和最近一次提交之间的差异,以及其他特定的比较。以下是 git diff
的详细用法和一些常见示例:
基本用法
1 | git diff |
显示工作区中未暂存的更改。
常见示例
- 查看工作区和暂存区之间的差异
1 | git diff |
这个命令会显示工作区中未暂存的更改。
- 查看暂存区和最近一次提交之间的差异
1 | git diff --cached |
这个命令(或者 git diff --staged
)会显示已暂存但还未提交的更改。
- 查看工作区和最近一次提交之间的差异
1 | git diff HEAD |
这个命令会显示工作区中所有未提交的更改,无论它们是否已经暂存。
- 查看两个分支之间的差异
1 | git diff branch1 branch2 |
这个命令会显示 branch1
和 branch2
之间的差异。
- 查看两个提交之间的差异
1 | git diff commit1 commit2 |
这个命令会显示 commit1
和 commit2
之间的差异。
- 查看特定文件的差异
1 | git diff HEAD <file> |
这个命令会显示当前工作区中的特定文件和最近一次提交之间的差异。
- 查看特定目录的差异
1 | git diff HEAD <directory>/ |
这个命令会显示当前工作区中的特定目录和最近一次提交之间的差异。
其他有用的选项
显示简洁的差异:
1
git diff --stat
这个命令会以简洁的统计方式显示更改。
忽略空白字符的差异:
1
git diff --ignore-all-space
这个命令会忽略空白字符的更改。
显示统一格式的差异(默认格式):
1
git diff --unified
这个命令会以统一格式显示更改,默认情况下
git diff
就是使用这种格式。仅显示名称的差异:
1
git diff --name-only
这个命令会仅显示文件名称,而不显示具体的更改内容。
例子
假设你有一个项目目录,修改了 file1.txt
和 file2.txt
文件,现在想查看这些修改:
查看未暂存的更改:
1
git diff
暂存更改:
1
git add file1.txt
查看已暂存的更改:
1
git diff --cached
提交更改:
1
git commit -m "修改了 file1.txt 和 file2.txt"
总结
git diff
是一个非常强大的工具,用于比较文件的不同版本。它可以帮助你在提交更改之前了解具体的修改内容,并且可以在多个不同的上下文中使用,从而提供灵活的比较方式。
19. 复制其他分支的提交到当前分支 cherry-pick
git cherry-pick <commit>
应用场景:我在bug修改提交或者main提交后,我想在我当前dev分支获取main提交的时候,就可以使用这个,不需要合并。
20. 忽略文件
在git仓库根目录中,命名一个.gitignore
在这个目录中的目录或者文件名都不会出现在git的提交中,隐私信息或者配置信息就不会发出去
也就是说git不再追踪.gitignore写入的文件
如果你忽略了,但是你确实想提交git add -f App.class
如果你发现你的目录写错了,但是找不到问题,git check-ignore -v App.class
会提醒你哪里出了问题
如果想添加不被排除的文件
例如
1 | *.class |
就可以实现不排除App.class了
21. 清理未追踪的文件
未追踪的文件指:
- 未通过add 添加到暂存区的文件
- .gitignore 文件写入的目录文件
通过git clean
可以清除未追踪的文件
git clean -n
显示哪些文件将被删除,并不是删除,而是删除前查看将删除的文件同git clean --dry-run
git clean -f
强制删除。git clean --force
git clean -f -d
删除未追踪的目录,git clean
一般只删除文件,不删除目录,需要删除目录则使用这个
git clean -f -X
仅删除忽略掉的文件。即.gitignore
指定的文件
git clean -f -x
删除所有未追踪的文件和忽略的文件。这个选项会删除所有未追踪的文件,包括那些在 .gitignore
文件中指定的文件。
22 .撤销提交的revert
相比reset的重置,把新的commit删除,revert会新建一个提交把旧的版本逆转,并保留原先的commit,保留提交历史的完整性
git revert <commitid>
1 | * c778266 qevert "revert_test_2" |
会发现原来的commit依旧存在,并且还添加了一个commit,显示逆转到了revert
允许多个撤销git revert <commit> <commit> <commit>....
,会一个一个撤销/逆转
1 | $ git revert e90405d 4e41599 c778266 |
1 | git revert 2ce70d9 |
出现冲突时
在提示的文件中修改冲突后,可以选择git add/rm <pathspec>
,添加到暂存区,再git revert --continue
继续还原
当有多个逆转提交时可以使用git revert --skip
跳过这个改变提交,而执行其他的逆转,比如git revert A B C D
,C出现了冲突,我选择git revert --skip
,这个时候ABD仍然逆转,C的修改不变。
git revert --abort
逆转过程中,有冲突的时候使用这个语句将中止当前所有逆转,并返回到git revert
前
23. 检索
git grep [options] pattern [-- [pathspec...]]
pattern
字符串或者正则表达式
[不同的模式]
pathspec
搜索的文件或者目录
常用选项
-i
:忽略大小写。1
git grep -i "pattern"
-n
:显示匹配行的行号。1
git grep -n "pattern"
-v
:反向匹配,显示不包含匹配模式的行。1
git grep -v "pattern"
-c
:只显示匹配的行数。1
git grep -c "pattern"
-l
:只显示包含匹配模式的文件名。1
git grep -l "pattern"
--cached
:在索引(暂存区)中搜索。1
git grep --cached "pattern"
<commit>
:在指定提交中搜索。1
2git grep "pattern" HEAD
git grep "pattern" commit_hash<branch>
:在指定分支中搜索。1
git grep "pattern" branch_name
--
:分隔符,用于区分路径和模式。1
git grep "pattern" -- path/to/file_or_directory
例子:
1 | $ git grep 测试 |
24. 溯源 blame
git blame [options] <file>
查看文件被谁修改以及提交信息等等
例子:
1 | $ git blame test.txt |
选项:
-L <start>,<end>
:限制只显示特定范围的行。1
git blame -L 10,20 <file>
只显示从第 10 行到第 20 行的修改记录。
-c
:使用简短的提交哈希。1
git blame -c <file>
-e
:显示作者的 email 地址。1
git blame -e <file>
-f
:显示完整的文件名和行号。1
git blame -f <file>
-l
:显示包含换行符的行。1
git blame -l <file>
-p
:显示更详细的原始信息。1
git blame -p <file>
--since=<date>
和--until=<date>
:限制显示从某个日期开始或截止的修改。1
2
3git blame --since=2.weeks <file>
例如:
$ git blame --since="2023-01-01" test.txt-C
:检测代码搬移(跨文件)。1
git blame -C <file>
25. flow 分支管理系统
一套详细的分支管理策略主要分为
- 主分支(master):始终保持可发布状态,包含已经发布的版本。
- 开发分支(develop):包含即将发布的功能,作为功能分支的集成分支。
- 功能分支(feature):用于开发新功能,基于
develop
创建,完成后合并回develop
。 - 发布分支(release):用于准备新版本的发布,基于
develop
创建,完成后合并回master
和develop
。 - 热修复分支(hotfix):用于修复紧急问题,基于
master
创建,完成后合并回master
和develop
。
需要先置安装,有独特的一套指令,以及良好的结构化规范,不过多了解。
26. worktree 仓库
当工作中需要频繁切换分支的时候,可以创建一个新的工作目录,相当于复制一个仓库来方便切换
git worktree add <path> [branch]
<path>
为路径[branch]
可选的分支名,如果不填写,则自动创建一个与路径目录名相同的分支。如果该分支已存在则切换到同名分支。如果没有这个分支则需要加一个
-b
例子:
1 |
|
删除工作目录
git worktree remove <path>
例子:
1 | $ git worktree remove ../my-feature-branch |
可以发现,工作目录虽然删除了,但是分支依旧还在。
特点:
共享同一个 Git 仓库:所有工作目录共享同一个 Git 仓库,因此对象存储和引用(如提交、分支、标签)是共享的。
独立的工作树和索引:每个工作目录都有自己的工作树和索引,因此在一个工作目录中的未提交更改不会影响其他工作目录。
类似贮藏和切换分支
适用于并行开发:使用
git worktree
可以同时在多个分支上进行开发,而不需要频繁切换分支。
999.给命令起别名
一些指令需要配置一堆参数,每次打的话会浪费很多时间例如查看日志`git log
一般都会带以下参数:git log --graph --all --pretty=oneline --abbrev-commit
每次都打会很麻烦,这个时候就需要起个别名,每次只要需要打一点指令就可以执行一长串的命令
alias
998.Git - Git 钩子 (git-scm.com)
不同方式本地连接github的方法
git bash 命令行
github 桌面版
github GUI
待续计划
- [ ] 变基 rebase