1. Git由来
- 1991年,Linus创建了开源的Linux。
- 2002年以前,世界各地的志愿者把源代码文件通过diff的方式发给Linus,然后由Linus本人通过手工方式合并代码。
- 2002年-2005年,使用商业的版本控制系统BitKeeper。
- 2005年,Linus花了两周时间自己用C写了一个分布式版本控制系统,这就是Git!
2. Git实现原理
2.1 集中式版本控制系统 VS 分布式版本控制系统
2.1.1 集中式版本控制系统
-
CVS、SVN
集中式版本控制系统,版本库是集中存放在中央服务器的,而干活的时候,用的都是自己的电脑,所以要先从中央服务器取得最新的版本,然后开始干活,干完活了,再把自己的活推送给中央服务器。中央服务器就好比是一个图书馆,你要改一本书,必须先从图书馆借出来,然后回到家自己改,改完了,再放回图书馆。集中式版本控制系统最大的毛病就是必须联网才能工作,如果在局域网内还好,带宽够大,速度够快,可如果在互联网上,遇到网速慢的话,可能提交一个10M的文件就需要5分钟,时间成本太高。
2.1.2 分布式版本控制系统
-
Git、Mercurial、Bazaar
分布式版本控制系统没有"中央服务器",每个人的电脑上都是一个完整的版本库,这样工作的时候就不需要联网了,因为版本库就在你自己的电脑上。
2.1.3 同步问题
- 集中式,因为所有版本是由中央服务器控制的,所以只要同步中央服务器就行。
- 分布式,你在自己电脑上改了文件A,你的同事也在他的电脑上改了文件A,这时,你们俩之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。在实际使用分布式版本控制系统的时候,其实很少在两人之间的电脑上推送版本库的修改,因为可能你们俩不在一个局域网内,两台电脑互相访问不了,也可能今天你的同事病了,他的电脑压根没有开机。因此,分布式版本控制系统通常也有一台充当"中央服务器"的电脑,但这个服务器的作用仅仅是用来方便"交换"大家的修改,没有它大家也一样干活,只是交换修改不方便而已。
2.1.4 安全性比较
- 集中式,中央服务器要是出了问题,所有人都没法干活了
- 分布式,每个人电脑里都有完整的版本库,某一个人的电脑坏掉了不要紧,随便从其他人那里复制一个就可以了。
2.2 Git 工作流程
2.3 工作区、暂存区、版本库
2.3.1 概念
- **工作区:**就是你在电脑里能看到的目录。
- **暂存区:**英文叫stage, 或index。一般存放在 “.git目录下” 下的index文件(.git/index)中,所以我们把暂存区有时也叫作索引(index)。
- **版本库:**工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库。
2.3.2 关系展示
- Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支
master
,以及指向master
的一个指针叫HEAD
。
2.4 版本库相关
2.4.1 概念
可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。
注意:所有的版本控制系统,其实只能跟踪文本文件的改动,比如TXT文件,网页,所有的程序代码等等,Git也不例外。版本控制系统可以告诉你每次的改动,比如在第5行加了一个单词“Linux”,在第8行删了一个单词“Windows”。而图片、视频这些二进制文件,虽然也能由版本控制系统管理,但没法跟踪文件的变化,只能把二进制文件每次改动串起来,也就是只知道图片从100KB改成了120KB,但到底改了什么,版本控制系统不知道,也没法知道。(Microsoft的Word格式是二进制格式,版本控制系统无法跟踪)
2.4.2 版本库创建
-
创建版本库命令
mkdir git_demo cd git_demo git init
-
操作示例
2.5 基础操作
2.5.1 添加文件
-
添加文件命令
vim demo.txt # 写入'I am a text' git add demo.txt git status # 可以看见有一个新的文件demo.txt git commit -m 'demo'
为什么Git添加文件需要
add
,commit
一共两步呢?因为commit
可以一次提交很多文件,所以你可以多次add
不同的文件。如果我们想取消已经add的文件可以使用git rm --cached 命令。 -
操作示例
2.5.2 修改文件
-
修改文件命令
vim demo.txt # 添加'demo' git status # 可以看见有一个被修改的文件demo.txt git diff demo.txt # 可以看见具体修改了什么内容
-
操作示例
2.5.3 撤销修改
-
撤销命令
vim demo.txt # 换行添加'checkout' git checkout -- demo.txt
撤销不仅对文件内的内容有效,也对文件有效。例:如果文件被删除然后撤销,那么文件就会被恢复。
-
操作示例
2.5.4 删除文件
-
删除命令
touch delete_test.txt # 创建一个文件 git add delete_test.txt # 添加到暂存区 git commit -m 'test delete' # 提交到版本库 rm delete_test.txt # 删除文件 git rm delete_test.txt git commit -m 'success delete file'
-
操作示例
2.5.5 版本回滚
-
回滚命令
git log # 查看想要回滚的版本commit id git reset --hard <commit id>
git reset参数说明:
git reset –-soft:回退到某个版本,只回退了commit的信息,不会恢复到index file一级。如果还要提交,直接commit即可;
git reset -–hard:彻底回退到某个版本,本地的源码也会变为上一个版本的内容,撤销的commit中所包含的更改被冲掉; -
操作示例
2.5.6 日志信息
如果你是照着之前的步骤来操作的,你的git log和我这的git log信息是有区别的,本节的图是为了好展示所以加入了一些其他操作。你也可以先跳过这一节,最后再来看这一节的内容。
-
git log
commit 的版本日志 包含提交的版本 操作者 日期 (方便查看commit的版本,但是版本回退后,使用git log 看不到回退版本号之后的版本记录)
-
git log --graph
图形化显示git log信息,具体符号意义说明:
* 表示一个commit | 表示分支前进 / 表示分叉 \ 表示合入
-
git reflog
使用git 命令进行操作的日志 包括当前步骤所在哪个版本(一个commit 产生一个版本, 指定版本回退只能回退到该commit) 以及操作的具体内容
版本回退后,仍然可以看到所有的版本记录 方便查看每个操作步骤所在的版本,可以根据版本号自由前进后退
2.5.7 标签管理
-
创建标签
$ git tag v1.0
-
查看所有标签
$ git tag
-
查看标签说明
$ git show v1.0
-
删除标签
$ git tag -d v0.1
-
推送标签到远程
$ git push origin v1.0
-
推送所有未推送的本地标签到远程
$ git push origin --tags
-
删除远程标签
-
先删除本地标签
$ git tag -d v1.0
-
再删除远程标签
$ git push origin :refs/tags/v1.0
-
3. 分支管理
3.1 创建与合并分支
3.1.1 分支原理
在[版本回滚](####2.5.5 版本回滚)里,我们可以看见,每次提交,Git都把它们串成一条时间线,这条时间线就是一个分支。截止到目前,只有一条时间线,在Git里,这个分支叫主分支,即master
分支。HEAD
严格来说不是指向提交,而是指向master
,master
才是指向提交的,所以,HEAD
指向的就是当前分支。
3.1.2 分支实战
-
具体步骤演示
-
新建dev分支并切换到dev分支,做修改并提交,看dev分支和master分支的区别
由于git checkout命令在切换分支和撤销修改时容易搞混淆。推荐切换分支使用新版git switch命令
-
合并dev分支到master分支,删除dev分支
注意到上面的
Fast-forward
信息,Git告诉我们,这次合并是“快进模式”,也就是直接把master
指向dev
的当前提交,所以合并速度非常快。在后面的[Fast forward模式](####3.3.1 Fast forward模式)会详细提到这部分内容。
-
-
具体步骤原理讲解
-
刚开始
-
新建一个dev分支
-
在dev分支新发起一次提交
-
把dev分支合并到master分支
-
合并完分支后,删除dev分支
-
3.2 解决合并时发生的冲突
3.2.1 发生冲突
-
具体步骤演示
hfm分支修改成
Creating a new branch is quick AND simple.
master分支修改成
Creating a new branch is quick & simple.
-
原理图示
3.2.2 解决冲突
-
具体步骤演示
将demo文件中冲突的地方改成:
Creating a new branch is quick and simple.
-
原理图示
3.3 分支管理策略
3.3.1 Fast forward模式
合并分支时,默认情况下,Git会用Fast forward
模式,这种模式直接把当前分支指向合并分支的当前提交,所以合并速度非常快。但这种模式下,删除分支后,会丢掉分支信息。
3.3.2 禁止Fast forward模式
可以使用git merge --no-ff来强制禁止Fast forward
模式,Git就会在merge时生成一个新的commit。
3.3.3 临时修改某个分支(git stash的使用)
并不是你不想提交,而是工作只进行到一半,还没法提交,预计完成还需1天时间。但是,必须在两个小时内修复该bug,怎么办?
Git提供了一个stash
功能,可以把当前工作现场"储藏"起来,等以后恢复现场后继续工作:
$ git stash
Saved working directory and index state WIP on hfm: 8ac106b hfm commit
"储藏"完毕就可以切换到另外一个分支进行工作了,工作完后切回原先的分支,可以看到之前存的信息:
$ git stash list
stash@{0}: WIP on hfm: 8ac106b hfm commit
我们可以将"储藏"的内容再还原出来继续之前的工作:
$ git stash pop
On branch hfm
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: demo.txt
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (b45f246f459c3de307391f6f036a86bf27e89441)
注:我们使用git stash往往是遇到了bug或者紧急的事情,这种改动在我们目前的分支也需要更改,所以我们需要将那个提交复制过来。我们可以使用
git cherry-pick <commit>
命令来同步在其他分支的修改。使用这个命令会自动给我们做一次提交。
3.3.4 Feature分支
添加一个新功能时,你肯定不希望因为一些实验性质的代码,把主分支搞乱了,所以,每添加一个新功能,最好新建一个feature分支,在上面开发,完成后,合并,最后,删除该feature分支。
3.3.5 分支策略
在实际开发中,我们应该按照几个基本原则进行分支管理:
首先,master
分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;
那在哪干活呢?干活都在dev
分支上,也就是说,dev
分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev
分支合并到master
上,在master
分支发布1.0版本;
每个人都在dev
分支上干活,每个人都有自己的分支,时不时地往dev
分支上合并就可以了。
合并分支时,加上--no-ff
参数就可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并,而fast forward
合并就看不出来曾经做过合并。
3.3.6 merge 和 rebase
现有如下状态的分支情况,我们来看看使用git merge和git rebase合并master到Feature分支上会有什么区别。
-
merge
-
如果使用git merge,那么会自动创建一个新的commit
优点:记录了真实的commit情况,包括每个分支的详情
缺点:因为每次merge会自动产生一个merge commit,所以在使用一些git 的GUI tools,特别是commit比较频繁时,看到分支很杂乱。
-
-
rebase
-
如果用git rebase,那么会先找公共祖先
-
然后将Feature分支从公共祖先到目前的commit都暂存起来
-
再将要合并的分支先提交到公共祖先之后
-
最后将暂存的部分提交到master之后
优点:得到更简洁的项目历史,去掉了merge commit
缺点:如果合并出现代码问题不容易定位,因为re-write了history注:由于会修改历史记录,所以不要在公共分支上使用此命令
-
4. 远程仓库
注:不同的平台新建仓库的步骤有点不一样,但是大同小异,根据自己的需求去官网查找对应的帮助文档都会有具体步骤,故此不在本文档赘叙新建仓库相关的内容了。
要参与任何一个 Git 项目的协作,必须要了解该如何管理远程仓库。远程仓库是指托管在网络上的项目仓库,可能会有好多个,其中有些你只能读,另外有些可以写。同他人协作开发某个项目时,需要管理这些远程仓库,以便推送或拉取数据,分享各自的工作进展。 管理远程仓库的工作,包括添加远程库,移除废弃的远程库,管理各式远程库分支,定义是否跟踪这些分支,等等。
4.1 查看当前的远程库
4.1.1 克隆及查看
-
要查看当前配置有哪些远程仓库,可以用
git remote
命令,它会列出每个远程库的简短名字。在克隆完某个项目后,至少可以看到一个名为 origin 的远程库,Git 默认使用这个名字来标识你所克隆的原始仓库git clone git@gitlab.liquidnetwork.com:backend/flash_shopping.git Cloning into 'flash_shopping'... remote: Counting objects: 6934, done. remote: Compressing objects: 100% (1651/1651), done. remote: Total 6934 (delta 5291), reused 6910 (delta 5275) Receiving objects: 100% (6934/6934), 1.01 MiB | 8.40 MiB/s, done. Resolving deltas: 100% (5291/5291), done.
-
加上
-v
选项(译注:此为--verbose
的简写,取首字母),显示对应的克隆地址git remote -v origin git@gitlab.liquidnetwork.com:backend/flash_shopping.git (fetch) origin git@gitlab.liquidnetwork.com:backend/flash_shopping.git (push)
4.2 添加远程仓库
4.2.1 添加
-
要添加一个新的远程仓库,可以指定一个简单的名字,以便将来引用,运行
git remote add [shortname] [url]
:$ git remote add test git@gitlab.liquidnetwork.com:backend/flash_shopping.git $ git remote -v origin git@gitlab.liquidnetwork.com:backend/flash_shopping.git (fetch) origin git@gitlab.liquidnetwork.com:backend/flash_shopping.git (push) test git@gitlab.liquidnetwork.com:backend/flash_shopping.git (fetch) test git@gitlab.liquidnetwork.com:backend/flash_shopping.git (push)
-
现在可以用字符串
test
指代对应的仓库地址了。$ git fetch test From gitlab.liquidnetwork.com:backend/flash_shopping * [new branch] broadcast_card -> test/broadcast_card * [new branch] check_flash -> test/check_flash * [new branch] comment -> test/comment * [new branch] deploy -> test/deploy
4.3 从远程仓库抓取数据
4.3.1 几种不同的抓取
-
可以用下面的命令从远程仓库抓取数据到本地:
$ git fetch [remote-name]
此命令会到远程仓库中拉取所有你本地仓库中还没有的数据。但是需要注意fetch 命令只是将远端的数据拉到本地仓库,并不自动合并到当前工作分支,只有当你确实准备好了,才能手工合并。
-
如果设置了某个分支用于跟踪某个远端仓库的分支,可以使用以下命令自动抓取数据下来
$ git pull
此命令实际上是执行了git fetch和git merge(可以给git pull加参数–rebase改成git rebase)
-
默认情况下
git clone
命令本质上就是自动创建了本地的 master 分支用于跟踪远程仓库中的 master 分支$ git clone
4.4 推送数据到远程仓库
4.4.1 推送
-
将本地仓库中的数据推送到远程仓库。实现这个任务的命令很简单:
git push [remote-name] [branch-name]
。$ git push origin master
只有在所克隆的服务器上有写权限,或者同一时刻没有其他人在推数据,这条命令才会如期完成任务。如果在你推数据前,已经有其他人推送了若干更新,那你的推送操作就会被驳回。你必须先把他们的更新抓取到本地,合并到自己的项目中,然后才可以再次推送。
4.5 跟踪远程分支
4.5.1 基本概念
- 从远程分支
checkout
出来的本地分支,称为 跟踪分支(tracking branch)。跟踪分支是一种和某个远程分支有直接联系的本地分支。在跟踪分支里输入git push
,Git 会自行推断应该向哪个服务器的哪个分支推送数据。同样,在这些分支里运行git pull
会获取所有远程索引,并把它们的数据都合并到本地分支中来。
4.5.2 如何跟踪
-
使用命令
git checkout -b [分支名] [远程名]/[分支名]
即可将本地分支跟踪到远程分支$ git checkout -b se origin/service
5. 其他
gitlab的用户管理方面属于运维控制的内容,本文档不再详细说明,感兴趣的可以移至参考链接
5.1 SSH公钥
5.1.1 生成SSH公钥
大多数 Git 服务器都会选择使用 SSH 公钥来进行授权。系统中的每个用户都必须提供一个公钥用于授权,没有的话就要生成一个。生成公钥的过程在所有操作系统上都差不多。 首先先确认一下是否已经有一个公钥了。SSH 公钥默认储存在账户的主目录下的 ~/.ssh
目录。进去看看:
$ cd ~/.ssh
$ ls
authorized_keys2 id_dsa known_hosts
config id_dsa.pub
关键是看有没有用 something
和 something.pub
来命名的一对文件,这个 something
通常就是 id_dsa
或 id_rsa
。有 .pub
后缀的文件就是公钥,另一个文件则是密钥。假如没有这些文件,或者干脆连 .ssh
目录都没有,可以用 ssh-keygen
来创建。该程序在 Linux/Mac 系统上由 SSH 包提供,而在 Windows 上则包含在 MSysGit 包里:
$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/schacon/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /Users/schacon/.ssh/id_rsa.
Your public key has been saved in /Users/schacon/.ssh/id_rsa.pub.
The key fingerprint is:
43:c5:5b:5f:b1:f1:50:43:ad:20:a6:92:6a:1f:9a:3a schacon@agadorlaptop.local
它先要求你确认保存公钥的位置(.ssh/id_rsa
),然后它会让你重复一个密码两次,如果不想在使用公钥的时候输入密码,可以留空。
现在,所有做过这一步的用户都得把它们的公钥给 Git 服务器的管理员(假设 SSH 服务被设定为使用公钥机制)。他们只需要复制 .pub
文件的内容然后发邮件给管理员。公钥的样子大致如下:
$ cat ~/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAklOUpkDHrfHY17SbrmTIpNLTGK9Tjom/BWDSU
GPl+nafzlHDTYW7hdI4yZ5ew18JH4JW9jbhUFrviQzM7xlELEVf4h9lFX5QVkbPppSwg0cda3
Pbv7kOdJ/MTyBlWXFCR+HAo3FXRitBqxiX1nKhXpHAZsMciLq8V6RjsNAQwdsdMFvSlVK/7XA
t3FaoJoAsncM1Q9x5+3V0Ww68/eIFmb1zuUFljQJKprrX88XypNDvjYNby6vw/Pb0rwert/En
mZ+AW4OZPnTPI89ZPmVMLuayrD2cE86Z/il8b+gw3r3+1nKatmIkjn2so1d01QraTlMqVSsbx
NrRFi9wrf+M7Q== schacon@agadorlaptop.local
5.1.2 添加到Gitlab
在gitlab中找到Profile Settings -> SSH keys,将刚生成的SSH公钥添加进来即可
5.2 初次运行 Git 前的配置
5.2.1 查看现有的Git配置
-
命令
$ git config --list
-
示例
5.2.2 配置用户名称及邮件地址
-
每次 Git 提交时都会引用你的用户名称和电子邮件地址,说明是谁提交了更新,所以会随更新内容一起被永久纳入历史记录,所以这两条配置信息很重要。
-
命令
$ git config --global user.name "huangfengmiao" $ git config --global user.email "huangfengmiao@liquidnetwork.com"
5.3 Git忽略提交规则
5.3.1 gitignore
-
使用场景
在使用Git的过程中,我们喜欢有的文件比如日志,临时文件,编译的中间文件等不要提交到代码仓库,这时就要设置相应的忽略规则,来忽略这些文件的提交。简单来说一个场景:在你使用git add .的时候,遇到了把你不想提交的文件也添加到了缓存中去的情况,比如项目的本地配置信息,如果你上传到Git中去其他人pull下来的时候就会和他本地的配置有冲突,所以这样的个性化配置文件我们一般不把它推送到git服务器中,但是又为了偷懒每次添加缓存的时候都想用git add .而不是手动一个一个文件添加,该怎么办呢?很简单,git为我们提供了一个.gitignore文件只要在这个文件中申明那些文件你不希望添加到git中去,这样当你使用git add .的时候这些文件就会被自动忽略掉。
-
使用方法
-
在Git项目中定义.gitignore文件
在.gitingore 文件中,遵循相应的语法,在每一行指定一个忽略规则。如:
*.log *.temp /vendor
-
在Git项目的设置中指定排除文件
这种方式只是临时指定该项目的行为,需要编辑当前项目下的 .git/info/exclude文件,然后将需要忽略提交的文件写入其中。需要注意的是,这种方式指定的忽略文件的根目录是项目根目录。
-
定义Git全局的 .gitignore 文件
除了可以在项目中定义 .gitignore 文件外,还可以设置全局的git .gitignore文件来管理所有Git项目的行为。这种方式在不同的项目开发者之间是不共享的,是属于项目之上Git应用级别的行为。这种方式也需要创建相应的 .gitignore 文件,可以放在任意位置。然后在使用以下命令配置Git:
$ git config --global core.excludesfile ~/.gitignore
-
-
gitignore匹配语法说明
- 空格不匹配任意文件,可作为分隔符,可用反斜杠转义
- 以“#”开头的行都会被 Git 忽略。即#开头的文件标识注释,可以使用反斜杠进行转义。
- 可以使用标准的glob模式匹配。所谓的glob模式是指shell所使用的简化了的正则表达式。
- 以斜杠"/“开头表示目录;”/“结束的模式只匹配文件夹以及在该文件夹路径下的内容,但是不匹配该文件;”/"开始的模式匹配项目跟目录;如果一个模式不包含斜杠,则它匹配相对于当前 .gitignore 文件路径的内容,如果该模式不在 .gitignore 文件中,则相对于项目根目录。
- 以星号"“通配多个字符,即匹配多个任意字符;使用两个星号”*" 表示匹配任意中间目录,比如
a/**/z
可以匹配 a/z, a/b/z 或 a/b/c/z等。 - 以问号"?"通配单个字符,即匹配一个任意字符;
- 以方括号"[]"包含单个字符的匹配列表,即匹配任何一个列在方括号中的字符。比如[abc]表示要么匹配一个a,要么匹配一个b,要么匹配一个c;如果在方括号中使用短划线分隔两个字符,表示所有在这两个字符范围内的都可以匹配。比如[0-9]表示匹配所有0到9的数字,[a-z]表示匹配任意的小写字母)。
- 以叹号"!“表示不忽略(跟踪)匹配到的文件或目录,即要忽略指定模式以外的文件或目录,可以在模式前加上惊叹号(!)取反。需要特别注意的是:如果文件的父目录已经被前面的规则排除掉了,那么对这个文件用"!"规则是不起作用的。也就是说”!“开头的模式表示否定,该文件将会再次被包含,如果排除了该文件的父级目录,则使用”!"也不会再次被包含。可以使用反斜杠进行转义。
5.3.2 忽略文件的规则
-
Git忽略文件的基本原则
- 忽略操作系统自动生成的文件,比如缩略图等;
- 忽略编译生成的中间文件、可执行文件等,也就是如果一个文件是通过另一个文件自动生成的,那自动生成的文件就没必要放进版本库,比如python自动产生的.pyc文件;
- 忽略你自己的带有敏感信息的配置文件,比如存放口令的配置文件。
-
忽略规则的优先级
在 .gitingore 文件中,每一行指定一个忽略规则,Git检查忽略规则的时候有多个来源,它的优先级如下(由高到低):
- 从命令行中读取可用的忽略规则
- 当前目录定义的规则
- 父级目录定义的规则,依次递推
- $GIT_DIR/info/exclude 文件中定义的规则
- core.excludesfile中定义的全局规则
-
忽略规则查看
如果你发下.gitignore写得有问题,需要找出来到底哪个规则写错了,可以用git check-ignore命令检查
$ git check-ignore -v HelloWorld.pyc .gitignore:1:*.pyc HelloWorld.pyc
-
Git忽略规则不生效原因和解决
-
.gitignore中已经标明忽略的文件目录下的文件,git push的时候还会出现在push的目录中,或者用git status查看状态,想要忽略的文件还是显示被追踪状态。
原因是因为在git忽略目录中,新建的文件在git中会有缓存,如果某些文件已经被纳入了版本管理中,就算是在.gitignore中已经声明了忽略路径也是不起作用的,
这时候我们就应该先把本地缓存删除,然后再进行git的提交,这样就不会出现忽略的文件了。$ git rm -r --cached . $ git add . $ git commit -m 'update .gitignore' $ git push
-