Git基础使用指南-命令详解

Software is like sex: it's better when it's free. —— Linus Torvalds


前情须知 -O-

工作流程

首先要明确的是Git的工作流程,你使用Git时,用了三个不同的区域对你的代码进行管理。
1.工作区(workshop):就是你当前写代码的那些文件,具体就是你当前正在编辑的项目。
2.缓存区(Index):是一个临时区域,保存你的临时改动。
3.仓库区(HEAD):你最后提交到的区域。
4.远程仓库*:将仓库同步到线上进行备份。

一般的流程:(工作区)编码 → 添加代码到(缓存区)→ 提交到仓库区(HEAD)→ 推送到远程仓库


基本使用

1.获得一个仓库

当要使用git对项目进行管理的时候,使init面命令进行git的初始化,就会自动进行相关的初始化操作,会在项目中创建隐藏的.git文件夹,里面有相关的配置信息。

$ git init
# 也可在初始化时指定默认分支的名称,否则默认一般为`master`
$ git init -b main
$ git init --initial-branch=main

# 或者先初始化,再指定分支名称
$ git init
$ git branch -M main

当然可以拿别人的仓库(克隆),也能得到一个仓库,比如对vue的源码感兴趣,那把它拿下来

$ git clone https://github.com/vuejs/core

2.在仓库里存东西

打开已经git初始的文件夹,这时你是在工作区要开始干活了。它的过程是这样的:你有个工作室(已init的文件夹,工作区),里面有个小菜篮(缓存区),工作里面还有个仓库(仓库区)。你干活的流程是,先从工作区取菜(东西)放到你菜蓝子,然后用蓝子把它放到了仓库。当然它并不是拿了,而是把它类似复制了。😂

装到蓝子里(add)

使用add命令,git就知道这菜(文件)蓝子里要有一份。执行后缓存区就会有这文件的备份,被add瞄准的文件git就会一直盯着它了

# 添加文件到缓存区 - 拿一个菜
$ git add [文件名1] [文件2]
# 添加文件夹到缓存区 - 拿一堆菜
$ git add [文件夹]
# 添加所有文件到缓存区 - 全不菜都拿了
$ git add .

Git会跟踪的文件的变化了,使用 git status 命令,就可以看到文件的状态了。

# 查看文件状态
$ git status
# 查看简洁的状态信息 short
$ git status -s

当然你将复制到篮子东西不复制了,将它从缓存区删除:

# 停止追踪指定文件,该文件仍会保留在工作区
$ git rm --cached [file]

篮子的货放到仓库里(commit)

使用git commit命令会将缓存区的操作,添加到仓库区,每次提交都要添加提交信息

# 将缓存区的文件提交到仓库区
#然后会打开vm编辑器要求输入提交信息
$ git commit
# 简化,提交和添加提交信息
$ git commit -m '提交信息'
# 跳过添加到缓存区,直接将上一次提交后的修改进行提交
# 所有已经跟踪过的文件暂存起来一并提交
$ git commit -a

当一个文件已经被提交后,要提交删除该文件的记录,使用$ git rm [文件名]命令,工作区的对应文件会被删除,删除记录会添加到缓存区,然后可以commit

修改提交信息(修改一般应在push之前)

在提交的时候总免不了提交信息输入有错误的时候。不改的话心里又不舒服,那怎么改呢?
1.如果是修改最后一次的提交,那直接使用:git commit --amend 就会进行入Vim编辑器编辑内容。
2.如果是要改多次的记录呢,可以使用rebase进行操作。

3.remot远程操作

Git的操作基本上都是本地进行的,但是若是要多人协助,保存/开源到Gitee或Github上就要进行远程操作了。

