自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

深入理解Babel - 項(xiàng)目管理工具Lerna解析

開發(fā) 開發(fā)工具
monorepo(monolithic repository),指的是單倉庫代碼,將多個(gè)項(xiàng)目代碼存儲(chǔ)在一個(gè)倉庫里。另外有一種模式是multirepo,指的是多倉庫代碼(one-repository-per-module),不同的項(xiàng)目分布在不同的倉庫里。React、Babel、Jest、Vue、Angular均采用monorepo進(jìn)行項(xiàng)目管理。

一、背景

Babel是一個(gè)比較龐大的項(xiàng)目,其子工程就有至少140個(gè)(如 babel/plugins/presets/lerna/babel-loader等),產(chǎn)出的子工具已經(jīng)是前端開發(fā)的基礎(chǔ)設(shè)施,對開發(fā)效率、代碼質(zhì)量等有非常高的要求。

在本文中,我們將了解Babel是怎樣進(jìn)行項(xiàng)目管理的。

圖片圖片

本文從工程管理、代碼管理、文檔管理、質(zhì)量管理四個(gè)方面對Babel項(xiàng)目管理進(jìn)行拆解分析。

工程管理

Babel是典型的monorepo項(xiàng)目,即單倉庫項(xiàng)目,所有的子模塊在同一個(gè)倉庫里。Babel目前有140+個(gè)子模塊,在工程管理部分,需要解決以下問題:

  • 模塊間如何方便地互相關(guān)聯(lián)進(jìn)行本地開發(fā);
  • 整個(gè)項(xiàng)目的版本控制;
  • 操作自動(dòng)化。

工程管理部分主要使用lerna、yarn等工具。

代碼風(fēng)格

Babel是多人協(xié)作開發(fā)的開源項(xiàng)目,如何保證代碼風(fēng)格一致,Babel使用的是社區(qū)常見的解決方案。

該模塊主要使用eslint、prettier等工具。

文檔

Babel的迭代速度很快、涉及的模塊很多,該模塊解決版本發(fā)布后如何自動(dòng)更新相關(guān)文檔等問題。

該模塊主要使用lerna等工具。

質(zhì)量控制

Babel的產(chǎn)品是前端開發(fā)的基礎(chǔ)設(shè)施,該模塊主要保證Babel的產(chǎn)出是高質(zhì)量的。

該模塊主要使用jest、git blame等工具。

二、monorepo

Babel使用monorepo模式進(jìn)行工程管理。

什么是monorepo

monorepo(monolithic repository),指的是單倉庫代碼,將多個(gè)項(xiàng)目代碼存儲(chǔ)在一個(gè)倉庫里。另外有一種模式是multirepo,指的是多倉庫代碼(one-repository-per-module),不同的項(xiàng)目分布在不同的倉庫里。React、Babel、Jest、Vue、Angular均采用monorepo進(jìn)行項(xiàng)目管理。

典型的monorepo結(jié)構(gòu)是:

├── packages
|   ├── pkg1
|   |   ├── package.json
|   ├── pkg2
|   |   ├── package.json
├── package.json

這是Babel源碼的目錄結(jié)構(gòu):

├─ lerna.json
├─ package.json
└─ packages/ # 這里將存放所有子項(xiàng)目目錄
    ├─ README.md
    ├─ babel-cli
    ├─ babel-code-frame
    ├─ babel-compat-data
    ├─ babel-core
    ├─ babel-generator
    ├─ babel-helper-annotate-as-pure
    ├─ babel-helper-builder-binary-assignment-operator-visitor
    ├─ babel-helper-builder-react-jsx
    ├─ ...

而rollup則采取了multirepo的模式:

├─ rollup
    ├─ package.json
    ├─ ...
├─ plugins
    ├─ package.json
    ├─ ...
├─ awesome
    ├─ package.json
    ├─ ...
├─ rollup-starter-lib
    ├─ package.json
    ├─ ...
├─ rollup-plugin-babel
    ├─ package.json
    ├─ ...
├─ rollup-plugin-commonjs
    ├─ package.json
    ├─ ...

