在此之前,推荐一个前端学习路线:https://objtube.github.io/front-end-roadmap

其中对于git部分给了许多宝贵的资源。

Git的诞生 - Git教程 - 廖雪峰的官方网站

Learn Git Branching

是什么

一个由Linus(Linux操作系统的开发者)使用C语言开发的,免费开源的,分布式的,代码版本控制系统,帮助开发团队维护代码。

可以用来记录代码内容,切换代码版本,多人开发时高效合并代码内容。

分布式vs集中式

集中式版本控制系统(比如SVN),版本库是集中存放在中央服务器的,而干活的时候,用的都是自己的电脑,所以要先从中央服务器取得最新的版本,然后开始干活,干完活了,再把自己的活推送给中央服务器。中央服务器就好比是一个图书馆,你要改一本书,必须先从图书馆借出来,然后回到家自己改,改完了,再放回图书馆。

集中式版本控制系统最大的毛病,就是必须联网才能工作,如果在局域网内还好,带宽够大,速度够快,可如果在互联网上,遇到网速慢的话,可能提交一个10M的文件就需要5分钟,这还不得把人给憋死啊。

那分布式版本控制系统,与集中式版本控制系统,有何不同呢?首先,分布式版本控制系统根本没有中央服务器,每个人的电脑上都是一个完整的版本库,这样,你工作的时候,就不需要联网了,因为版本库就在你自己的电脑上,那分布式的意思就是,版本库分布在每一台电脑上。既然每个人电脑上,都有一个完整的版本库,那多个人如何协作呢?比方说你在自己电脑上改了文件A,你的同事也在他的电脑上改了文件A,这时,你们俩之间只需把各自的修改,推送给对方,就可以互相看到对方的修改了。

和集中式版本控制系统相比,分布式版本控制系统的安全性要高很多,因为每个人电脑里都有完整的版本库,某一个人的电脑坏掉了,不要紧,随便从其他人那里复制一个就可以了。而集中式版本控制系统的中央服务器要是出了问题,所有人都没法干活了。

在实际使用分布式版本控制系统的时候,其实很少在两人之间的电脑上推送版本库的修改,因为可能你们俩不在一个局域网内,两台电脑互相访问不了,也可能今天你的同事病了,他的电脑压根没有开机。因此,分布式版本控制系统,通常也有一台充当中央服务器的电脑,但这个服务器的作用,仅仅是用来方便“交换”大家的修改,没有它大家也一样干活,只是交换修改不方便而已。

安装

最早Git是在Linux上开发的,很长一段时间内,Git也只能在Linux和Unix系统上跑。不过,慢慢地有人把它移植到了Windows上。现在,Git可以在Linux、Unix、Mac和Windows这几大平台上正常运行了。

  • 到官网下载安装包运行,不需要手动配置环境变量

  • 安装完成后,在开始菜单里找到“Git”->“Git Bash”,蹦出一个类似命令行窗口的东西,就说明Git安装成功!**, Git Bash其实就是git提供的命令行工具。**

  • 配置身份

    1
    2
    git config --global user.name "sanye"
    git config --global user.email "xxxxx@qq.com"

    每次提交代码时,需要表明自己的身份,因为Git是分布式版本控制系统,所以,每个机器都必须自报家门:你的名字和Email地址。你也许会担心,如果有人故意冒充别人怎么办?这个不必担心,真的有冒充的也是有办法可查的。

    注意git config命令的--global参数,用了这个参数,表示你这台机器上所有的Git仓库都会使用这个配置,当然也可以对某个仓库,指定不同的用户名和Email地址。

git仓库

记录文件状态,内容,和历史记录,就是一个**.git隐藏文件**

存储的内容

  • 添加的远程仓库的地址
  • 本地分支与远程分支的连接(追踪关系)
  • git hooks
  • 暂存区内容和版本库

删除了.git文件就相当于把仓库删除了,只剩下了工作区的文件。

创建仓库

把本地文件夹转换成git仓库:**git init,如果使用的是Windows系统,为了避免遇到各种莫名其妙的问题,请确保目录名(包括父目录)不包含中文**。然后当前文件夹下,就会出现一个.git目录。这个目录是Git来跟踪管理版本库的,没事千万不要手动修改这个目录里面的文件,不然改乱了,就把Git仓库给破坏了。

