91人妻人人澡人人爽人人精品,久久婷婷婬片A片AAA,人人妻人人澡人人爽人人DVD,国产三级片在线观看
登錄 log in
動態(tài)
DYNAMIC STATE
首頁    >   動態(tài)   
>   工作中如何打造優(yōu)雅的Git工作流和Commit規(guī)范!
HOME    >   DYNAMIC STATE   
>   工作中如何打造優(yōu)雅的Git工作流和Commit規(guī)范!
劉建飛
浙江千仞網(wǎng)絡股份有限公司
1701347650000

工作中如何打造優(yōu)雅的Git工作流和Commit規(guī)范!

前言

??Git大家都非常熟悉了,就不做過多介紹,但是如何用好Git、如何進行合理的分支開發(fā)、Merge你是否有一個規(guī)范流程呢???

不論是一個團隊一起開發(fā)一個項目,還是自己獨立開發(fā)一個項目,都少不了要和Git打交道,這些都是作為開發(fā)者必須要掌握的。每個團隊也許有自己的Git工作流,今天給你分享一個通用的流程和規(guī)范。

既然說到Git得先有個協(xié)同原則??:

統(tǒng)一使用Git作為版本控制的主要工具。

統(tǒng)一使用GitFlow流程管理控制版本

?? 全文字數(shù) : 5k

? 閱讀時長 : 6min

?? 關鍵詞 : Git命令、工作流、分支規(guī)范、Commit Messages規(guī)范

基本命令操作

我們來看下git的基本操作,這些命令基本可以完成我們?nèi)粘Υa版本開發(fā)合并需求

git add . :將變更從工作目錄移至暫存區(qū)域

git commit -m "fix: xxx" :將暫存區(qū)中的文件提交到本地倉庫中分支中

git pull:用于從遠程獲取代碼并合并本地的版本

git push:用于從將本地的分支版本上傳到遠程并合并

這些操作命令在各個工作區(qū)、倉庫之間如何進行流轉(zhuǎn)的呢?如下圖

git有好幾個區(qū),工作區(qū)(workspace)、暫存區(qū)(indexStage)、本地倉庫(local repository)、還有遠程倉庫(remote repository)。

遠程倉庫為我們保存一份代碼,如github,而工作區(qū)、暫存區(qū)和本地倉庫都在本地

常用分支建議

前面簡單講了下代碼提交流程,但是版本控制并不是簡單代碼提交就完事了,這里分享一些常用的分支開發(fā),但并不是任何項目都一定按照這種分支結(jié)構來定義,按你的需求來確定需要哪些。比如你一個人開發(fā)一個小型項目,那么就不用搞的那么復雜,如果是多人協(xié)同開發(fā)版本迭代較快,那么下面的分支內(nèi)容會讓你開發(fā)節(jié)奏更清晰合理!

生產(chǎn)分支(master)?

master分支是倉庫的主分支,也有人叫production分支,這個分支包含最近發(fā)布到生產(chǎn)環(huán)境的代碼,最近發(fā)布的release, 這個分支只能從其他分支合并,不能在這個分支直接修改?

master 分支一般由release、develop以及hotfix分支合并,任何時間都不能直接修改代碼

開發(fā)分支(develop)?

這個分支是我們的主開發(fā)分支,始終保持最新完成以及bug修復后的代碼.

包含所有要發(fā)布到下一個release的代碼,這個主要合并與其他分支,比如feature分支?

一般開發(fā)的新功能時,feature分支都是基于develop分支下創(chuàng)建的

補丁分支(hotfix)?

當我們在生產(chǎn)環(huán)境發(fā)現(xiàn)新的Bug時候,我們需要基于master分支創(chuàng)建一個hotfix分支,然后在hotfix分支上修復bug

完成hotfix后,我們要把hotfix分支合并回master和develop分支?,所以hotfix的改動會進入下一個release

發(fā)布分支(release)?

當你需要發(fā)布一個新功能的時候,要基于develop分支創(chuàng)建一個release分支

在release分支做為基準進行測試并修復bug,完成release后,把release合并到master和develop分支?

release 分支為預上線分支,發(fā)布提測階段,會release分支代碼為基準提測

功能分支(feature)?

feature分支主要是用來開發(fā)一個新的功能,一旦開發(fā)完成,我們合并回develop分支,然后提交合并請求到 release 分支進行提測。

分支命名: feature/ 開頭的為特性分支, 命名規(guī)則: feature/user_module、 feature/cart_module

Git工作流

上面那么多種分支類型,而且不同的分支又是基于其他分支,每次看完之后都記得,但是結(jié)合起來發(fā)現(xiàn)僅僅停留在有印象,是的,我們不好從單純的文字上理清分支之間的關系和合并方式。