# 添加一远程仓库,并未之命名
# 当你在github中新建仓库后,它就会让你运行该命令
# 让你的本地仓库和远程仓库关联,它可以添加多个
$ git remote add [远程仓库命名] [url]
$ git remote add origin https://gitee.com/mashiro-xxx/xxxx.git
# 查看所有远程仓库
$ git remote -v
# 删除远程仓库
$ git remote rm [远程仓库]
# 有远程仓库后,将新分支上传
$ git push -u [远程仓库] [分支]
$ git push -u origin master
# 将本地分支上传
$ git push [远程仓库名] [分支名]
$ git push origin master
# 直接推送到远程仓库
$ git push
# 暴力推送到远程仓库,不理会冲突
$ git push --force
# 将远程仓库的代码下载到本地
# 此操作并不会改变本地仓库
# 而是,会在本地有一个远程仓库的分支,如origin/master
$ git fetch [远程仓库]
# 将远程仓库拉取到本地,并合并到本地操作
# 其本质是 fetch 后将,本地分支与远程分支merge
$ git pull [远程仓库] [分支]
# 删除远程分支
$ git push origin --delete branch

4.回退操作

使用Git不仅为了方便版本管理,当然也是为了以备不时之需,所以也是回退代码的可能也是很高的呢。
注:执行回退操作前,切记要将当前工作区内容提交

# 撤销工作区指定文件的操作,撤销至add时的状态
$ git restore [文件]
# 将缓存区的文件回退至工作区
$ git checkout [文件]
# 将缓存区的全部文件回退到工作区
$ git checkout .
# 将工作区回退至上一次commit
$ git reset --hard
# 回退当前分支的HEAD为指定commit
# 同时重置暂存区和工作区,与指定commit一致
$ git reset --hard [commit]

# 回退到上一次提交
$ git reset HEAD^ --hard

# 查看提交历史
$ git log

回退说明:

# 回最后一次提交,并将文件的修改状态取消暂存
# 这将撤回提交,并将更改保留在工作目录中,但不再处于暂存状态。
$ git reset HEAD~1

# 撤回最后一次提交,并丢弃所有更改
# 这将撤回提交并删除所有未保存的更改,请谨慎使用,因为这会导致数据丢失。
$ git reset --hard HEAD~1

5.branch分支操作

分支就像是同一个变种衍生出来的各种变种,每个分支可以有不同的变异方向。不过在Git中分支是可控的,你可以增加,合并,删除。

# 查看当前所有分支
$ git branch
# 新建分支
$ git branch [分支名]
$ git branch dev
# 且换分支
$ git checkout [分支]
$ git checkout master
# 新建并切换到新建的分支
$ git checkout -b [分支]
$ git checkout -b feature_x
# 删除分支,若没有有未被合并的内容,则无法删除
# 不能删除当前所在的分支,如要删除需切换分支
$ git branch -d [分支]
# 强制删除分支
$ git branch -D [分支]
# 删除远程分支 origin为配置的远程仓库
$ git push origin -d [分支]

# 当前所在分支与指定分支合并
$ git merge [分支]
$ git merge dev

# 重命名分支
$ git checkout old-branch-name # 先切换分支
$ git branch -m new-branch-name
$ git branch -m old-branch-name new-branch-name # 或者在其它分支

合并分支
虽然我们使用git merge就能进行合并分支的操作,但是在合并分支的时候通常建议使用git merge --no-ff,详细看下各参数的不同

# 默认 快进模式(fast-forward)
$ git merge [分支]
# 默认是快进模式的,其等同于
$ git merge -ff [分支]

# 非快进模式
$ git merge --no-ff [分支]

# squash 合并的时候可将多次提交总结成一次在合并到分支
$ git merge --squash [分支]

方便演示,创建两条分支master,dev,然后在dev上拉出一个功能分支me_test
image

  1. 我们在me_test,添加两次提交 修改0201 和 修改0202,切换到dev然后使用 git merge me_test
# git log
PS D:\code_work\2022_v2\notes-on-vue-source-code> git log
commit 86a1b0d2afe842057800b955365995ea914b9e6f (HEAD -> dev, origin/dev)
Author: flytree <fff@fff.cn>
Date:   Tue Dec 13 11:11:30 2022 +0800

    修改0202

commit e637e2afa154b8c21829b4b464de6817305326c7
Author: flytree <fff@fff.cn>
Date:   Tue Dec 13 11:11:10 2022 +0800

    修改0201

image

2.我们在me_test,添加两次提交 修改0201 和 修改0202,切换到master然后使用 git merge --no-ff me_test