从其他服务器克隆git仓库,不需要git init,克隆下来得到的就是一个git仓库

git的三个区域

  • 工作区:实际开发中操作的文件夹,就是你在电脑里能看到的目录
  • 暂存区:提交代码之前的准备区域(暂存改动的文件),可以临时恢复代码内容,与版本库解耦合。暂存区本质是一个文件,保存了下次将提交的文件列表信息,一般在 Git 仓库目录中
  • 版本库:提交并保存暂存区的内容,产生一个版本快照,存储在版本库

查看状态

git status:查看文件详细状态,该指令会罗列出工作区中未被追踪的文件,以及被追踪了且修改了但是未被暂存的文件,同时还会罗列出暂存区中待提交的文件(版本库中没有的文件)。

1
2
3
4
5
6
7
8
9
10
11
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)
modified: README.md // 注释:README.md这个文件被修改了但是没暂存

Untracked files: //注释: 未被跟踪的文件
(use "git add <file>..." to include in what will be committed)
new-feature.js //注释: new-feature.js是未被跟踪的文件

// 注释:相对于 HEAD 中的文件,暂存区中文件没有任何的修改,所以不能(也没必要)创建新提交
no changes added to commit (use "git add" and/or "git commit -a")

git status -s:查看文件简略状态

1
2
3
4
5
6
7
$ git status -s
M README.md # 工作区修改了 README.md,但未 add
A src/new.js # 新增文件,已 add 到暂存区
AM src/updated.js # 先 add 了新文件,后来又在工作区修改了它
D old.js # 文件在工作区被删除(但暂存区还有)
R old.txt -> new.txt # 文件重命名
?? untracked.log # 新增的未跟踪文件

工作区文件状态

未跟踪(U):就比如你新建了一个文件,它就是未跟踪的,你可以直接把它删了,就好像从未新建过一样。

已跟踪:

  • 新添加(A):第一次被git暂存,之前版本记录没有此文件,标志着开始被git跟踪
  • 未修改(无符号):三个区域文件内容一致,通常在一次版本提交后
  • 已修改(M):工作区内容与暂存区内容不同
  • 已删除(D):工作区的一个已经被跟踪的文件被删除,但是版本库or暂存区中仍然存在

常用命令

暂存文件

  • git add <文件名>:暂存指定文件,实际上就是把文件修改添加到暂存区
  • git add .:暂存所有文件,把工作区所有文件添加到暂存区

提交文件

git commit -m <注释说明> :实际上就是把暂存区的所有内容,提交到当前分支;一旦提交(commit)后,如果你又没有对工作区做任何修改,那么工作区就是“干净”的,即工作区文件和版本库文件保持一致

查看指令

  • git ls-files:显示暂存区文件
  • git log:查看详细的提交历史记录,对于每个提交都包含版本号,该提交的作者,提交的日期,本次提交的注释
  • git log --oneline:查看简要的历史提交记录
  • git reflog --oneline:查看完整历史的简略信息记录了你的每一次命令/操作(包括,提交,切换,回退等)

回退命令

  • git reset --soft <版本号>:暂存区,工作区的所有文件都不变,只改变 head指向,回退到指定版本
  • git reset --mixed <版本号> :工作区文件不变,暂存区文件被覆盖为指定版本的文件。
  • git reset --hard <版本号>暂存区文件和工作区文件都被覆盖为指定版本的文件,但是若暂存区文件本来就和回退版本的文件相同,则不会改变工作区

git reset 主要改变的是当前分支的指针(branch pointer)的指向,而 HEAD 通常是间接随之改变的,因为 HEAD 默认就是指向当前分支的。

回退命令可以用来撤销某次错误的提交,也可以用来回退到先前的版本

删除文件

我们通过鼠标右键删除的文件,删除是工作区的文件,但是并不会保存到暂存区,而使用命令git rm <文件名> 删掉的文件,不仅会从你的工作目录中删除,还会将其标记为已删除状态,并添加到暂存区(staging area),这意味着你准备在下一次提交时记录这个删除操作。