monorepo的優(yōu)缺點(diǎn)

優(yōu)點(diǎn)

  • 便捷的代碼復(fù)用與依賴管理當(dāng)所有項(xiàng)目代碼都在一個(gè)工程里,抽離可復(fù)用的代碼就十分容易了。并且抽離后,如果復(fù)用的代碼有改動(dòng),可以通過一些工具,快速定位受影響的子工程,進(jìn)而做到子工程的版本控制。
  • 便捷的代碼重構(gòu)通過一些工具,monorepo項(xiàng)目中的代碼改動(dòng)可以快速地定位出代碼變更的影響范圍,對整個(gè)工程進(jìn)行快速的整體測試。而如果子工程分散在不同的工程分支里的話,通用代碼的重構(gòu)將難以觸達(dá)各個(gè)子工程。
  • 倡導(dǎo)開放、共享monorepo項(xiàng)目中,開發(fā)者可以方便地看到所有子工程,這樣響應(yīng)了"開放、共享"的組織文化。可以激發(fā)開發(fā)者對工程質(zhì)量等維護(hù)的熱情(畢竟別人看不到自己的代碼,亂不亂就看自己心情了),有助于團(tuán)隊(duì)建立良好的技術(shù)氛圍。

缺點(diǎn)

  • 復(fù)雜的權(quán)限管理因?yàn)樗凶庸こ碳性谝粋€(gè)工程里,某些子工程如果不希望對外展示的話,monorepo的權(quán)限管理就比較難以實(shí)現(xiàn)了,難以鎖定目標(biāo)工程做獨(dú)立的代碼權(quán)限管理。
  • 較高的熟悉成本相對于multirepo,monorepo涉及各種子工程、通用依賴等,新的開發(fā)者在理解整個(gè)項(xiàng)目時(shí),可能需要了解較多的信息才能入手,如通用依賴代碼、各子工程功能。
  • 較大的工程體積很明顯,所有子工程集成在一個(gè)工程里,代碼體積會(huì)非常大,對文件存儲(chǔ)系統(tǒng)等提出了較高的要求。
  • 較高的質(zhì)量風(fēng)險(xiǎn)成也蕭何敗蕭何,monorepo提供了便捷的代碼復(fù)用能力,同時(shí),一個(gè)公用模塊的某個(gè)版本有bug的話,很容易影響所有用到它的子工程。此時(shí),做好高覆蓋率的單元測試就比較重要了。

選擇

multirepo和monorepo是兩種不同的理念。

multirepo允許多元化發(fā)展,每個(gè)模塊獨(dú)立實(shí)現(xiàn)自己的構(gòu)建、單元測試、依賴管理等。monorepo抹平了模塊間的很多差異,通過集中管理和高度集成化的工具,減少開發(fā)和溝通時(shí)的成本。monorepo最大的問題可能就是不能管理占用空間太大的項(xiàng)目了。

所以,還是要根據(jù)項(xiàng)目的實(shí)際需求出發(fā)選擇用哪種項(xiàng)目管理模式。

三、lerna

lerna是基于git/npm/yarn等的工作流提效工具,用于維護(hù)monorepo。它是Babel 開發(fā)過程中提升開發(fā)效率產(chǎn)出的工具。

lerna本身也是一個(gè)monorepo的項(xiàng)目,并且,lerna為monorepo項(xiàng)目提供了如下支持:

  • 項(xiàng)目管理

lerna提供了一系列命令用于monorepo項(xiàng)目初始化、添加子項(xiàng)目、查看項(xiàng)目信息等。

  • 依賴管理

lerna支持為monorepo項(xiàng)目統(tǒng)一管理公共依賴、自動(dòng)安裝各個(gè)子項(xiàng)目的依賴、自動(dòng)創(chuàng)建子模塊符號鏈接等。

  • 版本管理

lerna可以根據(jù)項(xiàng)目代碼的變動(dòng)情況,發(fā)現(xiàn)影響的子項(xiàng)目范圍,在發(fā)布時(shí)提供語義化版本推薦等,極大提升了monorepo項(xiàng)目的版本管理效率。

