Это результат того, что кто-то обновляет свой проект, используя 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 будет (как вы отметили) удалять бесполезное слияние, и вы получите гораздо более чистую историю. В приведенном выше случае вы получите линейную историю развития. Это намного легче следовать. Однако вам нужно знать, что после переустановки вам необходимо перестроить и повторно протестировать свой код ... просто потому, что код легко сливается, это не значит, что результат правильный.
Если вы используете центральный репозиторий для обмена официальной линией разработки, вы можете реализовать крюк предварительного приема, который обнаруживает эти автоматические («глупые»/«бесполезные») слияния, и отклоняет push-принудительное пользователя для переустановки. На самом деле, вы хотите, чтобы крючок искал сообщение об ошибке слияния по умолчанию ...поэтому, если вы действительно хотите сохранить фиксацию слияния (иногда это имеет смысл), вы должны хотя бы написать сообщение интеллектуального фиксации.
Вот пример крючка. Я удалил кучу лишних вещей, поэтому я не смог его проверить.
#!/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
Я бы просто отказался от этого клона и клонировал еще одну копию. У вас есть какие-либо «не поддерживаемые ветви/коммиты» в этом клоне? –
Вы делитесь через центральный репозиторий (т. Е. Все ли вы нажимаете и вытаскиваете из общего репозитория)? –
Да, есть общий репозиторий, и там уже проделана дальнейшая работа. – miracle2k