git仓库批量备份

git的mirror参数

在git中,--mirror是一个用于克隆和推送操作的参数。它用于创建一个镜像仓库,包含了源仓库的所有分支、标签和提交历史记录。

当使用git clone --mirror <source-repo>命令时,会创建一个完全相同的镜像仓库,其中包含源仓库的所有内容。与普通克隆不同,镜像仓库会将所有的分支和标签都设为跟踪远程仓库的分支和标签。这意味着可以使用镜像仓库进行完整的版本控制操作,包括查看历史记录、切换分支等。

对于已经clone下载的仓库,如果远程仓库更新了,则可以用git fetch --prune对本地仓库保持同步。当执行该命令时,git会从远程仓库获取最新的提交和分支信息,并将这些更新同步到本地仓库的远程跟踪分支中。同时,它还会检查本地的远程跟踪分支,如果在远程仓库中已经删除了某个分支,那么它也会将这个本地的远程跟踪分支删除。

当在镜像仓库上执行git push --mirror <destination-repo>命令时,将会把镜像仓库的所有内容推送到目标仓库中,包括分支、标签和提交历史记录。

利用这些特性我们就可以完整备份git仓库。

命令行操作

$ git clone --mirror git@git.example.com/example.git
Cloning into bare repository 'example.git'...
remote: Enumerating objects: 760, done.
remote: Counting objects: 100% (760/760), done.
remote: Compressing objects: 100% (438/438), done.
remote: Total 760 (delta 280), reused 759 (delta 279)
Receiving objects: 100% (760/760), 4.79 MiB | 9.97 MiB/s, done.
Resolving deltas: 100% (280/280), done.
$ cd example.git/
$ tree -L 1
.
├── branches
├── config
├── description
├── HEAD
├── hooks
├── info
├── objects
├── packed-refs
└── refs

5 directories, 4 files


需要使用ssh或者git地址,不要使用http地址,并把ssh public key传输到git服务器上,避免clone的时候需要输入密码。对于单个仓库,手动执行足够了,但对于批量仓库操作需要封装成api待用。

python示例代码

import os
import sys
import time

class GitMirror():
    def __init__(self):
        pass

    @staticmethod
    def os_system(cmd):
        print("execute command [%s]" % cmd)
        os.system(cmd)

    @staticmethod
    def mirror_fetch(local_path, remote_path):
        local_git_path = local_path + ".git"
        parent_path = os.path.dirname(local_git_path)
        # not first run
        if os.path.exists(local_git_path):
            print("enter [%s] and fetch" % (local_git_path))
            GitMirror.os_system("git --git-dir=%s fetch --prune" % local_git_path)
        else:  # first run, git clone
            print("git clone mirror from [%s] " % (remote_path))
            GitMirror.os_system("mkdir -p %s; cd %s; git clone --mirror %s" % (parent_path, parent_path, remote_path))
        time.sleep(0.2)

if __name__ == "__main__":
    GitMirror.mirror_fetch("/home/dev/backup/example", "git@git.example.com/example.git")

批量获取仓库地址

