最近在整理个人gitee一些旧的分散仓库:
一个典型的场景是,多年前自己写了个全栈玩具项目,前后端分在了两个仓库中,现在希望将它们合并到一个仓库中管理。
期间,对某一个仓库进行分支合并时,因为被合并的来源分支删除过文件,导致合并到主分支后,主分支的文件也被删除了,当时没发现,还推到gitee上了。需要先本地回滚再强推。
吐槽一下:百度合并两个仓库的方法时,有被网上的复制粘贴恶心到,起码把自己的实践经历加进来吧,直接复制粘贴,还有漏步骤的。
经过网上检索答案,例如有A、B两个不同的仓库:
将A仓库的主分支代码,拉取到B仓库的一个新建分支for_a里,然后将for_a分支合并到B的主分支,完成!
说白了就是:将A仓库的一个(主)分支,merge到B仓库的一个(主)分支里。
大体步骤:
将A仓库的所有分支都先合并汇总到主分支,B仓库也是,如果分支简单,这一步忽略。
在B仓库添加A仓库的远程地址,作为自己的远程仓库来源之一,然后将A远程仓库fecth下来。这样A就加入到B的本地仓库中了。
git fecth 只把代码拉到本地仓库。例如这里只是把A仓库fetch到了B的本地仓库,也还没真正和B建立关联,所以工作区没办法看出fetch了。
git pull 会把代码拉到本地仓库和工作区,具体可百度。
在B仓库开辟一个新分支,先叫for_a,但初始化的代码来自A仓库主分支(上面fetch整个A仓库到B的本地仓库了)。这样A仓库的主分支以for_a分支的形式"嫁接"到了B仓库上。
将for_a分支与B仓库的主分支合并,A仓库主分支的代码还有提交记录都会并入到B仓库的主分支,成功!
目的是保证最终合并后,合并结果包含A和B各自的全量修改,并且后续合并其它分支可避免出现冲突。
合并步骤,以B为例(A也是一样的操作):
拉取远程仓库到本地,并切换到主分支:
# 拉取
git clone <b_url>
# 切换到主分支
git checkout master
将其它分支合并到主分支,例如有个dev的分支要合并到主分支
# 将dev分支合并到主分支
git merge dev
回车后,需要输入合并的message,键入insert键可以进行输入信息,键入esc结束输入。再敲入:wq
后回车,表示保持并退出,合并成功。
如果还有其它分支重复第二步操作即可。
合并完了,把更改同步到远端。
git push
如果没有误删问题,这里可以跳过
笔者的B仓库还有一个deploy的分支,这个分支创建的时候来源是主分支,但它是用来部署到服务器的,就把一些说明文档之类的都删除了,并且git记录了删除的操作。当时提交的记录也不规范,没有强调删了文件,哎呀。
将它合并到主分支后,没认真看,就直接推送到gitee上了。当打开gitee,发现怎么没了readme.md。回头看git日志:
git log
发现主分支把deploy分支的删除文档类文件的操作也同步过来了,赶紧在本地仓库回滚:
将merge过来的删除文件的操作,从本地仓库(git commit
的地方)回退到暂存区(git add
的地方):
git reset --soft HEAD^
执行以下命令查看暂存区状态,可以看到delete的操作回退到暂存区里了(此时工作区、暂存区的版本是一样的,都是删了文件的,而本地仓库里的已经回退到没删除前的版本)
git status
把暂存区里的版本撤销,将删除文件操作从暂存区回退到工作区(暂存区的版本不撤销的话,工作区会以暂存区版本为参照基准,否则没办法在第3步将有原始文件的版本覆盖本地)
git restore --staged .
查看工作区状态,会发现delete操作只存在于工作区了,暂存区内容为空。
git status
删除了文件的版本已经从完全撤销了,最新的版本是没有删除文件的版本,将最新版本的内容覆盖工作区,文件就回到工作区了:
git restore .
以上步骤只是操作本地的仓库,还要把回滚的操作同步到远程仓库,让远程仓库也恢复该文件:
# 因为要推送的版本比远程仓库的版本旧,所以要强推
git push --force
合并前准备:
a_code
的文件夹,并将所有代码文件转移到该目录下(隐藏的.git
文件夹不要移),然后修改同步到远端。该a_code
目录用来合并到B仓库中,避免A和B的代码会混一块。合并:
先克隆B仓库到本地,并切换到B仓库目录下:
git clone [b_url]
在本地的B仓库中,添加A远程仓库地址作为B仓库的远程仓库之一:
git remote add a_origin [a_url]
将A仓库的内容,拉取到B的本地仓库中缓存起来,此时A已经被认为是B的一部分了:
git fetch a_origin
在B仓库初始化一个新分支,并以A仓库的master主分支为来源(上一步把A并入B的本地仓库了):
# 相当于把A仓库的主分支嫁接到B仓库的新分支上
git checkout -b for_a_branch a_origin/master
检查有哪些分支:
git branch
# master for_a_branch
为了稳妥,在新创建的for_a_branch分支试一下合并分支代码:
执行执行合并分支命令后,需要在vi命令行输入合并的message。可参考上面:合并A、B各自主分支那一步。
# 确保切换到for_a_branch
git checkout for_a_branch
# 在for_a_branch分支将master分支的代码合并过来
git merge master --allow-unrelated-histories
合并成功后,切回master主分支,把for_a_branch分支的代码合并过来:
git checkout master
git merge for_a_branch
最后,把master分支的代码推送到远端即可,本地的for_a_branch分支无需推送,直接删除本地整个库,重新拉取远端的即可(前提是先看看远端推送成功没有)。
git push
到这里已经成功了!
如果当前工作区分支和要推送到的远程分支命名不一样,是无法推送的
# 将当前所在的master分支代码推送到远端的main分支上
git push <git_url> master:main
新建本地分支并推送到远端
# 创建本地新分支
git branch test
# 切换到新分支
git checkout test
# 将新分支推送到远端
git push -u <git_url> test
本地删除分支
# 切换到其它分支上,不能是要删除的分支
git checkout <other_branch>
# 将test分支安全删除
git branch -d test
# 将当前分支强制删除
git branch -D test
查看base操作历史
history