撤销命令

  • git rm --cached <文件标识>:文件标识可通过git ls-files(列出暂存区所有文件)查看,这个指令用于移除暂存区的某个文件,用于在commit之前撤销某个错误的暂存
  • git restore <目标文件>.表示全部文件,如果你想撤销对某个文件的所有未提交更改,并将其恢复到与最近一次提交(HEAD)一致的状态,可以使用这个指令。**这个命令不会影响暂存区的内容,只会影响你的工作目录**。
  • git restore --staged <目标文件>:如果你已经将文件添加到了暂存区(即使用了 git add),但之后又想取消该文件的暂存,同时保持工作目录中的修改不变,可以使用这个指令,这会将文件在暂存区的状态重置为与最近一次提交相同,但保留工作目录中的更改。

分支管理

概述

每次提交,Git都把它们串成一条时间线,这条时间线就是一个分支。截止到目前,只有一条时间线,在Git里,这个分支叫主分支,即master分支。HEAD严格来说不是指向提交,而是指向mastermaster才是指向提交的,所以,HEAD指向的就是当前分支

每次提交,master分支都会向前移动一步,这样,随着你不断提交,master分支的线也越来越长。

当我们创建新的分支,例如dev时,Git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上,就实现了分支切换

Git创建,切换一个分支很快,因为除了增加一个dev指针,改改HEAD的指向,工作区的文件都没有任何变化

不过,从现在开始,对工作区的修改和提交就是针对dev分支了,比如新提交一次后,dev指针往前移动一步,而master指针不变

假如我们在dev上的工作完成了,就可以把dev合并到master上。Git怎么合并呢?最简单的方法,就是直接把master,指向dev的当前提交,就完成了合并,我们管这种合并叫做**fast-forward**。

所以Git合并分支也很快!就改改指针,工作区内容也不变!

合并完分支后,甚至可以删除dev分支。删除dev分支就是把dev指针给删掉,删掉后,我们就剩下了一条master分支

查看所有分支

1
2
3
$ git branch
* dev
master

git branch命令会列出所有分支,当前分支前面会标一个*号。然后,我们就可以在dev分支上正常提交

创建分支

1
git branch <分支名>

创建一个新的指针,指向当前分支所指向的提交,一般是最新的提交。

切换分支

1
git checkout <branch-name> //切换分支

这会修改head指针指向,让head指针指向这个分支

1
git checkout -b <branch-name> //切换到创建的分支上去(执行了两个操作)

切换分支后,工作区文件内容,暂存区的文件快照,两者都会变成目标分支 HEAD 提交,所记录的状态,如果你暂存区有未提交的更改,此时切换分支通常会报错,因为 Git 不想悄悄丢弃你已暂存的内容。

切换分支后,以后提交的版本记录结点,就会挂在当前的新分支上去

在 Git 2.23 版本中,引入了一个名为 git switch 的新命令,最终会取代 git checkout,因为 checkout 作为单个命令有点超载(它承载了很多独立的功能)。

除了切换分支,**git checkout指令还能让head指针指向具体的提交,而不是分支。只需要执行git checkout 提交的哈希值(输入前几位也行)即可,由此我们能总结出,git checkout其实是用来修改head的指向**的

除了指定哈希值来确定提交结点,git还提供了相对引用的方式,这种方式需要借助指针(分支指针或者head指针)

  • 使用 ^ 向上移动 1 个提交记录

    所以说git checkout main ^不是切换到main分支不是让head指向main,而是切换到main指向的结点的父节点,让head指向这个父节点。

  • 使用 ~<num> 向上移动多个提交记录,如 ~3

    通过下面这个指令强制移动分支指针main到c4的第三级父节点。

修改当前分支名

1
git branch -M master //修改当前分支名为master

合并分支与删除分支

1
git merge <分支名>

把一条分支合并到当前分支,一般是合并到主分支master(要先切换到主分支),分支合并后,删除被合并的分支,要注意的是删除分支,并不会删除分支上的任何提交,只是删除一个指针(创建分支也只是创建一个指针)。如果该分支(被删除的分支)包含尚未合并到当前分支的提交,Git 会 拒绝删除并报错;目的是防止你意外丢失未合并的工作。

1
git branch -d <分支名> // 删除被合并的分支指针

然后会得到一个新的合并提交

合并冲突

合并分支通常不会产生冲突,比如A员工的分支负责home.vue组件的开发,B员工的分支负责message.vue组件的开发,都产生了一次提交,然后合并后就会得到新的提交,包含了这2个员工的代码,也并不会产生冲突。

fast-forward