gitlab, github, gitee,gerrit等git托管服务都提供了REST api,可以通过这些api批量获取仓库信息。以gitlab为例(https://docs.gitlab.com/ee/api/rest/ )

一 获取Access Tokens

首先需要获取Acess Tokens, 在gitlab用户管理界面中找到 “Access Tokens” 标签,输入token名字,勾选 "api"生成token。注意,生成token后务必保存下来,因为后面就再也看不到了,如果没存下来,只能重新生成。
在这里插入图片描述

二 通过api获取全部projects

通过curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects"可以获取本人以及本人可见的项目(Projects API | GitLab)。

把curl命令转换成python。

在获取全部项目的时候,每次只能返回1页的项目,所以想要获取全部项目,需要分页获取。

返回的项目信息中,有一个非常重要的字段"ssh_url_to_repo",有了项目地址就可以进行完整备份了。

import requests

class GitlabApi():

    def __init__(self, token, url):
        self.token = token
        self.url = "%s%s" %(url, "api/v4/")
        self.header = {
            "Content-Type": "application/json",
            "Private-Token": self.token
            }

    def get_all_projects(self):
        data = []
        page = 0
        total_pages = 1
        while page < total_pages:
            api_url = "%s%s%s" % (self.url, "projects", "?page=%d" % page)
            res = requests.get(api_url, headers = self.header)
            total_pages = int(res.headers["X-Total-Pages"])
            data += res.json()
            page += 1
        return data


if __name__ == "__main__":
    api = GitlabApi("your_token", "http://git.example.com/")
    res = api.get_all_projects()
    for i in res:
        print(i)

三 根据项目信息备份全部仓库

根据服务器的路径,在本地也做一个对应的目录结构。

def signal_handler(signum, frame):
    sys.exit(0)

if __name__ == "__main__":
    signal.signal(signal.SIGINT, signal_handler)
    signal.signal(signal.SIGTERM, signal_handler)

    api = GitlabApi("your_token", "http://git.example.com/")

    download_path = os.path.join(os.path.abspath(os.getcwd()), "tmp")
    res = api.get_all_projects()
    for i in res:
        path = os.path.join(download_path, i["path_with_namespace"])
        GitMirror.mirror_fetch(path, i["ssh_url_to_repo"])
        with open("%s%s.json"%(path, i["name"]), "w") as fout:
            fout.write(json.dumps(i, indent=4))
    print("total %d" % len(res))

完整代码

import json
import os.path
import sys
import signal
import time
import requests


class GitlabApi():

    def __init__(self, token, url):
        self.token = token
        self.url = "%s%s" %(url, "api/v4/")
        self.header = {
            "Content-Type": "application/json",
            "Private-Token": self.token
            }

    def get_all_projects(self):
        data = []
        page = 0
        total_pages = 1
        while page < total_pages:
            api_url = "%s%s%s" % (self.url, "projects", "?page=%d" % page)
            res = requests.get(api_url, headers = self.header)
            total_pages = int(res.headers["X-Total-Pages"])
            data += res.json()
            page += 1
        return data


class GitMirror():
    def __init__(self):
        pass

    @staticmethod
    def os_system(cmd):
        print("execute command [%s]" % cmd)
        os.system(cmd)

    @staticmethod
    def mirror_fetch(local_path, remote_path):
        local_git_path = local_path + ".git"
        parent_path = os.path.dirname(local_git_path)
        # not first run
        if os.path.exists(local_git_path):
            print("enter [%s] and fetch" % (local_git_path))
            GitMirror.os_system("git --git-dir=%s fetch --prune" % local_git_path)
        else:  # first run, git clone
            print("git clone mirror from [%s] " % (remote_path))
            GitMirror.os_system("mkdir -p %s; cd %s; git clone --mirror %s" % (parent_path, parent_path, remote_path))
        time.sleep(0.2)

def signal_handler(signum, frame):
    sys.exit(0)

if __name__ == "__main__":
    signal.signal(signal.SIGINT, signal_handler)
    signal.signal(signal.SIGTERM, signal_handler)

    api = GitlabApi("your_token", "http://git.example.com/")

    download_path = os.path.join(os.path.abspath(os.getcwd()), "tmp")
    res = api.get_all_projects()
    for i in res:
        path = os.path.join(download_path, i["path_with_namespace"])
        GitMirror.mirror_fetch(path, i["ssh_url_to_repo"])
        with open("%s%s.json"%(path, i["name"]), "w") as fout:
            fout.write(json.dumps(i, indent=4))
    print("total %d" % len(res))

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/358528.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ICMP——网际控制报文协议

目录 1.1 网际控制报文协议 ICMP 1.2 ICMP 报文的格式 1.2.1 ICMP 报文的种类 ICMP 差错报告报文 ICMP 询问报文 1.3 ICMP 的应用 1.4 ICMP抓包 1.4.1 ICMP请求包&#xff08;request&#xff09; 1.4.2 ICMP应答包&#xff08;reply&#xff09; 1.1 网际控制报文协议…

WPOpenSocial实现WordPress的QQ登录

个人建站不可避免的需要自己搭建用户数据库的问题&#xff0c;可用户却往往因为注册繁琐而放弃浏览您的网站&#xff0c;由此可见&#xff0c;一个社交账号一键登录方式尤为重要。选择适合您网站需求的社交插件&#xff0c;可以提升用户互动&#xff0c;增加社交分享&#xff0…

深度解析单片机:历史、发展与您关心的问题

什么是单片机&#xff1f; 定义&#xff1a;单片机是一种集成了中央处理器&#xff08;CPU&#xff09;、内存和外设功能的微型计算机系统。与传统计算机相比&#xff0c;单片机通常集成在一个芯片上&#xff0c;用于控制特定的应用。#单片机# 特点&#xff1a; 封装紧凑&…

HarmonyOS NEXT 星河版项目案例

参考代码&#xff1a;HeimaHealthy: 鸿蒙项目案例练习 (gitee.com) 1.欢迎页面 Entry Component struct WelcomePage {State message: string Hello Worldbuild() {Column({space: 10}) {Row() {// 1.中央slogonImage($r(app.media.home_slogan)).width(260)}.layoutWeight(…

机器学习模型预测贷款审批

机器学习模型预测贷款审批 作者&#xff1a;i阿极 作者简介&#xff1a;数据分析领域优质创作者、多项比赛获奖者&#xff1a;博主个人首页 &#x1f60a;&#x1f60a;&#x1f60a;如果觉得文章不错或能帮助到你学习&#xff0c;可以点赞&#x1f44d;收藏&#x1f4c1;评论&…

Redis学习——高级篇④

Redis学习——高级篇④ Redis7高级之Redis与Mysql数据双写一致性工程案例&#xff08;四&#xff09; 4.1 MySQL主从复制原理4.2 canal 工作原理4.3 mySQL->canal->redis 双写一致性1.环境2.配置Mysql3.配置canal4. Canal客户端&#xff08;Java编写&#xff0…

Python 数据分析实战——为什么销售额减少?酒卷隆治_案例1

# 为什么黑猫游戏的销售额会减少&#xff1f; # 数据集 DAU : 每天至少来访问一次的用户数据 数据内容 数据类型 字段名 访问时间 string&#xff08;字符串&#xff09; log_data 应用名称 string&#xff08;字符串&#xff09; app_name 用户 ID int&#xff08;数值&…

【第二十一课】拓扑序列bfs (acwing-848有向图的拓扑序列 / c++代码 )

拓扑序列 关于拓扑排序有几点&#xff1a; 1.拓扑序列中&#xff0c;每条有向边都是从序列中前面的顶点指向后面的顶点。 2.有向无环图(DAG)一定有拓扑序列。存在环的图一定没有拓扑序列&#xff0c;因为环必定有从后面的点指向前面的点的边。 3.一个有向无环图一定至少有一…

代理IP在游戏中的作用有哪些?

游戏代理IP的作用是什么&#xff1f;IP代理软件相当于连接客户端和虚拟服务器的软件“中转站”&#xff0c;在我们向远程服务器提出需求后&#xff0c;代理服务器首先获得用户的请求&#xff0c;然后将服务请求转移到远程服务器&#xff0c;然后将远程服务器反馈的结果转移到客…

vue实践:构建高效的电子签名功能

前言 在现代数字化时代&#xff0c;电子签名成为了一种方便、高效且安全的签署文件的方式。本文将介绍电子签名的原理和实现方法&#xff0c;帮助你快速掌握这一重要的工具。 电子签名是什么&#xff1f; 电子签名是一种数字化的签名方式&#xff0c;用于验证和确认电子文档、…

ES集群节点、主从、负责均衡

集群 节点介绍 Elasticsearch的协调节点并不是master节点。在Elasticsearch集群中&#xff0c;有几种不同类型的节点&#xff0c;其中包括&#xff1a; Master节点&#xff1a;负责集群范围内的管理和控制&#xff0c;例如创建或删除索引&#xff0c;决定哪些分片分配给哪个…

vxe-table从2.0升级到3.0,vxe-table-plugin-virtual-tree虚拟滚动失效

问题&#xff1a;系统一直使用的vxe-table2.0&#xff0c;vxe-table2.0不支持树的虚拟滚动&#xff0c;为了解决这个问题&#xff0c;引入了vxe-table-plugin-virtual-tree插件&#xff0c;现在系统vxe-table升级3.0&#xff0c;vxe-table-plugin-virtual-tree的虚拟滚动失效了…

Python第三方扩展库Matplotlib

Python第三方扩展库Matplotlib Matplotlib 是第三方库&#xff0c;不是Python安装程序自带的库&#xff0c;需要额外安装&#xff0c;它是Python的一个综合性的绘图库&#xff0c;提供了大量的绘图函数用于创建静态、动态、交互式的图形和数据可视化&#xff0c;可以帮助用户创…

Android App开发-简单控件(1)——文本显示

本章介绍了App开发常见的几类简单控件的用法&#xff0c;主要包括&#xff1a;显示文字的文本视图、容纳视图的常用布局、响应点击的按钮控件、显示图片的图像视图等。然后结合本章所涉及的知识&#xff0c;完成一个实战项目“简单计算器”的设计与实现。 1.1 文本显示 本节介绍…

(九)springboot实战——springboot3下的webflux项目参数验证及其全局参数验证异常处理

前言 在上一节内容中&#xff0c;我们介绍了如何在webflux项目中自定义实现一个全局的异常处理器ErrorWebExceptionHandler&#xff0c;正常情况下其可以处理我们系统的运行时异常&#xff0c;但是无法处理参数验证的异常WebExchangeBindException&#xff0c;所以这里提供另外…

彻底解决 MAC Android Studio gradle async 时出现 “connect timed out“ 问题

最近在编译一个比较老的项目&#xff0c;git clone 之后使用 async 之后出现一下现象&#xff1a; 首先确定是我网络本身是没有问题的&#xff0c;尝试几次重新 async 之后还是出现问题&#xff0c;网上找了一些方法解决了本问题&#xff0c;以此来记录一下问题是如何解决的。 …

JavaWeb学习|Session

学习材料声明 所有知识点都来自互联网&#xff0c;进行总结和梳理&#xff0c;侵权必删。 引用来源&#xff1a;尚硅谷最新版JavaWeb全套教程,java web零基础入门完整版 Session 1、Session 就一个接口&#xff08;HttpSession&#xff09;。 2、Session 就是会话。它是用来…

虚拟化平台、主机

虚拟化技术介绍 一、常见虚拟化技术 二、虚拟化与云计算的关系 虚拟化是什么 虚拟化是一种技术&#xff0c;就是将不可拆分的实体资源变成可以自由划分的逻辑资源&#xff0c;从而实现资源的整合、隔离、在分配&#xff0c;云计算就是利用了虚拟化技术的这个特点 云计算是…

java框架面试篇

Spring框架 spring Bean线程安全问题 Scope注解 我们可以在bean的类上加Scope注解来声明这个Bean是单个实例还是多个实例。在默认情况下Bean是单个实例的&#xff0c;此时的注解中的属性默认为Scope("singleton")&#xff0c;Scope("prototype")则是一…