GitLab 服务器宕机时的项目代码恢复方法

 更新时间:2025年04月01日 08:46:38   作者:laugh12321  
当 GitLab 服务器意外宕机且没有备份时,项目代码的恢复变得尤为关键,这篇文章主要介绍了GitLab服务器宕机时的项目代码恢复方法,需要的朋友可以参考下

重要前提:GitLab 数据挂载盘必须能够正常读取,且 /var/opt/gitlab/git-data/repositories 目录下的数据可以完整拷贝。

当 GitLab 服务器意外宕机且没有备份时,项目代码的恢复变得尤为关键。以下是经过优化的恢复流程,相比传统方法更为简洁高效。

一、数据拷贝与准备

  • 挂载数据盘将宕机服务器的数据盘挂载到其他正常运行的主机或服务器上。确保 /var/opt/gitlab/git-data 目录下的所有内容能够完整拷贝到新的主机或服务器中。

    sudo mount /dev/sdX /mnt/data  # 示例挂载命令,需根据实际情况调整
  • 拷贝数据将 /var/opt/gitlab/git-data 目录下的所有内容完整拷贝到新主机的指定目录,例如 /mnt/recovery

    sudo cp -r /mnt/data/var/opt/gitlab/git-data /mnt/recovery/

二、识别项目数据

GitLab 的项目数据存储在 /var/opt/gitlab/git-data/repositories/@hashed 目录下,文件夹名称经过哈希处理,无法直接识别项目信息。但每个项目文件夹(如 xxxxx.git)下的 config 文件中存储了项目相关的部分信息,可以提取仓库所有者及仓库名称。

注意xxx.wiki.git 和 xxx.design.git 文件夹通常可以忽略,因为它们不包含重要代码数据,且其 config 文件中也不包含仓库所有者及仓库名称。

三、简化恢复方法

传统的恢复方法通常需要搭建新的 GitLab 服务器并进行数据镜像,但这种方法存在以下问题:

  • 需要确保新旧服务器的 GitLab 版本完全一致,否则可能导致数据无法正确镜像。
  • 操作步骤繁琐,耗时且容易出错。

事实上,我们可以采用更简单的方法直接恢复代码,无需搭建新服务器。

以项目文件夹 73/47/73475cb40a568e8da8a045ced110137e159f890ac4da883b6b17dc651b3a8049.git 为例,以下是具体步骤:

  • 设置安全目录由于 GitLab 的项目目录可能被识别为不安全目录,需要通过以下命令将其标记为安全目录:

    git config --global --add safe.directory /mnt/recovery/repositories/@hashed/73/47/73475cb40a568e8da8a045ced110137e159f890ac4da883b6b17dc651b3a8049.git
  • 克隆项目在上文中提到,config 文件中存储了完整的仓库所有者和仓库名称(例如 author/project_name)。我们可以通过克隆操作将项目恢复到本地目录。假设目标项目路径是 your_clone_dir/author/project_name,那么可以执行以下命令来完成克隆:

    git clone /mnt/recovery/repositories/@hashed/73/47/73475cb40a568e8da8a045ced110137e159f890ac4da883b6b17dc651b3a8049.git your_clone_dir/author/project_name

四、自动化恢复脚本

为了进一步简化操作,以下是一个 Python 脚本,可以快速执行上述操作,只需提供哈希化仓库的源目录和克隆仓库的目标目录。

#!/usr/bin/env python
# -*-coding:utf-8 -*-
# ==============================================================================
# Copyright (c) 2025 laugh12321 Authors. All Rights Reserved.
#
# Licensed under the GNU General Public License v3.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://www.gnu.org/licenses/gpl-3.0.html  
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
# File    :   hashed_repo_cloner.py
# Version :   1.0
# Author  :   laugh12321
# Contact :   laugh12321@vip.qq.com
# Date    :   2025/03/31 14:51:38
# Desc    :   None
# ==============================================================================
from pathlib import Path
import configparser
import subprocess
import argparse
from typing import Optional
from rich.progress import track
import sys
def extract_repo_name_from_config(config_path: Path) -> str:
    """
    从Git配置文件中提取仓库完整路径
    :param config_path: Git配置文件路径
    :return: 仓库完整路径
    :raises ValueError: 如果配置缺少gitlab段或fullpath键
    :raises FileNotFoundError: 如果配置文件不存在
    """
    if not config_path.is_file():
        raise FileNotFoundError(f"Git config file not found: {config_path}")
    config = configparser.ConfigParser()
    config.read(config_path)
    if 'gitlab' not in config or 'fullpath' not in config['gitlab']:
        raise ValueError(f"Config file missing required gitlab section or fullpath key: {config_path}")
    return config.get('gitlab', 'fullpath')
