本文为个人自用 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> 分支的直接后继。

例如,假设有两个分支 masterdev,它们的提交历史如下:

1
2
master: A - B - C - D
dev: A - B - E - F

其中,A、B、C、D、E、F 都是提交 ID 的简写,A 是最早的提交,F 是最新的提交。如果我们想要将 dev 分支变基到 master 分支上,也就是说,我们想要将 EF 这两个提交重新应用到 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'EF 的副本,它们的内容和 EF 相同,但是它们的提交 ID 不同,因为它们是在 D 的基础上重新生成的。这样,dev 分支就变成了 master 分支的直接后继,它们的历史线性化了。

但是,如果在 master 分支上的 CD 这两个提交,和 dev 分支上的 EF 这两个提交,都对同一个文件的同一行内容做了不同的修改,那么在执行 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 表示目标分支的最新提交,也就是 DE 表示正在应用的提交,也就是 EGit 会中断变基的过程,让你手动解决冲突,你可以选择保留其中一个版本的内容,或者合并两个版本的内容,或者删除整个内容,然后保存文件,执行 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

Gittag 有两种类型:轻量标签(lightweight)和含附注的标签(annotated)。轻量标签就是一个指向特定提交的引用,它不会存储任何额外的信息。含附注标签是存储在 Git 数据库中的一个完整对象,它有一个标签名,标签信息,标签签名等信息。一般我们都建议使用含附注型的标签,以便保留相关信息;当然,如果只是临时性加注标签,或者不需要旁注额外信息,用轻量标签也没问题。

Gittag 的使用方法如下:

  • 创建轻量标签的命令如下: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