lerna命令集

命令行列表

lerna官網(wǎng)有對各種命令各種用法的詳細(xì)介紹,這些命令可以分為:項(xiàng)目管理、依賴管理、版本管理三大類。

圖片圖片

全局配置項(xiàng)

lerna有一批通用參數(shù),所有子命令均可以使用。

--concurrency

當(dāng)lerna將任務(wù)并行執(zhí)行時(shí),需要使用多少線程(默認(rèn)為邏輯CPU內(nèi)核數(shù))。

lerna publish --concurrency 1

--loglevel<silent|error|warn|success|info|verbose|silly>

要報(bào)告什么級別的日志。如果失敗,所有日志都寫到當(dāng)前工作目錄中的lerna-debug.log中。

任何高于該設(shè)置的日志都會(huì)顯示出來。默認(rèn)值是"info"。

--max-buffer<bytes>

為每個(gè)底層進(jìn)程調(diào)用設(shè)置的最大緩沖區(qū)長度。例如,當(dāng)有人希望在運(yùn)行l(wèi)erna import的同時(shí)導(dǎo)入包含大量提交的倉庫時(shí),就是它出場的時(shí)候了。在這種情況下,內(nèi)置的緩沖區(qū)長度可能不夠。

--no-progress

禁用進(jìn)度條。在CLI環(huán)境中總是這樣。

--no-sort

默認(rèn)情況下,所有任務(wù)都按照拓?fù)渑判虻捻樞蛟诎蠄?zhí)行,以尊重所討論的包的依賴關(guān)系。在不保證lerna調(diào)用一致的情況下,以最努力的方式打破循環(huán)。

如果只有少量的包有許多依賴項(xiàng),或者某些包執(zhí)行的時(shí)間長得不成比例,拓?fù)渑判蚩赡軙?huì)導(dǎo)致并發(fā)瓶頸。--no-sort配置項(xiàng)禁用排序,而是以最大并發(fā)的任意順序執(zhí)行任務(wù)。

如果您運(yùn)行多個(gè)watch命令,該配置項(xiàng)也會(huì)有所幫助。因?yàn)閘erna run將按照拓?fù)渑判虻捻樞驁?zhí)行命令,所以在繼續(xù)執(zhí)行之前可能會(huì)等待某個(gè)命令。當(dāng)您運(yùn)行"watch"命令時(shí)會(huì)阻塞執(zhí)行,因?yàn)樗麄兺ǔ2粫?huì)結(jié)束。

--reject-cycles

如果(在bootstrap、exec、publish或run中)發(fā)現(xiàn)循環(huán),則立即失敗。

lerna bootstrap --reject-cycles

過濾器參數(shù)

--scope<glob>

只包含名稱與給定通配符匹配的包。

lerna exec --scope my-component -- ls -la     
lerna run --scope toolbar-* test     
lerna run --scope package-1 --scope *-2 lint

--ignore<glob>

排除名稱與給定通配符匹配的包。

lerna exec --ignore package-{1,2,5}  -- ls -la     
lerna run --ignore package-1  test     
lerna run --ignore package-@(1|2) --ignore package-3 lint

--no-private

排除私有的包。默認(rèn)情況下是包含它們的。

--since [ref]

只包含自指定ref以來已經(jīng)改變的包。如果沒有傳遞ref,它默認(rèn)為最近的標(biāo)記。

# 列出自最新標(biāo)記以來發(fā)生變化的包的內(nèi)容
    $ lerna exec --since -- ls -la


    # 為自“master”以來所有發(fā)生更改的包運(yùn)行測試
    $ lerna run test --since master


    # 列出自“某個(gè)分支”以來發(fā)生變化的所有包
    $ lerna ls --since some-branch

在CI中使用時(shí),如果您可以獲得PR將要進(jìn)入的目標(biāo)分支,那么它將特別有用,因?yàn)槟梢詫⑵渥鳛?-since配置項(xiàng)的ref。這對于進(jìn)入master和feature分支的PR來說很有效。

--exclude-dependents

