学堂在线部分网课笔记
- Web前端攻城狮
- 第七章 JavaScript进阶
- 7.1 组件封装
- 7.2各司其职
- 7.3过程抽象
- 过程抽象:
- 控制代码执行次数:
- once:
- 高阶函数:
- 一些高阶函数:
- Throttle整体代码见课件7_03_过程抽象.pdf或者访问:https://code.h5jun.com/gale/1/embed?html(网址截于课件内)
- Debounced整体代码见课件7_03_过程抽象.pdf或者访问:https://code.h5jun.com/wik/3/embed?html(网址截于课件内)
- Consumer整体代码见课件7_03_过程抽象.pdf或者访问:https://code.h5jun.com/roka/embed?html(网址截于课件内)
- Consumer2整体代码见课件7_03_过程抽象.pdf或者访问:https://code.h5jun.com/bucu/3/embed?html(网址截于课件内)
- 命令式与声明式:
- iterative:
- 第八章 前端调试
- 第九章 网络技术基础
- 第十一章 前端工程化
Web前端攻城狮
第七章 JavaScript进阶
7.1 组件封装
1.组件是指Web页面上抽出来一个个包含模板(HTML)、功能(JS)和样式(CSS)的单元。好的组件具备封装性、正确性、扩展性、复用性。
.eg.:轮播图设计:
结构设计:HTML
首先设计HTML结构。轮播图是一个典型的列表结构,我们可以使用无序列表
- 元素来实现。
<div id="my-slider" class="slider-list">
<ul>
<li class="slider-list_item--selected">
<img src="https://p5.sst.qhing.com/t0119c746247889dd070.png" />
</li>
<li class="slider-list_item">
<img src="https://p5.sst.qhing.com/t011adc46247889dd070.png" />
</li>
<li class="slider-list_item">
<img src="https://p5.sst.qhing.com/t011adc462475b84d070.png" />
</li>
<li class="slider-list_item">
<img src="https://p5.sst.qhing.com/t011adc46247889dd578.png" />
</li>
</ul>
</div>
结构设计:CSS
1.使用css绝对定位将图片重叠在同一位置
2.轮播图切换的状态使用修饰符(modifier)
3.轮播图的切换动画使用 css transition
#my-slider{
position: relative;
width: 790px;
}
.slider-list ul{
list-style-type: none;
position: relative;
padding: 0;
margin: 0;
}
.slider-list_item,.slider-list_item--selected{
position: absolute;
transition: opacity ls;
opacity: 0;
text-align: center;
}
slider-list_item--selected{
transition: opacity ls;
opacity: 1;
}
API设计
API设计应保证原子操作,职责单一,满足灵活性。
getSeletedItem() 可以将当前轮播到的图片元素获取到
getSelectedItemIndex() 当前播放到几张图了,获得下标
slideTo() 指定播放到某一张图片的1位置去
slideNext() 结合slideTo()
slidePrevious() 结合slideTo()
class Slider{
constructor(id){
this.container = document.getElementById(id);
this.items = this.container
.querySelectorAll('.sliderlist item, .sliderlist item selected');
}
getSelectedItem(){
const selected = this.container
.querySelector('.sliderlist item selected');
return selected
}
getSelectedItemIndex(){
return Array.from(this.items).indexOf(this.getSelectedItem());
}
slideTo(idx){
const selected = this.getSelectedItem();
if(selected){
selected.className = 'sliderlist item';
}
const item = this.items[idx];
if(item){
item.className = 'sliderlist item selected';
}
}
slideNext(){
const currentIdx = this.getSelectedItemIndex();
const nextIdx = (currentIdx + 1) % this.items.length;
this.slideTo(nextIdx);
}
slidePrevious(){
const currentIdx = this.getSelectedItemIndex();
const previousIdx = (this.item.length + currentIdx - 1) % this.item.length;
this.slideTo(previousIdx);
}
}
控制流设计
设置控制结构,响应用户操作。可以使用自定义事件来解耦行为。
整体代码见课件7_01_组件封装.pdf或者访问:https://code.h5jun.com/reba/embed?html (网址截于课件内)
优化1:插件化:
将控制元素抽取成插件,插件与组件之间通过依赖注入方式建立联系。
优化2:模板化:
将HTML模版化,更易于扩展。
class Slider{
constructor(id, opts = {images:[], cycle: 3000}){
...
}
render(){
const images = this.options.images;
const content = images.map(image=>`
<li class="sliderlist_item">
<img src="${image}" />
</li>
`.trim());
return `<ul>${content.join('')}</ul>`;
}
...
}
优化3:组件模型:
将普通的组件模型抽象出来。
7.2各司其职
在web开发中,html负责网页的结构,css负责网页上各元素的展示样式,js负责网页和用户的交互。想要成为一名优秀的前端工程师,首先要做的就是遵守这三者各司其职的原则,让我们的代码易于维护和扩展。
版本一:
通过JS直接修改元素样式
整体代码见课件7_02_各司其职.pdf或者访问:https://code.h5jun.com/hefaj/embed?html(网址截于课件内)
版本二:
用CSS的class表示状态,用JS切换
版本三:
纯展现类交互可以只用HTML+CSS实现
<body>
<input id="modeCheckBox" type="checkbox">
<div class="content">
<header>
<label id="modeBtn" for="modeCheckBox"> label>
<h1>深夜食堂</h1>
</header>
<main>
...
</main>
</div>
</body>
#modeCheckBox:checked + .content {
backgroundcolor: black;
color: white;
transition: all 1s;
}
7.3过程抽象
过程抽象:
(1)用来处理局部细节控制的一些方法。
(2)函数式编程思想的基础应用。
控制代码执行次数:
限制某个方法只能执行一次。
(1)一些异步交互
(2)一次性的HTTP请求
once:
为了能够让“只执行一次”的需求覆盖不同的事件处理,我们可以将这个需求剥离出来。这个过程我们称为过程抽象。
高阶函数:
(1)以函数作为参数
(2)以函数作为返回值
(3)常用于作为函数装饰器
一些高阶函数:
- once
- throttle
- debounced
- consumer
- iterative
Throttle整体代码见课件7_03_过程抽象.pdf或者访问:https://code.h5jun.com/gale/1/embed?html(网址截于课件内)
Debounced整体代码见课件7_03_过程抽象.pdf或者访问:https://code.h5jun.com/wik/3/embed?html(网址截于课件内)
Consumer整体代码见课件7_03_过程抽象.pdf或者访问:https://code.h5jun.com/roka/embed?html(网址截于课件内)
Consumer2整体代码见课件7_03_过程抽象.pdf或者访问:https://code.h5jun.com/bucu/3/embed?html(网址截于课件内)
命令式与声明式:
let list = [1, 2, 3, 4];
let map1 = [];
for(let i = 0; i < list.length; i++ ){
map1.push(list[i] * 2);
}
let list = [1, 2, 3, 4];
const double = x=>x * 2;
list.map(double);
iterative:
高阶函数iterative让函数支持多个参数迭代求解。
function add(x, y){
return x + y;
}
function sub(x, y){
return x - y;
}
console.log(add(add(add(1,2),3),4));//不好!!
console.log([1, 2, 3, 4].reduce(add));
console.log([1, 2, 3, 4].reduce(sub));
//------------------------------------------------
function iterative(fn){
return function(...args){
return args.reduce(fn.bind(this));
}
}
const add = iterative((x, y)=> x + y);
const sub = iterative((x, y)=> x - y);
console.log(add(1,2,3,4));
console.log(sub(1,2,3,4));
toggle (imperative)整体代码见课件7_03_过程抽象.pdf或者访问:https://code.h5jun.com/tuda/2/embed?html(网址截于课件内)
toggle (declarative)整体代码见课件7_03_过程抽象.pdf或者访问:https://code.h5jun.com/nal/3/embed?html(网址截于课件内)
toggle (三态)整体代码见课件7_03_过程抽象.pdf或者访问:https://code.h5jun.com/foqo/2/embed?html(网址截于课件内)
第八章 前端调试
8.1前端调试(1)
01页面调试
使用Chrome DevTools面板进行网页调试
1.Elements
(1)检查和调整⻚⾯
(2)编辑样式
(3)编辑DOM结构
2.Console
(1)日志输出
(2)命令行
(3)审查建议
3、Source
(1)代码调试
(2)持久化保存
(3)代码覆盖率
4、Network
(1)网络抓包
(2)网络模拟
(3)请求重放与拦截
5、Application
管理数据localStorage,cookie等
6、模拟与仿真
(1)设备模拟
(2)网络模拟
(3)处理性能模拟
(4)地理位置模拟
(5)媒体查询模拟
(6)设备状态模拟
7、移动真机调试
(1)安卓浏览器:chrome://inspect
(2)iOS Safari:OSX Safari
(3)Fiddler,Charles
(4)vConsole
02审查网站性能
使用Performance面板本地审查网页性能
03监控性能和报错
使用一定手段在线上收集网页的性能和报错情况
1.错误收集
错误收集的方法
// 主要通过监控window.onerror来收集错误信息。
window.onerror = function(msg, url, line, col, error) {
// 功能⼀:错误⽩名单
for (var i = 0; i < er.WHITELIST.length; i++) {
if (msg.indexOf(er.WHITELIST[i]) >= 0) {
return true;
}
}
// 功能⼆:抽样上报
if (Math.random() > 0.9) {
return true;
}
setTimeout(function() {
col = col || (window.event window.event.errorCharacter) || 0;
var data = {
mod: 'error',
url: location.href,
msg: msg,
ua: navigator.userAgent
};
if ( !!error && !!error.stack) {
//如果浏览器有堆栈信息
//直接使用
data.mag = erroe.stack.toString();
}else if( !!arguments.callee) {
// 尝试通过callee拿堆栈信息
var ext = [],
f = argument.callee.caller,
c = 3;
// 只拿三层堆栈信息
while (f && --c > 0) {
ext.push(f.toString());
if (f == f.caller) {
break;
}
f = f.caller;
}
ext = ext.join(',');
data.msg = ext;
}
if (data.msg) {
// 一个页面生命周期内同样的错误只上报一次
if (reported[msg]) {
return true;
}
report(data); // 上报错误
reported[msg] = true;
}
},0);
return true;
};
2.性能数据收集:
性能数据收集的方法:
// 主要使⽤performance API进⾏性能收集
var timing = performance.timing;
var entries = window.performance.getEntries();
var imgCount = 0,
bgCount = 0,
jsCount = 0,
cssCount = 0;
var domainList = {};
var otherResourceList = [];
var reg = /^http(s)?:\/\/(.*?)\//;
for (var i = 0; i < entries.length; i ) {
var entry = entries[i];
var name = entry.name;
if (entry.entryType == 'resource') {
if (entry.initiatorType == 'img') {
imgCount++;
}
if (
entry.initiatorTypr == 'css' &&
/\.(?:jpg|png|webp|gif|jpeg)(?:$|\?)/i.test(name)
){
bgCount++;
}
if(/\.js(?:$|\?)/.test(name)){
jsCount++;
}
if(/\.css(?:$|\?)/.test(name)){
cssCount++;
}
// 非本域资源
if (
entry.duration != 0 &&
location.hostname &&
name.indexOf(location.hostname) < 0
){
var domain = name.match(reg);
if(domain && domain.length > 0) {
domain = domain[2];
if (domainList[domain]) {
continue;
}
domainList[domain] = true;
otherResourceList.push({
domain: domain,
duration: entry.duration.toFixed(0)
});
}
}
}
}
// 对未知资源随机上报最多五个
otherResourceList = otherResourceList
.sort(function() {
return Math.random() - 0.5;
})
.slice(0, 5);
var domainObj = {};
for (var x = 0,y = otherResourceList.length; x < y; x ++){
domainObj[otherResourceList[x].domain] = otherResourceList[x].duration;
}
var res = {
white: timing.domLoading - timing.navigationStart,
ready: timing.domContentLoadedEventEnd - timing.navigationStart,
onload: timing.loadEventEnd - timing.fetchStart,
render: timing.domComplete - timing.domLoading,
dns: timing.domainLookupEnd - timing.domainLookupStart,
tcp: timing.connectEnd - timing.connectStart,
img: imgCount,
bg: bgCount,
imgs: imgCount + bgCount,
js: jsCount,
css: cssCount,
resources: entries.length,
tags: document.getElementsByTagName('*').length,
others: JSON.stringify(domainObj)
};
report(res);
window.adEventListener('load', function() {
setTimeout(function() {
logPerformance();
}, 0);
});
3.部署位置
(1)性能分析脚本尽可能地最后执行,避免影响业务。
(2)错误监控的实现方式是监听window.onerror事件,因此需要放在页面头部来保证事件及时绑定。
第九章 网络技术基础
9.1 URL & HTTP协议
概览
01 URL
统一资源定位符,网址
<scheme>:<scheme-specific-part>
<scheme-specific-part>
// 协议的详细部分(通用部分)://用户名:密码@主机名:端口号/路径
// <user>:<password>@<host>:<port>/<urlpath>
网址分为两个部分:
协议部分、协议的具体内容,中间用:隔开
HTTP URL:
http: <host>:<port>/<path>?<searchpart>
如果省略写端⼝号:<port>,端⼝号默认为80
URL示例(清华大学部分端口号示例):
http://www.tsinghua.edu.cn/
http://news.tsinghua.edu.cn/info/1002/80573.htm
http://www.tsinghua.edu.cn/ssjgy.jsp?wbtreeid=1001
HTTP URL基本结构:
http://www.example.com:80/path/to/myfle.html?key1=value1&key2=value2#SomewhereInTheDocument
http :协议 protocol
www .example.com :主机 host
:80 :端口号 port
/path/to/myfle.html :路径 path
?key1=value1&key2=value2 :参数 search
#SomewhereInTheDocument :哈希(锚点) hash
绝对URL与相对URL:
常见应用:
HTML
<a>, <img>, <form>, <script>, <link>, <iframe>, <video>, <audio>, <object>
CSS
@import, @fontface, backgroundimage, borderimage, liststyleimage
JavaScript
XMLHttpRequest, fetch, location, open
02 HTTP协议
HTTP1.1 协议是以 ASCII 码传输,建⽴在 TCP/IP 协议之上的应⽤层规范。
例子见9.1URL&HTTP协议.pdf
1.请求消息格式
<⽅法><空格><URI><空格><HTTP版本> //消息行
<字段名>:<字段值> //消息头
... // |
... // |
<空⾏> //消息头
<消息体> //消息体
2.响应消息格式
<HTTP版本><空格><状态码><空格><响应短语> //状态行
<字段名>:<字段值> //消息头
... // |
... // |
<空⾏> //消息头
<消息体> //消息体
方法:
状态码
HTTP Headers
HTTP Body
不是所有的请求都有 body:
例如获取资源的请求,GET,HEAD,DELETE 和OPTIONS。
有些请求将数据发送到服务器以便更新数据,比如POST。
实体头 Content-Type
⽤于指示资源的MIME类型(media types)。
Content-Type: text/html; charset=utf-8
Content-Type: image/jpeg
常⻅的MIME类型
请求头 Cookie
网站为了辨别用户身份而储存在用户本地终端(Client Side)上的数据。
设置方式:
#1. 响应头
Set-Cookie
#2. JavaScript
document.cookie
⼤小限制:4KB
响应头 Set-Cookie
Cookie安全策略
1.Path
2.Domain (hostonly*)
3.Expires (Max-Age)
4.Secure
5.HttpOnly
6.SameSite
服务端设置:
Set-Cookie:key=value;path=path;domain=domain;maxage=max-age-in-seconds;expires=date-in-GMTString-format;secure;htt
ponly;samesite=samesite
浏览器端设置:
document.cookie="key=value;path=path;domain=domain;max-age=max-age-in-seconds;expires=date-in-GMTString-format;secure;samesite=samesite";
浏览器同源策略(Same-origin policy)
用于限制⼀个源的文档或者它加载的脚本如何能与另⼀个源的资源进行交互。
1.协议相同
2.主机相同
3.端口相同
原始URL:http://store.company.com/dir/page.html
同源策略限制范围
- Cookie、LocalStorage 和 IndexDB 无法读取。
- DOM 无法获得。
- AJAX、Fetch 请求不能发送。
跨域 HTTP 请求
JSONP
1.浏览器端发起⼀个JavaScript文件请求
//创建回调函数
function handler(data){
console.log(data);
}
//发起GET请求,请求JavaScript
var script = document.createElement('script');
script.src = 'http://example.com/api?callback=handler';
document.body.insertBefore(script,document.body.firstChild);
2.服务端动态生成JavaScript文件,作为Response body
handler({errno:0,data:[1,2,3]});
CROS
- 浏览器端使用Ajax或Fetch技术发起HTTP请求,以Ajax为例:
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
console.log(xhr.responseText);
}
};
xhr.open('GET', 'http://example.com/api', true);
xhr.send();
- 服务端在Response header中添加响应头,同时将数据作为Response body
Access-Control-Allow-Origin: *
Access-Control-Allow-Origin: https://www.tsinghua.edu.cn
//--------------------------------------------------------
{errno:0,data:[1,2,3]}
03 DNS
域名系统
域名(Domain Name)
为互联网上任何可用的网页服务器提供了方便人类理解的地址。
域名结构
.eg. www. tsinghua.edu.cn
cn:TLD,顶级域名(Top-Level Domain,常见的顶级域名有 .com, .org, .net, .cn)
edu:SLD,二级域名,edu是一个类别域名,高校专用(Secondary Level Domain)
tsinghua:三级域名
www:四级域名
对于每⼀级域名⻓度的限制是63个字符,域名总⻓度则不能超过253个字符
购买域名
-
查询未注册域名:whois 360.cn =>查询360.cn是否被注册
-
购买选中的域名(.eg.:example.com)
-
设置DNS服务器地址(可选)
-
设置域名IP
因特网域名空间
hosts文件(DNS的前身)
Hosts文件是⼀个没有扩展名的操作系统⽂件,以表的形式存储了主机名和IP地址的映射关系。
##
# Host Database
#
# localhost is used to confgure the loopback interface
# when the system is booting. Do not change this entry.
##
127.0.0.1 localhost
166.111.4.100 www.example.com
DNS服务器(Name Server)
DNS服务器的基本工作
hosts文件和DNS的关系
DNS解析过程
dig +trace .tsinghua.edu.cn
相关见9.1URL&HTTP协议.pdf
DNS预解析
强制查询特定主机名:
<link rel="dns-prefetch" href="https://fonts.googleapis.com/">
<link rel="dns-prefetch" href="//www.spreadfrefox.com">
04 TCP/IP协议栈
协议栈
套接字(socket)
- 客户端IP地址
- 客户端端⼝号
- 服务器IP地址
- 服务器端⼝号
收发数据
05 TLS/SSL
HTTPS
超⽂本传输安全协议通常称为HTTP over TLS,数据经由HTTP进⾏通信,但利⽤SSL/TLS来加密数据包。
TLS/SSL
传输层安全性协议(Transport Layer Security)及其前身安全套接层(Secure Sockets Layer)是⼀种安全协议,⽬的是为互联⽹通信提供安全及数据完整性保障。
HTTPS 的优势
- 身份验证
- 数据完整性
- 保密性
混合内容(Mixed Content)
混合内容是指初始 HTML 内容通过安全的 HTTPS 连接加载,但其他资源(例如,图像、视频、样式表、脚本)则通过不安全的 HTTP 连接加载。
被动混合内容:
<img>, <video> <audio>
主动混合内容:
<script>, <link>, <iframe>, <object>, XMLHttpRequest, fetch
第十一章 前端工程化
11.1 ESLint基础
01 解决什么问题
var hasBarProperty = foo.hasOwnProperty("bar");
var isPrototypeOfBar = foo.isPrototypeOf(bar);
var barIsEnumerable = foo.propertyIsEnumerable("bar");
foo对象的方法有可能被串改的,这种使用会带来安全隐患
var hasBarProperty = Object.prototype.hasOwnProperty.call(foo, "bar");
var isPrototypeOfBar = Object.prototype.isPrototypeOf.call(foo, bar);
var barIsEnumerable = {}.propertyIsEnumerable.call(foo, "bar");
以上是更好的做法
02 工作原理
- 使⽤ Espree(解析器) 解析 JavaScript
- 使⽤ AST (抽象语法树)去分析代码中的模式
- https://astexplorer.net/ (左侧填入js代码,右侧自动生成对js分析的AST分析树)
03 如何使用
(1)安装和初始化
npm install eslint savedev./node_modules/eslint/bin/eslint.js init
安装、初始化等全过程见11.1ESLint基础.pdf
(2)配置规则
规则配置、检验代码等见11.1ESLint基础.pdf/P26
警告级别:
- “off” or 0 - 关闭规则
- “warn” or 1 - 将规则视为⼀个警告(不会影响退出码)
- “error” or 2 - 将规则视为⼀个错误 (退出码为1)
全局变量:
globals 配置属性设置为⼀个对象该对象包含以你希望使用的每个全局变量"writable" 以允许重写变量,或 “readonly” 不允许重写变量
(3)检验代码
见11.1ESLint基础.pdf
发展趋势:
事实上的WEB前端标准与开发框架的高度结合
见11.1ESLint基础.pdf
11.2 git基础
01 什么是git
git是⼀款用来执行版本控制的软件,和Subversion、CVS具有相似的特性,例如可以保存修改历史、能恢复某些历史的修改等等。同时,git与传统的版本控制软件在设计思想和实现上差异比较大。
Git与之前的版本控制软件的差异
早期版本控制软件,例如Subversion,其依赖中⼼服务器以及客户端到服务器的网络连通性,服务器充当中心结点,所有客户端通过网络协议执行版本控制操作,如果客户端无法连接网络服务,则无法执行相关操作,这种软件架构称为集中式版本控制,其优点在于部署简便,不需要考虑多个客户端如何协作。
与集中式对应的则是分布式版本控制,git就是分布式版本控制软件的⼀种,每个客户端都拥有完整的仓库代码,除非需要远程协作,大部分操作是发生在本地⽂件系统,摆脱对于网络连通性的强依赖,甚至中心服务器故障时,可以使用某个客户端充当新的中心节点。
除了分布式之外,git对待版本更新的方法和Subversion有些不同,Subversion会把版本看成是⼀组文件随时间的累积结果,基于差异去控制版本。
git把每次提交保存为文件系统的快照,出于效率考虑如果没有修改则不保存,只是保留指向之前版本的链接,整体上看git更像是个内容寻址文件系统,如下所示
Git的简史
Linux内核开源社区从2002年开始使用BitKeeper,同样是⼀款分布式版本控制软件,在2005年BitKeeper的商业公司同Linux内核开源社区的合作关系结束,于是Linux内核开源社区不得不另起炉灶。最初他们对git有以下期待:
- 速度
- 简单的设计
- ⽀持非线性开发模式即允许大量并行开发分支
- 完全分布式
- 有能力高效管理类似 Linux 内核⼀样的超大规模项目
02 基本原理
1)对象数据库
2)树对象
3)提交对象
对象状态
在git中对象包括三种状态,分别是已提交(commited)、已修改(modified)、已暂存(staged)
- 已修改表示已经修改了⽂件,但是还没有保存到本地文件数据库
- 已暂存表示对⼀个已修改文件的当前版本做了标记,使之包含在下次提交的快照中
- 已提交表示数据已经安全地保存在本地数据库中
以上三种状态对象的集合则是git目录、工作区和暂存区,其中已提交对应git目录,已修改对应工作区,已暂存对应暂存区
1)对象数据库
所有git相关的数据都是存储在.git目录下,其中git对象存储在.git/objects即对象数据库。
可以通过git hash-object,实现插⼊⼀个对象到对象数据库中
过程见11.2git基础.pdf
2)树对象
类似于 UNIX 文件系统的方式存储文件路径,所有内容均以树对象和数据对象的形式存储。其中树对象对应了 UNIX 中的目录项,数据对象则大致上对应了 inodes 或文件内容。⼀个树对象包含了⼀条或多条树对象记录,每条记录含有⼀个指向数据对象或者子树对象的指针以及相应的模式、类型、文件名信息。
过程见11.2git基础.pdf
3)提交对象
提交对象是引用树对象并记录谁在什么时候增加树对象以及父提交,相当于树对象的操作记录
过程见11.2git基础.pdf
4)引用对象
引用对象就是提交对象的别名,我们可以用git update-ref创建引用对象,如下所示
过程见11.2git基础.pdf
5)git对象
git所做的工作实质就是将被改写的文件保存为数据对象, 更新暂存区,记录树对象,最后创建⼀个指明了顶层树对象和父提交的提交对象。
这三种主要的 Git 对象——数据对象、树对象、提交对象——最终均以单独文件的形式保存在 .git/objects ⽬录下
03 常见操作
如何提交变更
临时保留修改
有时在⼯作区的修改还没有达到提交状态,这时如果有⼀个临时的想法想去实现,可以使⽤git stash来临时保存工作区状态
撤销修改
分支管理
分支合并
在⼤型项目开发中,合并分支往往非常频繁,这是因为需要经常集成其他人的贡献和代码,最常用的合并是通过git merge实现
如果test分支创建后,master分支又产生新的提交对象,就不符合快速合并原则,需要人工处理
与远程协作
将本地的分支关联到远程分⽀,实际上就是创建⼀类特殊的远程引⽤对象,这个引用对象是只读的。
通过git push将本地的对象提交到远程,如下就是把本地的master分支推送到远程,前提是需要对目标仓库有写权限。
——The End