如果 dev分支基于 master分支创建,然后在 master 分支上没有新的提交,那么将 dev 分支合并回 master分支时,就可以进行 fast-forward 合并。直接让master指向dev指向的提交即可。

这个时候不会产生新的结点,也不会有合并冲突,之后我们甚至可以删除dev分支

但是fast-forward有一个缺点,就是删除dev分支后,就看不出曾经有分支的痕迹了

因为本次合并要创建一个新的commit,所以加上-m参数,把commit描述写进去。

Merge 合并

Git 会创建一个新的提交,称为合并提交。这个提交有两个父节点:一个是目标分支的最新提交,另一个是当前分支的最新提交。

不使用Fast forward模式,merge后就像这样,此时即便删除了feature1分支(其实就是删除一个指针),也能看出分支存在的痕迹,因为删除分支,不会删除提交的结点。

在合并两个最新提交的时候可能存在冲突,比如两个提交对同一个文件的相同部分,做了不同的修改,这个时候需要手动解决冲突

Git 会在冲突的文件中插入冲突标记

1
2
3
4
5
<<<<<<< HEAD
console.log("Hello from main");
=======
console.log("Hello from feature");
>>>>>>> feature
  • <<<<<<< HEAD:当前分支(你正在合并到的分支)的内容
  • =======:分隔线
  • >>>>>>> feature:要合并进来的分支的内容

让开发者手动修改产生冲突的文件,解决合并冲突,再文件保存,然后执行git add .,再执行git commit

合并提交包含了解决冲突后的结果,或者在没有冲突的情况下,包含了源分支提交的全部内容

分支策略

在实际开发中,我们应该按照几个基本原则进行分支管理

首先,master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;

那在哪干活呢?干活都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本;

你和你的小伙伴们每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了。

我们自己在dev分支上拉的新分支,再合并

所以,团队合作的分支看起来就像这样:

如果项目出现了bug,还需要从master中拉出一条新的分支,然后修改bug,bug修复后,再合并到master分支,同时还要和dev分支合并。

总结

  • 先有一条主分支master,也叫做生产分支,用来发布生产版本,再从主分支上拉一条开发分支,再从开发分支上拉几条功能分支
  • 当某个功能开发完毕,就合并到开发分支。
  • 当功能开发的差不多了,就从开发分支上拉取一条预发布分支(release),在这个分支上修改bug产生新的提交,然后再合并回开发分支和主分支
  • 生产版本中出现了bug,则再拉出一条fix分支,修复代码,产生提交,再将fix分支合并到主分支和dev分支(开发分支)

git rebase

在上文我们看到了,使用git merge合并两个分支出现冲突时,总会产生新的提交,并导致最后的提交记录不是线性的,而是分叉的

git rebase也能实现合并操作,并且能保证合并后的历史记录是线性的。

如果我们想把feature1分支合并到master分支,使用rebase,我们需要先切换到feature1分支,然后执行git rebase master

表明当前分支要进行变基操作,以master分支为新的根基,然后feature1分支的所有独有提交,都会把master分支的最新提交,当作父节点,进行一次合并,并按原来的顺序挂载到master分支上。

如果在变基过程中出现冲突,Git 会暂停变基操作,并提示你解决冲突。你需要手动编辑文件以解决冲突,然后继续变基操作:git rebase --continue,如果决定放弃当前的 rebase 操作,可以使用:git rebase --abort

假设原始的历史记录如下:

1
2
3
A---B---C---D---E (master)
\
F---G---H (feature1)

执行 git checkout feature1 然后 git rebase master 后,历史记录变为:

1
2
3
A---B---C---D---E (master)
\
F'---G'---H' (feature1)

这里,F, G, H 被重新应用为 F', G', H'。尽管它们代表相同的代码更改,但由于基点改变,它们成为了新的提交对象,拥有不同的哈希值。

注意

不能在刚创建一个仓库的时候就创建,查看分支。要先进行一次commit操作,才会真正建立master分支。这是因为分支的指针要指向提交结点的,只有进行了提交,才有指针指向该提交,才算是真正的建立了分支,成为一个有效的对象。

git远程仓库

保存版本库的历史记录,多人协作

