Git 笔记
本文为个人自用 Git 笔记,记录了 Git 的常用命令,不定时更新(●’◡’●)。
Git 常用命令
clone
基本格式为:
git clone [url] [directory]
,其中[directory]
表示需要创建目录的本地名称,省略则默认为版本库的名称。
有一些附加参数如下
-l | --local
:只有当指定的版本库是一个本地路径才会生效,能跳过正常的传输机制,直接复制.git
目录下的部分文件,即使不指定这个选项默认也会采用本地优化,但注意由于硬链接的特性,本地优化的克隆方式存在一些风险。-s | --shared
:当远程版本库在本地机器上时,使用这个选项可以让本地版本库与远程版本库共享对象文件,而不是复制或链接。--depth <depth>
:使用这个选项可以创建一个浅克隆,即只获取最近的<depth>
个提交,而不是整个历史记录。这样可以节省时间和空间。--single-branch
:使用这个选项可以只克隆远程版本库的一个分支,而不是所有分支,来节省克隆时间。默认情况下,这个分支是当前活动分支。
1
2
3
4
5
6
# 克隆本地机器上的一个项目到本地,目录名为another-runoob-name
git clone /path/to/repo another-runoob-name
# 克隆一个项目到本地,只获取最近的10个提交,目录名为shallow-clone
git clone --depth 10 https://github.com/tianqixin/runoob-git-test shallow-clone
# 克隆一个项目到本地,只获取远程的dev分支,目录名为dev-clone
git clone --single-branch -b dev https://github.com/tianqixin/runoob-git-test dev-clone
add
基本格式为:
git add [file1] [file2] …
,其中file
为文件名称。
有一些附加参数如下
-u
:只会添加已经被跟踪的文件,也就是说,它会将修改过或删除过的文件添加到暂存区,但是不会添加新文件。-A
:会添加所有的文件,包括修改过、删除过和新建的文件。
1
2
3
4
5
6
7
8
# 一个项目,里面有三个文件:a.txt, b.txt, c.txt。其中 a.txt 和 b.txt 是已经被跟踪的文件,c.txt 是新建的文件。
# 添加所有文件
git add .
# 添加 a.txt 和 b.txt
git add -u
# 添加所有的文件
git add -A
commit
基本格式为:
git commit [file1] [file2] … -m 'msg'
,没有file
文件默认为全部提交。
1
git commit test.txt -m 'test'
branch
基本格式为:
git branch <branchname>
,创建一个新的分支。有一些附加参数如下
-a
:显示本地分支和远程分支。-m | -M
:重命名当前分支,-M
为强制重命名,即使名称已存在会强制覆盖掉分支名称。-d | -D
:删除分支,-D
强制删除。-v | -vv
:显示本地分支最后一次提交记录,-vv
显示本地分支与远程分支的关联。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 创建一个 test 分支
git branch test
# 显示本地分支和远程分支
git branch -a
# 删除本地的 test 分支
git branch -d test
# 显示本地分支与远程分支的关联
git branch -vv
# 将本地的 dev 分支重命名为 develop 分支
git branch -m dev develop
# 将已存在的本地分支与已存在的远程分支相关联
git branch -u origin/dev
# 取消本地分支与远程分支的关联
git branch --unset-upstream
status
基本格式为:
git status
1
git status
merge
基本格式为:
git merge <branchname>
。
快速合并的时候是不会生成提交记录的
1
2
3
4
# 合并 dev 分支
git merge dev
# 合并
git merge --abort
TIP:
最新提交是合并提交,那么它有两个父提交,分别是合并前的两个分支的最新提交。当你用git reset --hard HEAD^
回退时,你其实是回退到合并提交的第一个父提交,也就是当前分支合并前的最新提交。这样你就会丢失合并提交和另一个分支的所有修改。如果你想回退到合并提交的第二个父提交,也就是另一个分支合并前的最新提交,你可以用git reset --hard HEAD^2
,其中2
表示第二个父提交。
rebase
Git rebase
是一种变基操作,它可以将一个分支的提交重新应用到另一个分支上,从而使两个分支的历史线性化。Git rebase
的好处是可以保持提交历史的清晰和简洁,避免不必要的合并提交。但是,Git rebase
也有一些缺点,其中之一就是可能会产生冲突。
Git rebase
的基本用法是:
1
git rebase <base-branch> <target-branch>
这个命令的意思是,将 <target-branch>
分支变基到 <base-branch>
分支上。也就是说,将 <target-branch>
分支上的提交,重新应用到 <base-branch>
分支的最新提交之后,从而使 <target-branch>
分支的历史成为 <base-branch>
分支的直接后继。
例如,假设有两个分支 master
和 dev
,它们的提交历史如下:
1
2
master: A - B - C - D
dev: A - B - E - F
其中,A、B、C、D、E、F
都是提交 ID
的简写,A
是最早的提交,F
是最新的提交。如果我们想要将 dev
分支变基到 master
分支上,也就是说,我们想要将 E
和 F
这两个提交重新应用到 master
分支的最新提交 D
上,从而使 dev
分支的历史线性化,我们可以在 dev
分支上执行以下命令:
1
git rebase master dev
或者,我们可以先切换到 dev
分支,然后执行:
1
git rebase master
这样,dev
分支的提交历史就变成了:
1
2
master: A - B - C - D
dev: A - B - C - D - E' - F'
这里,E'
和 F'
是 E
和 F
的副本,它们的内容和 E
和 F
相同,但是它们的提交 ID
不同,因为它们是在 D
的基础上重新生成的。这样,dev
分支就变成了 master
分支的直接后继,它们的历史线性化了。
但是,如果在 master
分支上的 C
和 D
这两个提交,和 dev
分支上的 E
和 F
这两个提交,都对同一个文件的同一行内容做了不同的修改,那么在执行 git rebase master
时,就会发生冲突。例如,假设在 master
分支上的 C
提交,修改了文件 file.txt
的第 10
行,将原来的内容 "Hello World"
改成了 “Hello Git"
,而在 dev
分支上的 E
提交,也修改了文件 file.txt
的第 10
行,将原来的内容 "Hello World"
改成了 "Hello Bing"
。那么当 Git
尝试将 E
提交应用到 D
上时,就会遇到冲突,因为 Git
不知道要保留哪个版本的内容。这时候,Git
会在 file.txt
的第 10
行,用特殊的符号标记出冲突的部分,如下所示:
1
2
3
4
5
6
<<<<<<< HEAD
Hello Git
=======
Hello Bing
> > > > > > > E
这里,HEAD
表示目标分支的最新提交,也就是 D
,E
表示正在应用的提交,也就是 E
。Git
会中断变基的过程,让你手动解决冲突,你可以选择保留其中一个版本的内容,或者合并两个版本的内容,或者删除整个内容,然后保存文件,执行 git add file.txt
命令,将文件标记为已解决冲突,再执行 git rebase --continue
命令,继续变基的过程。如果你没有冲突需要解决,或者你想放弃变基的操作,你可以执行 git rebase --abort
命令,回到变基之前的状态。如果你想跳过某个提交,不将它应用到目标分支上,你可以执行 git rebase --skip
命令,继续变基的过程。
当你解决完所有的冲突后,Git
会将 dev
分支的指针移动到最新的提交上,也就是 F'
,这样,dev
分支就变成了 master
分支的直接后继,它们的历史线性化了。但是,你要注意,dev
分支的提交记录已经被重写了,它的提交 ID
和提交顺序都可能发生了变化,这可能会影响你和其他人的工作,所以在使用 Git rebase
时,要谨慎操作,并且与团队成员保持沟通。
Git rebase
还有一些高级用法,例如交互式变基,它可以让你修改、重排、合并、拆分、删除或者重新编写你的提交记录。你可以使用 git rebase -i <base-branch>
命令来启动交互式变基,它会打开一个文本编辑器,让你选择你想要执行的操作。
switch
git switch
相比与git checkout
而言更注重于分支操作,而不会用于恢复文件
基本格式为:git switch <branchname
。
常用命令:
- 切换到已存在的分支:
git switch <branch>
- 创建并切换到新的分支:
git switch -c <new-branch> [<start-point>]
- 从任意分支分离工作树:
git switch --detach [<start-point>]
- 创建并切换到孤儿分支:
git switch --orphan <new-branch>
- 切换到上一次切换的分支:
git switch -
其中,<branch>
是要切换到的分支名,<new-branch>
是要创建的新分支名,<start-point>
是新分支的起始点,可以是一个提交或者另一个分支。如果省略<start-point>
,则默认为当前 HEAD 所指向的位置。
1
2
3
4
5
6
7
8
9
10
# 切换到 dev 分支
git switch dev
# 创建一个新的分支 feature 并从 dev 分支进行开发
git switch -c feature dev
# 检查某个提交的状态,可以尝试在这个状态下新建一个分支解决问题
git switch --detach HEAD~2
# 切换到孤儿分支 docs
git switch --orphan docs
# 切换到上一次分支
git switch -
restore
将文件恢复到最近一次提交的状态
基本格式为:git restore <file>
1
2
3
4
5
6
7
8
9
10
# 恢复工作树的文件
git restore file.txt
# 恢复暂存区的文件
git restore --staged file.txt
# 恢复到特定提交或者分支的状态
git restore --source=dev file.txt
# 交互式模式
git restore --patch
# 同时恢复暂存区和工作树的文件
git restore --staged --worktree file.txt
log
用于显示日志提交信息
基本格式为git log
进入git log
界面后的操作
- 空格键:向下滚动一屏幕的内容
- 回车键:向下滚动一行的内容
b
键:向上滚动一屏幕的内容k
键:向上滚动一行的内容q
键:退出git log
界面
1
git log
fetch
从远程仓库获取数据但不会自动合并
基本用法为:git fetch <remote>
- 从默认的远程仓库获取数据:
git fetch
- 从指定的远程仓库获取数据:
git fetch <remote>
- 从指定的远程仓库和分支获取数据:
git fetch <remote> <branch>
- 从指定的远程仓库和分支获取数据并更新本地分支:
git fetch <remote> <branch>:<branch>
- 从所有配置的远程仓库获取数据:
git fetch --all
1
2
3
4
5
6
# fetch 远程库
git fetch origin
# 切换到 main 分支
git switch main
# 合并分支远程 main 分支
git merge origin/main
push
将本地的提交向远程库推送
基本格式为:git push <remote> <branch>
1
2
3
4
5
6
7
8
9
10
# 推送所有分支,将当前分支推送远程仓库的同名分支
git push -a origin
# 推送标签
git push --tags origin
# 强制推送,将本地的 main 分支推送到远程仓库的 main 分支上
git push -f origin main
# 删除远程仓库的 feature 分支
git push origin --delete feature
# 将本地仓库的 master 分支推送到远程仓库的 dev 分支上
git push origin master:dev
pull
从远程库获取数据并合并
基本格式为:git pull <remote> <branch>
1
2
3
4
5
6
# 拉去远程库 main 分支的数据并合并到当前分支
git pull origin main
# 要从 origin 远程仓库的 dev 分支获取最新的提交并合并到当前分支的 my-dev 分支
git pull origin dev:my-dev
# 使用 rebase 选项来拉取代码,在远程库的基础上应用本地更改,不会额外生成合并提交
git pull --rebase origin main
checkout
用于切换分支、恢复文件或检出提交。
基本格式为:git checkout <branch>
1
2
3
4
5
6
7
8
# 切换分支
git checkout dev
# 创建新的分支并切换
git checkout -b dev
# 恢复文件状态,效果与 git restore <file>
git checkout -- file.txt
# 分离工作树,相当于 git switch --detach <commit>
git checkout abc123
reset
用于将当前的
HEAD
复位到指定状态
基本格式为:git reset --[option] <commit>
有三个选项
mixed
:将文件回退到工作区,此时会保留工作区中的文件,但会丢弃暂存区中的文件。soft
:将文件回退到暂存区,此时会保留工作区和暂存区中的文件。hard
:将文件回退到修改前,此时会丢弃工作区和暂存区中的文件。
当版本不同的时候,更改会存放在工作区或者暂存区。
1
2
# 将 HEAD 复位到上一个状态
git reset --hard HEAD^
revert
用于创建一次新的提交来回滚版本
基本格式为:git revert <commit>
1
git revert HEAD
stash
该命令用于将当前工作目录中的临时更改保存到一个栈中,以便你可以切换到其他分支或提交上继续工作,注意新建的文件不会被
stash
暂存,需要全部add
到工作区或者加上-u
参数,另外当所有文件都在暂存区的话,pop
之后新文件会放到暂存区,而修改的文件放在工作区。
基本格式为:git stash
1
2
3
4
5
6
7
8
9
10
11
# 保存特定的信息
git stash save "Work in progress"
# 保存特定的新文件
git stash push -u .\source\_posts\JS\ES6.md
git stash list
# 恢复并删除stash中存储的最新修改
git stash pop
# 恢复但不删除stash中存储的最新修改
git stash apply
# 恢复但不删除stash中存储的特定提交
git stash apply stash@{0}
remote
用于对远程库进行操作
1
2
3
4
5
6
7
8
9
10
11
12
# 添加远程库
git remote add upstream https://github.com/runoob/runoob-git-test.git
# 更改远程库的连接
git remote set-url origin [email protected]:tianqixin/runoob-git-test.git
# 将远程库 upstream 重命名为 source
git remote rename upstream source
# 删除远程库
git remote rm source
# 列出当前仓库中已配置的所有远程仓库的名称和 URL
git remote -v
# 本地仓库中删除过时的远程分支引用的
git remote prune origin
cherry-pick
基本格式为
git cherry-pick <commitHash>
git cherry-pick <commitHash>
:将某一提交应用到当前分支。git cherry-pick <branchname>
:将某一分支的最新提交应用到当前分支git cherry-pick <HashA> <HashB>
:将多个提交应用到当前分支选项:
-x
:在提交信息的末尾追加一行(cherry picked from commit ...)
,方便以后查到这个提交是如何产生的。-s,--signoff
:在提交信息的末尾追加一行操作者的签名,表示是谁进行了这个操作。
1
2
3
4
# 转移 A 到 B 之间的提交,不包括 A
git cherry-pick A..B
# 转移 A 到 B 之间的提交,包括 A
git cherry-pick A^..B
tag
Git
的tag
有两种类型:轻量标签(lightweight
)和含附注的标签(annotated
)。轻量标签就是一个指向特定提交的引用,它不会存储任何额外的信息。含附注标签是存储在 Git 数据库中的一个完整对象,它有一个标签名,标签信息,标签签名等信息。一般我们都建议使用含附注型的标签,以便保留相关信息;当然,如果只是临时性加注标签,或者不需要旁注额外信息,用轻量标签也没问题。
Git
的tag
的使用方法如下:
- 创建轻量标签的命令如下:
git tag <tag_name> <commit_id>
,其中<tag_name>
是标签的名称,<commit_id>
是要标记的提交的 ID,如果省略<commit_id>
,默认>会使用当前所在分支的最新提交作为标签指向的提交。- 创建含附注标签的命令如下:
git tag -a <tag_name> -m "<tag_message>" <commit_id>
,其中-a
选项表示创建一个带注解的标签,-m
选项表示添加标签的信息,<tag_message>
是标签的描述,<commit_id>
是要标记的提交的 ID,如果省略<commit_id>
,默认会使用当前所在分支的最新提交作为标签指向的提交。- 查看当前项目中的所有标签,可以使用以下命令:
git tag
,如果想查看某个具体标签的信息,可以使用以下命令:git show <tag_name>
。- 推送标签到远程服务器,可以使用以下命令:
git push origin <tag_name>
,如果要一次性推送所有本地标签,可以使用以下命令:git push origin --tags
。- 删除本地标签的命令如下:
git tag -d <tag_name>
,删除远程标签的命令如下:git push origin :refs/tags/<tag_name>
。
1
2
# 推送 tag 标签
git tag -a v1.0 -m “Release version 1.0”
Git 使用技巧
查看本地分支与远程分支的关联
1
2
git branch -vv
git remote show origin
将本地分支与远程分支关联
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 本地创建了分支而远程没有
git push -u origin main
git push --set-upstream origin main
# 远程创建了分支而本地没有
git checkout -b dev origin/dev
git checkout --track origin/dev
git checkout -t origin/dev
git switch -c fix/time-picker upstream/dev
git fetch upstream dev:test1
# 远程分支与本地分支都有
git branch --set-upstream-to=origin/dev
# 缩写
git branch -u origin/dev
# 取消本地分支与远程分支的关联
git branch --unset-upstream
如何回退版本
git reset --hard HEAD^
git revert HEAD
git checkout commit_id
查看 Git 日志
1
git log
如何修改 git commit 信息
vim
编辑器的使用
- 按下
i
键,进入插入模式,可以修改提交信息。- 按下
Esc
键,退出插入模式,回到命令模式。- 在命令模式下,输入
:wq
,保存并退出编辑界面。- 在命令模式下,输入
:q!
,放弃修改并退出编辑界面。
1
git commit --amend
暂存工作区
1
2
git stash
git stash pop
多个上游的管理
需要多种命令的组合
1
2
3
4
5
6
7
8
# 添加远程库
git remote add upstream https://github.com/runoob/runoob-git-test.git
# fetch 远程库
git fetch origin
# 合并分支
git merge upstream1/main
# 删除远程仓库的 feature 分支
git push origin --delete feature
设置代理
1
2
3
4
# 设置代理
git config --global http.proxy http://127.0.0.1:7890
# 取消代理
git config --global --unset http.proxy
将文件从 Git 中移除
1
2
3
4
# 从 git 中删除,但仍然保留索引
git rm --cached .\ui\bs\auto-imports.d.ts .\ui\bs\components.d.ts
# 索引和本地都删除
git rm .\ui\bs\auto-imports.d.ts .\ui\bs\components.d.ts