日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【git重案组】如何逃避git blame的追踪?

發(fā)布時(shí)間:2024/2/28 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【git重案组】如何逃避git blame的追踪? 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

導(dǎo)語:程序員的血腥復(fù)仇——論如何偷偷修改代碼而不被別人發(fā)現(xiàn)...

背景介紹

上周筆者在工作中發(fā)現(xiàn)git倉庫出現(xiàn)了一個(gè)奇怪的問題,master分支中某文件的一次commit丟失掉了,但diff中沒有任何記錄,這讓筆者一度懷疑是git或者code平臺(tái)自己出了問題。

在code平臺(tái)一條條比對后發(fā)現(xiàn)變動(dòng)發(fā)生在feature分支merge master分支之后。

原本SHA為8950d的edit.vue 文件最近一次修改是在一周前。

在merge之后該文件回滾到了兩周前。

通過查詢該文件的commit記錄,可以看到最近的一次SHA為49c1a的commit確實(shí)丟掉了。

先明確前提,這是在一次merge中丟失的,而非經(jīng)歷了rebase或者reset操作,并沒有對歷史記錄進(jìn)行修改。

這里回顧下整個(gè)過程中的git 操作流,先從master checkout一個(gè)feature分支,在該分支提交了幾次commit,merge master 到 feature,然后在master再次merge feature。

應(yīng)該說這里雖然有不規(guī)范之處(沒有提交merge request而是本地直接在master上merge然后push),但整體還算常規(guī)操作,即使是在merge中發(fā)生了沖突,不小心操作失誤,按道理也不會(huì)沒有diff記錄。

merge的parent-1和parent-2

google一下找到了一篇相似的文章https://blog.laisky.com/p/git-merge/

該文章是在master分支上git pull,由于pull 的默認(rèn)行為是 pull —merge,所以其實(shí)也是在merge中丟失的。

原文作者給出了一個(gè)比較清晰的解釋:

眾所周知,merge 是將兩個(gè) branch 合并為一個(gè),所以每一個(gè) merge commit 擁有兩個(gè) parents。當(dāng)我們在 gitlab 或者 source tree 查看一個(gè)提交的具體修改時(shí),其實(shí)就是將本次提交和其 parent 做 diff。而由于 merge commit 有兩個(gè) parent,并會(huì)將其排序?yàn)?1 和 2,當(dāng)你試圖查看一個(gè) merge commit 的修改時(shí),其實(shí)顯示的是相對于 parent-1 的 diff。這樣的一個(gè)問題是,如果 remote 不幸成為了 parent-2,那么你就可以通過巧妙的構(gòu)造 parent-1 來實(shí)現(xiàn)一次“隱身”的代碼修改。

我們提取原文核心,重點(diǎn)在于merge時(shí)的diff記錄是相對于當(dāng)前分支,假如當(dāng)前分支是兩周前的版本,而外來分支是一周前的版本,當(dāng)merge時(shí)放棄掉一周前的版本,對原分支來說這次merge之后與之前并未發(fā)生改變,所以diff中自然也沒有記錄。

merge request 的不同之處

這個(gè)解釋似乎也說的過去,不過在合并到master分支之前必然要本地merge一下master才可以快速合并,這個(gè)操作是逃避不了的,如果在本地merge時(shí)錯(cuò)誤解決沖突會(huì)被隱藏下來,這豈不是git一個(gè)很大的缺陷嗎?那code平臺(tái)的merge request后的code review還有意義嗎?

筆者自己搭建了一個(gè)測試倉庫發(fā)現(xiàn)如果提交merge request,在code review的diff界面是看得到這次修改的,在提交之后也能在history中看到diff。難道gitlab(code平臺(tái)應(yīng)該是基于gitlab開發(fā)的)平臺(tái)自己的diff算法更高級(jí),所以才能發(fā)現(xiàn)這次錯(cuò)誤?

筆者到這里產(chǎn)生了一個(gè)猜測,在本地操作的時(shí)候git 的diff算法有缺陷,它簡單地把每一次commit的diff patch在一起,而code平臺(tái)是老老實(shí)實(shí)做了兩個(gè)文件夾的diff。