创建远程仓库

  • 注册账号,创建一个远程仓库,初始为空,获得远程仓库地址

  • 当我们将本地的代码推送到远程仓库时,需要进行身份验证,通常使用SSH进行身份验证,需要进行如下配置:

    • 创建SSH Key。在用户主目录下(比如:C:\Users\<用户名>\.ssh),看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsaid_rsa.pub这两个文件,如果已经有了,可直接跳到下一步。如果没有,打开Shell(Windows下打开Git Bash),创建SSH Key:

      1
      ssh-keygen -t rsa -C "youremail@example.com"

      你需要把邮件地址换成你自己的邮件地址,然后一路回车,使用默认值即可,由于这个Key也不是用于军事目的,所以也无需设置密码。如果一切顺利的话,可以在用户主目录(比如:C:\Users\<用户名>\.ssh)里找到.ssh目录,里面有id_rsaid_rsa.pub两个文件,这两个就是SSH Key的秘钥对,id_rsa是私钥,不能泄露出去,id_rsa.pub是公钥,可以放心地告诉任何人。

    • 登陆GitHub,打开Account->settingsSSH Keys页面,然后,点Add SSH Key,填上任意Title,在Key文本框里粘贴id_rsa.pub文件的内容,点Add Key,你就应该看到已经添加的Key。

    • 为什么GitHub需要SSH Key呢?因为GitHub需要识别出你推送的提交确实是你推送的,而不是别人冒充的,而Git支持SSH协议,所以,GitHub只要知道了你的公钥,就可以确认只有你自己才能推送。当然,GitHub允许你添加多个Key。假定你有若干电脑,你一会儿在公司提交,一会儿在家里提交,只要把每台电脑的Key都添加到GitHub,就可以在每台电脑上往GitHub推送了。

添加远程仓库

本地Git仓库添加远程仓库地址:git remote add <远程仓库别名> <远程仓库地址>,远程地址添加一次就行,会保存在git仓库

1
git remote add origin https://gitee.com/lidongxu/work.git

而且如果如果我们之前配置了SSH key,使用的远程仓库地址也要选择SSH类型的,通常一个本地仓库只会添加一个远程仓库,而且一般命名为origin

推送代码push

  • git push -u <远程仓库别名> <本地分支名>:<远程分支名>,例如,git push -u origin master,这里的master是master:master的简写,指定把本地的哪个分支提交到远程哪个分支名,如果这两个分支名相同则可以简写。在执行此命令前,你不需要在 master 分支上也能执行,Git 会直接推送本地的 master 分支(无论你当前在哪个分支),但通常我们是在 master 分支上执行这个命令,更符合直觉;
  • 注意这是一个更新操作,不是合并操作,如果在远程同名分支有新的提交(在本地同名分支没有的提交),还会提示我们先进行pull操作,关于pull操作在后文有介绍。
  • 如果远程库是空的,我们第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容,推送到远程新的master分支上,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以省去-u
  • 执行git branch -vv就能查看本地分支和远程分支之间的关联,比如origin/master表示远程仓库origin的master分支的指针

注意

第一次使用gitee需要填写登录信息,如果需要修改gitee登录信息,可以在控制面板->window凭据->普通凭据处修改,删除。

当你第一次使用Git的clone或者push命令连接GitHub时,会得到一个警告:

1
2
3
The authenticity of host 'github.com (xx.xx.xx.xx)' can't be established.
RSA key fingerprint is xx.xx.xx.xx.xx.
Are you sure you want to continue connecting (yes/no)?

这是因为Git使用SSH连接,而SSH连接在第一次验证GitHub服务器的Key时,需要你确认GitHub的Key的指纹信息是否真的来自GitHub的服务器,输入yes回车即可。Git会输出一个警告,告诉你已经把GitHub的Key添加到本机的一个信任列表里了。

这个警告只会出现一次,后面的操作就不会有任何警告了。

抓取分支pull

在本地分支上产生了几个版本记录后,想提交(push)该分支到远程仓库,执行git push origin <branch-name>,如果推送失败,说明远程分支比你的本地新,需要先用git pull拉取远程代码;

git pullgit fetch origin/当前分支名git merge origin/当前分支名两个操作的简写,git fetch只会将远程仓库的某个分支拉取到本地,但是不会合并,而git merge可以将当前分支,和拉取过来的远程分支合并

不指定远程仓库名就是origin仓库,不指定分支名就是本地同名分支

