Была аналогичная проблема. Гит проблему не решал, ибо все на шаредах, на одном нам гит врубили, но хостов прорва, более 60 проектов. Кароче, на каждый клянчить гит не получилось. Пришлось писать приложение на пайтоне, который синхронизировал все остальные с мастер-хостом по сфтп. Также с БД, писал файл инструкций, который выполнялся на каждом хосте с ссш, также скриптами.
Ну и докучи был написан пхп скрипт анализа баз данных после всех изменений, на случай если что-то пойдет не так, который брал базу мастер хоста, паковал ее структуру в массив и после проверялось на наличие\отсутствие полей\таблиц по всем бд. Весь скрипт выкладывать не буду, но сбор бд в массив делал так:
function createStruct($shop){
if(!isset($shop['db'])) return false;
$tablesArray = array();
$link = mysql_connect($shop['db']['host'], $shop['db']['user'], $shop['db']['password']);
mysql_select_db($shop['db']['name'], $link);
$resultTables = mysql_query("show tables", $link);
if(mysql_affected_rows($link) > 0){
while($table = mysql_fetch_array($resultTables)){
$tablesArray[$table[0]] = array();
}
}
if(empty($tablesArray)) return false;
foreach($tablesArray as $tableName => $tmpval){
$resultFields = mysql_query('DESCRIBE '.$tableName, $link);
if(mysql_affected_rows($link) > 0){
while($rowField = mysql_fetch_assoc($resultFields)){
$tablesArray[$tableName][$rowField['Field']] = array(
'type' => $rowField['Type'],
'null' => $rowField['Null'],
'key' => $rowField['Key'],
'default' => $rowField['Default'],
'extra' => $rowField['Extra']
);
}
}
}
mysql_close($link);
return $tablesArray;
}
Код не идеален, но за идеальностью и не гнался.
Вот часть обработки сверки:
$ideal = createStruct($shops[0]);
$equal = createStruct($shops[$_SESSION['sc']]);
if($equal === false || empty($equal)){
$html = '<table><tr><td><h3>Проблемы с подключение к базе сайта <b>'.$s->shop_name.'</b>, возможно база не была создана, либо не верные коды доступа, либо прекратила свое существование.</h3></td></tr></table>';
}else{
$html = '<table>';
$html .= '<tr><td><h3>'.$s->shop_name.'</h3></td></tr>';
foreach($ideal as $table => $fields){
if(!isset($equal[$table])){
$html .= '<tr><td>Отсутствует таблица <b>'.$table.'</b></td></tr>';
}else{
$html .= '<tr><td>';
foreach($ideal[$table] as $key => $fieldRow){
if(!isset($equal[$table][$key])){
$html .= 'В таблице <b>'.$table.'</b> не хватает поля <b>'.$key.'</b><br>';
}else{
foreach($ideal[$table][$key] as $okey => $oval){
if($equal[$table][$key][$okey] !== $oval){
$text = $equal[$table][$key][$okey];
if($equal[$table][$key][$okey] === NULL){
$text = 'NULL';
}elseif($equal[$table][$key][$okey] === ''){
$text = ' (ПУСТОТА) ';
}elseif($equal[$table][$key][$okey] === TRUE){
$text = 'TRUE';
}elseif($equal[$table][$key][$okey] === FALSE){
$text = 'FALSE';
}
$html .= 'Опции поля <b>'.$key.'</b> в таблице <b>'.$table.'</b> не идентичны. Идеал: '.$oval.' Исследуемый: '.$text.'<br>';
}
}
}
}
$html .= '</td></tr>';
}
if(isset($equal[$table])){
unset($equal[$table]);
unset($ideal[$table]);
}
}