當(dāng)使用--since運(yùn)行命令時(shí),排除所有傳遞的被依賴項(xiàng),覆蓋默認(rèn)的“changed”算法。

如果沒有--since該參數(shù)時(shí)無效的,會(huì)拋出錯(cuò)誤。

--include-dependents

在運(yùn)行命令時(shí)包括所有傳遞的被依賴項(xiàng),無視--scope、--ignore或--since。

--include-dependencies

在運(yùn)行命令時(shí)包括所有傳遞依賴項(xiàng),無視--scope、--ignore或--since。

與接受--scope(bootstrap、clean、ls、run、exec)的任何命令組合使用。確保對任何作用域的包(通過--scope或--ignore)的所有依賴項(xiàng)(和dev依賴項(xiàng))也進(jìn)行操作。

注意:這將會(huì)覆蓋--scope和--ignore。

例如,如果一個(gè)匹配了--ignore的包被另一個(gè)正在引導(dǎo)的包所以來,那么它仍會(huì)照常工作。

當(dāng)您想要“設(shè)置”一個(gè)依賴于其他正在設(shè)置的包其中的一個(gè)包時(shí),這是非常有用的。

lerna bootstrap --scope my-component --include-dependencies     
# my-component 及其所有依賴項(xiàng)將被引導(dǎo)
lerna bootstrap --scope "package-*" --ignore "package-util-*" --include-dependencies     
# 所有匹配 "package-util-*" 的包將被忽略,除非它們依賴于名稱匹配 "package-*" 的包

--include-merged-tags

lerna exec --since --include-merged-tags -- ls -la

在使用--since命令時(shí),它包含來自合并分支的標(biāo)記。這只有在從feature分支進(jìn)行大量發(fā)布時(shí)才有用,通常情況下不推薦這樣做。

lerna原理解析

文件結(jié)構(gòu)

以下是lerna的主要目錄結(jié)構(gòu)(省略了一些文件和文件夾):

lerna
├─ CHANGELOG.md -- 更新日志
├─ README.md -- 文檔
├─ commands -- 核心子模塊
├─ core -- 核心子模塊
├─ utils -- 核心子模塊
├─ lerna.json -- lerna 配置文件
├─ package-lock.json -- 依賴聲明
├─ package.json -- 依賴聲明
├─ scripts -- 內(nèi)置腳本
└─ yarn.lock -- 依賴聲明

有趣的是,lerna本身也是用lerna進(jìn)行開發(fā)管理的。它是一個(gè)monorepo項(xiàng)目,其各個(gè)子項(xiàng)目分布在lerna/commands/*、core/*、utils/*目錄下。

另外,在源碼中,經(jīng)常會(huì)看到名稱為@lerna/command的子項(xiàng)目,如lerna/core/lerna/index.js的內(nèi)容是:

const cli = require("@lerna/cli");


const addCmd = require("@lerna/add/command");
const bootstrapCmd = require("@lerna/bootstrap/command");
const changedCmd = require("@lerna/changed/command");
const cleanCmd = require("@lerna/clean/command");
const createCmd = require("@lerna/create/command");
const diffCmd = require("@lerna/diff/command");
const execCmd = require("@lerna/exec/command");
const importCmd = require("@lerna/import/command");
const infoCmd = require("@lerna/info/command");
const initCmd = require("@lerna/init/command");
const linkCmd = require("@lerna/link/command");
const listCmd = require("@lerna/list/command");
const publishCmd = require("@lerna/publish/command");
const runCmd = require("@lerna/run/command");
const versionCmd = require("@lerna/version/command");

這些子項(xiàng)目分布在lerna/commands/*、core/*、utils/*下,截至本文截稿時(shí),lerna有61個(gè)子項(xiàng)目。

以下是各子項(xiàng)目分布:

圖片圖片

命令行注冊

lerna命令注冊工作集中在lerna/core/lerna/*路徑下。

lerna/core/lerna/package.json

該文件的bin字段定義了lerna命令:

"bin": {         
    "lerna": "cli.js"     
}

lerna/core/lerna/cli.js

該文件描述了命令行的執(zhí)行入口:

#!/usr/bin/env node


    "use strict";


    /* eslint-disable import/no-dynamic-require, global-require */
    const importLocal = require("import-local");


    if (importLocal(__filename)) {
        require("npmlog").info("cli", "using local version of lerna");
    } else {
        require(".")(process.argv.slice(2));
    }