沒關系,用個圖把之間的關系梳理清楚:

其實核心是要弄明白主干和各個開發(fā)分支的關系,以及你的開發(fā)分支該和誰去合并。

不過還是那句話根據(jù)自己的項目和業(yè)務團隊去指定Git工作,不能為了更風去創(chuàng)建并不適合團隊的分支,不然會導致開發(fā)在無聊的敲命令,花費時間在各種分支的合并上,反而降低了效率。

適合別人的未必適合大家,互相交流,選擇合適自己的!

更多方位的流程,大家可以看看這篇文章# 字節(jié)研發(fā)設施下的 Git 工作流

Commit編寫規(guī)范

好的Commit messages 日志編寫會帶來極大的幫助,它也反映了一個開發(fā)人員是否是良好的協(xié)作者,更重要的是在后續(xù)修復bug和實現(xiàn)新的feture時,對于之前實現(xiàn)的功能、解決的bug可以一目了然,而不用通過閱讀代碼去了解曾經(jīng)的實現(xiàn),因為這會是意見非常痛苦的事情!

忘了說,你的Commit messages會是Code Review人員參考基本,你應該不想被無情的打回吧???????

目前,社區(qū)有多種 Commit messages 的寫法規(guī)范。來自Angular (前端框架)規(guī)范是目前使用最廣的寫法,比較合理和系統(tǒng)化。

其實瀏覽過Github開源項目的同學,如果有注意Pull requests的話就有了解,行我們看下Angular的提交規(guī)范到底是咋樣的,為啥會成為參考標桿??????。

Commit messages提交可以參照以下格式

<type>: <subject><BLANK LINE> 空白行<body><BLANK LINE> 空白行<footer>

  • type: 本次 commit 的類型,諸如 bugfix docs style 等

  • scope: 本次 commit 波及的范圍

  • subject: 簡明扼要的闡述下本次 commit 的主旨,在原文中特意強調(diào)了幾點 :

    . 使用祈使句,是不是很熟悉又陌生的一個詞,來傳送門在此 祈使句

    . 首字母不要大寫

    . 結(jié)尾無需添加標點

  • body: 同樣使用祈使句,在主體內(nèi)容中我們需要把本次 commit 詳細的描述一下,比如此次變更的動機,如需換行,則使用 |

  • footer: 描述下與之關聯(lián)的 issue 或 break change

Commit Type的類別

  • feat: 添加新特性

  • fix: 修復bug

  • docs: 僅僅修改了文檔

  • style: 僅僅修改了空格、格式縮進、都好等等,不改變代碼邏輯

  • refactor: 代碼重構,沒有加新功能或者修復bug

  • perf: 增加代碼進行性能測試

  • test: 增加測試用例

  • chore: 改變構建流程、或者增加依賴庫、工具等

Commit messages格式要求

標題行:50個字符以內(nèi),描述主要變更內(nèi)容

主體內(nèi)容:更詳細的說明文本,建議72個字符以內(nèi)。需要描述的信息包括:

  • 為什么這個變更是必須的? 它可能是用來修復一個bug,增加一個feature,提升性能、可靠性、穩(wěn)定性等等

  • 他如何解決這個問題? 具體描述解決問題的步驟

  • 是否存在副作用、風險?

如果需要的化可以添加一個鏈接到issue地址或者其它文檔

來看這個這位老哥在Angular項目詳細的commit信息,大家可以對照上面的規(guī)范看,可以用一個詞描述這種好的Commit方式【“賞心悅目”】,也許這也就是為什么這個項目的Commit會成為眾多人模仿的原因吧!

關于名詞簡稱

軟件團隊中經(jīng)常需要Git進行團隊協(xié)作開發(fā),但是不少職場小寶朋友對于從大佬口中冒出來的一些字母縮略詞一臉蒙蔽,比如MR、CR,這里一次說個明白,讓你不再迷茫各種簡稱,哈哈!

這里總結(jié)了一些,

  • CR:Code Review. 請求代碼審查。

  • PR:pull request. 拉取請求,給其他項目提交代碼。

  • MR:merge request. 合并請求

  • ACK:Acknowledgement. 承認,同意。表示接受代碼的改動。

  • TL;DR:Too Long; Didn't Read. 太長懶得看。常見于README文檔。

  • WIP:Work In Progress. 進展中,主要針對改動較多的 PR,可以先提交部分,標題或 Tag 加上 WIP,表示尚未完成,這樣別人可以先 review 已提交的部分。

鏈接:https://juejin.cn/post/7295304057655672842

(版權歸原作者所有,侵刪)