git diff的差異

在google之后,果然發(fā)現(xiàn)了不同(其實(shí)并不然…)!

在幾個(gè)stackoverflow的問答和github的issue中筆者發(fā)現(xiàn) github平臺(tái)的pull request(雖然gitlab是merge request,實(shí)際上差不多)是使用了git diff的三點(diǎn)操作,而直接diff是兩點(diǎn)操作,區(qū)別如下:

筆者一度以為突破口就在這里,但是仔細(xì)分析了git log —graph之后發(fā)現(xiàn)在merge request之前本地feature分支就已經(jīng)merge了一次master,在這個(gè)情形下git diff的兩點(diǎn)操作和三點(diǎn)操作根本沒什么不同。

鏈接:What are the differences between double-dot “..” and triple-dot “…” in Git diff commit ranges? - Stack Overflow

https://github.community/t5/How-to-use-Git-and-GitHub/GitHub-pull-requests-showing-invalid-diff-for-already-merged/td-p/3000


merge的原理和fast-forward

Git merge采取三路合并策略,三路分別是基準(zhǔn)分支(分叉的節(jié)點(diǎn))、mine、theirs。

如果mine和theirs相對基準(zhǔn)都發(fā)生了改變 那git 就報(bào)沖突,然后讓你人工決斷。否則,git將取相對于base變化的那個(gè)為最終結(jié)果。

一次普通的merge會(huì)新建一個(gè)commit節(jié)點(diǎn)(7號(hào)節(jié)點(diǎn))。

而如果在feature分支從master checkout之后,master并未出現(xiàn)新的commit,就會(huì)出現(xiàn)三種策略。

默認(rèn)git merge會(huì)采取第三種策略,直接將master指針移到feature的頭上即可,這里不會(huì)出現(xiàn)一個(gè)message為“merge xxx into xxx”的commit。

回到問題發(fā)生的場景上,在feature分支上執(zhí)行g(shù)it merge master的時(shí)候發(fā)生了一次普通的合并,生成一個(gè)“merge xxx into xxx”的commit,由于上文說到的原因,這個(gè)commit節(jié)點(diǎn)沒有記錄diff。當(dāng)checkout回master再從master merge feature分支的時(shí)候,滿足了fast-forward的條件,所以沒有再次進(jìn)行diff操作,沒有對上次失誤進(jìn)行再次檢查。

而code平臺(tái)merge request默認(rèn)的操作是—no-ff(這里補(bǔ)充一下,github是有squash選項(xiàng)的,但是code平臺(tái)不支持),所以會(huì)強(qiáng)制再次進(jìn)行一次diff,這時(shí)候上次merge中隱藏的錯(cuò)誤得到了一個(gè)再次暴露出來的機(jī)會(huì),在code review中就可以發(fā)現(xiàn)了。

解決方案這個(gè)問題出現(xiàn)的根本原因有兩個(gè):
  • 淺層原因:merge時(shí)錯(cuò)誤處理了沖突

  • 深層原因:沒有走code平臺(tái)merge request,沒有禁止master分支直接pull

筆者回顧這個(gè)問題時(shí)想到,假如別有用心的人利用這種機(jī)制上的漏洞,在merge中故意修改代碼,這些修改將不會(huì)出現(xiàn)在git的任何一次commit diff中,除非對master分支上一個(gè)挨一個(gè)commit排查。
甚至于在merge時(shí)采取squash或者rebase等方法,把這次commit 與其他commit混淆起來,是否就可以徹底把自己隱匿起來呢?
為了避免重現(xiàn)此次錯(cuò)誤,強(qiáng)烈建議提高master分支敏感性,設(shè)置為protected分支禁止直接操作,所有對master分支的merge統(tǒng)一走merge request!
額外提一句,還應(yīng)該避免在公用開發(fā)機(jī)上設(shè)置code平臺(tái) ssh 密鑰,防止被盜用身份提交commit。
是否真的發(fā)生過利用這種方案惡意報(bào)復(fù)公司的案例呢?筆者也是很好奇。

總結(jié)

以上是生活随笔為你收集整理的【git重案组】如何逃避git blame的追踪?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。