Python實現(xiàn)自動化遷移Github倉庫并保留所有歷史記錄
通過本文提供的詳細(xì)步驟、Python自動化代碼和最佳實踐,您可以:
- 安全高效地遷移GitHub倉庫,確保完整的歷史記錄
- 使用自動化腳本減少人工操作錯誤
- 批量處理多個倉庫,提高遷移效率
- 驗證遷移結(jié)果,確保數(shù)據(jù)完整性
- 處理各種邊緣情況,提供完整的解決方案
記得在實際使用前:
- 在測試環(huán)境中驗證腳本
- 備份重要數(shù)據(jù)
- 獲取必要的權(quán)限和token
- 通知相關(guān)團(tuán)隊成員
一、GitHub倉庫遷移詳細(xì)步驟
方法1:使用Git命令手動遷移
步驟1:克隆原始倉庫
git clone --mirror https://github.com/username/original-repo.git cd original-repo.git
步驟2:創(chuàng)建新倉庫
- 在GitHub上創(chuàng)建新的空倉庫
- 獲取新倉庫的URL
步驟3:推送所有內(nèi)容到新倉庫
git push --mirror https://github.com/username/new-repo.git
步驟4:清理本地文件
cd .. rm -rf original-repo.git
方法2:使用GitHub API遷移
步驟1:獲取個人訪問令牌
- 在GitHub Settings → Developer settings → Personal access tokens
- 生成具有repo權(quán)限的token
步驟2:使用API創(chuàng)建倉庫
curl -H "Authorization: token YOUR_TOKEN" \
-d '{"name":"new-repo", "description":"Migrated repository"}' \
https://api.github.com/user/repos
二、Python自動化遷移代碼
import os
import subprocess
import requests
import json
import shutil
from pathlib import Path
class GitHubRepoMigrator:
def __init__(self, github_token, temp_dir="/tmp/git_migration"):
self.github_token = github_token
self.temp_dir = temp_dir
self.headers = {
"Authorization": f"token {github_token}",
"Accept": "application/vnd.github.v3+json"
}
def create_github_repo(self, repo_name, description="", private=False):
"""在GitHub上創(chuàng)建新倉庫"""
url = "https://api.github.com/user/repos"
data = {
"name": repo_name,
"description": description,
"private": private,
"auto_init": False
}
response = requests.post(url, headers=self.headers, data=json.dumps(data))
if response.status_code == 201:
print(f"? 成功創(chuàng)建倉庫: {repo_name}")
return response.json()["clone_url"]
else:
raise Exception(f"創(chuàng)建倉庫失敗: {response.json()}")
def clone_repository(self, source_url, local_path):
"""克隆原始倉庫(包含所有分支和標(biāo)簽)"""
if os.path.exists(local_path):
shutil.rmtree(local_path)
print(f"?? 正在克隆倉庫: {source_url}")
result = subprocess.run([
"git", "clone", "--mirror", source_url, local_path
], capture_output=True, text=True)
if result.returncode != 0:
raise Exception(f"克隆失敗: {result.stderr}")
print("? 倉庫克隆完成")
def push_to_new_repo(self, local_path, target_url):
"""推送到新倉庫"""
os.chdir(local_path)
print(f"?? 正在推送到新倉庫: {target_url}")
# 更新遠(yuǎn)程URL
subprocess.run(["git", "remote", "set-url", "origin", target_url], check=True)
# 推送所有內(nèi)容
result = subprocess.run([
"git", "push", "--mirror"
], capture_output=True, text=True)
if result.returncode != 0:
raise Exception(f"推送失敗: {result.stderr}")
print("? 推送完成")
def verify_migration(self, original_url, new_url):
"""驗證遷移是否成功"""
print("?? 驗證遷移結(jié)果...")
# 臨時克隆新倉庫進(jìn)行驗證
verify_path = f"{self.temp_dir}/verify"
if os.path.exists(verify_path):
shutil.rmtree(verify_path)
# 克隆新倉庫
subprocess.run(["git", "clone", new_url, verify_path],
capture_output=True, check=True)
os.chdir(verify_path)
# 檢查分支數(shù)量
branches_result = subprocess.run([
"git", "branch", "-r"
], capture_output=True, text=True)
branches = [b.strip() for b in branches_result.stdout.split('\n') if b.strip()]
print(f"?? 分支數(shù)量: {len(branches)}")
# 檢查標(biāo)簽數(shù)量
tags_result = subprocess.run([
"git", "tag"
], capture_output=True, text=True)
tags = [t.strip() for t in tags_result.stdout.split('\n') if t.strip()]
print(f"??? 標(biāo)簽數(shù)量: {len(tags)}")
# 檢查提交歷史
log_result = subprocess.run([
"git", "log", "--oneline", "-5"
], capture_output=True, text=True)
print("?? 最近5次提交:")
print(log_result.stdout)
shutil.rmtree(verify_path)
def migrate_repository(self, source_url, new_repo_name, description="", private=False):
"""執(zhí)行完整的倉庫遷移流程"""
try:
print(f"?? 開始遷移倉庫: {source_url} -> {new_repo_name}")
# 創(chuàng)建本地臨時目錄
local_path = f"{self.temp_dir}/{new_repo_name}.git"
os.makedirs(self.temp_dir, exist_ok=True)
# 步驟1: 在GitHub上創(chuàng)建新倉庫
new_repo_url = self.create_github_repo(new_repo_name, description, private)
# 步驟2: 克隆原始倉庫
self.clone_repository(source_url, local_path)
# 步驟3: 推送到新倉庫
self.push_to_new_repo(local_path, new_repo_url)
# 步驟4: 驗證遷移
self.verify_migration(source_url, new_repo_url)
# 清理
shutil.rmtree(local_path)
print(f"?? 遷移完成! 新倉庫URL: {new_repo_url}")
return new_repo_url
except Exception as e:
print(f"? 遷移失敗: {e}")
# 清理臨時文件
if os.path.exists(self.temp_dir):
shutil.rmtree(self.temp_dir)
raise e
def main():
# 配置信息
GITHUB_TOKEN = "your_github_token_here" # 替換為你的GitHub token
SOURCE_REPO_URL = "https://github.com/username/original-repo.git" # 原始倉庫URL
NEW_REPO_NAME = "new-repository-name" # 新倉庫名稱
DESCRIPTION = "Migrated repository with full history" # 倉庫描述
IS_PRIVATE = False # 是否私有倉庫
# 創(chuàng)建遷移器實例
migrator = GitHubRepoMigrator(GITHUB_TOKEN)
# 執(zhí)行遷移
try:
new_repo_url = migrator.migrate_repository(
SOURCE_REPO_URL,
NEW_REPO_NAME,
DESCRIPTION,
IS_PRIVATE
)
print(f"\n?? 遷移總結(jié):")
print(f" 原始倉庫: {SOURCE_REPO_URL}")
print(f" 新倉庫: {new_repo_url}")
print(f" 狀態(tài): ? 成功")
except Exception as e:
print(f" 狀態(tài): ? 失敗 - {e}")
if __name__ == "__main__":
main()
三、高級遷移工具(支持批量操作)
import csv
import time
from datetime import datetime
class BatchGitHubMigrator:
def __init__(self, github_token, config_file="migration_config.csv"):
self.migrator = GitHubRepoMigrator(github_token)
self.config_file = config_file
def read_migration_config(self):
"""讀取遷移配置文件"""
migrations = []
with open(self.config_file, 'r', encoding='utf-8') as file:
reader = csv.DictReader(file)
for row in reader:
migrations.append(row)
return migrations
def batch_migrate(self):
"""批量遷移倉庫"""
migrations = self.read_migration_config()
results = []
print(f"?? 開始批量遷移 {len(migrations)} 個倉庫")
for i, config in enumerate(migrations, 1):
print(f"\n--- 處理第 {i}/{len(migrations)} 個倉庫 ---")
try:
start_time = datetime.now()
new_url = self.migrator.migrate_repository(
config['source_url'],
config['new_name'],
config.get('description', ''),
config.get('private', 'false').lower() == 'true'
)
end_time = datetime.now()
duration = (end_time - start_time).total_seconds()
results.append({
'source': config['source_url'],
'new_repo': new_url,
'status': 'success',
'duration': duration
})
print(f"? 完成 ({duration:.1f}秒)")
except Exception as e:
results.append({
'source': config['source_url'],
'new_repo': '',
'status': f'failed: {str(e)}',
'duration': 0
})
print(f"? 失敗: {e}")
# 添加延遲避免API限制
time.sleep(2)
self.generate_report(results)
return results
def generate_report(self, results):
"""生成遷移報告"""
report_file = f"migration_report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv"
with open(report_file, 'w', newline='', encoding='utf-8') as file:
writer = csv.writer(file)
writer.writerow(['源倉庫', '新倉庫', '狀態(tài)', '耗時(秒)'])
for result in results:
writer.writerow([
result['source'],
result['new_repo'],
result['status'],
result['duration']
])
print(f"\n?? 遷移報告已生成: {report_file}")
# 統(tǒng)計信息
success_count = sum(1 for r in results if r['status'] == 'success')
print(f"?? 統(tǒng)計: 成功 {success_count}/{len(results)}")
# 使用示例
def batch_migration_example():
migrator = BatchGitHubMigrator("your_github_token_here")
migrator.batch_migrate()
四、詳細(xì)論述:GitHub倉庫遷移的最佳實踐
1. 遷移前的準(zhǔn)備工作
風(fēng)險評估
- 評估依賴關(guān)系:檢查是否有其他項目依賴此倉庫
- 通知團(tuán)隊成員:確保所有相關(guān)人員了解遷移計劃
- 備份原始倉庫:在遷移前創(chuàng)建完整的備份
技術(shù)準(zhǔn)備
- 確保Git版本在2.0以上以獲得最佳性能
- 準(zhǔn)備足夠的磁盤空間存儲鏡像倉庫
- 獲取足夠的API調(diào)用配額
2. 遷移過程中的關(guān)鍵技術(shù)要點
使用--mirror參數(shù)的重要性
# 正確的方式 - 包含所有內(nèi)容 git clone --mirror original-repo.git # 錯誤的方式 - 可能丟失信息 git clone original-repo.git
--mirror參數(shù)確保:
- 所有分支(包括遠(yuǎn)程跟蹤分支)
- 所有標(biāo)簽
- 所有提交歷史
- Git配置和鉤子
- 引用和reflog歷史
3. 遷移后的驗證步驟
完整性檢查清單
- 分支驗證:比較新舊倉庫的分支數(shù)量
- 標(biāo)簽驗證:確認(rèn)所有標(biāo)簽都已遷移
- 提交驗證:檢查關(guān)鍵提交的SHA值是否一致
- 大文件驗證:如果使用Git LFS,驗證大文件
- 工作流驗證:檢查GitHub Actions工作流
4. 常見問題及解決方案
問題1:認(rèn)證失敗
# 解決方案:使用正確的認(rèn)證方式
headers = {
"Authorization": f"token {token}",
# 或者使用 Basic Auth
# "Authorization": "Basic " + base64.b64encode(f"username:{token}".encode()).decode()
}
問題2:網(wǎng)絡(luò)超時
# 解決方案:添加重試機(jī)制
import requests
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry
session = requests.Session()
retry_strategy = Retry(
total=3,
backoff_factor=1,
status_forcelist=[429, 500, 502, 503, 504],
)
session.mount("https://", HTTPAdapter(max_retries=retry_strategy))
5. 企業(yè)級遷移策略
分階段遷移
- 測試階段:遷移非關(guān)鍵倉庫進(jìn)行測試
- 并行運行:新舊倉庫并行運行一段時間
- 全面切換:確認(rèn)無誤后全面切換到新倉庫
監(jiān)控和回滾
- 設(shè)置監(jiān)控檢查遷移狀態(tài)
- 準(zhǔn)備回滾計劃應(yīng)對意外情況
- 記錄遷移過程中的所有操作
五、配置文件和用法示例
批量遷移配置文件 (migration_config.csv)
source_url,new_name,description,private
https://github.com/org/old-repo1.git,new-repo1,Migrated repository 1,true
https://github.com/org/old-repo2.git,new-repo2,Migrated repository 2,false
https://github.com/org/old-repo3.git,new-repo3,Migrated repository 3,true
環(huán)境準(zhǔn)備腳本
#!/bin/bash # setup_migration.sh # 安裝必要的依賴 pip install requests # 設(shè)置Git配置 git config --global user.name "Migration Bot" git config --global user.email "bot@company.com" # 創(chuàng)建遷移目錄 mkdir -p /tmp/git_migration echo "環(huán)境準(zhǔn)備完成"
以上就是Python實現(xiàn)自動化遷移Github倉庫并保留所有歷史記錄的詳細(xì)內(nèi)容,更多關(guān)于Python自動化遷移Github倉庫的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python3中的map函數(shù)調(diào)用后內(nèi)存釋放問題
這篇文章主要介紹了Python3中的map函數(shù)調(diào)用后內(nèi)存釋放問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-02-02
一文詳解如何基于Python的tkinter庫創(chuàng)建圖形用戶界面
Tkinter是Python中用于創(chuàng)建圖形用戶界面 (GUI) 的標(biāo)準(zhǔn)庫之一,它基于Tk GUI工具包,這篇文章主要介紹了如何基于Python的tkinter庫創(chuàng)建圖形用戶界面的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2025-07-07
python將十六進(jìn)制值轉(zhuǎn)換為字符串的三種方法
這篇文章主要給大家介紹了關(guān)于python將十六進(jìn)制值轉(zhuǎn)換為字符串的三種方法,工作內(nèi)容的需要需求,經(jīng)常需要使用到字符同16進(jìn)制,以及各個進(jìn)制之間的轉(zhuǎn)換,需要的朋友可以參考下2023-07-07
Python實現(xiàn)的HTTP并發(fā)測試完整示例
這篇文章主要介紹了Python實現(xiàn)的HTTP并發(fā)測試,涉及Python多線程并發(fā)操作相關(guān)實現(xiàn)技巧,需要的朋友可以參考下2015-05-05