lerna/core/lerna/index.js

該文件為命令行引入了所有l(wèi)erna指令:

"use strict";


const cli = require("@lerna/cli");


const addCmd = require("@lerna/add/command");
const bootstrapCmd = require("@lerna/bootstrap/command");
const changedCmd = require("@lerna/changed/command");
const cleanCmd = require("@lerna/clean/command");
const createCmd = require("@lerna/create/command");
const diffCmd = require("@lerna/diff/command");
const execCmd = require("@lerna/exec/command");
const importCmd = require("@lerna/import/command");
const infoCmd = require("@lerna/info/command");
const initCmd = require("@lerna/init/command");
const linkCmd = require("@lerna/link/command");
const listCmd = require("@lerna/list/command");
const publishCmd = require("@lerna/publish/command");
const runCmd = require("@lerna/run/command");
const versionCmd = require("@lerna/version/command");


const pkg = require("./package.json");


module.exports = main;


function main(argv) {
const context = {
    lernaVersion: pkg.version,
};


return cli()
    .command(addCmd)
    .command(bootstrapCmd)
    .command(changedCmd)
    .command(cleanCmd)
    .command(createCmd)
    .command(diffCmd)
    .command(execCmd)
    .command(importCmd)
    .command(infoCmd)
    .command(initCmd)
    .command(linkCmd)
    .command(listCmd)
    .command(publishCmd)
    .command(runCmd)
    .command(versionCmd)
    .parse(argv, context);
}

Commander類

lerna的子命令均繼承自Command類,比如lerna init命令定義為:

const { Command } = require("@lerna/command");


class InitCommand extends Command {
    ...
}

Command類定義在@lerna/command,位于lerna/core/command目錄。

有一些寫法值得借鑒,比如個(gè)別方法需要InitCommand的實(shí)例自行定義,否則拋錯(cuò),InitCommand類的定義如下:

class InitCommand extends Command {
    ...


    initialize() {
        throw new ValidationError(this.name, "initialize() needs to be implemented.");
    }


    execute() {
        throw new ValidationError(this.name, "execute() needs to be implemented.");
    }
}

import-local

上文提到,lerna/core/lerna/cli.js描述了命令行的執(zhí)行入口:

#!/usr/bin/env node


"use strict";


/* eslint-disable import/no-dynamic-require, global-require */
const importLocal = require("import-local");


if (importLocal(__filename)) {
    require("npmlog").info("cli", "using local version of lerna");
} else {
    require(".")(process.argv.slice(2));
}

其中,import-local的作用是,實(shí)現(xiàn)本地開發(fā)版本和生產(chǎn)版本的切換。import-local/index.js的內(nèi)容是:

'use strict';
const path = require('path');
const resolveCwd = require('resolve-cwd');
const pkgDir = require('pkg-dir');


module.exports = filename => {
    const globalDir = pkgDir.sync(path.dirname(filename));
    const relativePath = path.relative(globalDir, filename);
    const pkg = require(path.join(globalDir, 'package.json'));
    const localFile = resolveCwd.silent(path.join(pkg.name, relativePath));
    const localNodeModules = path.join(process.cwd(), 'node_modules');
    const filenameInLocalNodeModules = !path.relative(localNodeModules, filename).startsWith('..');


    // Use path.relative() to detect local package installation,
    // because __filename's case is inconsistent on Windows
    // Can use === when targeting Node.js 8
    // See https://github.com/nodejs/node/issues/6624
    return !filenameInLocalNodeModules && localFile && path.relative(localFile, filename) !== '' && require(localFile);
};

依賴管理

Babel使用lerna進(jìn)行依賴管理。其中,lerna自己實(shí)現(xiàn)了一套依賴管理機(jī)制,也支持基于yarn的依賴管理。這里主要介紹lerna的hoisting。

