记一次使用git reset、git push --force的场景

场景

最近在整理个人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仓库各自进行主分支合并

目的是保证最终合并后,合并结果包含A和B各自的全量修改,并且后续合并其它分支可避免出现冲突。

合并步骤,以B为例(A也是一样的操作):

  1. 拉取远程仓库到本地,并切换到主分支:

    # 拉取
    git clone <b_url>
    # 切换到主分支
    git checkout master
    
  2. 将其它分支合并到主分支,例如有个dev的分支要合并到主分支

    # 将dev分支合并到主分支
    git merge dev
    
  3. 回车后,需要输入合并的message,键入insert键可以进行输入信息,键入esc结束输入。再敲入:wq后回车,表示保持并退出,合并成功。

  4. 如果还有其它分支重复第二步操作即可。

  5. 合并完了,把更改同步到远端。

    git push
    

插曲,误删文件并commit 、push怎么办

如果没有误删问题,这里可以跳过

笔者的B仓库还有一个deploy的分支,这个分支创建的时候来源是主分支,但它是用来部署到服务器的,就把一些说明文档之类的都删除了,并且git记录了删除的操作。当时提交的记录也不规范,没有强调删了文件,哎呀。

将它合并到主分支后,没认真看,就直接推送到gitee上了。当打开gitee,发现怎么没了readme.md。回头看git日志:

git log

发现主分支把deploy分支的删除文档类文件的操作也同步过来了,赶紧在本地仓库回滚:

  1. 将merge过来的删除文件的操作,从本地仓库(git commit的地方)回退到暂存区(git add的地方):

    git reset --soft HEAD^
    

    执行以下命令查看暂存区状态,可以看到delete的操作回退到暂存区里了(此时工作区、暂存区的版本是一样的,都是删了文件的,而本地仓库里的已经回退到没删除前的版本)

    git status
    
  2. 把暂存区里的版本撤销,将删除文件操作从暂存区回退到工作区(暂存区的版本不撤销的话,工作区会以暂存区版本为参照基准,否则没办法在第3步将有原始文件的版本覆盖本地)

    git restore --staged .
    

    查看工作区状态,会发现delete操作只存在于工作区了,暂存区内容为空。

    git status
    
  3. 删除了文件的版本已经从完全撤销了,最新的版本是没有删除文件的版本,将最新版本的内容覆盖工作区,文件就回到工作区了:

    git restore .
    
  4. 以上步骤只是操作本地的仓库,还要把回滚的操作同步到远程仓库,让远程仓库也恢复该文件:

    # 因为要推送的版本比远程仓库的版本旧,所以要强推
    git push --force
    

将A、B仓库进行合并

合并前准备:

  • 在A仓库主分支中,创建一个a_code的文件夹,并将所有代码文件转移到该目录下(隐藏的.git文件夹不要移),然后修改同步到远端。该a_code目录用来合并到B仓库中,避免A和B的代码会混一块。

合并:

  1. 先克隆B仓库到本地,并切换到B仓库目录下:

    git clone [b_url]
    
  2. 在本地的B仓库中,添加A远程仓库地址作为B仓库的远程仓库之一:

    git remote add a_origin [a_url]
    
  3. 将A仓库的内容,拉取到B的本地仓库中缓存起来,此时A已经被认为是B的一部分了:

    git fetch a_origin
    
  4. 在B仓库初始化一个新分支,并以A仓库的master主分支为来源(上一步把A并入B的本地仓库了):

    # 相当于把A仓库的主分支嫁接到B仓库的新分支上
    git checkout -b for_a_branch a_origin/master
    
  5. 检查有哪些分支:

    git branch
    # master for_a_branch
    
  6. 为了稳妥,在新创建的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
    
  7. 合并成功后,切回master主分支,把for_a_branch分支的代码合并过来:

    git checkout master
    git merge for_a_branch
    
  8. 最后,把master分支的代码推送到远端即可,本地的for_a_branch分支无需推送,直接删除本地整个库,重新拉取远端的即可(前提是先看看远端推送成功没有)。

    git push
    

到这里已经成功了!

其它git命令

  • 如果当前工作区分支和要推送到的远程分支命名不一样,是无法推送的

    # 将当前所在的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
    

你可能感兴趣的:(git)