Я часто сталкиваюсь с такой ситуацией в моей компании, и мы нашли 2 основных решения этой проблемы. Оба они используют способность git сохранять коммиты в истории в определенных ситуациях. Кстати, хорошей практикой является никогда не указывать ссылки на подмодули sh, которые указывают на удаляемые ветви (т.е. ветви функций).
Я предполагаю, что, как и я, вы не хотите использовать pu sh feature_branch, чтобы не загрязнять ваш удаленный репозиторий и быть устойчивыми к рабочим партнерам в режиме инквизитора, которые очищают все старые отправленные ветви функций
Проблема в том, что когда вы делаете ребаз, коммиты переигрываются поверх истории мастера. Это новые коммиты (скажем, X ', Y' и Z '), с новым ha sh, а голова ветки перемещается на вершину Z'. Таким образом, X, Y, Z останутся на мертвой ветке и будут удалены со временем (90 дней с настройками по умолчанию). В дополнение к этому, они не будут выдвигаться по умолчанию, когда вы сделаете sh вашу перебазированную ветвь.
- Classi c, чистый способ: сделайте слияние вместо ребазирования
Сделайте слияние. E, F, G будут связаны с коммитом слияния. Таким образом, X, Y, Z будут оставаться навсегда и без изменений, даже если ветвь удалена (в этом случае будет использоваться только ссылка на ветвь. Но за счет нелинейной истории на ведущем устройстве). Когда у вас будет pu sh родительская ветвь, X, Y, Z тоже будут выталкиваться.
Сохранять коммиты в истории с тегами Одно из решений для сохранения коммитов X, Y, Z в истории - это тег Z (до перебазирования (тег доживет до него). ) или после (но вам придется заново найти его в истории с помощью reflog), это не имеет значения). Если этот тег затем нажать, X, Y, Z не будут очищены. Это довольно грязно и имеет побочные эффекты, но делает работу. Конечно, вам нужно будет сделать этот тег sh! (если честно, это довольно эквивалентно pu sh ветке. Разница в том, что вы можете назвать его конкретно, например, DONT_DELETE_THIS_FOOL;))
Вот небольшой скрипт, который вы можете запустить, чтобы что любая подмодульная зависимость не будет потеряна (пометив каждый подмодуль и pu sh их) (используйте -h для получения справки):
#!/bin/bash
check_tags () {
slength=${#1}
slength=$((slength+1))
refmajor=`echo $2`
refminor=`echo $3`
refrevision=`echo $4`
echo "Check for anterior tags in $5..."
for tag in $(git tag -l -n "$1*.*.*" | cut -d" " -f1 | cut -c "$slength"- ); do
temptagMajor=`echo $tag | cut -d. -f1`
temptagMinor=`echo $tag | cut -d. -f2`
temptagRevision=`echo $tag | cut -d. -f3`
if [[ temptagMajor -gt tagMajor ]] || [[ temptagMajor -eq tagMajor && temptagMinor -gt tagMinor ]] || [[ temptagMajor -eq tagMajor && temptagMinor -eq tagMinor && temptagRevision -gt tagRevision ]]; then
tagMajor=$temptagMajor
tagMinor=$temptagMinor
tagRevision=$temptagRevision
fi
done
echo "Latest versioning tag found : $1$tagMajor.$tagMinor.$tagRevision (want to apply $1$refmajor.$refminor.$refrevision)"
if [[ tagMajor -gt refmajor ]]; then
echo "Cannot tag with $1$refmajor.$refminor.$refrevision : anterior tag with greater major revision number (found $tagMajor, wanted $refmajor). Use -f to ignore."
return 1
elif [[ tagMajor -eq refmajor ]] && [[ tagMinor -gt refminor ]]; then
echo "Cannot tag with $1$refmajor.$refminor.$refrevision : anterior tag with equal major revision number but greater minor revision number (found $tagMinor, wanted $refminor). Use -f to ignore."
return 1
elif [[ tagMajor -eq refmajor ]] && [[ tagMinor -eq refminor ]] && [[ tagRevision -gt refrevision ]]; then
echo "Cannot tag with $1$refmajor.$refminor.$refrevision : anterior tag with equal major and minor revision number, but greater revision number (found $tagRevision, wanted $refrevision). Use -f to ignore."
return 1
elif [[ tagMajor -eq refmajor ]] && [[ tagMinor -eq refminor ]] && [[ tagRevision -eq refrevision ]]; then
echo "Cannot tag with $1$refmajor.$refminor.$refrevision : anterior tag with equal major, minor, and revision number (found $1$tagMajor.$tagMinor.$tagRevision, wanted $1$refmajor.$refminor.$refrevision). Use -f to ignore."
return 1
else
return 0
fi
}
function subcheck() {
if [[ ! -d .git ]]; then
echo "not a git repo"
return 1
fi;
if ! [[ `git submodule status` ]]; then
echo 'no submodule'
return 1
fi
submodules=($(git config --file .gitmodules --get-regexp path | awk '{ print $2 }'))
currentDirectory=$(pwd)
for submodule in "${submodules[@]}"
do
printf "\n\nEntering '$submodule'\n"
cd "$currentDirectory/$submodule"
check_tags $1 $2 $3 $4 $submodule
if [[ $? -eq 1 ]]; then
cd "$currentDirectory"
return 1
fi
done
cd "$currentDirectory"
}
#export -f check_tags
# Check arguments
while getopts v:hfti: option
do
case "${option}"
in
v) VERSION=${OPTARG};;
h) HELP='help';;
f) FORCE='force';;
t) TEST='test';;
i) INDEX=${OPTARG};;
esac
done
printf "Tag release script v0.1\n"
# Help
if [ "$HELP" != "" ]; then
echo 'GIT Release Script'
echo "Options :"
echo 'Use -v to specify version (mandatory). Ex : "-v 1.0.2"'
echo 'Use -t to run unit test of -v inputs'
echo 'Use -f to force tagging / skip anterior tag versions check'
echo 'Use -i to specify index (optional). Ex : "-v 1.0.2 -i A" for a indA + v1.0.2 double tag.'
exit 1
fi
# Tests for bad inputs
if [ "$HELP" != "" ]; then
array=( ".2.3" "1..3" "1.2." "A.2.3" "1.A.3" "1.2.A" "1A3.123.123" "123.1D3.123" "123.123.1A3" "nougatine" "1.3" )
arr=(${array[*]})
echo "Tested valudes : ${#arr[*]}"
for ix in ${!arr[*]}
do
printf " %s\n" "${arr[$ix]}"
. release_script.sh -v ${arr[$ix]}
done
fi
# Version
if [ "$VERSION" == "" ]; then
echo "Argument missing"
echo "Run -h for help"
exit 1
fi
major=`echo $VERSION | cut -d. -f1`
minor=`echo $VERSION | cut -d. -f2`
revision=`echo $VERSION | cut -d. -f3`
if [ -n "$(printf '%s\n' "$major" | sed 's/[0-9]//g')" ] || [ "$major" == "" ]; then
echo "Invalid major version argument (was \"$major\")"
echo "Run -h for help"
exit 1
fi
if [ -n "$(printf '%s\n' "$minor" | sed 's/[0-9]//g')" ] || [ "$minor" == "" ] ; then
echo "Invalid minor version argument (was \"$minor\")"
echo "Run -h for help"
exit 1
fi
if [ -n "$(printf '%s\n' "$revision" | sed 's/[0-9]//g')" ] || [ "$revision" == "" ]; then
echo "Invalid revision version argument (was \"$revision\")"
echo "Run -h for help"
exit 1
fi
# Fetching
git fetch --all
echo "Fetching tags"
git fetch --tag
tagMajor=0
tagMinor=0
tagRevision=0
versionLabel=v$VERSION
url=$(git config --get remote.origin.url)
basename=$(basename "$url" .git)
# Check previous available versions if no -f specified
if [ "$FORCE" == "" ]; then
if [ "$INDEX" != "" ]; then
echo "Check for anterior index tag in $basename..."
for tag in $(git tag -l -n "ind$INDEX" ); do
if [[ "ind$INDEX" == $tag ]] ; then
echo "\"ind$INDEX\" tag already exists in $basename. Use -f to ignore."
exit 1
fi
done
echo "No conflict found for "ind$INDEX" index tag"
fi
check_tags v "$major" "$minor" "$revision" "$basename"
if [[ $? -eq 1 ]]; then
#echo "Error found, won't tag"
exit 1
fi
subcheck ${basename}_v $major $minor $revision
if [[ $? -eq 1 ]]; then
exit 1
fi
fi
# Release tag script
versionLabel=v$VERSION
url=$(git config --get remote.origin.url)
basename=$(basename "$url" .git)
echo "Tagging project $basename (\"$versionLabel\")"
git tag $versionLabel
#TODO : check index
if [ "$INDEX" != "" ]; then
echo "Tagging index $INDEX"
git tag "ind$INDEX"
fi
echo "Tagging submodules (\"${basename}_$versionLabel\")"
git submodule foreach "git tag ${basename}_$versionLabel || :"
echo "Pushing project tag"
git push --tags
echo "Pushing submodules tags"
git submodule foreach 'git push --tags || :'