子模塊相同的依賴可以通過依賴提升(hoisting),將相同的依賴安裝在根目錄下,本地包之間用軟連接實(shí)現(xiàn)。

lerna bootstrap

該命令執(zhí)行時(shí),會(huì)在每個(gè)子項(xiàng)目下面,各自安裝其中package.json聲明的依賴。

這樣會(huì)有一個(gè)問題,相同的依賴會(huì)被重復(fù)安裝,除了占用更多空間外,依賴安裝速度也受影響。

lerna bootstrap --hoist

--hoist標(biāo)記時(shí),lerna bootstrap會(huì)識(shí)別子項(xiàng)目下名稱和版本號相同的依賴,并將其安裝在根目錄的node_modules下,子項(xiàng)目的node_modules會(huì)生成軟連接。

這樣節(jié)省了空間,也減少了依賴安裝的耗時(shí)。

yarn install

當(dāng)在項(xiàng)目中聲明yarn作為依賴安裝的底層依賴,如:

lerna.json

{             
    "npmClient": "yarn",             
    "useWorkspaces": true,         
}

package.json

{             
    "workspaces": [                 
        "packages/*"             
    ]         
}

相對于lerna,yarn提供了更強(qiáng)大的依賴分析能力、hoisting算法。而且,默認(rèn)情況下,yarn會(huì)開啟hoist功能,也可以設(shè)置nohoist關(guān)閉該功能:

{             
    "workspaces": {                 
        "packages": [                     
            "Packages/*",                 
        ],                 
        "nohoist": [                     
            "**"                 
        ]             
     }         
}

lerna中涉及的git命令

lerna中廣泛使用了git命令用于內(nèi)部工作,這里列舉了lerna中使用的git命令。

git init
git rev-parse
git describe
git rev-list
git tag
git log
git config
git diff-index
git --version
git show
git am
git reset
git ls-files
git diff-tree
git commit
git ls-remote
git checkout
git push
git add
git remote
git show-ref

沒有必要逐個(gè)介紹git命令,我們選取幾個(gè)不是很常見的git命令介紹,了解其作用、lerna哪些命令用到了它們。

git rev-parse

  • 主要用于解析git引用(如分支名稱、標(biāo)簽名稱等)或表達(dá)式,并輸出對應(yīng)的SHA-1值。它的作用包括但不限于:

解析提交、分支、標(biāo)簽等引用,獲取對應(yīng)的SHA-1值。

校驗(yàn)是否為有效的引用或表達(dá)式。

生成git對象的唯一標(biāo)識(shí)符。

下面是一個(gè)git rev-parse命令的執(zhí)行結(jié)果案例:

$ git rev-parse HEAD
f7f6d6f2b6b47eb8c4cf4b8bf5f83e0b8028c031
  • 關(guān)聯(lián)的lerna命令
  • lerna version:在執(zhí)行版本升級操作時(shí),lerna會(huì)使用git rev-parse來獲取先前提交的哈希值作為上一個(gè)版本的參考。
  • lerna changed:用于列出自上次標(biāo)記以來發(fā)生變更的包,可能會(huì)用到git rev-parse來比較不同提交之間的差異。
  • lerna diff:顯示自上次標(biāo)記以來的所有包的diff,也可能會(huì)使用git rev-parse來比較不同提交之間的差異。
  • lerna源碼案例libs/commands/import/src/index.ts
getCurrentSHA() {
    return this.execSync("git", ["rev-parse", "HEAD"]);
}


getWorkspaceRoot() {
    return this.execSync("git", ["rev-parse", "--show-toplevel"]);
}

git describe

  • 主要用于根據(jù)最接近的標(biāo)簽來描述當(dāng)前提交的位置。它的作用包括但不限于:

找到最接近當(dāng)前提交的標(biāo)簽。

根據(jù)最接近的標(biāo)簽以及提交的SHA-1值生成一個(gè)描述字符串。

可以幫助識(shí)別當(dāng)前提交相對于標(biāo)簽的距離,以及提交是否是基于標(biāo)簽進(jìn)行的修改。