也就是说git pull 默认会从 origin 远程仓库,拉取与本地当前分支同名的分支,并将其与本地当前分支合并。

远程合并冲突

远程合并本质上其实还是本地合并,因为会拉取远程最新的分支到本地,然后再进行合并。如果合并有冲突,则手动解决冲突,修改文件,在再调用git add .再调用git commit

没有冲突或者解决掉冲突后,再用git push origin <branch-name>或者git push推送就能成功!

注意

如果git pull提示no tracking information,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream-to <branch-name> origin/<branch-name>来创建本地分支和远程分支之间的连接。

克隆远程仓库

如果有多个人协作开发,那么每个人各自从远程克隆一份就可以了。

你也许还注意到,GitHub给出的地址不止一个,默认的git://使用ssh,速度快,但也可以使用https等其他协议。

使用https除了速度慢以外,还有个最大的麻烦是每次推送都必须输入口令,但是在某些只开放http端口的公司内部就无法使用ssh协议而只能用https

新建一个文件并打开,右键打开git bash命令行,执行如下代码

1
git clone <远程仓库地址>

例如: git clone https://gitee.com/lidongxu/work.git,或者git clone -b template url,指定克隆远程仓库地址(url)的template分支

这个操作建立了本地仓库和远程仓库的连接,git 会自动为远程仓库,在本地创建一个默认的别名,这个别名叫做 origin,所以可以省略添加远程仓库的操作

移除远程仓库

  • git remote -v :获取所有远程仓库
  • git remote remove <远程仓库别名>,移除远程仓库,不同远程仓库的别名不能相同。此处的“删除”其实是解除了本地和远程的绑定关系,并不是物理上删除了远程库。远程库本身并没有任何改动。要真正删除远程库,需要登录到GitHub,在后台页面找到删除按钮再删除。

fork

我们一直用GitHub作为免费的远程仓库,如果是个人的开源项目,放到GitHub上是完全没有问题的。其实GitHub还是一个开源协作社区,通过GitHub,既可以让别人参与你的开源项目,也可以参与别人的开源项目。

在GitHub出现以前,开源项目开源容易,但让广大人民群众参与进来比较困难,因为要参与,就要提交代码,而给每个想提交代码的群众都开一个账号那是不现实的,因此,群众也仅限于报个bug,即使能改掉bug,也只能把diff文件用邮件发过去,很不方便。

但是在GitHub上,利用Git极其强大的克隆和分支功能,广大人民群众真正可以第一次自由参与各种开源项目了。

如何参与一个开源项目呢?比如人气极高的bootstrap项目,这是一个非常强大的CSS框架,你可以访问它的项目主页https://github.com/twbs/bootstrap,点Fork就在自己的账号下克隆了一个bootstrap仓库,然后,从自己的账号下clone

1
git clone git@github.com:michaelliao/bootstrap.git

一定要从自己的账号下,clone自己fork的仓库,这样你才能推送修改。如果从bootstrap的作者的仓库地址git@github.com:twbs/bootstrap.git克隆,因为没有权限,你将不能推送修改。

Bootstrap的官方仓库:twbs/bootstrap、你在GitHub上克隆的仓库:my/bootstrap,以及你自己克隆到本地电脑的仓库,他们的关系就像下图显示的那样:

如果你想修复bootstrap的一个bug,或者新增一个功能,立刻就可以开始干活。

创建新分支,进行修改:

1
2
3
4
git checkout -b fix/some-bug
# 修改代码...
git add .
git commit -m "Fix: resolve issue with modal backdrop"

推送到你自己的 GitHub 仓库https://github.com/my/bootstrap:

1
git push origin fix/some-bug

这会在 https://github.com/my/bootstrap 中创建一个新分支。打开 https://github.com/my/bootstrap,GitHub 通常会自动提示:“Your recently pushed branches: fix/some-bug — Compare & pull request”,点击 Pull request,在 PR 页面,确认目标是:

  • base repository: twbs/bootstrap
  • base branch: main(或官方指定的开发分支)
  • head repository: my/bootstrap
  • compare branch: fix/some-bug

如果你希望bootstrap的官方库能接受你的修改,**你就可以在你的fork的仓库上发起一个pull request**(注意不是在官方仓库上发起)到原始仓库。到当然,对方是否接受你的pull request就不一定了。