晚睡小猫 發表於 2025-11-7 11:06:00

完整教程:如何迁移Github仓库并保留所有历史记录并用Python实现自动化

<style>pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", monospace !important; font-size: 14px !important; line-height: 1.6 !important; padding: 16px !important; margin: 16px 0 !important; background-color: rgba(248, 248, 248, 1) !important; border: 1px solid rgba(225, 228, 232, 1) !important; border-radius: 6px !important; tab-size: 4 !important; -moz-tab-size: 4 !important; max-width: 100% !important; box-sizing: border-box !important }
code { font-family: "Consolas", "Monaco", "Courier New", monospace !important; font-size: 14px !important; white-space: pre !important; word-wrap: normal !important; word-break: normal !important; overflow-wrap: normal !important; display: inline !important; background: rgba(0, 0, 0, 0) !important; border: none !important; padding: 0 !important; margin: 0 !important; line-height: inherit !important }
pre code { background: rgba(0, 0, 0, 0) !important; border: 0 !important; border-radius: 0 !important; display: block !important; line-height: 1.6 !important; margin: 0 !important; max-width: none !important; overflow: visible !important; padding: 0 !important; white-space: pre !important; word-wrap: normal !important; word-break: normal !important; color: inherit !important }
.token.comment, .token.prolog, .token.doctype, .token.cdata { color: rgba(112, 128, 144, 1) !important; font-style: italic !important }
.token.punctuation { color: rgba(153, 153, 153, 1) !important }
.token.atrule, .token.attr-value, .token.keyword { color: rgba(0, 119, 170, 1) !important; font-weight: bold !important }
.token.function, .token.class-name { color: rgba(221, 74, 104, 1) !important; font-weight: bold !important }
.token.selector, .token.attr-name, .token.string, .token.char, .token.builtin, .token.inserted { color: rgba(102, 153, 0, 1) !important }
.token.property, .token.tag, .token.boolean, .token.number, .token.constant, .token.symbol, .token.deleted { color: rgba(153, 0, 85, 1) !important }
.cnblogs-markdown pre, .cnblogs-post-body pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; background-color: rgba(248, 248, 248, 1) !important; border: 1px solid rgba(225, 228, 232, 1) !important; border-radius: 6px !important; padding: 16px !important; margin: 16px 0 !important }
pre, pre, pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important }</style>
      <div class="markdown_views prism-atom-one-dark" id="content_views"><svg style="display: none" xmlns="http://www.w3.org/2000/svg"><path d="M5,0 0,2.5 5,5z" id="raphael-marker-block" stroke-linecap="round" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0)"></path></svg><p>通过本文提供的详细步骤、Python自动化代码和最佳实践,您可以:</p><ol><li><strong>安全高效地迁移GitHub仓库</strong>,确保完整的历史记录</li><li><strong>使用自动化脚本</strong>减少人工操作错误</li><li><strong>批量处理多个仓库</strong>,提高迁移效率</li><li><strong>验证迁移结果</strong>,确保数据完整性</li><li><strong>处理各种边缘情况</strong>,提供完整的解决方案</li></ol><p>记得在实际使用前:</p><ul><li>在测试环境中验证脚本</li><li>备份重要数据</li><li>获取必要的权限和token</li><li>通知相关团队成员</li></ul><h3>一、GitHub仓库迁移详细步骤</h3><h4>方法1:使用Git命令手动迁移</h4><p><strong>步骤1:克隆原始仓库</strong></p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-bash"><span class="token function">git</span> clone <span class="token parameter variable">--mirror</span> https://github.com/username/original-repo.git