下面是一個(gè)git describe命令的執(zhí)行結(jié)果案例:

$ git describe
polaris-release-1.0.0-c12345
  • 關(guān)聯(lián)的lerna命令
  • lerna version:在執(zhí)行版本升級操作時(shí),lerna可能會(huì)使用git describe 來確定當(dāng)前提交的位置,以便生成新的版本號。
  • lerna源碼案例libs/commands/diff/src/lib/get-last-commit.ts
export function getLastCommit(execOpts?: ExecOptions) {
  if (hasTags(execOpts)) {
    log.silly("getLastTagInBranch", "");
    return childProcess.execSync("git", ["describe", "--tags", "--abbrev=0"], execOpts);
  }
  log.silly("getFirstCommit", "");
  return childProcess.execSync("git", ["rev-list", "--max-parents=0", "HEAD"], execOpts);
}

git rev-list

  • 主要用于列出提交對象的SHA-1哈希值。它的作用包括但不限于:

列出提交對象的哈希值,可以按時(shí)間、作者、提交者等順序進(jìn)行排序。

支持使用范圍、分支、標(biāo)簽等參數(shù)來限制輸出的提交范圍。

下面是一個(gè)git rev-list命令的執(zhí)行結(jié)果案例:

$ git rev-list HEAD
f7f6d6f2b6b47eb8c4cf4b8bf5f83e0b8028c031
a3d8b4e1c2e1d0a9b8c6e5f7d6a4b3e8a1b2c3d4

這里git rev-list HEAD將列出當(dāng)前HEAD指向的提交及其之前的所有提交的 SHA-1 哈希值。

  • 關(guān)聯(lián)的lerna命令
  • lerna changed:列出自上次標(biāo)記以來發(fā)生變更的包,可能會(huì)使用git rev-list 來獲取兩個(gè)標(biāo)記之間的提交列表。
  • lerna diff:顯示自上次標(biāo)記以來的所有包的diff,也可能會(huì)使用git rev-list 來獲取兩個(gè)標(biāo)記之間的提交列表。
  • lerna 源碼案例libs/commands/diff/src/lib/get-last-commit.ts
export function getLastCommit(execOpts?: ExecOptions) {
  if (hasTags(execOpts)) {
    log.silly("getLastTagInBranch", "");
    return childProcess.execSync("git", ["describe", "--tags", "--abbrev=0"], execOpts);
  }
  log.silly("getFirstCommit", "");
  return childProcess.execSync("git", ["rev-list", "--max-parents=0", "HEAD"], execOpts);
}

git diff-index

  • 主要用于比較索引和工作樹之間的差異,并將其輸出為標(biāo)準(zhǔn)輸出。它的作用包括但不限于:

檢查暫存區(qū)(index)和當(dāng)前工作目錄之間的差異。

可以與不同的選項(xiàng)一起使用,以便輸出不同格式的差異信息。

下面是一個(gè)git diff-index命令的執(zhí)行結(jié)果案例:

$ git diff-index HEAD
:100644 100644 bcd1234... 0123456... M        file.txt

這里git diff-index HEAD將顯示當(dāng)前提交(HEAD)和工作目錄之間的差異。

  • 關(guān)聯(lián)的lerna命令
  • lerna changed:列出自上次標(biāo)記以來發(fā)生變更的包時(shí),可能會(huì)用到git diff-index來比較索引和工作樹之間的差異。
  • lerna源碼案例libs/commands/import/src/index.ts
export class ImportCommand extends Command<ImportCommandOptions> {
    ...
    if (this.execSync("git", ["diff-index", "HEAD"])) {
      throw new ValidationError("ECHANGES", "Local repository has un-committed changes");
    }
    ...
}

git diff-tree

  • 主要用于比較兩棵樹之間的差異,并以特定的格式輸出。它的作用包括但不限于:

比較兩個(gè)樹對象之間的差異,例如提交對象和樹對象之間的差異。

可以用于查看提交之間的差異,文件的更改等信息。

下面是一個(gè)git diff-tree命令的執(zhí)行結(jié)果案例:

