2013-10-15 82 views
4

當我提交--amend時,如果提交已經被推送到遠程存儲庫,那麼它是不安全的提交。如何通過預先提交鉤子來檢測commit --amend?

我想檢測不安全的提交 - 通過預先提交鉤子和中止進行審批。

但預提交鉤子沒有參數。我不知道如何檢測 - 已知。

我該怎麼辦?

回答

2

TL; DR版本:下面有一個腳本(中間的一種),用於強制執行可能適用於您的特定工作流程,也可能不適用。它並不完全阻止特定git commit --amend s(此外,您始終可以使用--no-verify跳過該腳本),並且它確實可以防止(或至少警告)其他git commit s,這可能是也可能不是您想要的。

要使其出錯而不是警告,請將WARNING更改爲ERROR並將sleep 5更改爲exit 1

編輯:示數出是不是一個好主意,因爲你不能告訴,在這個混帳掛鉤,這是一個「修改」提交,所以這將失敗(您必須添加--no-verify)如果您只需向具有上游並且位於上游的分支添加新的提交。


這不是一定不安全的,因爲git commit --amend實際上並不變化在回購任何承諾,它只是增加了一個新的,不同的提交和重新點分支的頂端出現。舉例來說,如果你的分支看起來是這樣的:

A - B - C - D  <-- master, origin/master 
      \ 
      E - F <-- HEAD=branch, origin/branch 

那麼什麼是成功的git commit --amend確實是這樣的:

A - B - C - D  <-- master, origin/master 
      \ 
      E - F <-- origin/branch 
       \ 
       G <-- HEAD=branch 

你還是犯F,並承諾GF的「修訂版」 。但是,確實G不是F的「快進」,在這種情況下您可能不應該使用git push -f origin branch

類似的情況下,如果你已經那種情況下,即發生後(沒有或儘管下面的腳本來完成),成功git commit --amend

A - B - C - D  <-- master, origin/master 
      \ 
      E - F <-- origin/branch 
       \ 
       G <-- HEAD=branch 

如果你現在git commit (即使沒有--amend),您將添加一個新的提交,例如,G連接到H;但再次嘗試推H是非快進的。

您無法專門測試--amend,但是您可以檢查是否存在「上游」,如果是,那麼當前的HEAD是否是該上游的祖先。這是一個稍微低俗的預先提交鉤子,它可以做到這一點(帶有警告和睡眠,而不是錯誤退出)。

#!/bin/sh 

# If initial commit, don't object 
git rev-parse -q --verify HEAD >/dev/null || exit 0 

# Are we on a branch? If not, don't object 
branch=$(git symbolic-ref -q --short HEAD) || exit 0 

# Does the branch have an upstream? If not, don't object 
upstream=$(git rev-parse -q --verify @{upstream}) || exit 0 

# If HEAD is contained within upstream, object. 
if git merge-base --is-ancestor HEAD $upstream; then 
    echo "WARNING: if amending, note that commit is present in upstream" 
    sleep 5: 
fi 
exit 0 

這裏的基本問題是,即使沒有使用git commit --amend這種情況也會一直髮生。比方說,你用相同的設置上面開始,但承諾F還不存在:

A - B - C - D  <-- master, origin/master 
      \ 
      E  <-- HEAD=branch, origin/branch 

現在的你,在你的回購協議的副本,決定在branch工作。您修復bug和git commit

A - B - C - D  <-- master, origin/master 
      \ 
      E  <-- origin/branch 
       \ 
       F <-- HEAD=branch 

你現在提前origingit push origin branch會做正確的事。但是當你修復一個bug時,Joe修復了他的副本中的另一個bug,並將他的版本推到origin/branch,將你擊敗到push步驟。所以,你運行git fetch更新和你現在有這樣的:

A - B - C - D  <-- master, origin/master 
      \ 
      E - J <-- origin/branch 
       \ 
       F <-- HEAD=branch 

(其中J是喬的承諾)。這是一個非常正常的狀態,如果能夠git commit添加另一個修復程序(例如,第三個錯誤),然後合併或重新包含Joe的修復程序,那將會很不錯。示例pre-commit鉤子將會對象。

如果你總是重定位或合併第一個,然後添加你的第三個修復,腳本不會反對。讓我們看看會發生什麼,當我們進入F - 和 - J以上情況和使用git merge(或git pull,做了合併):

A - B - C - D    <-- master, origin/master 
      \ 
      E - J   <-- origin/branch 
       \ \ 
       F - M  <-- HEAD=branch 

你現在在提交M,合併,這是「提前「J。所以腳本@{upstream}發現提交J並檢查HEAD提交(M)是否爲J的祖先。這不是,並追加新的提交是允許的,所以你的「修正第三蟲」提交N給你:

A - B - C - D    <-- master, origin/master 
      \ 
      E - J   <-- origin/branch 
       \ \ 
       F - M - N <-- HEAD=branch 

另外,您可以git rebaseJ,讓你去解決你的第三個錯誤之前:

A - B - C - D   <-- master, origin/master 
      \ 
      E - J  <-- origin/branch 
       \ \ 
       (F) F' <-- HEAD=branch 

(這裏F'是櫻桃採摘提交F;我把括號圍繞F來表明,儘管它仍然在你的回購協議,它不再具有任何分支標籤指向它,所以它主要是看不見的。 )現在預先提交的鉤子腳本將不會被客觀化再次。

1

一個快速的方法來檢測「純粹」的修訂在pre-commit鉤子:

if git diff --cached --quiet ; then 
    echo "This is a pure amend" 
else 
    echo "This is a commit with changes" 
fi 

「純」我的意思是你只重寫提交消息並沒有任何的變化承諾。如果在致電git commit --amend時索引發生任何變化,那麼您的重寫次數超過了提交信息,這將表現得好像您正在執行傳統的git commit

相關問題