<span class="token builtin class-name">cd</span> original-repo.git</code></pre>
<p><strong>步骤2:创建新仓库</strong></p><ul><li>在GitHub上创建新的空仓库</li><li>获取新仓库的URL</li></ul><p><strong>步骤3:推送所有内容到新仓库</strong></p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-bash"><span class="token function">git</span> push <span class="token parameter variable">--mirror</span> https://github.com/username/new-repo.git</code></pre>
<p><strong>步骤4:清理本地文件</strong></p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-bash"><span class="token builtin class-name">cd</span> <span class="token punctuation">..</span>
<span class="token function">rm</span> <span class="token parameter variable">-rf</span> original-repo.git</code></pre>
<h4>方法2:使用GitHub API迁移</h4><p><strong>步骤1:获取个人访问令牌</strong></p><ul><li>在GitHub Settings → Developer settings → Personal access tokens</li><li>生成具有repo权限的token</li></ul><p><strong>步骤2:使用API创建仓库</strong></p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-bash"><span class="token function">curl</span> <span class="token parameter variable">-H</span> <span class="token string">"Authorization: token YOUR_TOKEN"</span> <span class="token punctuation">\</span>
<span class="token parameter variable">-d</span> <span class="token string">'{"name":"new-repo", "description":"Migrated repository"}'</span> <span class="token punctuation">\</span>
https://api.github.com/user/repos</code></pre>
<h3>二、Python自动化迁移代码</h3>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-python"><span class="token keyword">import</span> os
<span class="token keyword">import</span> subprocess
<span class="token keyword">import</span> requests
<span class="token keyword">import</span> json
<span class="token keyword">import</span> shutil
<span class="token keyword">from</span> pathlib <span class="token keyword">import</span> Path
<span class="token keyword">class</span> <span class="token class-name">GitHubRepoMigrator</span><span class="token punctuation">:</span>
<span class="token keyword">def</span> <span class="token function">__init__</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> github_token<span class="token punctuation">,</span> temp_dir<span class="token operator">=</span><span class="token string">"/tmp/git_migration"</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
self<span class="token punctuation">.</span>github_token <span class="token operator">=</span> github_token
self<span class="token punctuation">.</span>temp_dir <span class="token operator">=</span> temp_dir
self<span class="token punctuation">.</span>headers <span class="token operator">=</span> <span class="token punctuation">{</span>
<span class="token string">"Authorization"</span><span class="token punctuation">:</span> <span class="token string-interpolation"><span class="token string">f"token </span><span class="token interpolation"><span class="token punctuation">{</span>github_token<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">,</span>
<span class="token string">"Accept"</span><span class="token punctuation">:</span> <span class="token string">"application/vnd.github.v3+json"</span>
<span class="token punctuation">}</span>
<span class="token keyword">def</span> <span class="token function">create_github_repo</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> repo_name<span class="token punctuation">,</span> description<span class="token operator">=</span><span class="token string">""</span><span class="token punctuation">,</span> private<span class="token operator">=</span><span class="token boolean">False</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
<span class="token triple-quoted-string string">"""在GitHub上创建新仓库"""</span>
url <span class="token operator">=</span> <span class="token string">"https://api.github.com/user/repos"</span>
data <span class="token operator">=</span> <span class="token punctuation">{</span>
<span class="token string">"name"</span><span class="token punctuation">:</span> repo_name<span class="token punctuation">,</span>
<span class="token string">"description"</span><span class="token punctuation">:</span> description<span class="token punctuation">,</span>
<span class="token string">"private"</span><span class="token punctuation">:</span> private<span class="token punctuation">,</span>
<span class="token string">"auto_init"</span><span class="token punctuation">:</span> <span class="token boolean">False</span>
<span class="token punctuation">}</span>
response <span class="token operator">=</span> requests<span class="token punctuation">.</span>post<span class="token punctuation">(</span>url<span class="token punctuation">,</span> headers<span class="token operator">=</span>self<span class="token punctuation">.</span>headers<span class="token punctuation">,</span> data<span class="token operator">=</span>json<span class="token punctuation">.</span>dumps<span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token keyword">if</span> response<span class="token punctuation">.</span>status_code <span class="token operator">==</span> <span class="token number">201</span><span class="token punctuation">:</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"✅ 成功创建仓库: </span><span class="token interpolation"><span class="token punctuation">{</span>repo_name<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
<span class="token keyword">return</span> response<span class="token punctuation">.</span>json<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token string">"clone_url"</span><span class="token punctuation">]</span>
<span class="token keyword">else</span><span class="token punctuation">:</span>
<span class="token keyword">raise</span> Exception<span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"创建仓库失败: </span><span class="token interpolation"><span class="token punctuation">{</span>response<span class="token punctuation">.</span>json<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
<span class="token keyword">def</span> <span class="token function">clone_repository</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> source_url<span class="token punctuation">,</span> local_path<span class="token punctuation">)</span><span class="token punctuation">:</span>
<span class="token triple-quoted-string string">"""克隆原始仓库(包含所有分支和标签)"""</span>
<span class="token keyword">if</span> os<span class="token punctuation">.</span>path<span class="token punctuation">.</span>exists<span class="token punctuation">(</span>local_path<span class="token punctuation">)</span><span class="token punctuation">:</span>
shutil<span class="token punctuation">.</span>rmtree<span class="token punctuation">(</span>local_path<span class="token punctuation">)</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f" 正在克隆仓库: </span><span class="token interpolation"><span class="token punctuation">{</span>source_url<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
result <span class="token operator">=</span> subprocess<span class="token punctuation">.</span>run<span class="token punctuation">(</span><span class="token punctuation">[</span>
<span class="token string">"git"</span><span class="token punctuation">,</span> <span class="token string">"clone"</span><span class="token punctuation">,</span> <span class="token string">"--mirror"</span><span class="token punctuation">,</span> source_url<span class="token punctuation">,</span> local_path
<span class="token punctuation">]</span><span class="token punctuation">,</span> capture_output<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">,</span> text<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span>
<span class="token keyword">if</span> result<span class="token punctuation">.</span>returncode <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">:</span>
<span class="token keyword">raise</span> Exception<span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"克隆失败: </span><span class="token interpolation"><span class="token punctuation">{</span>result<span class="token punctuation">.</span>stderr<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"✅ 仓库克隆完成"</span><span class="token punctuation">)</span>
<span class="token keyword">def</span> <span class="token function">push_to_new_repo</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> local_path<span class="token punctuation">,</span> target_url<span class="token punctuation">)</span><span class="token punctuation">:</span>
<span class="token triple-quoted-string string">"""推送到新仓库"""</span>
os<span class="token punctuation">.</span>chdir<span class="token punctuation">(</span>local_path<span class="token punctuation">)</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f" 正在推送到新仓库: </span><span class="token interpolation"><span class="token punctuation">{</span>target_url<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
<span class="token comment"># 更新远程URL</span>
subprocess<span class="token punctuation">.</span>run<span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">"git"</span><span class="token punctuation">,</span> <span class="token string">"remote"</span><span class="token punctuation">,</span> <span class="token string">"set-url"</span><span class="token punctuation">,</span> <span class="token string">"origin"</span><span class="token punctuation">,</span> target_url<span class="token punctuation">]</span><span class="token punctuation">,</span> check<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span>
<span class="token comment"># 推送所有内容</span>
result <span class="token operator">=</span> subprocess<span class="token punctuation">.</span>run<span class="token punctuation">(</span><span class="token punctuation">[</span>
<span class="token string">"git"</span><span class="token punctuation">,</span> <span class="token string">"push"</span><span class="token punctuation">,</span> <span class="token string">"--mirror"</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span> capture_output<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">,</span> text<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span>
<span class="token keyword">if</span> result<span class="token punctuation">.</span>returncode <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">:</span>
<span class="token keyword">raise</span> Exception<span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"推送失败: </span><span class="token interpolation"><span class="token punctuation">{</span>result<span class="token punctuation">.</span>stderr<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"✅ 推送完成"</span><span class="token punctuation">)</span>
<span class="token keyword">def</span> <span class="token function">verify_migration</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> original_url<span class="token punctuation">,</span> new_url<span class="token punctuation">)</span><span class="token punctuation">:</span>
<span class="token triple-quoted-string string">"""验证迁移是否成功"""</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">" 验证迁移结果..."</span><span class="token punctuation">)</span>
<span class="token comment"># 临时克隆新仓库进行验证</span>
verify_path <span class="token operator">=</span> <span class="token string-interpolation"><span class="token string">f"</span><span class="token interpolation"><span class="token punctuation">{</span>self<span class="token punctuation">.</span>temp_dir<span class="token punctuation">}</span></span><span class="token string">/verify"</span></span>
<span class="token keyword">if</span> os<span class="token punctuation">.</span>path<span class="token punctuation">.</span>exists<span class="token punctuation">(</span>verify_path<span class="token punctuation">)</span><span class="token punctuation">:</span>
shutil<span class="token punctuation">.</span>rmtree<span class="token punctuation">(</span>verify_path<span class="token punctuation">)</span>
<span class="token comment"># 克隆新仓库</span>
subprocess<span class="token punctuation">.</span>run<span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">"git"</span><span class="token punctuation">,</span> <span class="token string">"clone"</span><span class="token punctuation">,</span> new_url<span class="token punctuation">,</span> verify_path<span class="token punctuation">]</span><span class="token punctuation">,</span>
capture_output<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">,</span> check<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span>
os<span class="token punctuation">.</span>chdir<span class="token punctuation">(</span>verify_path<span class="token punctuation">)</span>
<span class="token comment"># 检查分支数量</span>
branches_result <span class="token operator">=</span> subprocess<span class="token punctuation">.</span>run<span class="token punctuation">(</span><span class="token punctuation">[</span>
<span class="token string">"git"</span><span class="token punctuation">,</span> <span class="token string">"branch"</span><span class="token punctuation">,</span> <span class="token string">"-r"</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span> capture_output<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">,</span> text<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span>
branches <span class="token operator">=</span> <span class="token punctuation">[</span>b<span class="token punctuation">.</span>strip<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">for</span> b <span class="token keyword">in</span> branches_result<span class="token punctuation">.</span>stdout<span class="token punctuation">.</span>split<span class="token punctuation">(</span><span class="token string">'\n'</span><span class="token punctuation">)</span> <span class="token keyword">if</span> b<span class="token punctuation">.</span>strip<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f" 分支数量: </span><span class="token interpolation"><span class="token punctuation">{</span><span class="token builtin">len</span><span class="token punctuation">(</span>branches<span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
<span class="token comment"># 检查标签数量</span>
tags_result <span class="token operator">=</span> subprocess<span class="token punctuation">.</span>run<span class="token punctuation">(</span><span class="token punctuation">[</span>
<span class="token string">"git"</span><span class="token punctuation">,</span> <span class="token string">"tag"</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span> capture_output<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">,</span> text<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span>
tags <span class="token operator">=</span> <span class="token punctuation">[</span>t<span class="token punctuation">.</span>strip<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">for</span> t <span class="token keyword">in</span> tags_result<span class="token punctuation">.</span>stdout<span class="token punctuation">.</span>split<span class="token punctuation">(</span><span class="token string">'\n'</span><span class="token punctuation">)</span> <span class="token keyword">if</span> t<span class="token punctuation">.</span>strip<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"️标签数量: </span><span class="token interpolation"><span class="token punctuation">{</span><span class="token builtin">len</span><span class="token punctuation">(</span>tags<span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
<span class="token comment"># 检查提交历史</span>
log_result <span class="token operator">=</span> subprocess<span class="token punctuation">.</span>run<span class="token punctuation">(</span><span class="token punctuation">[</span>
<span class="token string">"git"</span><span class="token punctuation">,</span> <span class="token string">"log"</span><span class="token punctuation">,</span> <span class="token string">"--oneline"</span><span class="token punctuation">,</span> <span class="token string">"-5"</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span> capture_output<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">,</span> text<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">" 最近5次提交:"</span><span class="token punctuation">)</span>
<span class="token keyword">print</span><span class="token punctuation">(</span>log_result<span class="token punctuation">.</span>stdout<span class="token punctuation">)</span>
shutil<span class="token punctuation">.</span>rmtree<span class="token punctuation">(</span>verify_path<span class="token punctuation">)</span>
<span class="token keyword">def</span> <span class="token function">migrate_repository</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> source_url<span class="token punctuation">,</span> new_repo_name<span class="token punctuation">,</span> description<span class="token operator">=</span><span class="token string">""</span><span class="token punctuation">,</span> private<span class="token operator">=</span><span class="token boolean">False</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
<span class="token triple-quoted-string string">"""执行完整的仓库迁移流程"""</span>
<span class="token keyword">try</span><span class="token punctuation">:</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f" 开始迁移仓库: </span><span class="token interpolation"><span class="token punctuation">{</span>source_url<span class="token punctuation">}</span></span><span class="token string"> -&gt; </span><span class="token interpolation"><span class="token punctuation">{</span>new_repo_name<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
<span class="token comment"># 创建本地临时目录</span>
local_path <span class="token operator">=</span> <span class="token string-interpolation"><span class="token string">f"</span><span class="token interpolation"><span class="token punctuation">{</span>self<span class="token punctuation">.</span>temp_dir<span class="token punctuation">}</span></span><span class="token string">/</span><span class="token interpolation"><span class="token punctuation">{</span>new_repo_name<span class="token punctuation">}</span></span><span class="token string">.git"</span></span>
os<span class="token punctuation">.</span>makedirs<span class="token punctuation">(</span>self<span class="token punctuation">.</span>temp_dir<span class="token punctuation">,</span> exist_ok<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span>
<span class="token comment"># 步骤1: 在GitHub上创建新仓库</span>
new_repo_url <span class="token operator">=</span> self<span class="token punctuation">.</span>create_github_repo<span class="token punctuation">(</span>new_repo_name<span class="token punctuation">,</span> description<span class="token punctuation">,</span> private<span class="token punctuation">)</span>
<span class="token comment"># 步骤2: 克隆原始仓库</span>
self<span class="token punctuation">.</span>clone_repository<span class="token punctuation">(</span>source_url<span class="token punctuation">,</span> local_path<span class="token punctuation">)</span>
<span class="token comment"># 步骤3: 推送到新仓库</span>
self<span class="token punctuation">.</span>push_to_new_repo<span class="token punctuation">(</span>local_path<span class="token punctuation">,</span> new_repo_url<span class="token punctuation">)</span>
<span class="token comment"># 步骤4: 验证迁移</span>
self<span class="token punctuation">.</span>verify_migration<span class="token punctuation">(</span>source_url<span class="token punctuation">,</span> new_repo_url<span class="token punctuation">)</span>
<span class="token comment"># 清理</span>
shutil<span class="token punctuation">.</span>rmtree<span class="token punctuation">(</span>local_path<span class="token punctuation">)</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f" 迁移完成! 新仓库URL: </span><span class="token interpolation"><span class="token punctuation">{</span>new_repo_url<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
<span class="token keyword">return</span> new_repo_url
<span class="token keyword">except</span> Exception <span class="token keyword">as</span> e<span class="token punctuation">:</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"❌ 迁移失败: </span><span class="token interpolation"><span class="token punctuation">{</span>e<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
<span class="token comment"># 清理临时文件</span>
<span class="token keyword">if</span> os<span class="token punctuation">.</span>path<span class="token punctuation">.</span>exists<span class="token punctuation">(</span>self<span class="token punctuation">.</span>temp_dir<span class="token punctuation">)</span><span class="token punctuation">:</span>
shutil<span class="token punctuation">.</span>rmtree<span class="token punctuation">(</span>self<span class="token punctuation">.</span>temp_dir<span class="token punctuation">)</span>
<span class="token keyword">raise</span> e
<span class="token keyword">def</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
<span class="token comment"># 配置信息</span>
GITHUB_TOKEN <span class="token operator">=</span> <span class="token string">"your_github_token_here"</span><span class="token comment"># 替换为你的GitHub token</span>
SOURCE_REPO_URL <span class="token operator">=</span> <span class="token string">"https://github.com/username/original-repo.git"</span><span class="token comment"># 原始仓库URL</span>
NEW_REPO_NAME <span class="token operator">=</span> <span class="token string">"new-repository-name"</span><span class="token comment"># 新仓库名称</span>
DESCRIPTION <span class="token operator">=</span> <span class="token string">"Migrated repository with full history"</span><span class="token comment"># 仓库描述</span>
IS_PRIVATE <span class="token operator">=</span> <span class="token boolean">False</span><span class="token comment"># 是否私有仓库</span>
<span class="token comment"># 创建迁移器实例</span>
migrator <span class="token operator">=</span> GitHubRepoMigrator<span class="token punctuation">(</span>GITHUB_TOKEN<span class="token punctuation">)</span>
<span class="token comment"># 执行迁移</span>
<span class="token keyword">try</span><span class="token punctuation">:</span>
new_repo_url <span class="token operator">=</span> migrator<span class="token punctuation">.</span>migrate_repository<span class="token punctuation">(</span>
SOURCE_REPO_URL<span class="token punctuation">,</span>
NEW_REPO_NAME<span class="token punctuation">,</span>
DESCRIPTION<span class="token punctuation">,</span>
IS_PRIVATE
<span class="token punctuation">)</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"\n 迁移总结:"</span></span><span class="token punctuation">)</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"   原始仓库: </span><span class="token interpolation"><span class="token punctuation">{</span>SOURCE_REPO_URL<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"   新仓库: </span><span class="token interpolation"><span class="token punctuation">{</span>new_repo_url<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"   状态: ✅ 成功"</span></span><span class="token punctuation">)</span>
<span class="token keyword">except</span> Exception <span class="token keyword">as</span> e<span class="token punctuation">:</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"   状态: ❌ 失败 - </span><span class="token interpolation"><span class="token punctuation">{</span>e<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
<span class="token keyword">if</span> __name__ <span class="token operator">==</span> <span class="token string">"__main__"</span><span class="token punctuation">:</span>
main<span class="token punctuation">(</span><span class="token punctuation">)</span></code></pre>
<h3>三、高级迁移工具(支持批量操作)</h3>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-python"><span class="token keyword">import</span> csv
<span class="token keyword">import</span> time
<span class="token keyword">from</span> datetime <span class="token keyword">import</span> datetime
<span class="token keyword">class</span> <span class="token class-name">BatchGitHubMigrator</span><span class="token punctuation">:</span>
<span class="token keyword">def</span> <span class="token function">__init__</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> github_token<span class="token punctuation">,</span> config_file<span class="token operator">=</span><span class="token string">"migration_config.csv"</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
self<span class="token punctuation">.</span>migrator <span class="token operator">=</span> GitHubRepoMigrator<span class="token punctuation">(</span>github_token<span class="token punctuation">)</span>
self<span class="token punctuation">.</span>config_file <span class="token operator">=</span> config_file
<span class="token keyword">def</span> <span class="token function">read_migration_config</span><span class="token punctuation">(</span>self<span class="token punctuation">)</span><span class="token punctuation">:</span>
<span class="token triple-quoted-string string">"""读取迁移配置文件"""</span>
migrations <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
<span class="token keyword">with</span> <span class="token builtin">open</span><span class="token punctuation">(</span>self<span class="token punctuation">.</span>config_file<span class="token punctuation">,</span> <span class="token string">'r'</span><span class="token punctuation">,</span> encoding<span class="token operator">=</span><span class="token string">'utf-8'</span><span class="token punctuation">)</span> <span class="token keyword">as</span> <span class="token builtin">file</span><span class="token punctuation">:</span>
reader <span class="token operator">=</span> csv<span class="token punctuation">.</span>DictReader<span class="token punctuation">(</span><span class="token builtin">file</span><span class="token punctuation">)</span>
<span class="token keyword">for</span> row <span class="token keyword">in</span> reader<span class="token punctuation">:</span>
migrations<span class="token punctuation">.</span>append<span class="token punctuation">(</span>row<span class="token punctuation">)</span>
<span class="token keyword">return</span> migrations
<span class="token keyword">def</span> <span class="token function">batch_migrate</span><span class="token punctuation">(</span>self<span class="token punctuation">)</span><span class="token punctuation">:</span>
<span class="token triple-quoted-string string">"""批量迁移仓库"""</span>
migrations <span class="token operator">=</span> self<span class="token punctuation">.</span>read_migration_config<span class="token punctuation">(</span><span class="token punctuation">)</span>
results <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f" 开始批量迁移 </span><span class="token interpolation"><span class="token punctuation">{</span><span class="token builtin">len</span><span class="token punctuation">(</span>migrations<span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token string"> 个仓库"</span></span><span class="token punctuation">)</span>
<span class="token keyword">for</span> i<span class="token punctuation">,</span> config <span class="token keyword">in</span> <span class="token builtin">enumerate</span><span class="token punctuation">(</span>migrations<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"\n--- 处理第 </span><span class="token interpolation"><span class="token punctuation">{</span>i<span class="token punctuation">}</span></span><span class="token string">/</span><span class="token interpolation"><span class="token punctuation">{</span><span class="token builtin">len</span><span class="token punctuation">(</span>migrations<span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token string"> 个仓库 ---"</span></span><span class="token punctuation">)</span>
<span class="token keyword">try</span><span class="token punctuation">:</span>
start_time <span class="token operator">=</span> datetime<span class="token punctuation">.</span>now<span class="token punctuation">(</span><span class="token punctuation">)</span>
new_url <span class="token operator">=</span> self<span class="token punctuation">.</span>migrator<span class="token punctuation">.</span>migrate_repository<span class="token punctuation">(</span>
config<span class="token punctuation">[</span><span class="token string">'source_url'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
config<span class="token punctuation">[</span><span class="token string">'new_name'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
config<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">'description'</span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
config<span class="token punctuation">.</span>get<span class="token punctuation">(</span><span class="token string">'private'</span><span class="token punctuation">,</span> <span class="token string">'false'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>lower<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token string">'true'</span>
<span class="token punctuation">)</span>
end_time <span class="token operator">=</span> datetime<span class="token punctuation">.</span>now<span class="token punctuation">(</span><span class="token punctuation">)</span>
duration <span class="token operator">=</span> <span class="token punctuation">(</span>end_time <span class="token operator">-</span> start_time<span class="token punctuation">)</span><span class="token punctuation">.</span>total_seconds<span class="token punctuation">(</span><span class="token punctuation">)</span>
results<span class="token punctuation">.</span>append<span class="token punctuation">(</span><span class="token punctuation">{</span>
<span class="token string">'source'</span><span class="token punctuation">:</span> config<span class="token punctuation">[</span><span class="token string">'source_url'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string">'new_repo'</span><span class="token punctuation">:</span> new_url<span class="token punctuation">,</span>
<span class="token string">'status'</span><span class="token punctuation">:</span> <span class="token string">'success'</span><span class="token punctuation">,</span>
<span class="token string">'duration'</span><span class="token punctuation">:</span> duration
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"✅ 完成 (</span><span class="token interpolation"><span class="token punctuation">{</span>duration<span class="token punctuation">:</span><span class="token format-spec">.1f</span><span class="token punctuation">}</span></span><span class="token string">秒)"</span></span><span class="token punctuation">)</span>
<span class="token keyword">except</span> Exception <span class="token keyword">as</span> e<span class="token punctuation">:</span>
results<span class="token punctuation">.</span>append<span class="token punctuation">(</span><span class="token punctuation">{</span>
<span class="token string">'source'</span><span class="token punctuation">:</span> config<span class="token punctuation">[</span><span class="token string">'source_url'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token string">'new_repo'</span><span class="token punctuation">:</span> <span class="token string">''</span><span class="token punctuation">,</span>
<span class="token string">'status'</span><span class="token punctuation">:</span> <span class="token string-interpolation"><span class="token string">f'failed: </span><span class="token interpolation"><span class="token punctuation">{</span><span class="token builtin">str</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token string">'</span></span><span class="token punctuation">,</span>
<span class="token string">'duration'</span><span class="token punctuation">:</span> <span class="token number">0</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"❌ 失败: </span><span class="token interpolation"><span class="token punctuation">{</span>e<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
<span class="token comment"># 添加延迟避免API限制</span>
time<span class="token punctuation">.</span>sleep<span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span>
self<span class="token punctuation">.</span>generate_report<span class="token punctuation">(</span>results<span class="token punctuation">)</span>
<span class="token keyword">return</span> results
<span class="token keyword">def</span> <span class="token function">generate_report</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> results<span class="token punctuation">)</span><span class="token punctuation">:</span>
<span class="token triple-quoted-string string">"""生成迁移报告"""</span>
report_file <span class="token operator">=</span> <span class="token string-interpolation"><span class="token string">f"migration_report_</span><span class="token interpolation"><span class="token punctuation">{</span>datetime<span class="token punctuation">.</span>now<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>strftime<span class="token punctuation">(</span><span class="token string">'%Y%m%d_%H%M%S'</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token string">.csv"</span></span>
<span class="token keyword">with</span> <span class="token builtin">open</span><span class="token punctuation">(</span>report_file<span class="token punctuation">,</span> <span class="token string">'w'</span><span class="token punctuation">,</span> newline<span class="token operator">=</span><span class="token string">''</span><span class="token punctuation">,</span> encoding<span class="token operator">=</span><span class="token string">'utf-8'</span><span class="token punctuation">)</span> <span class="token keyword">as</span> <span class="token builtin">file</span><span class="token punctuation">:</span>
writer <span class="token operator">=</span> csv<span class="token punctuation">.</span>writer<span class="token punctuation">(</span><span class="token builtin">file</span><span class="token punctuation">)</span>
writer<span class="token punctuation">.</span>writerow<span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'源仓库'</span><span class="token punctuation">,</span> <span class="token string">'新仓库'</span><span class="token punctuation">,</span> <span class="token string">'状态'</span><span class="token punctuation">,</span> <span class="token string">'耗时(秒)'</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
<span class="token keyword">for</span> result <span class="token keyword">in</span> results<span class="token punctuation">:</span>
writer<span class="token punctuation">.</span>writerow<span class="token punctuation">(</span><span class="token punctuation">[</span>
result<span class="token punctuation">[</span><span class="token string">'source'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
result<span class="token punctuation">[</span><span class="token string">'new_repo'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
result<span class="token punctuation">[</span><span class="token string">'status'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
result<span class="token punctuation">[</span><span class="token string">'duration'</span><span class="token punctuation">]</span>
<span class="token punctuation">]</span><span class="token punctuation">)</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"\n 迁移报告已生成: </span><span class="token interpolation"><span class="token punctuation">{</span>report_file<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
<span class="token comment"># 统计信息</span>
success_count <span class="token operator">=</span> <span class="token builtin">sum</span><span class="token punctuation">(</span><span class="token number">1</span> <span class="token keyword">for</span> r <span class="token keyword">in</span> results <span class="token keyword">if</span> r<span class="token punctuation">[</span><span class="token string">'status'</span><span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token string">'success'</span><span class="token punctuation">)</span>
<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f" 统计: 成功 </span><span class="token interpolation"><span class="token punctuation">{</span>success_count<span class="token punctuation">}</span></span><span class="token string">/</span><span class="token interpolation"><span class="token punctuation">{</span><span class="token builtin">len</span><span class="token punctuation">(</span>results<span class="token punctuation">)</span><span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>
<span class="token comment"># 使用示例</span>
<span class="token keyword">def</span> <span class="token function">batch_migration_example</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
migrator <span class="token operator">=</span> BatchGitHubMigrator<span class="token punctuation">(</span><span class="token string">"your_github_token_here"</span><span class="token punctuation">)</span>
migrator<span class="token punctuation">.</span>batch_migrate<span class="token punctuation">(</span><span class="token punctuation">)</span></code></pre>
<h3>四、详细论述:GitHub仓库迁移的最佳实践</h3><h4>1. 迁移前的准备工作</h4><p><strong>风险评估</strong></p><ul><li>评估依赖关系:检查是否有其他项目依赖此仓库</li><li>通知团队成员:确保所有相关人员了解迁移计划</li><li>备份原始仓库:在迁移前创建完整的备份</li></ul><p><strong>技术准备</strong></p><ul><li>确保Git版本在2.0以上以获得最佳性能</li><li>准备足够的磁盘空间存储镜像仓库</li><li>获取足够的API调用配额</li></ul><h4>2. 迁移过程中的关键技术要点</h4><p><strong>使用<code>--mirror</code>参数的重要性</strong></p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-bash"><span class="token comment"># 正确的方式 - 包含所有内容</span>
<span class="token function">git</span> clone <span class="token parameter variable">--mirror</span> original-repo.git
<span class="token comment"># 错误的方式 - 可能丢失信息</span>
<span class="token function">git</span> clone original-repo.git</code></pre>
<p><code>--mirror</code>参数确保:</p><ul><li>所有分支(包括远程跟踪分支)</li><li>所有标签</li><li>所有提交历史</li><li>Git配置和钩子</li><li>引用和reflog历史</li></ul><h4>3. 迁移后的验证步骤</h4><p><strong>完整性检查清单</strong></p><ol><li><strong>分支验证</strong>:比较新旧仓库的分支数量</li><li><strong>标签验证</strong>:确认所有标签都已迁移</li><li><strong>提交验证</strong>:检查关键提交的SHA值是否一致</li><li><strong>大文件验证</strong>:如果使用Git LFS,验证大文件</li><li><strong>工作流验证</strong>:检查GitHub Actions工作流</li></ol><h4>4. 常见问题及解决方案</h4><p><strong>问题1:认证失败</strong></p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-python"><span class="token comment"># 解决方案:使用正确的认证方式</span>
headers <span class="token operator">=</span> <span class="token punctuation">{</span>
<span class="token string">"Authorization"</span><span class="token punctuation">:</span> <span class="token string-interpolation"><span class="token string">f"token </span><span class="token interpolation"><span class="token punctuation">{</span>token<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">,</span>
<span class="token comment"># 或者使用 Basic Auth</span>
<span class="token comment"># "Authorization": "Basic " + base64.b64encode(f"username:{token}".encode()).decode()</span>
<span class="token punctuation">}</span></code></pre>
<p><strong>问题2:网络超时</strong></p>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-python"><span class="token comment"># 解决方案:添加重试机制</span>
<span class="token keyword">import</span> requests
<span class="token keyword">from</span> requests<span class="token punctuation">.</span>adapters <span class="token keyword">import</span> HTTPAdapter
<span class="token keyword">from</span> requests<span class="token punctuation">.</span>packages<span class="token punctuation">.</span>urllib3<span class="token punctuation">.</span>util<span class="token punctuation">.</span>retry <span class="token keyword">import</span> Retry
session <span class="token operator">=</span> requests<span class="token punctuation">.</span>Session<span class="token punctuation">(</span><span class="token punctuation">)</span>
retry_strategy <span class="token operator">=</span> Retry<span class="token punctuation">(</span>
total<span class="token operator">=</span><span class="token number">3</span><span class="token punctuation">,</span>
backoff_factor<span class="token operator">=</span><span class="token number">1</span><span class="token punctuation">,</span>
status_forcelist<span class="token operator">=</span><span class="token punctuation">[</span><span class="token number">429</span><span class="token punctuation">,</span> <span class="token number">500</span><span class="token punctuation">,</span> <span class="token number">502</span><span class="token punctuation">,</span> <span class="token number">503</span><span class="token punctuation">,</span> <span class="token number">504</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span>
session<span class="token punctuation">.</span>mount<span class="token punctuation">(</span><span class="token string">"https://"</span><span class="token punctuation">,</span> HTTPAdapter<span class="token punctuation">(</span>max_retries<span class="token operator">=</span>retry_strategy<span class="token punctuation">)</span><span class="token punctuation">)</span></code></pre>
<h4>5. 企业级迁移策略</h4><p><strong>分阶段迁移</strong></p><ol><li><strong>测试阶段</strong>:迁移非关键仓库进行测试</li><li><strong>并行运行</strong>:新旧仓库并行运行一段时间</li><li><strong>全面切换</strong>:确认无误后全面切换到新仓库</li></ol><p><strong>监控和回滚</strong></p><ul><li>设置监控检查迁移状态</li><li>准备回滚计划应对意外情况</li><li>记录迁移过程中的所有操作</li></ul><h3>五、配置文件和用法示例</h3><h4>批量迁移配置文件 (migration_config.csv)</h4>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-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</code></pre>
<h4>环境准备脚本</h4>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-bash"><span class="token shebang important">#!/bin/bash</span>
<span class="token comment"># setup_migration.sh</span>
<span class="token comment"># 安装必要的依赖</span>
pip <span class="token function">install</span> requests
<span class="token comment"># 设置Git配置</span>
<span class="token function">git</span> config <span class="token parameter variable">--global</span> user.name <span class="token string">"Migration Bot"</span>
<span class="token function">git</span> config <span class="token parameter variable">--global</span> user.email <span class="token string">"bot@company.com"</span>
<span class="token comment"># 创建迁移目录</span>
<span class="token function">mkdir</span> <span class="token parameter variable">-p</span> /tmp/git_migration
<span class="token builtin class-name">echo</span> <span class="token string">"环境准备完成"</span></code></pre>
</div><br><br>
来源:https://www.cnblogs.com/ycfenxi/p/19199099
頁: [1]
查看完整版本: 完整教程:如何迁移Github仓库并保留所有历史记录并用Python实现自动化