def add_safe_directory(git_dir: Path) -> None:
    """
    将Git目录添加到安全目录列表
    :param git_dir: Git仓库路径
    """
    subprocess.run(
        ["git", "config", "--global", "--add", "safe.directory", str(git_dir)],
        check=True,
        stdout=subprocess.DEVNULL,  # 将标准输出重定向到 /dev/null
        stderr=subprocess.DEVNULL   # 将标准错误重定向到 /dev/null
    )
def clone_repository(source_dir: Path, target_dir: Path, repo_name: str) -> None:
    """
    克隆仓库到目标目录
    :param source_dir: 源Git仓库路径
    :param target_dir: 目标目录路径
    :param repo_name: 仓库名称
    """
    target_path = target_dir / repo_name
    subprocess.run(
        ["git", "clone", str(source_dir), str(target_path)],
        check=True,
        stdout=subprocess.DEVNULL,  # 将标准输出重定向到 /dev/null
        stderr=subprocess.DEVNULL   # 将标准错误重定向到 /dev/null
    )
def process_git_repositories(hashed_repos_dir: Path, output_dir: Path) -> None:
    """
    处理所有哈希化的Git仓库并将其克隆到输出目录
    :param hashed_repos_dir: 包含哈希化仓库的目录
    :param output_dir: 输出目录
    """
    # 预过滤.git目录,排除wiki和design仓库
    git_folders = [
        folder for folder in hashed_repos_dir.rglob("*.git")
        if not folder.name.endswith((".wiki.git", ".design.git"))
    ]
    if not git_folders:
        print("No valid Git repositories found to process.")
        return
    for git_folder in track(git_folders, description="Processing repositories"):
        config_path = git_folder / "config"
        try:
            repo_name = extract_repo_name_from_config(config_path)
            add_safe_directory(git_folder)
            clone_repository(git_folder, output_dir, repo_name)
        except Exception as e:
            print(f"Error processing {git_folder.name}: {e}")
            sys.exit()  # 终止程序
def validate_directory(path: Optional[str]) -> Path:
    """
    验证并将路径字符串转换为Path对象
    :param path: 路径字符串
    :return: Path对象
    :raises ValueError: 如果路径不存在或不是目录
    """
    if path is None:
        raise ValueError("Path cannot be None")
    path_obj = Path(path)
    if not path_obj.exists():
        raise ValueError(f"Path does not exist: {path}")
    if not path_obj.is_dir():
        raise ValueError(f"Path is not a directory: {path}")
    return path_obj
def parse_arguments():
    """
    解析命令行参数
    :return: 包含参数的命名空间
    """
    parser = argparse.ArgumentParser(
        description="将GitLab哈希化仓库克隆到目标目录",
        formatter_class=argparse.ArgumentDefaultsHelpFormatter
    )
    parser.add_argument(
        "--source",
        type=str,
        required=True,
        help="包含哈希化仓库的源目录(必须)"
    )
    parser.add_argument(
        "--output",
        type=str,
        required=True,
        help="克隆仓库的目标目录(必须)"
    )
    return parser.parse_args()
def main():
    args = parse_arguments()
    try:
        source_dir = validate_directory(args.source)
        output_dir = Path(args.output)
        process_git_repositories(source_dir, output_dir)
    except ValueError as e:
        print(f"Argument error: {e}")
        return 1
    return 0
if __name__ == "__main__":
    exit(main())

使用方法

运行以下命令即可启动脚本:

python hashed_repo_cloner.py --source gitlab_hashed_dir --output project_out_dir

五、后续操作

  • 验证恢复结果进入克隆后的项目目录,检查代码完整性,确保所有分支和提交记录都已正确恢复。

    cd project_out_dir/author/project_name
    git log  # 查看提交记录
    git branch -a  # 查看所有分支
  • 重新托管到 GitLab 或其他平台如果需要将恢复的代码重新托管到 GitLab 或其他代码托管平台,可以按照以下步骤操作:

    • 在目标平台创建新的仓库。
    • 将本地克隆的项目推送到新仓库:
      git remote add origin <新仓库的URL>
      git push -u origin --all
      git push -u origin --tags

通过上述方法,我们无需搭建新服务器,也无需担心版本兼容问题,能够快速高效地恢复 GitLab 项目代码。

到此这篇关于GitLab 服务器宕机时的项目代码恢复方法的文章就介绍到这了,更多相关GitLab 服务器宕机内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Nginx使用Keepalived部署web集群(高可用高性能负载均衡)实战案例

    Nginx使用Keepalived部署web集群(高可用高性能负载均衡)实战案例

    本文介绍Nginx+Keepalived实现Web集群高可用负载均衡的部署与测试,涵盖架构设计、环境配置、健康检查、故障切换及VIP漂移验证,确保服务高可用性与性能
    2025-05-05
  • 文件服务器 File Browser安装配置详解

    文件服务器 File Browser安装配置详解

    这篇文章主要为大家介绍了文件服务器 File Browser安装配置详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-11-11
  • 在Windows上使用qemu安装ubuntu24.04服务器的详细指南

    在Windows上使用qemu安装ubuntu24.04服务器的详细指南

    本文介绍了在Windows上使用QEMU安装Ubuntu 24.04的全流程:安装QEMU、准备ISO镜像、创建虚拟磁盘、配置启动参数(含加速和图形界面选项)、完成安装及网络设置,并提供常见问题解决方案,如性能优化和键盘响应问题,感兴趣的朋友一起看看吧
    2025-06-06
  • rsync只同步指定目录的方法(已测)

    rsync只同步指定目录的方法(已测)

    今天在配置文件同步的时候,只需要同步指定目录,因为一些目录是不需要同步的而且数量比较大,这里简单分享下–include参数的使用
    2015-01-01
  • Nexus使用Api进行操作

    Nexus使用Api进行操作

    今天小编就为大家分享一篇关于Nexus使用Api进行操作,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-12-12
  • hadoop格式化HDFS出现错误解决办法

    hadoop格式化HDFS出现错误解决办法

    这篇文章主要介绍了hadoop格式化HDFS出现错误解决办法的相关资料,hadoop格式化HDFS报错java.net.UnknownHostException,这里提供解决办法,需要的朋友可以参考下
    2017-09-09
  • DNSlog外带原理及注入分析(最新推荐)

    DNSlog外带原理及注入分析(最新推荐)

    DNS的全称是Domain Name System(网络名称系统),它作为将域名和IP地址相互映射,使人更方便地访问互联网,最近一直听到DNSlog外带原理等词但对其原理一直只是自己的理解(回显DNS请求后的日志)并没有真正的了解过,所以这里做一下记录,感兴趣的朋友一起看看吧
    2024-01-01
  • CDN中的OCSP Stapling是什么?需要开启吗?

    CDN中的OCSP Stapling是什么?需要开启吗?

    最近使用CDN时,CDN后台都有一个OCSP Staplin的选项,一般在设置HTTPS里面,不知道什么意思,这里简单为大家分享一下
    2024-01-01
  • dubbo的配置文件详解(推荐)

    dubbo的配置文件详解(推荐)

    这篇文章主要介绍了dubbo 配置文件详解(推荐),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-10-10
  • 构建及部署jenkins pipeline实现持续集成持续交付脚本

    构建及部署jenkins pipeline实现持续集成持续交付脚本

    这篇文章主要为大家介绍了构建及部署jenkins pipeline实现持续集成持续交付脚本,哟需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步
    2022-03-03

最新评论