# git log
commit eba5bac837fd67d2fd55e5f054598a3656a6e5fc
Merge: bef1f6b 86a1b0d
Author: flytree <fff@fff.cn>
Date:   Tue Dec 13 11:13:48 2022 +0800

    Merge branch 'me_test'

commit 86a1b0d2afe842057800b955365995ea914b9e6f (origin/dev, dev)
Author: flytree <fff@fff.cn>
Date:   Tue Dec 13 11:11:30 2022 +0800

    修改0202

commit e637e2afa154b8c21829b4b464de6817305326c7
Author: zhongyu <zhongyu@sdicmicro.cn>
Date:   Tue Dec 13 11:11:10 2022 +0800

    修改0201

image
git log上看只是多了一次提交,但是从图上看是能看到它是保留分支记录的,能看出分支合并的过程的。这也体现在回退上。
当使用git reset HEAD^ --hard回退到上一个版本时,前者能回退到是分支合并前的版本,后者是合并分支中的上一版本。

6.tag操作

如果我们使用的是两个分支的模式进行开发,即master和dev分支进行开发。

  • 当有新功能(新需求时)在dev上拉出一个分支
  • 开发完后合并到dev分支,测试完后合并到master分支。
  • 然后就可以将刚拉出的分支删除了。
  • 在master分支上打标签,如 v1.0.0

相关命令:

# 查看已有tag
git tag

# 新建tag
git tag <标签名>

# 新建带注释tag
git tag -a <标签名> -m '注释信息'

# 查看tag详情
git shwo <标签名>

# 将tag推送到远程仓库
git push origin <标签名>
# 将所有未推送tag推送到远端
git push origin --tags

# 删除本地tag
git tag -d <标签名>
# 删除远程tag
# 先删除本地tag,然后
git push origin :refs/tags/<标签名>

# 切换到指定标签
## 1.1 查看标签
### 查看所有标签
git tag
### 搜索标签
git tag -l "v3.4.*"
## 1.2 检出标签(这个命令会使仓库进入“Detached HEAD”状态。这意味着HEAD指针当前不在一个分支上, 也就是改不了代码只能浏览)
git checkout v3.4.0
## 1.3 修改标签 用原标签新建一个分支如:
git checkout -b <新分支名称> <tag名称>
git checkout -b nv3.4.0 v3.4.0

# 回退到指定tag
git shwo <标签名> # 得到提交的hash
git reset --hard cddfeds # reset到tag的hash

7.临时存储更改stash

若在dev分支开发时,已经更改了文件。但要在突然要在别的分支进行修改。
且我们在当前分支的开发未完成,不想提交那么快,可使用git stash命令。
它会将当前的记录先保存在一个临时的区域(堆栈中),让你可以先储存当前的更改,而放心切换分支了。

# 查看所有提交的记录
$ git log
# 暂时将未提交的变化保存,会自动生成保存的记录
$ git stash

# 可以在stash时添加说明
$ git stash save '保存dev修改'

# 使用最新的stash
$ git stash pop

# 查看所有保存的stash的列表
$ git stash list

可以使用vscode中提供的菜单进行操作:
image

8.gitignore

.gitignore文件可以配置哪些文件要忽略处理,使用些脚手架工具之类创建的时候大多是会自动生成的。不过有时候,还是得自己配置些东西,一些基本配置说明。

说明:已经add的文件,即使后面在gitignore中忽略了,还是会进行跟踪。所以在在init后就尽快创建gitignore会比较好哦。

