Git学习笔记
Git Notes
零、我在学习Git过程中用到的资料
尚硅谷Git入门到精通全套教程(涵盖GitHub\Gitee码云\GitLab)
https://learngitbranching.js.org/?locale=zh_CN
其他资料(待更新)
一、Git概述
Git是分布式的版本控制系统。
版本控制:记录文件内容变化,最重要的是记录文件修改历史记录。
版本控制系统有两类:
- 集中式版本控制系统:CVS、SVN等,所有的文件修改版本保存在一个单一的集中服务器。用户从服务器上提取最新版文件进行修改,再提交到服务器。
- 分布式版本控制系统:Git等,提取的不是最新版本的文件快照,而是镜像整个代码仓库为一个本地库,每一次提取实际上就是对代码库进行备份。修改完后将代码推送至代码托管中心(远程库),远程库的代码是最新的。
- 主要区别在于:服务器断网也可以开发,且每个客户端都保存着完整代码。
Git运行机制:
图源:https://walkssi.com/git/ - 工作区:代码存放的位置。在工作区可以修改代码,且没有历史记录;
- 暂存区:将工作区的代码添加(
git add
)到暂存区,也可以修改代码并且没有历史记录; - 本地库:将暂存区的代码提交(
git commit
)到本地库,就会生成历史版本。在本地库的版本不能修改。若发现代码不尽人意,只能在工作区修改后再次提交,提交后本地库同时存在这两个版本。例如,先提交了v1版本,发现不好,则只能在v1版本基础上修改然后提交为v2; - 远程库(代码托管中心):将本地库的代码推送(
git push
)至远程库。
注意⚠️:所有的版本控制系统,包括Git,只能跟踪纯文本文件的改动,比如TXT文件、网页、程序源代码等。图片、视频,以及Microsoft的Word格式等二进制文件,没法跟踪文件内部的变化。
二、常用的Git命令
1 | git config --global user.name <your name> # 设置全局用户签名 |
设置用户签名
用于区分不同的本地作者身份,在每一个提交的版本之中可以看到是谁提交的(这里的用户名与GitHub的用户名没有关系)。
1 | git config --global user.name <your name> # 设置全局用户签名 |
在C:\Users\SDYZZY\.gitconfig
文件中可以查看是否成功。
初始化本地库
让Git获得项目目录的管理权。在项目目录内执行git init
来初始化本地库,完成后项目目录内会增加一个.git
隐藏文件夹。
1 | (base) sdyzzy@SDYZZY-MacBook-Pro git_study % git init |
查看本地库状态
在项目目录内执行git status
来查看本地库状态,包括目前所处的分支(branch),有无需要添加暂存区、提交本地库的文件或目录。
1 | (base) sdyzzy@SDYZZY-MacBook-Pro git_study % git status |
main
指当前分支(Windows里面为master)。no commits yet
指目前没有提交过任何文件nothing to commit (create/copy files and use "git add" to track)
指当前没有文件需要提交。
新建一个文档hello.txt
,然后再查看本地库状态。输出中的Untracked files:
表示此时在工作区存在一个叫hello.txt
的未追踪的文件,可以使用git add
追踪(即添加到暂存区)。
1 | (base) sdyzzy@SDYZZY-MacBook-Pro git_study % touch hello.txt |
注意⚠️:新建的空目录无法被检测到,因为git是对“文件的内容”来计算的。解决方法是在空目录中随意创建一个文件,使得git可以检测到该目录的存在。
忽略指定文件或目录
在项目目录内创建一个名为.gitignore
的文件,在其中添加需要忽略的文件名或目录名(一行只能输入一个名称),可以使用通配符忽略一类文件或目录。
- 以
#
开始:注释行。 - 以
/
开始:防止递归(也就是只忽略当前目录下的该文件,而不忽略子目录下的同名文件)。 - 以
/
结尾:指定目录(也就是忽略项目中所有该名称的目录)。 - 问号
?
只匹配一个任意字符。星号*
匹配零个或多个任意字符。方括号[abc]
匹配任何一个在方括号中的字符 (这个例子要么匹配一个 a,要么匹配一个 b,要么匹配一个 c);如果在方括号中使用短划线分隔两个字符, 表示所有在这两个字符范围内的都可以匹配(比如 [0-9] 表示匹配所有 0 到 9 的数字)。两个星号**
表示匹配任意中间目录,比如a/**/z
可以匹配a/z
、a/b/z
或a/b/c/z
等。
1 | # .gitignore |
例如扩展名为.pyc
的文件根据.py
文件自动生成,因此无须让Git跟踪它们,这些文件存储在目录\__pycache__
中。
1 | >>vim .gitignore |
添加到暂存区
使用
git add <filename1> <filename2> ...
可以指定添加哪些文件到暂存区使用
git add --all
可以将项目目录中所有被修改过的文件添加到暂存区。
1 | (base) sdyzzy@SDYZZY-MacBook-Pro git_study % git add hello.txt |
此时再查看本地库状态,Changes to be committed:
表示已经追踪到了文件,并且等待提交本地库。由于现在文件只存在于暂存区(可以用git rm --cached <filename>
把暂存区内的文件删除,但是工作区里仍然存在,需要手动删除),所以还未形成历史版本。
注意⚠️:在Windows系统中可能会由于转换行末换行符而产生警告,一般不用管,如下图所示。
提交到本地库
git commit -m "commit message" <filename1> <filename2>
。将暂存区内的指定文件提交到本地库。使用-m
或--message
参数添加本次的修改内容,要求简单具体。- 如果不指定filename,则会将暂存区中的所有文件提交到本地库。
- 下面的代码表示在本地库主分支(main)提交了一个信息为“create hello.txt”的hello.txt文件,(精简的)commit number为9c84112,1个文件被改变,0行内容被插入,0行内容删除。
1 | (base) sdyzzy@SDYZZY-MacBook-Pro git_study % git commit -m "create hello.txt" hello.txt |
提交多行信息:
如果给出多个
-m
选项,则它们的值被串联为单独的段落(段落之间会空一行)。1
2
3
4
5
6
7
8
9
10>>git commit -m "refactor" -m "delete file1"
>>git status
Author: SDYZZY <sdyzzy@mail.ustc.edu.cn>
Date: Mon Nov 13 23:06:44 2023 +0800
refactor
delete f1.md
end.先输入一个引号,然后键入内容,按回车键换行,继续输入。信息输入结束后,输入另一半引号,按回车键提交。
1
2
3
4
5
6
7
8
9
10
11
12>>git commit -m "refactor
>>delete f5
>>
>>end."
>>git status
Author: SDYZZY <sdyzzy@mail.ustc.edu.cn>
Date: Mon Nov 13 23:05:21 2023 +0800
refactor
delete f5
end.
commit规范:
1
2
3
4
5
6
7<type>(<scope>): <subject>
<body>
# 示例
feat(新增视图层):添加登录页面
- 支持自动登录
登录页面,新增链接参数解析,如果链接中包含from=auto,则表示进行自动登录type
: commit 的类型,包括但不限于feat
: 新功能;fix
: 修复BUG;docs
: 文档更新;style
: 代码风格相关无影响运行结果的;- perf: 优化/性能提升;
refactor
: 重构;- revert: 撤销修改;
- test: 增加测试内容;
- undef: 不确定的分类。
scope
: commit 影响的范围,比如某某组件、某某页面。subject
: commit 的简短描述,不超过50个字符。Body
: 本次 commit 的详细描述,可以分成多行。
从工作区、暂存区、本地库删除:
git rm <filename>
:使用该命令删除工作区的文件,然后将“删除”这一修改提交本地库(添加暂存区已经由git自动完成,因此这一语句相当于rm <filename>
+git add <filename>
),前提是暂存区里面没有该文件(如果有可以用下面的命令)。git rm --cached <filename>
:如果不想继续跟踪某个文件,可以使用该语句将该文件从git中移除,然后将“删除”这一修改提交本地库(也可以使用该命令删除暂存区的文件)。git restore <filename>
:文件在暂存区且在工作区做了修改,执行该命令可以将工作区的文件恢复到最后一次add的状态(也就是和暂存区一致)。git restore --staged <filename>
:文件在暂存区且在工作区做了修改,执行该命令可以将暂存区文件删除,且工作区文件不变(如果工作区未做修改,那么将暂存区的文件删除就相当于使文件不被追踪)。
查看commit记录
git log
会按时间从新到旧顺序列出项目所有的提交历史。git log --oneline
:每次提交的记录只显示1行。git log <filename>
:查看特定文件的commit记录。git log -p <filename>
:查看特定文件的commit记录以及每次提交所引入的差异。
git reflog
显示最近1个月 HEAD 和分支引用的指向。每当 HEAD 所指向的位置发生了变化,Git 就会将这个信息存储到引用日志里。
1 | (base) sdyzzy@SDYZZY-MacBook-Pro git_study % vim hello.txt # 添加一行文本“Hello world” |
其中的(HEAD -> main)
表示 HEAD 指针指向 main 分支的 commit number 为4601fc5的版本。
版本穿梭
git reset --hard commit_number
用于回退到过去的某个版本。
1 | (base) sdyzzy@SDYZZY-MacBook-Pro git_study % git log --oneline |
HEAD 指针已经指向了 commit number 为 9c84112 的历史版本,并且输出文件发现确实回到了该版本。实际上是 HEAD 指针指向了 main ,然后 main 指针改变指向了 9c84112 版本(在\.git\refs\heads\main
文件内可以查看 main 指向的版本),因此版本穿梭的关键是改变指针指向。
修改commit记录
- 修改最后一次commit的记录:
git commit --amend -m "your new log"
,只需在原来的commit命令加上一个--amend
参数,并提供新的记录即可。 - 修改更早的记录:
git rebase -i commit_number
,进入rebase命令的交互模式,commit_number表示从最后一次commit到commit_number(不包括)指定的那一次commit。此命令会进入一个vim编辑器,里面显示了这些commit的信息。参数pick
表示不对commit做改动;reword
表示修改commit信息,将需要修改的记录对应的参数改为reword
后,保存退出。然后会立即弹出另一个vim编辑器,在该编辑器之中修改commit信息,然后保存退出。命令执行结束后,所有被修改的commit以及它之后的commit的SHA-1值都会改变(因为历史信息被修改了)。 - 用
git reset
版本穿梭,然后重新提交。 - 合并多个commit为一个commit:
git rebase -i commit_number
,rebase命令的交互模式,commit_number表示从最后一次commit到commit_number(不包括)指定的那一次commit。此命令会进入一个vim编辑器,里面显示了这些commit的信息。将pick
修改为squash
,然后保存退出,在弹出的vim编辑器里面修改commit信息。 git rebase -i
可以实现commit合并、分解、删除、修改记录、调整顺序、在指定的commit之间添加新的commit等。
1 | (base)sdyzzy@SDYZZY-MacBook-Pro test % git reflog |
追加文件到最后一次commit
有时会发现某些文件被漏掉了没有提交,但是又不愿意为此新建一次提交,可以使用该方法将漏掉的文件添加到最近一次的提交中。先添加到暂存区,然后按照上面的方法提交本地库并修改提交记录git commit --amend -m "your log"
或者只提交本地库不修改记录git commit --amend --no-edit
。
取消版本控制
rm -rf .git
。由于版本信息都存储在.git
文件夹之中,因此删除该文件夹就可以取消版本控制。
版本迭代(修改文件)示例
修改hello.txt.,然后再查看状态:红色表明修改了且还未追踪。
然后进行添加、提交:此时指针已经指向新的版本。
总结
首先使用git reflog
或者git log
查看各个版本情况,修改后就可以用git add 文件名
添加到暂存区,然后用git commit -m "版本信息" 文件名
提交到本地库,若一段时间后不满意当前的版本,可以用git reset --hard 版本号
回退到过去的某个版本。
三、Git分支
1 | git branch -l # --list,查看本地分支 |
多个分支
用户分支,测试分支,开发分支……不同分支互不干扰,可以同时推进,完成开发后就可以进行分支合并(在用户看来就是更新),如果失败也可以直接删除分支。
分支底层就是指针的引用,当创建一个新的commit的时候,当前分支(也就是HEAD指向的那个分支)会指向这个新的commit,而其他分支的指向不会发生任何变化。
切换分支的时候,git会用新的分支的commit内容来更新暂存区和工作目录(最好commit了再切换分支)。
创建分支
git branch <new branch name>
:创建分支。git branch <new branch name> commit_number
:在指定的commit处创建分支。
创建热修复分支hot-fix:
查看已有分支
git branch -l
:查看本地分支。git branch -v
:查看本地分支以及最后一次commit的hash值。git branch -a
:查看本地、远程分支。
切换分支
git checkout 分支名
。可以看到星号已经转移到了hot-fix分支前。切换分支后,目录内的文件也会跟着切换(例如某个文件在A分支有而B分支没有,则从A分支切换到B分支后目录内该文件会消失,再切换回A分支又会出现)。
分支合并
git merge –no-ff <branch name>
:将branch name分支合并入当前分支。相当于用新的分支覆盖了当前分支(分支仅仅是指针,所以合并分支实际上是指的合并commit,因此分支名也可以用commit号代替)。
Git 合并两个分支时,如果顺着一个分支走下去可以到达另一个分支的话,那么 Git 在合并两者时,只会简单地把指针右移,叫做“快进”(fast-forward)。这种情况历史里面看不出来曾经做过合并,而且如果删除分支则会丢失merge分支的信息。
加上
--no-ff
参数可以禁止fast-forward模式,这样合并后的历史记录能看出来曾经做过合并。正常合并:由master分支的文件创建了hot-fix分支,且master分支没有修改,但是hot-fix分支修改了,因此可以直接合并。
冲突合并:两个分支上的同一文件同一位置有两套不同的修改,不能直接合并。
例如,现在在main分支,新建一个分支切换过去,并创建一个merge.md文件并输入“This is BIG”,添加提交。然后回到main分支,也创建一个merge.md文件并输入“This is small”,添加提交。接着尝试git merge,会报错。此时可以vim进入该文件看冲突在哪里,并手动修改。然后直接添加提交提交即可完成merge。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64(base) sdyzzy@SDYZZY-MacBook-Pro test % git branch future
(base) sdyzzy@SDYZZY-MacBook-Pro test % git checkout future
(base) sdyzzy@SDYZZY-MacBook-Pro test % echo "This is BIG" >> merge.md
(base) sdyzzy@SDYZZY-MacBook-Pro test % git add .
(base) sdyzzy@SDYZZY-MacBook-Pro test % git commit -m "BIG"
(base) sdyzzy@SDYZZY-MacBook-Pro test % cat merge.md
This is BIG
(base) sdyzzy@SDYZZY-MacBook-Pro test % git checkout main
(base) sdyzzy@SDYZZY-MacBook-Pro test % echo "This is small" >> merge.md
(base) sdyzzy@SDYZZY-MacBook-Pro test % git add .
(base) sdyzzy@SDYZZY-MacBook-Pro test % git commit -m "small"
(base) sdyzzy@SDYZZY-MacBook-Pro test % cat merge.md
This is small
(base) sdyzzy@SDYZZY-MacBook-Pro test % git merge future
Auto-merging merge.md
CONFLICT (add/add): Merge conflict in merge.md
Automatic merge failed; fix conflicts and then commit the result.
(base) sdyzzy@SDYZZY-MacBook-Pro test % git status
On branch main
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both added: merge.md
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)
(commit or discard the untracked or modified content in submodules)
modified: git_study (untracked content)
no changes added to commit (use "git add" and/or "git commit -a")
(base) sdyzzy@SDYZZY-MacBook-Pro test % vim merge.md
<<<<<<< HEAD
This is small
=======
This is BIG
>>>>>>> future # 手动将所有内容删除,然后键入" This is medium",保存
(base) sdyzzy@SDYZZY-MacBook-Pro test % git commit -am "medium"
[main 3149370] medium
(base) sdyzzy@SDYZZY-MacBook-Pro test % git log --graph
* commit 314937084e5fd0805e834071275149bdd6f1b59f (HEAD -> main)
|\ Merge: 782b132 b0a3a75
| | Author: SDYZZY <sdyzzy@mail.ustc.edu.cn>
| | Date: Mon Nov 20 20:05:28 2023 +0800
| |
| | medium
| |
| * commit b0a3a754dc12d5a23f94d11564934fe09377de89 (future)
| | Author: SDYZZY <sdyzzy@mail.ustc.edu.cn>
| | Date: Mon Nov 20 19:52:33 2023 +0800
| |
| | BIG
| |
* | commit 782b13206ac8a35774f17443c20d9d6009497cb1
|/ Author: SDYZZY <sdyzzy@mail.ustc.edu.cn>
| Date: Mon Nov 20 19:53:38 2023 +0800
|
| small
(base) sdyzzy@SDYZZY-MacBook-Pro test % git branch -d future
Deleted branch future (was b0a3a75).
需要手动合并:打开文件,手动删除多余的,然后添加、提交(此时提交不能带文件名)。此时切回hot-fix分支,文件没有被修改,只有master分支(合并分支)被修改了:
总结
分支master、hot-fix是指向具体版本记录的指针,head则指向当前分支。因此创建分支就是多创建一个指针。
四、Git标签
1 | git tag <your tag> commit_number # 创建轻量标签 |
标签与分支类似,都是指向某个commit的指针。区别在于,分支会随着commit的前进而前进,但是标签一直留在那个commit上。
标签分类:
轻量标签(lightweight tag)和有附注的标签(annotated tag)。
轻量标签一般用于个人使用或者暂时标记。更推荐使用有附注的标签,一般在开发到阶段性的时候贴上标签,比如版本号1.0.0。
轻量标签:
git tag <your tag> commit_number
。查看轻量标签只显示指向的那个commit的信息。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17>>git log --oneline
70916df (HEAD -> main) refactor
03d9f85 refactor delete f5
>>git tag 测试标签 03d9f85
>>git log --oneline
70916df (HEAD -> main) refactor
03d9f85 (tag: 测试标签) refactor delete f5
>>git show 测试标签
commit 03d9f850b6f87779940534bf71b7e841d3809e54 (tag: 测试标签)
Author: SDYZZY <sdyzzy@mail.ustc.edu.cn>
Date: Mon Nov 13 23:05:21 2023 +0800
refactor
delete f5
end
...有附注的标签:
git tag <your tag> commit_number -a -m "your annotation"
。参数-a
让git创建有附注的标签,-m
输入附注。查看有辅助的标签除了显示commit信息以外,还会显示谁在什么时候贴了这张标签以及附注信息。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21>>git tag 测试有附注的标签 70916df -a -m "这里是一些附注"
>>git log --oneline
70916df (HEAD -> main, tag: 测试有附注的标签) refactor
03d9f85 (tag: 测试标签) refactor delete f5
>>git show 测试有附注的标签
tag 测试有附注的标签
Tagger: SDYZZY <sdyzzy@mail.ustc.edu.cn>
Date: Tue Nov 14 19:44:06 2023 +0800
这里是一些附注
commit 70916dfdd42836afbc36cb2e4a973b9545752577 (HEAD -> main, tag: 测试有附注的标签)
Author: SDYZZY <sdyzzy@mail.ustc.edu.cn>
Date: Mon Nov 13 23:06:44 2023 +0800
refactor
delete f1.md
end.
...
查看标签:
git show <your tag>
。删除标签:
git tag -d <your tag>
。例子:
1
2
3git tag v1.4-lw # 创建轻量标签
git tag -a v2.0 -m '描述信息' # 创建附注标签
git tag -a v1.2 9fceb02 # 后期对指定提交打标签
五、Git与Github
本地库和远程库之间通过SSH通信,因此创建远程库之前需要先设置RSA 密钥对:
1 | ssh-keygen -t rsa -C "email@example.com" |
该命令会在用户主目录下生成 .ssh
目录,包含 id_rsa
(私钥)和 id_rsa.pub
(公钥)等文件。
创建远程库
1.1点击New Repository
1.2起远程库名,一般与本地库相同
1.3选择公共库与私有库(公共库读取权限公开)
1.4点击code,可以看到远程库的Https和ssh的地址链接
远程库操作
1 | git remote -v # 查看当前所有远程地址别名 |
创建远程库别名:
git remote add 别名 远程地址
。链接太长,对链接起别名,以后push和pull就可以直接用别名代替链接,一般就用库名作为别名(默认的别名都是origin)。推送本地库至远程库:
git push 别名或远程库链接 分支
。拉取远程库至本地库:
git pull 远程库别名或地址 远程分支名
。本地库与远程库已经不同步了,将远程库的内容拉取到本地库克隆远程库至本地库:
git clone 远程库地址
。(一般使用SSH地址。如果使用https克隆,则不需要init,也不需要登陆账号)。clone做了这三件事:拉取代码;初始化本地库;创建别名。git clone
和git pull\fetch
的区别:clone通常在第一次看到某个项目时将其下载到本地;pull\fetch则是用于之后的更新。
邀请合作者
点击settings–>collaborators->add people
拉取远程库
拉取过程实际上是git fetch
命令完成的。拉取后远程库的内容会变成本地库的一个远端分支,然后再使用git merge <拉取的>
,将远端分支与main分支合并。即git pull = git fetch + git merge
。
PullRequest过程
fork别人的仓库到自己账户下。
git clone
于自己的本地。本地修改
git push
于自己账户下的仓库。在自己的仓库,点击Contribute,Open pull request, 输入PR相关信息,发送。
有时在自己fork之后,原项目作了更新,此时想让自己本地的和fork的项目跟上原项目,可以将原项目设置为自己的上游项目,fetch后手动合并。具体步骤如下:
git remote add <原项目别名> <原项目地址>
,将原项目设置为远程节点。这一步做完后使用git remote -v
可以发现现在有两个远程节点,一个是fork之后在自己账号下那个仓库的,另一个就是刚设置的原项目仓库。git fetch <原项目别名> <原项目分支>
,将最新的原项目抓取下来。git merge FETCH_HEAD
或者git merge <原项目别名>/<原项目分支>
,将抓取的内容和本地合并。此时本地项目已经和原项目进度相同。git push <远程库别名>/<远程分支>
,将本地项目推送至远程库,此时fork的项目也和原项目进度相同。
六、Git原理
使用git add
将文件添加到暂存区后,git会生成一个blob对象,这个Blob对象存储了文件的内容(不是文件本身,而是压缩后的内容)。然后git根据这个Blob的内容计算出一个hash,并以hash的前两个字节为目录名,后38个字节为文件名,将这个Blob对象存储在.git/objects
目录下(只要内容一样就是同一个Blob对象,比如两个不同名的空文件)。
文件的内容以Blob对象的形式存放;
文件及目录的名称以Tree对象的形式存放,Tree对象的内容是某些Blob对象或者其它Tree对象的hash及名称(如果Tree对象里面还有其它Tree对象,那么该Tree对象就是个目录)
commit对象指向某个Tree对象,并且还对指向前一次的commit对象(除了第一次commit以外)
Tag对象指向某个commit对象。
实际上除了Blob对象是存储的文件内容,其他对象都可以看作是存储的指针(hash),通过指针来判断归属关系。
Git flow
附录1:其他命令
查看文件和最后一次commit的区别
1 | git diff <file name> |
-
表示第 1 个文件。+
表示第 2 个文件@@ -1,2 +1,3@@
表示比较的区块:- 第 1 个文件的第 1 行起的连续 2 行
- 第 2 个文件的第 1 行起的连续 3 行
附录2:使用过程中遇到的一些问题
提示
fatal: detected dubious ownership in repository
:原因:根源在于文件夹的所有人和当前用户不一致。
解决方法:在文件夹的属性-安全-高级里面,更改所有者,并应用到所有的子目录和文件。
Git 报错:
1
Updates were rejected because the remote contains work that you do not have locally.
问题描述:在存在本地库且创建新的远程库后用
README
或者LICENSE
初始化过的情况下,如果直接push就会出现上述报错。问题在于初始化过程使得远程库具有了一些本地库所没有的文件(比如README
),这时直接push就会被git给reject。解决方法:在链接远程库之后、push之前,先
git pull
远程库到本地库(or optionally,git pull origin master --allow-unrelated-histories
if you have initialized repo in github and also committed locally),然后再进行push。解决方法2:直接
git push -f <远程分支> <本地分支>
,强行push。解决方法3:创建远程库后,不要初始化。