這是某人使用git pull
(或等同於git fetch
和git merge
)更新項目的結果。想象一下,你是庫看起來像是這樣的:
o---o---o [origin/master]
\
A---B---C [master]
也就是說,你所做的承諾A
,在什麼是原回購頂部B
和C
。
與此同時,其他人進行更改並將其推送到共享存儲庫。如果你再運行git fetch
你的資料庫是這樣的:
o---o---o---D---E---F [origin/master]
\
A---B---C [master]
現在,如果你運行git merge
(記住:git pull
只是git fetch
其次是git merge
)。你也會有這樣的:
o---o---o---D---E---F [origin/master]
\ \
A---B---C---G [master]
假設一切順利,G
可能只是一個「愚蠢」的合併提交;從技術上講,G
的狀態不同於F
和C
,所以它必須有不同的考慮。現在
,如果你把這個變化,你就會有這樣的:
o---o---o---D---E---F
\ \
A---B---C---G [origin/master]
如果你繼續發展你會得到這樣的:
o---o---o---D---E---F
\ \
A---B---C---G [origin/master]
\
H---I---J [master]
現在,如果你繼續這樣做(如果許多人繼續這樣做),你最終會得到一張像你圖片中的那棵樹。這不是「錯誤」,但許多人不喜歡它,因爲它使得發展史難以跟上。
解決這個問題的方法是教人們重新定位。 Rebasing會(如你所記錄的)遠離無用的合併提交,並且給你一個更清晰的歷史記錄。在上面的例子中,你會得到一個線性的發展歷史。這更容易遵循。但是,您需要知道,在重新綁定之後,您需要重新編譯和重新測試代碼......僅僅因爲合併代碼並不意味着結果是正確的。
如果您使用中央存儲庫共享官方開發線,則可以實施預接收掛鉤,以檢測這些自動(「愚蠢」/「無用」)合併提交併拒絕推送 - 強制用戶要麼變硬。實際上,您希望掛鉤查找默認的合併提交消息...所以,如果你確實想保持合併提交(有時候這很有意義),你至少必須編寫一個智能提交消息。
下面是一個示例鉤子。我剝去了一堆額外的東西,所以我沒有去測試它。
#!/bin/bash
# This script is based on Gnome's pre-receive-check-policy hook.
# This script *only* checks for extraneous merge commits.
# Used in some of the messages
server=git.wherever.com
GIT_DIR=$(git rev-parse --git-dir 2>/dev/null)
in_import() {
test -e "$GIT_DIR/pending"
}
forced() {
test -n "$GNOME_GIT_FORCE"
}
check_commit() {
commit=$1
subject="$(git log $commit -1 --pretty=format:%s)"
if expr "$subject" : ".*Merge branch.*of.*\(git\|ssh\):" > /dev/null 2>&1; then
if ! in_import && ! forced ; then
cat &2
---
The commit:
EOF
git log $commit -1 >&2
cat &2
Looks like it was produced by typing 'git pull' without the --rebase
option when you had local changes. Running 'git pull --rebase' now
will fix the problem. Then please try, 'git push' again. Please see:
http://live.gnome.org/Git/Help/ExtraMergeCommits
---
EOF
exit 1
fi
fi
}
check_ref_update() {
oldrev=$1
newrev=$2
refname=$3
change_type=update
if expr $oldrev : "^0\+$" > /dev/null 2>&1; then
change_type=create
fi
if expr $newrev : "^0\+$" > /dev/null 2>&1; then
if [ x$change_type = xcreate ] ; then
# Deleting an invalid ref, allow
return 0
fi
change_type=delete
fi
case $refname in
refs/heads/*)
# Branch update
branchname=${refname#refs/heads/}
range=
# For new commits introduced with this branch update, we want to
# run some checks to catch common mistakes.
#
# Expression here is same as in post-receive-notify-cia; we take
# all the branches in the repo, as "^/ref/heads/branchname", other
# than the branch we are actualy committing to, and exclude commits
# already on those branches from the list of commits between
# $oldrev and $newrev.
if [ -n "$range" ] ; then
for merged in $(git rev-parse --symbolic-full-name --not --branches | \
egrep -v "^\^$refname$" | \
git rev-list --reverse --stdin "$range"); do
check_commit $merged
done
fi
;;
esac
return 0
}
if [ $# = 3 ] ; then
check_ref_update [email protected]
else
while read oldrev newrev refname; do
check_ref_update $oldrev $newrev $refname
done
fi
exit 0
我只是放棄這個克隆,克隆另一個副本。這個克隆中是否有任何「未備份的分支/提交」? – 2010-02-18 14:48:42
您是否通過中央存儲庫共享(即,您是否都在共同存儲庫中進行推送和共享)? – 2010-02-18 19:15:27
是的,有一個公共存儲庫,並且已經完成了進一步的工作。 – miracle2k 2010-02-20 06:35:57