` if(dynamicsTypeOne==1){ if(dynamicsTitleOne){ let textBox = document.createElement('div') textBox.innerHTML = dynamicsTitleOne textBox.style.fontSize = '0.3rem' textBox.style.marginBottom = '0.3rem' textBox.style.textAlign = 'center' document.querySelector('.content').appendChild(textBox) } if(dynamicsCoverOne){ let videoBox = document.createElement('video') videoBox.src = imgHead(dynamicsCoverOne) videoBox.autoplay = true videoBox.loop = true videoBox.controls = true videoBox.style.width = '100%' videoBox.style.marginBottom = '0.2rem' document.querySelector('.content').appendChild(videoBox) } if(dynamicsDetailOne){ //好像是視頻封面圖 // dynamicsDetailOne = dynamicsDetailOne.split(',') // dynamicsDetailOne.forEach((item,value)=>{ // let imgBox = document.createElement('img') // imgBox.src = imgHead(item) // document.querySelector('.trends_detail_mainBox').appendChild(imgBox) // }) } }else if(dynamicsTypeOne==0) { console.log('00000000000123'); if(dynamicsTitleOne){ let textBox = document.createElement('div') textBox.innerHTML = dynamicsTitleOne textBox.style.fontSize = '0.3rem' textBox.style.marginBottom = '0.3rem' textBox.style.textAlign = 'center' document.querySelector('.content').appendChild(textBox) } if(dynamicsDetailOne){ if(dynamicsTitleOne){ let dynamicsDetail = JSON.parse(dynamicsDetailOne) dynamicsDetail.forEach(item=>{ if(item.type==1){ let textBox = document.createElement('div') textBox.innerHTML = item.value textBox.style.fontSize = '0.3rem' textBox.style.marginBottom = '0.3rem' textBox.style.textAlign = 'center' document.querySelector('.content').appendChild(textBox) } if(item.type==2){ let imgBox = document.createElement('img') imgBox.src = imgHead(item.value) document.querySelector('.content').appendChild(imgBox) } }) }else { let textBox = document.createElement('div') textBox.innerHTML = dynamicsDetailOne textBox.style.fontSize = '0.3rem' textBox.style.marginBottom = '0.3rem' textBox.style.textAlign = 'center' document.querySelector('.content').appendChild(textBox) } } if(dynamicsCoverOne){ dynamicsCoverOne = dynamicsCoverOne.split(',') dynamicsCoverOne.forEach((item,value)=>{ let imgBox = document.createElement('img') imgBox.src = imgHead(item) if(value == dynamicsCoverOne.length-1){ imgBox.style.marginBottom = '0.2rem' } document.querySelector('.content').appendChild(imgBox) }) } }else { if(dynamicsTitleOne && dynamicsTypeOne!=3){ let textBox = document.createElement('div') textBox.innerHTML = dynamicsTitleOne textBox.style.fontSize = '0.3rem' textBox.style.marginBottom = '0.3rem' textBox.style.textAlign = 'center' document.querySelector('.content').appendChild(textBox) } if(dynamicsCoverOne && dynamicsTypeOne!=3){ dynamicsCoverOne = dynamicsCoverOne.split(',') dynamicsCoverOne.forEach((item,value)=>{ let imgBox = document.createElement('img') imgBox.src = imgHead(item) if(value == dynamicsCoverOne.length-1){ imgBox.style.marginBottom = '0.2rem' } document.querySelector('.content').appendChild(imgBox) }) } if(dynamicsDetailOne){ let textBox = document.createElement('div') textBox.innerHTML = dynamicsDetailOne textBox.style.fontSize = '0.2rem' document.querySelector('.content').appendChild(textBox) } } let timeone = $(".middle_right").text() console.log(timeone,'timeone'); // 輸出格式化后的日期字符串 if(timeone){ let timestamp = timeone.trim()*1; // 創(chuàng)建一個新的 Date 對象,并將時間戳作為參數(shù)傳遞 const date = new Date(timestamp); // 使用 Date 對象的方法來獲取日期和時間 const year = date.getFullYear(); const month = date.getMonth() + 1; // 月份從 0 開始,所以要加 1 const day = date.getDate(); const hours = date.getHours(); const minutes = date.getMinutes(); const seconds = date.getSeconds(); console.log(year,'year'); console.log(month,'month'); console.log(day,'day'); console.log(hours,'hours'); console.log(minutes,'minutes'); console.log(seconds,'seconds'); // 格式化日期輸出 const formattedDate = year+'-'+((month<10)?('0'+month):month)+'-'+((day<10)?('0'+day):day)+' '+((hours<10)?('0'+hours):hours)+':'+((minutes<10)?('0'+minutes):minutes); console.log(formattedDate); // 輸出格式化后的日期字符串 let timetwo = '發(fā)布日期:'+formattedDate $(".middle_right").html(timetwo) }else{ $(".middle_right").html('') }