$ git diff-tree HEAD~2 HEAD
100644 blob a3d8b4e1c2e1d0a9b8c6e5f7d6a4b3e8a1b2c3d4        file.txt
  • 關(guān)聯(lián)的lerna命令
  • lerna diff:顯示自上次標(biāo)記以來的所有包的diff時(shí),可能會(huì)使用git diff-tree 來比較不同提交之間的差異。
  • lerna源碼案例libs/commands/publish/src/lib/get-projects-with-tagged-packages.ts
export async function getProjectsWithTaggedPackages(
  projectNodes: ProjectGraphProjectNodeWithPackage[],
  projectFileMap: ProjectFileMap,
  execOpts: ExecOptions
): Promise<ProjectGraphProjectNodeWithPackage[]> {
  log.silly("getTaggedPackages", "");


  // @see https://stackoverflow.com/a/424142/5707
  // FIXME: --root is only necessary for tests :P
  const result = await childProcess.exec(
    "git",
    ["diff-tree", "--name-only", "--no-commit-id", "--root", "-r", "-c", "HEAD"],
    execOpts
  );


  const stdout: string = result.stdout;
  const files = new Set(stdout.split("\n"));


  return projectNodes.filter((node) => projectFileMap[node.name]?.some((file) => files.has(file.file)));
}

git show-ref

  • 主要用于顯示引用(如分支和標(biāo)簽)的名稱和其對應(yīng)的提交哈希值。它的作用包括但不限于:

列出git倉庫中的所有引用及其對應(yīng)的提交哈希值。

可以用于查看分支、標(biāo)簽等引用的信息。

下面是一個(gè)git show-ref命令的執(zhí)行結(jié)果案例:

$ git show-ref
a3d8b4e1c2e1d0a9b8c6e5f7d6a4b3e8a1b2c3d4 HEAD
a3d8b4e1c2e1d0a9b8c6e5f7d6a4b3e8a1b2c3d4 refs/heads/main
f7f6d6f2b6b47eb8c4cf4b8bf5f83e0b8028c031 refs/tags/v1.0.0
  • 關(guān)聯(lián)的lerna命令
  • lerna version:在執(zhí)行版本升級操作時(shí),lerna可能會(huì)使用git show-ref 來獲取引用的信息,以確定當(dāng)前提交的位置。
  • lerna源碼案例libs/commands/version/src/lib/remote-branch-exists.ts
export function remoteBranchExists(gitRemote: string, branch: string, opts: ExecOptions) {
  log.silly("remoteBranchExists", "");


  const remoteBranch = `${gitRemote}/${branch}`;


  try {
    childProcess.execSync("git", ["show-ref", "--verify", `refs/remotes/${remoteBranch}`], opts);
    return true;
  } catch (e) {
    return false;
  }
}


責(zé)任編輯:武曉燕 來源: 得物技術(shù)
相關(guān)推薦

2013-07-17 09:54:17

2013-07-15 15:00:26

項(xiàng)目管理工具

2022-11-09 08:12:07

2009-07-31 16:38:50

ibmdwRational

2011-11-10 09:53:52

項(xiàng)目管理

2009-09-24 14:30:04

DotProject

2009-05-19 10:18:39

2024-09-05 08:13:05

2011-08-12 10:38:09

MongoDB

2013-09-12 10:03:09

項(xiàng)目管理項(xiàng)目管理工具

2013-09-12 10:19:03

移動(dòng)項(xiàng)目管理

2014-09-09 09:32:50

項(xiàng)目管理管理工具

2013-06-20 10:25:56

2019-08-14 09:43:34

項(xiàng)目管理工具

2010-11-15 15:22:51

開源云計(jì)算管理工具

2010-06-01 15:25:27

JavaCLASSPATH

2016-12-08 15:36:59

HashMap數(shù)據(jù)結(jié)構(gòu)hash函數(shù)

2020-07-21 08:26:08

SpringSecurity過濾器

2022-10-12 07:53:46

并發(fā)編程同步工具

2012-04-09 09:43:49

云計(jì)算云管理
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號