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

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

一、数据拷贝与准备

  1. 挂载数据盘

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

    sudo mount /dev/sdX /mnt/data  # 示例挂载命令,需根据实际情况调整
  2. 拷贝数据

    /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.gitxxx.design.git 文件夹通常可以忽略,因为它们不包含重要代码数据,且其 config 文件中也不包含仓库所有者及仓库名称。

三、简化恢复方法

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

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

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

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

  1. 设置安全目录

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

    git config --global --add safe.directory /mnt/recovery/repositories/@hashed/73/47/73475cb40a568e8da8a045ced110137e159f890ac4da883b6b17dc651b3a8049.git
  2. 克隆项目

    在上文中提到,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

五、后续操作

  1. 验证恢复结果

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

    cd project_out_dir/author/project_name
    git log # 查看提交记录
    git branch -a # 查看所有分支
  2. 重新托管到 GitLab 或其他平台

    如果需要将恢复的代码重新托管到 GitLab 或其他代码托管平台,可以按照以下步骤操作:

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

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

GitLab 服务器宕机时的项目代码恢复方法的更多相关文章

  1. 防止服务器宕机时MySQL数据丢失的几种方案

    这篇文章主要介绍了防止服务器宕机时MySQL数据丢失的几种方案,结合实践介绍了Replication和Monitor以及Failover这三个项目的应用,需要的朋友可以参考下. 对于多数应用来说,My ...

  2. jenkins(8): 实战jenkins+gitlab持续集成发布php项目(代码不需要编译)

    一. jenkins 的配置 1.前提条件安装了GitLab Plugin (源码管理使用),GitLab Hook(gitlab webhook需要) Manage Jenkins--->Ma ...

  3. summernote图片上传功能保存到服务器指定文件夹+php代码+java方法

    1.summernote富文本编辑器 summernote是一款基于bootstrap的富文本编辑器,是一款十分好用的文本编辑器,还附带有图片和文件上传功能. 那么在我们网站中想吧这个图片上传到服务器 ...

  4. Git系列②之部署企业级开源仓库gitlab服务器

    Git系列②之部署企业级开源仓库gitlab服务器 上一篇我们介绍了github的常见使用方法,下面开始部署本地开源仓库gitlab GitLab 是一个用于仓库管理系统的开源项目. 1.安装配置gi ...

  5. 使用Jenkins结合Gogs和SonarQube对项目代码进行测试、部署、回滚,以及使用keepalived+haproxy调度至后端tomcat

    0 环境说明 主tomcat:192.168.0.112 备tomcat:192.168.0.183 haproxy+keepalived-1:192.168.0.156 haproxy+keepal ...

  6. IDEA新项目代码上传到gitlab远程仓库

    IDEA新项目代码上传到gitlab远程仓库 具体步骤 创建本地仓库 IDEA:VCS-->Import into Version Control-->Create Git Reposit ...

  7. xcode 把项目代码提交到远程SVN服务器

    环境 xcode 7  Mac air xcode默认支持GIT源码管理工具,但现在想把代码提交到已有到SVN服务器上,步骤如下: 1,在safari中打开svn链接地址,信任证书,输入用户名密码 , ...

  8. Centos 7搭建Gitlab服务器以及操作(创建项目,创建群组,创建用户,添加密钥)

    一. 安装并配置依赖包 在CentOS系统上安装所需的依赖:ssh,防火墙,postfix(用于邮件通知) ,wget,以下这些命令也会打开 系统防火墙中的HTTP和SSH端口访问 安装前准备 命令: ...

  9. pycharm项目代码上传远程centos服务器

    pycharm项目代码上传远程centos服务器 在工作中,我们经常会遇到如下情况,在windows系统下的pycharm中开发项目,但是需要在linux服务器上部署和运行我们的项目.那么我们的项目是 ...

  10. lunix或者centos服务器下如何下载自己在github上面的项目代码

    1.在github找到项目压缩包下载地址 打开自己的github主页找到需要下载的项目首页,如图所示,找到zip下载地址(ps:如何找这个地址我就不多说了,了解过一点html的同学肯定很容易可以找到) ...

随机推荐

  1. Solution Set -“似一捧细泉的奔逃”

    目录 0.「OurOJ #47912」优美的分配方案 1.「OurOJ #47927」海之女仆 2.「OurOJ #47950」中档题 3.「OurOJ #47933」坐标 4.「OurOJ #479 ...

  2. 10.3 - AM - 模拟赛 总结

    复盘 T1 很水,一道异或求和,但是某两位仁兄因没打括号而死. T2 很水,一道字符串处理,但是我和某位仁兄因没特判而死(虽然没有 hack 掉我,所以我理论上还是满分). T3 不水,看了很久,没想 ...

  3. Canvas简历编辑器-选中绘制与拖拽多选交互方案

    Canvas简历编辑器-选中绘制与拖拽多选交互方案 在之前我们聊了聊如何基于Canvas与基本事件组合实现了轻量级DOM,并且在此基础上实现了如何进行管理事件以及多层级渲染的能力设计.那么此时我们就依 ...

  4. K_V键值存储对比

    memcached-键值存储 redis-键值存储 RocksDB-键值存储 KeyDB-键值存储 DynamoDB-键值存储 levelDB-键值存储 etcd-键值存储 Redis与其他数据库对比 ...

  5. Spring Cloud认知学习(一)--Eureka使用、Ribbon使用

    Spring Cloud是一个微服务架构,他有多种组件来管理微服务的方方面面.Spring Cloud是用于构建微服务开发和治理的框架的集合. Spring Cloud是最热门的Java技术毋庸置疑. ...

  6. 利用bash脚本函数执行创建用户和组,并设置sudo权限等

    示例:利用bash脚本函数执行创建用户和组,并设置sudo权限等: Linux服务器设置历史命令记录,及命令执行的时间: sudo echo 'HISTTIMEFORMAT="%F %T w ...

  7. 多方安全计算(3):MPC万能钥匙-混淆电路

    学习&转载文章:多方安全计算(3):MPC万能钥匙-混淆电路 前言 我们在讲解不经意传输(Oblivious Transfer,OT)的文章(安全多方计算(1):不经意传输协议)中提到,利用n ...

  8. TCA 复习

    HTML中预览PDF 手机端无法识别embed <embed src="***.pdf" id="review" style="width:11 ...

  9. 【小记】在 Google Colab 等平台上运行 GPU 容器

    最近想到了可能的创新点,准备开始做实验了.咱想先在 Colab 这种提供免费 GPU 算力的平台上跑一些小实验,后续再转移到实验室机器上. 如果每次都要重复搭建环境多少有些麻烦了. 那咱用容器化技术不 ...

  10. startup文件中 bash_profile 和 bashrc 区别的总结

    原理上讲"交互式,登陆shell"启动时会加载"profile"系列的startup文件"交互式,非登陆shell"启动时会加载" ...