# 忽略 node_modules 文件(或夹)
# 如 project/b/node_modules 这样也会被忽略
node_modules
# 忽略当前目录下的dist文件
/dist
# 忽略所有以 .idea 结尾的文件
*.idea
# 不忽略 lib.idea,前面配置了也不忽略
!lib.idea
# 忽略 bulid/ 文件夹下的所有文件
bulid/
# 忽略 doc/a.txt, 不包括 doc/xxx/c.txt
doc/*.txt

进阶操作

1.分支进阶

创建无父依赖的分支

$ git checkout --orphan 分支名

此命令在创建分支时不会有父分支,也就是它创建的分支是独立的,和父分支没有依赖关系。创建成功后,原分支的文件会在创建时添加到当前暂存区。它是个全新的分支,没有任何的提交。
使用此命令可以将多个(相关)项目,放到统一仓库下进行git管理。

本地分支于远程分支名不同的pull和push

# 将远程指定分支 拉取到 本地指定分支上:
git pull origin <远程分支名>:<本地分支名>

# 将本地当前分支 推送到 远程指定分支上(注意:pull是远程在前本地在后,push相反):
git push origin <本地分支名>:<远程分支名>
git push github master:main

Git将本地某一个分支的内容上传到远程不同名分支

2.cherry-pick

git cherry-pick 命令用于从一个分支中选择特定的提交(commit),并将其应用到当前分支。这与常规的合并(merge)或变基(rebase)不同,后者通常会将多个提交整合到目标分支中。cherry-pick 允许开发者灵活地选择单个提交,从而避免将整个分支的更改合并过来。

使用场景

  • 修复错误:当在一个分支上发现了错误并进行了修复,但需要将该修复应用到另一个分支时,可以使用 cherry-pick。
  • 选择性合并:在团队协作中,可能只想将某些特定的提交从一个分支合并到另一个分支,而不是整个分支的所有更改。
  • 恢复丢失的提交:如果某个提交在合并时被遗漏,可以通过 cherry-pick 将其恢复到目标分支。
  • 从废弃分支中提取提交:如果某个功能分支被放弃,但其中的某些提交仍然有用,可以将这些提交提取到其他分支中。

冲突处理

  • 若出cherry-pick时出现冲突,解决冲突后可以使用git cherry-pick --continue继续操作,创建一个新的提交,包含解决冲突后的内容。
  • 如果需要,取消 cherry-pick: 如果在解决冲突时决定不再继续git cherry-pick --abort取消。

3.git revert

是一个用于撤销 Git 提交的命令。与其他撤销命令(如 git reset)不同,git revert 不会删除提交历史,而是通过创建一个新的提交来反转指定提交的更改。这使得 git revert 在协作开发中非常安全,因为它保留了所有的提交历史。

使用git revert HEAD进行回退后,回生成并新加一个revert的提交记录(可修改),回退的提交不保留在工作区(可从提交记录中查看)。
使用git reset HEAD~1进行回退后,会将要回退的记录删除,不新加记录,回退的内容保留在工作区。

使用场景

  • 修复错误:当你发现某个提交引入了错误时,可以使用 git revert 来撤销该提交,而不影响后续的提交。
  • 保持历史记录:在需要撤销某些更改但又不想丢失历史记录时,使用 git revert 是最佳选择。
  • 协作开发:在团队项目中,使用 git revert 可以避免对其他开发者的提交历史造成影响。

4.Rebase变基

修改提交的信息

使用 git rebase -i HEAD~2**
可改最近两次的记录,当然也可~3之类的。
如我有三次提交记录:

commit fd6169282b10e2141631ff8c64d2f286068138fe
提交2
commit ab87b986a872c56df8c55de228e76911993e4a7b
提交1
commit 65818ffaa30e9ccf6b51433f485fa77af365e91b
init

执行之后,上面的是你提交的记录,下面的注释是命令说明:

pick ab87b98 提交1
pick fd61692 提交2

# Rebase 65818ff..fd61692 onto 65818ff (2 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.

i进入编辑模式,将要修改的记录前的pick改成eedit。然后wq保存退出。便会有提示。

  • git commit --amend进行入修改你之前改了e的条目。然后修改保存退出。
edit ab87b98 提交1
pick fd61692 提交2
  • 然后执行git rebase --continue你的修改记录就出现在你当前分支上了。
  • git log就能看到你的提交信息已经修改了。

合并提交记录(信息)

如有多次交琐碎的提交想要合并成一次提交,那也可以使用git rebase进行合并提交的操作。如想将最近两次提交合并成一次提交。

使用git rebase -i HEAD~2,可以修改最近两次的内的提交记录,将要合并的记录前面改成ssquash

pick ab87b98 提交1
s fd61692 提交2

然后就会有之前的信息,进行修改,没被注释的信息都是可以修改的,然后会作为此次合并的信息。修改后,wq保存就是此次合并的修改了。

合并指定的提交

如果提交的记录是比较久的了,可以直接提交的SHA直接进行操作。使用你要合并的提交的前一次提交的SHA直接。
image

如想要操作1.3.2次及之后的提交,则使用‘第1.3次提交-合并’的SHA值,就能定位到了:

git rebase -i 05efd0344b65809050e2070e95b4e2b6491e9d11

# 结果
pick 46a266f 第1.3.2次提交
pick 0a96fb5 第1.3.3次提交
pick 64b1866 第1.3.4次提交

然后同样的将pick改成s就能合并了。

修改提交的作者,邮箱等信息

# rebse
git rebase -i 05efd0344b65809050e2070e95b4e2b6491e9d11

e标记要修改的提交,wq保存后使用,会出现提示

pick 46a266f 第1.3.2次提交
e 0a96fb5 第1.3.3次提交
pick 64b1866 第1.3.4次提交

然后使用--author参数,执行后再编辑提交信息。

git commit --amend --author="fly <fly@tree.com>"

使用git rebase --continue结束rebase,将更改更新到仓库。
image

3.使用代理加快clone速度

受限于国内的网络环境,在返回GitHub的时候可能会很慢。而且拉取或克隆GitHub上的项目也会非常慢。为了优化体验,可以设置代理。

http的代理

## 设置
git config --global http.proxy "http://127.0.0.1:8080"
git config --global https.proxy "http://127.0.0.1:8080"
## 取消
git config --global --unset http.proxy
git config --global --unset https.proxy

为GitHub指定socket5代理

## 设置
git config --global http.https://github.com.proxy 'socks5://127.0.0.1:10808'
## 取消
git config --global --unset http.https://github.com.proxy

其代理的是https这种协议的链接,所以:

# 有代理
https://github.com/flutter/samples.git
# 无代理
git@github.com:flutter/samples.git

git配置操作

# 查看当前所有配置
git config -l
# 删除某一项配置
git config --global --unset user.name
# 编辑配置
git config --global --edit

4.多账户共同使用(ssh key)

在某些场景,比如有工作和个人的git账户,账户不同要同步到网站也是不同的,可进行配置后能同时使用。

1.首先对不同的账户都生成密钥文件

ssh-keygen -t rsa -C mailegitee@qq.com
ssh-keygen -t rsa -C mailegitlab@qq.com

2.在.ssh文件夹下创建config文件,为不同的域指定对应的密钥。配置文件内容:

# 配置gitee
Host gitee.com
    HostName gitee.com
    IdentityFile ~/.ssh/gitee/id_rsa
    PreferredAuthentications publickey
    User yourname

# 配置gitlab
Host 192.2.2.18
    HostName 192.2.2.18
    IdentityFile ~/.ssh/gitlab/id_rsa
    PreferredAuthentications publickey
    User 你的名字

3.把公钥在不同的站点进行设置。
image

此时可以进行提交,但提交所使用的nameemail都是全局设置的。如要单独设置,则在仓库目录添加局部的信息:

// 全局配置
git config --global user.name  "username"
git config --global user.email  "email"

// 局部配置
git config  user.name "xxx"
git config  user.email "flyree@fzsw.com"

查看配置的命令:

git config --list

添加远程仓库:

git remote add gitee https://gitee.com/xxxflytreexx/xxxx.git
git push -u origin "master"

git remote add gitlab https://gitlab.com/xxxflytreexx/xxxx.git
git push -u gitlab "master"

5.Git导出提交记录

工作中若要导出提交记录可以通过命令进行导出。如使用git log --pretty=oneline > log.txt可以在项目根目录下导出提交记录。导出时可能会有乱码可添加编码参数,如:

# 指定编码
git log --encoding='gbk' > log.txt
git log --encoding='utf-8' > log.txt

git log也有很多的参数,-pretty 选项进行设置。--pretty 选项接受多种预定义格式和自定义格式字符串。可以支持更加自定义的导出操作:
1. 预定义格式:
--pretty 选项可以接受以下预定义格式:

  • oneline: 每行显示一个提交,简洁紧凑。
  • short: 显示提交哈希、作者、日期和提交信息标题。
  • medium: 显示提交哈希、作者、日期和完整的提交信息。
  • full: 显示提交哈希、作者、提交者、日期和完整的提交信息。
  • fuller: 与 full 类似,但还包含作者日期和提交者日期。
  • format:: 允许使用自定义格式字符串。 这是最灵活的选项。
  • email: 以电子邮件格式显示提交信息。
  • raw: 显示原始提交数据。
    示例:
  • git log --pretty=oneline: 简洁地显示每个提交的哈希值和标题。
  • git log --pretty=short: 显示更详细的信息,包括作者和日期。
  • git log --pretty=fuller: 显示最完整的信息,包括作者和提交者的日期。
  • git log --pretty=email: 以电子邮件格式显示提交信息,适合发送给其他人。

2. 自定义格式字符串:
--pretty=format: 允许你使用自定义格式字符串来精确控制输出。格式字符串使用类似 printf 的格式说明符。
一些常用的格式说明符:

  • %H: 完整的提交哈希值。
  • %h: 简短的提交哈希值。
  • %T: 树的哈希值。
  • %t: 简短的树的哈希值。
  • %P: 父提交的哈希值(多个父提交用空格分隔)。
  • %p: 简短的父提交的哈希值。
  • %s: 提交信息标题。
  • %b: 完整的提交信息。
  • %an: 作者姓名。
  • %ae: 作者邮箱。
  • %ad: 作者日期(默认格式)。
  • %ar: 作者日期(相对时间)。
  • %at: 作者日期(Unix 时间戳)。
  • %ai: 作者日期(ISO 8601 格式)。
  • %cn: 提交者姓名。
  • %ce: 提交者邮箱。
  • %cd: 提交者日期(默认格式)。
  • %cr: 提交者日期(相对时间)。
  • %ct: 提交者日期(Unix 时间戳)。
  • %ci: 提交者日期(ISO 8601 格式)。
  • %d: 引用名称。
  • %n: 换行符。

使用示例:

# --author 过滤作者
# --since 过滤提交时间
git log --encoding="gbk" --pretty=format:"%ai - %an: %s , %b" --since="3 day ago" --author="zzz" > commit.log

# 导出到桌面,且导出表格
git log --encoding="gbk" --pretty=format:"%ai - %an: %s , %b" --since="3 day ago" --author="zzz" >> ~/Desktop/commit.csv

导出示例:
image

Git提交规范指南

社区里有多种commit message写法规范, 本段主要介绍比较广泛的Angular规范,如:
image

一. 类型:提交类型指定为下面其中一个:

  1. build:对构建系统或者外部依赖项进行了修改
  2. ci:对CI配置文件或脚本进行了修改
  3. docs:对文档进行了修改
  4. feat:增加新的特征
  5. fix:修复bug
  6. pref:提高性能的代码更改
  7. refactor:既不是修复bug也不是添加特征的代码重构
  8. style:不影响代码含义的修改,比如空格、格式化、缺失的分号等
  9. test:增加确实的测试或者矫正已存在的测试
  10. chore 杂项任务,如更新了依赖,修改了ReadMe

二. 主题

主题包括了对本次修改的简洁描述,有以下准则

  1. 使用命令式,现在时态:“改变”不是“已改变”也不是“改变了”
  2. 不要大写首字母
  3. 不在末尾添加句号
docs(*): update end-of-life messages (#17177)
* Docs homepage
* Docs banner
* Security and support pages
* GitHub README
* CHANGELOG

Angular提交信息规范(中文)

一些错误处理

1.remote: [session-fa4615b5] Access denied

可能是本地存储的凭证不正确,可以修改,或者删除。删除后,再次提交,会弹窗让你输入用户名和密码。

windows可在此路径修改:控制面板\用户帐户\凭据管理器
image

2.git提交到仓库的文件夹不能点击

无法点击的灰色文件夹中含有 .git 文件
https://blog.csdn.net/qq_45718618/article/details/121299431

3.Deletion of directory '/xxx' failed.

操作时(如,切换分支,rebase等)出现次错误,一般可能是文件被占用,导致git无法修改文件。可以看下是否是vscode之类编辑打开了项目,关闭后再操作即可。

posted @ 2021-03-27 22:49  会飞的一棵树  阅读(1088)  评论(0编辑  收藏  举报