今天综合利用 DeepSeek V3 和 R1 推理模型,成功解决了一个复杂的 Git 操作,谨以此文记录 DeepSeek 使用心得,以备后续复盘。这本是我一次操作上的疏漏,未能将 Fork 到本地的代码与原项目彻底脱钩,直到很晚才发现问题,已经很难快速用简单的 Git 命令恢复原样了。于是,我想到了 DeepSeek。
现有一个从 GitHub 复刻(fork)到我本地的开源项目。从复刻到本地那天起,我又陆续在 main 分支提交了很多次(没有其他分支)。现在需要将我本人提交的所有节点从该副本完整迁移到另一个新仓库,并要求保留所有节点的历史提交记录(提交时间、注释信息等)。
【图 0:迁移 Git 子版本树的需求描述示意图】
该需求涉及从原 Git 库彻底剥离需要的子版本树。Git 还没有能一步实现节点树 “脱钩” 的操作命令。但大方向是明确的,无非以下四步 ——
以上四步逻辑关系清晰,正好可以用 DeepSeek 一试身手。
因为涉及多次复杂 Git 操作,先用 V3 网页版直接提问(刻意未加任何提示词技巧):
我有一个本地 Git 代码仓库,是从 GitHub 一个开源项目上 fork 到本地的,但这样产生的提交不计入 GitHub 网站的个人贡献,因此我在提交了很多本地新增的版本后决定将其剥离出来。但我不知道应该怎么操作。帮帮我
以下是整理后的 DeepSeek V3 的回复,可以看到 V3 模型第一次理解有偏差:
要将本地 Git 仓库从 GitHub 的 fork 中剥离出来,使其成为一个独立的仓库,并保留所有提交历史,可以按照以下步骤操作:
1 2 3 4 5 6 7 8 9 10 11 12 |
# 1. 备份当前仓库 # 2. 移除与上游仓库的关联: cd /path/to/your/repo git remote remove origin # 3. 创建新的 GitHub 仓库(不要初始化 README 或 .gitignore) # 4. 将本地仓库关联到新仓库: git remote add origin https://github.com/yourusername/new-repo-name.git # 5. 推送代码到新仓库: git push -u origin --all git push -u origin --tags # 6. 确保本地分支跟踪新的远程分支: git branch --set-upstream-to=origin/main main |
要是按上述回复进行操作,其实只是把远程分支更新到了新仓库,完全没有实现想要的“脱钩”效果。
继续追问:
如果只想保留部分提交历史,比如只有我自己的提交历史,又该如何?
这次它听懂了,但给出的方案是借助第三方工具(由于不是理想回复,具体内容已精简):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# 1. 安装 `git filter-repo` pip install git-filter-repo # 2. 为避免直接操作原始仓库,建议先备份 git clone /path/to/your/repo new-repo cd new-repo # 3. 通过以下命令保留只有你提交的历史: git filter-repo --commit-callback ' if b"your-username" not in commit.committer_email: commit.skip() ' # 4. 清理远程信息 git remote remove origin # 5. 创建新的 GitHub 仓库 new-repo-name # 6. 关联新仓库并推送 git remote add origin https://github.com/your-username/new-repo-name.git git push -u origin --all git push -u origin --tags # 7. 效果验证(略) |
由于需要安装第三方依赖,解决方案的可移植性较差。因此还需继续追问。
由于我想要的是 Git 原生命令,因此再次追问:
我不想安装第三方工具,Git 没有原生方法实现吗?
这次它终于听懂了,想到了孤立分支(--orphan)和 cherry-pick 节点提取命令 ——
如果你不想安装第三方工具(如 git filter-repo),Git 本身也提供了原生方法来实现部分提交历史的保留,但操作会稍微复杂一些。以下是使用 Git 原生命令实现的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# 1. 克隆你的本地仓库 git clone /path/to/your/repo new-repo cd new-repo # 2. 创建一个新的分支 git checkout --orphan new-branch # 3. 筛选并重新提交你的更改 # 从提交历史筛选想要的提交哈希值: git log --author="your-username" --oneline # 逐个挑选提交 git cherry-pick <commit-hash> # 如果需要挑选多个提交,可以将哈希值列出来: git cherry-pick <commit-hash-1> <commit-hash-2> <commit-hash-3> # 4. 清理旧分支 git branch -D main # 删除旧的主分支 git branch -m new-branch main # 将新分支重命名为主分支 # 5. 清理旧的远程分支 git remote remove origin # 6. 创建新的 GitHub 仓库 # 7. 关联新仓库并推送 git remote add origin https://github.com/your-username/new-repo-name.git git push -u origin main # 8. 验证 |
这里 DeepSeek 还漏掉了一个关键细节:cherry-pick 在遇到多个 commit 版本时需要严格遵守先后顺序。在我进一步的提示下,它才补全了这部分内容,并且给出了发生冲突时的解决方案,但比较官方:
如果在挑选提交时发生冲突:
Git 会暂停挑选过程,并标记冲突文件。
手动解决冲突后,使用以下命令继续:
1 2 |
git add <resolved-files> git cherry-pick --continue |
如果你想跳过当前提交(例如冲突无法解决),可以使用:
1 |
git cherry-pick --skip |
如果你想取消整个挑选过程,可以使用:
1 |
git cherry-pick --abort |
由于 git log 命令得到的 commit 顺序是从新到旧,与 cherry-pick 相反,因此可以让 DeepSeek 帮我获取正确排序的哈希列表。这类简单任务 V3 完成得很好:
1 2 3 4 5 6 7 8 9 10 11 12 |
# 1. 逆序输出提交历史 git log --reverse # 2. 筛选指定日期之后的提交 git log --since="2024-09-13 00:00:00" # 3. 只保留哈希值 git log --pretty=format:"%H" # 4. 组合命令 git log --since="2024-09-13 00:00:00" --reverse --pretty=format:"%H" # 5. 解释参数 # --since="2024-09-13 00:00:00":筛选出指定日期之后的提交。 # --reverse:将提交历史从最旧到最新排列。 # --pretty=format:"%H":只输出提交的哈希值。 |
为了节省时间,我将最后的 PowerShell 命令作了进一步格式化处理,只保留 SHA1 哈希值的前八位,并用空格进行分隔:
1 |
(git log --since="2024-09-13 00:00:00" --reverse --pretty=format:"%H" | % { $_.Substring(0, 8) }) -join " " |
然后按照最后一次需求确认的结果,尝试用 --orphan + cherry-pick 来实现:
1 2 3 4 5 6 7 8 9 10 11 |
# 备份到新文件夹,再行处理 > git clone F:\Courses\Postman2\ newRepo Cloning into 'newRepo'... done. > cd newRepo # 获取待迁移节点列表(从早到晚排序) > $tmp = (git log --since="2024-09-13 00:00:00" --reverse --pretty=format:"%H" | % { $_.Substring(0, 8) }) -join " " # 从 main 分支切到孤立分支 master > git checkout --orphan master # 移除暂存区(stage)内的所有提交内容 > git rm --cached * |
最后这步是为了清空当前工作区内的无关变更,以便执行 git cherry-pick 命令:
【图 1:切到孤立分支 master 后,移除暂存区(stage)内的所有提交内容】
之后就可以删除工作区内的冗余内容了(除了 .git 文件夹保留,其余均可删除):
1 2 3 4 5 6 7 |
# 查看当前待删文件(夹) > git status -s ?? LICENSE ?? README.md ?? code/ ?? notes/ > rm -Recurse -Force LICENSE,code,notes,README.md |
【图 2:清空工作区内的所有无关内容】
然后就可以放心执行 git cherry-pick 了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# 批量执行节点迁移 > $tmp 3b2de1fe e8f40cf3 1b02df31 00988a80 b0718962 a29d52c5 71ccc45b 1b0c9af2 24f0bdf5 d77cf64b c6be7f0b a0284fa4 bd0b88f3 3c548a07 e713024c 3b792f58 e29381e8 8cff3c5b 2ae4c28d 11887a88 254d26c7 125356db e6fead8b 2413c3b7 bfdf3bee > git cherry-pick 3b2de1fe e8f40cf3 1b02df31 00988a80 b0718962 a29d52c5 71ccc45b 1b0c9af2 24f0bdf5 d77cf64b c6be7f0b a0284fa4 bd0b88f3 3c548a07 e713024c 3b792f58 e29381e8 8cff3c5b 2ae4c28d 11887a88 254d26c7 125356db e6fead8b 2413c3b7 bfdf3bee # ... error: could not apply 3b2de1f... Init my own repo. Added translation folder hint: After resolving the conflicts, mark them with hint: "git add/rm <pathspec>", then run hint: "git cherry-pick --continue". hint: You can instead skip this commit with "git cherry-pick --skip". hint: To abort and get back to the state before "git cherry-pick", hint: run "git cherry-pick --abort". hint: Disable this message with "git config advice.mergeConflict false" > |
但是按默认的合并方式,会得到很多冲突报错,中断命令:
【图 3:批量执行 cherry-pick 后出现一堆冲突文件】
此时只需要用 git add * 命令直接将其标记为已解决,就能继续了:
【图 4:手动处理冲突内容,并继续 git cherry-pick 操作】
接着,Git 会自动弹出本轮 操作的提交注释页,询问是否需要修改注释内容。这里无需修改,直接关闭即可:
【图:5:批量操作后的提交界面(无需修改,直接关闭即可)】
最后,再用 gitk --all 命令查看版本树,新的子版本树就诞生了:
【图 6:利用 gitk --all 查看当前所有版本树,新的子树(上方)已经生成完毕,且历史提交日期不变】
处理完最复杂的两步后,剩下的都是些简单的收尾工作:
1 2 3 4 5 6 7 8 9 10 11 |
# 删除本地旧分支 main > git branch -D main Deleted branch main (was bfdf3be). # 删除远程跟踪分支 origin > git remote remove origin # 分支 master 重命名为 main > git branch -m master main # 新建目标仓库,重置远程跟踪分支 > git remote add origin git@github.com:SafeWinter/learn-postman2.git # 推送到远程仓库 > git push -u origin main |
这样就实现了 Git 子版本树的完整迁移:
上述操作过程看似一气呵成,其实中途有很多次微调没有记录,这里略作复盘:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# runcommit.ps1 param( [Parameter(Mandatory=$true, Position=0)] [string]$CommitHash )
# 获取作者日期和提交日期 $AUTHOR_DATE = git show -s --format=%aI $CommitHash $COMMITTER_DATE = git show -s --format=%cI $CommitHash
# 设置环境变量 $env:GIT_AUTHOR_DATE = $AUTHOR_DATE.Trim() $env:GIT_COMMITTER_DATE = $COMMITTER_DATE.Trim()
# 执行 cherry-pick git cherry-pick --keep-redundant-commits --allow-empty $CommitHash # 运行方法:.\runcommit.ps1 commit_SHA_value (Enter) |
该问题在浏览器查看历史提交记录时才会出现,GitHub 目前只能按实际提交时间排序,而 Gitee 则可以选择排序方式。相比之下,国产的 Git 托管平台在展示历史提交方面更有优势。