文章目录[隐藏]
在当今的软件开发和版本控制领域,Git已成为不可或缺的工具。然而,随着项目的不断演进和团队协作的日益复杂,Git操作也时常面临各种挑战。本文将介绍一个具体的案例,展示如何借助先进的AI模型DeepSeek V3以及Git的原生命令,解决一个复杂的版本迁移问题。通过这一实例,读者不仅能够领略到AI在辅助软件开发中的巨大潜力,还能学习到实用的Git操作技巧,以应对日常工作中可能遇到的各种复杂情况。
1 背景介绍
今天综合利用 DeepSeek V3
和 R1
推理模型,成功解决了一个复杂的 Git
操作,谨以此文记录 DeepSeek
使用心得,以备后续复盘。这本是我一次操作上的疏漏,未能将 Fork 到本地的代码与原项目彻底脱钩,直到很晚才发现问题,已经很难快速用简单的 Git 命令恢复原样了。于是,我想到了 DeepSeek。
2 需求描述
现有一个从 GitHub
复刻(fork)到我本地的开源项目。从复刻到本地那天起,我又陆续在 main
分支提交了很多次(没有其他分支)。现在需要将我本人提交的所有节点从该副本完整迁移到另一个新仓库,并要求保留所有节点的历史提交记录(提交时间、注释信息等)。
【图 0:迁移 Git 子版本树的需求描述示意图】
3 思路分析
该需求涉及从原 Git
库彻底剥离需要的子版本树。Git
还没有能一步实现节点树 “脱钩” 的操作命令。但大方向是明确的,无非以下四步 ——
先找到脱钩位置(简单);
从脱钩点产生一个新的
Git
根节点(未知);设法将脱钩点后续产生的提交版本依次追加到新的根节点上(未知);
最后删除原有版本树,重置远程推送分支
origin
(简单);
以上四步逻辑关系清晰,正好可以用 DeepSeek
一试身手。
4 实现过程
4.1 第一次需求确认
因为涉及多次复杂 Git
操作,先用 V3
网页版直接提问(刻意未加任何提示词技巧):
我有一个本地 Git 代码仓库,是从 GitHub 一个开源项目上 fork 到本地的,但这样产生的提交不计入 GitHub 网站的个人贡献,因此我在提交了很多本地新增的版本后决定将其剥离出来。但我不知道应该怎么操作。帮帮我
以下是整理后的 DeepSeek V3
的回复,可以看到 V3
模型第一次理解有偏差:
要将本地 Git 仓库从 GitHub 的 fork 中剥离出来,使其成为一个独立的仓库,并保留所有提交历史,可以按照以下步骤操作:
#1.备份当前仓库#2.移除与上游仓库的关联:cd/path/to/your/repogitremoteremoveorigin#3.创建新的GitHub仓库(不要初始化README或.gitignore)#4.将本地仓库关联到新仓库:gitremoteaddoriginhttps://github.com/yourusername/new-repo-name.git#5.推送代码到新仓库:gitpush-uorigin--allgitpush-uorigin--tags#6.确保本地分支跟踪新的远程分支:gitbranch--set-upstream-to=origin/mainmain
要是按上述回复进行操作,其实只是把远程分支更新到了新仓库,完全没有实现想要的“脱钩”效果。
4.2 第二次需求确认
继续追问:
如果只想保留部分提交历史,比如只有我自己的提交历史,又该如何?
这次它听懂了,但给出的方案是借助第三方工具(由于不是理想回复,具体内容已精简):
#1.安装`gitfilter-repo`pipinstallgit-filter-repo#2.为避免直接操作原始仓库,建议先备份gitclone/path/to/your/reponew-repocdnew-repo#3.通过以下命令保留只有你提交的历史:gitfilter-repo--commit-callback\'ifb\"your-username\"notincommit.committer_email:commit.skip()\'#4.清理远程信息gitremoteremoveorigin#5.创建新的GitHub仓库new-repo-name#6.关联新仓库并推送gitremoteaddoriginhttps://github.com/your-username/new-repo-name.gitgitpush-uorigin--allgitpush-uorigin--tags#7.效果验证(略)
由于需要安装第三方依赖,解决方案的可移植性较差。因此还需继续追问。
4.3 第三次需求确认
由于我想要的是 Git 原生命令,因此再次追问:
我不想安装第三方工具,Git 没有原生方法实现吗?
这次它终于听懂了,想到了孤立分支(--orphan
)和 cherry-pick
节点提取命令 ——
如果你不想安装第三方工具(如 git filter-repo),Git 本身也提供了原生方法来实现部分提交历史的保留,但操作会稍微复杂一些。以下是使用 Git 原生命令实现的方法:
#1.克隆你的本地仓库gitclone/path/to/your/reponew-repocdnew-repo#2.创建一个新的分支gitcheckout--orphannew-branch#3.筛选并重新提交你的更改#从提交历史筛选想要的提交哈希值:gitlog--author=\"your-username\"--oneline#逐个挑选提交gitcherry-pick#如果需要挑选多个提交,可以将哈希值列出来:gitcherry-pick#4.清理旧分支gitbranch-Dmain#删除旧的主分支gitbranch-mnew-branchmain#将新分支重命名为主分支#5.清理旧的远程分支gitremoteremoveorigin#6.创建新的GitHub仓库#7.关联新仓库并推送gitremoteaddoriginhttps://github.com/your-username/new-repo-name.gitgitpush-uoriginmain#8.验证
这里 DeepSeek
还漏掉了一个关键细节:cherry-pick
在遇到多个 commit
版本时需要严格遵守先后顺序。在我进一步的提示下,它才补全了这部分内容,并且给出了发生冲突时的解决方案,但比较官方:
如果在挑选提交时发生冲突:
Git 会暂停挑选过程,并标记冲突文件。
手动解决冲突后,使用以下命令继续:
gitaddgitcherry-pick--continue
如果你想跳过当前提交(例如冲突无法解决),可以使用:
gitcherry-pick--skip
如果你想取消整个挑选过程,可以使用:
gitcherry-pick--abort
4.4 V3 模型:中间结果的处理
由于 git log
命令得到的 commit
顺序是从新到旧,与 cherry-pick
相反,因此可以让 DeepSeek
帮我获取正确排序的哈希列表。这类简单任务 V3 完成得很好:
#1.逆序输出提交历史gitlog--reverse#2.筛选指定日期之后的提交gitlog--since=\"2024-09-1300:00:00\"#3.只保留哈希值gitlog--pretty=format:\"%H\"#4.组合命令gitlog--since=\"2024-09-1300:00:00\"--reverse--pretty=format:\"%H\"#5.解释参数#--since=\"2024-09-1300:00:00\":筛选出指定日期之后的提交。#--reverse:将提交历史从最旧到最新排列。#--pretty=format:\"%H\":只输出提交的哈希值。
为了节省时间,我将最后的 PowerShell
命令作了进一步格式化处理,只保留 SHA1
哈希值的前八位,并用空格进行分隔:
(gitlog--since=\"2024-09-1300:00:00\"--reverse--pretty=format:\"%H\"|%{$_.Substring(0,8)})-join\"\"
4.5 方案验证,首战告捷
然后按照最后一次需求确认的结果,尝试用 --orphan
+ cherry-pick
来实现:
#备份到新文件夹,再行处理>gitcloneF:\\Courses\\Postman2\\newRepoCloninginto\'newRepo\'...done.>cdnewRepo#获取待迁移节点列表(从早到晚排序)>$tmp=(gitlog--since=\"2024-09-1300:00:00\"--reverse--pretty=format:\"%H\"|%{$_.Substring(0,8)})-join\"\"#从main分支切到孤立分支master>gitcheckout--orphanmaster#移除暂存区(stage)内的所有提交内容>gitrm--cached*
最后这步是为了清空当前工作区内的无关变更,以便执行 git cherry-pick
命令:
【图 1:切到孤立分支 master 后,移除暂存区(stage)内的所有提交内容】
之后就可以删除工作区内的冗余内容了(除了 .git
文件夹保留,其余均可删除):
#查看当前待删文件(夹)>gitstatus-s??LICENSE??README.md??code/??notes/>rm-Recurse-ForceLICENSE,code,notes,README.md
【图 2:清空工作区内的所有无关内容】
然后就可以放心执行 git cherry-pick
了:
#批量执行节点迁移>$tmp3b2de1fee8f40cf31b02df3100988a80b0718962a29d52c571ccc45b1b0c9af224f0bdf5d77cf64bc6be7f0ba0284fa4bd0b88f33c548a07e713024c3b792f58e29381e88cff3c5b2ae4c28d11887a88254d26c7125356dbe6fead8b2413c3b7bfdf3bee>gitcherry-pick3b2de1fee8f40cf31b02df3100988a80b0718962a29d52c571ccc45b1b0c9af224f0bdf5d77cf64bc6be7f0ba0284fa4bd0b88f33c548a07e713024c3b792f58e29381e88cff3c5b2ae4c28d11887a88254d26c7125356dbe6fead8b2413c3b7bfdf3bee#...error:couldnotapply3b2de1f...Initmyownrepo.Addedtranslationfolderhint:Afterresolvingtheconflicts,markthemwithhint:\"gitadd/rm\",thenrunhint:\"gitcherry-pick--continue\".hint:Youcaninsteadskipthiscommitwith\"gitcherry-pick--skip\".hint:Toabortandgetbacktothestatebefore\"gitcherry-pick\",hint:run\"gitcherry-pick--abort\".hint:Disablethismessagewith\"gitconfigadvice.mergeConflictfalse\">
但是按默认的合并方式,会得到很多冲突报错,中断命令:
【图 3:批量执行 cherry-pick 后出现一堆冲突文件】
此时只需要用 git add *
命令直接将其标记为已解决,就能继续了:
【图 4:手动处理冲突内容,并继续 git cherry-pick 操作】
接着,Git
会自动弹出本轮 操作的提交注释页,询问是否需要修改注释内容。这里无需修改,直接关闭即可:
【图:5:批量操作后的提交界面(无需修改,直接关闭即可)】
最后,再用 gitk --all
命令查看版本树,新的子版本树就诞生了:
【图 6:利用 gitk --all 查看当前所有版本树,新的子树(上方)已经生成完毕,且历史提交日期不变】
处理完最复杂的两步后,剩下的都是些简单的收尾工作:
#删除本地旧分支main>gitbranch-DmainDeletedbranchmain(wasbfdf3be).#删除远程跟踪分支origin>gitremoteremoveorigin#分支master重命名为main>gitbranch-mmastermain#新建目标仓库,重置远程跟踪分支>gitremoteaddorigingit@github.com:SafeWinter/learn-postman2.git#推送到远程仓库>gitpush-uoriginmain
这样就实现了 Git
子版本树的完整迁移:
5 总结复盘
上述操作过程看似一气呵成,其实中途有很多次微调没有记录,这里略作复盘:
DeepSeek
延续了 “遇强则强” 的大模型风格,要想得到满意的答复,提问者除了精准描述问题外,还需要对相关领域有扎实的基础;否则DeepSeek
只会跟着你的思路,无法立即看出问题的根源所在;一旦需求明确后,
DeepSeek
往往能很快提供准确回复,且该方案准确率极高(--orphan
+cherry-pick
组合);这种感觉就像是在和付费版ChatGPT 4x
对话,但又是完全免费使用,非常震撼;务必重视
R1
模型的推理过程,这是后续大幅提高准确率的关键。R1
模型会将当前会话的历史记录全部导入推理过程,十分智能;建议大家还是多用网页或手机版 DeepSeek,能在本地部署的都是完整模型的蒸馏版,虽然无需联网交流,但表现是大打折扣的;与其跟风“大炼钢铁”,不如多用 DeepSeek 解决一些实际问题;
本文介绍的版本树剥离方案还存在一个问题:各历史节点的提交时间和作者修改不一致——前者为当前操作时间,后者为历史记录时间1。要让提交时间也回归到历史节点,只能从历史节点中提取提交时间,然后逐一提交。但这样的单独处理,只要存在对原内容的修改,当次
cherry-pick
操作就会中断,且必须手动处理内容冲突,DeepSeek
暂时无法给出包含手动处理版本冲突的自动化脚本,只能给出没有中断的情况下每次迁移的自动化脚本(如下所示)。要实现彻底自动化,还需要提问者自身对bash
脚本或PowerShell
脚本有相当程度的透彻理解。
#runcommit.ps1param([Parameter(Mandatory=$true,Position=0)][string]$CommitHash)#获取作者日期和提交日期$AUTHOR_DATE=gitshow-s--format=%aI$CommitHash$COMMITTER_DATE=gitshow-s--format=%cI$CommitHash#设置环境变量$env:GIT_AUTHOR_DATE=$AUTHOR_DATE.Trim()$env:GIT_COMMITTER_DATE=$COMMITTER_DATE.Trim()#执行cherry-pickgitcherry-pick--keep-redundant-commits--allow-empty$CommitHash#运行方法:.\\runcommit.ps1commit_SHA_value(Enter)
该问题在浏览器查看历史提交记录时才会出现,GitHub
目前只能按实际提交时间排序,而Gitee
则可以选择排序方式。相比之下,国产的Git
托管平台在展示历史提交方面更有优势。
总结
本文通过详细描述一个复杂的Git迁移问题及其解决方案,展示了DeepSeek V3在辅助解决软件开发问题中的独特价值。通过与AI模型的多次交互,我们逐步明确了需求,并最终找到了使用原生Git命令(--orphan分支和cherry-pick操作)的有效解决方案。这一过程不仅体现了AI在理解和解决复杂问题上的能力,也展示了Git作为版本控制工具的强大功能和灵活性。本文所提供的解决方案和思路,对于广大软件开发者和版本控制用户来说,具有重要的参考和借鉴意义。