當我提交--amend時,如果提交已經被推送到遠程存儲庫,那麼它是不安全的提交。如何通過預先提交鉤子來檢測commit --amend?
我想檢測不安全的提交 - 通過預先提交鉤子和中止進行審批。
但預提交鉤子沒有參數。我不知道如何檢測 - 已知。
我該怎麼辦?
當我提交--amend時,如果提交已經被推送到遠程存儲庫,那麼它是不安全的提交。如何通過預先提交鉤子來檢測commit --amend?
我想檢測不安全的提交 - 通過預先提交鉤子和中止進行審批。
但預提交鉤子沒有參數。我不知道如何檢測 - 已知。
我該怎麼辦?
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
,並承諾G
是F
的「修訂版」 。但是,確實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
你現在提前origin
和git 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 rebase
到J
,讓你去解決你的第三個錯誤之前:
A - B - C - D <-- master, origin/master
\
E - J <-- origin/branch
\ \
(F) F' <-- HEAD=branch
(這裏F'
是櫻桃採摘提交F
;我把括號圍繞F
來表明,儘管它仍然在你的回購協議,它不再具有任何分支標籤指向它,所以它主要是看不見的。 )現在預先提交的鉤子腳本將不會被客觀化再次。
一個快速的方法來檢測「純粹」的修訂在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
。