【私人面试题】如果我在面试中问到git, 你又该如何应对?

如果我在面试中问到git,你又该如何应对?

本文从实际工作经验出发,叙述了工作种常见的、和git提交代码相关的场景问题,并从此场景中引申出的4点问题,并记录了这些问题的解决办法。

实际场景

我要开发两个功能A和B,公司目前实行的标准是:

  • 首先切换至main分支(也就是项目的主分支),使用git pull拉最新代码,然后使用git checkout -b feat/A切到开发分支,在feat/A上完成功能A的开发之后,commit然后push到远程仓库中;
  • 然后开始开发B功能,使用git pull拉最新代码,然后使用git checkout -b feat/B切到开发分支,在feat/B上完成功能B的开发之后,commit然后push到远程仓库中。

问题一

在feat/A上提交并推送至远程仓库之后,开始开发B功能,但是这个时候由于粗心,导致没有做切换到main,然后pull,然后checkout -b feat/B,所以此时我依然在feat/A上。开发完B功能之后,不小心commit了,但是没有push到远程仓库,请问此时我该如何做才能弥补错误,使提交符合规范?

我期望的答案

如果新的commit还没有被推送,处理的代价是最小的,按如下的步骤即可解决:

  1. 使用reset将提交内容返回到工作区
  2. stash feat B的内容
  3. 切换至主分支并拉新代码
  4. 创建B分支
  5. 将修改内容放到B分支上
  6. 提交并推送
bash 复制代码
# 使用reset将提交内容返回到工作区
git reset HEAD~
# stash feat B的内容
git stash
# 切换至主分支并拉新代码
git checkout main && git pull
# 创建B分支
git checkout -b feat/B
# 将修改内容放到B分支上
git stash pop
# 提交并推送
git add .
git commit -m "feat: B"
git push origin HEAD

问题二

在feat/A上提交并推送至远程仓库之后,开始开发B功能,但是这个时候由于粗心,导致没有做切换到main,然后pull,然后checkout -b feat/B ,所以此时我依然在feat/A上。开发完B功能之后,不小心commit了,并且push到了远程仓库,请问此时我该如何做才能弥补错误,使提交符合规范?

我期望的答案

如果新的commit已经被推送,处理起来是比较棘手的,但是又可以分成两种情况: 假设错误commit的hash值为:abc123

  • feat/A没有被合并到主分支
    1. 在feat/A上生成一次revert提交记录,覆盖B功能代码
    2. 将revert之后的本地分支推送到远程仓库
    3. 切换至主分支并拉新代码
    4. 创建B分支
    5. 使用cherry-pick将abc123提交记录复制一份到B分支上
    6. 提交并推送
bash 复制代码
# 在feat/A上生成一次revert提交记录,覆盖B功能代码
git revert abc123
# 将revert之后的本地分支推送到远程仓库
git push origin HEAD -f
# 切换至主分支并拉新代码
git checkout main && git pull
# 创建B分支
git checkout -b feat/B
# 使用cherry-pick将abc123提交记录复制一份到B分支上
git cherry-pick abc123
# 提交并推送
git add .
git commit -m "feat: B"
git push origin HEAD
  • feat/A已经被合并到主分支
    1. 回到主分支,拉取最新代码,创建然后切换到一个名为fix/revert-A的分支
    2. 在fix/revert-A分支上使用revert abc123覆盖B功能代码
    3. 将fix/revert-A分支推送到远程仓库并联系组长合并到主分支
    4. 切换至主分支并拉新代码
    5. 创建B分支
    6. 使用cherry-pick将abc123提交记录复制一份到B分支上
    7. 提交并推送
bash 复制代码
# 回到主分支,拉取最新代码,创建然后切换到一个名为fix/revert-A的分支
git checkout main && git pull && git checkout -b fix/revert-A
# 在fix/revert-A分支上使用revert abc123覆盖B功能代码
git revert abc123
# 将fix/revert-A分支推送到远程仓库并联系组长合并到主分支
git add . && git commit -m "fix: revert" && git push origin HEAD
# 切换至主分支并拉新代码
git checkout main && git pull
# 创建B分支
git checkout -b feat/B
# 使用cherry-pick将abc123提交记录复制一份到B分支上
git cherry-pick abc123
# 提交并推送
git add .
git commit -m "feat: B"
git push origin HEAD

问题三

使用revert之后,导致feat/A中commit记录多了一次revert记录,我不想要这个revert记录,如何使其消失?

我期望的答案

这属于问题二的第一种情况,只需在执行``之前rebase一下,将revert记录抹平即可: 假设在feat/A上正常提交A功能产生的commit的记录的hash值为:xyz456

bash 复制代码
# 在feat/A上生成一次revert提交记录,覆盖B功能代码
git revert abc123
# 使用rebase抹平此次revert记录
git log # 找到xyz456
git rebase -i xyz456^ # 表示将xyz456这个commit之后的提交合成一个
# 根据自己的需要填表,保存,关闭;其实就是把自己不想要的commit前面的pick改成fixup

# 将revert之后的本地分支推送到远程仓库
git push origin HEAD -f
# 切换至主分支并拉新代码
git checkout main && git pull
# 创建B分支
git checkout -b feat/B
# 使用cherry-pick将abc123提交记录复制一份到B分支上
git cherry-pick abc123
# 提交并推送
git add .
git commit -m "feat: B"
git push origin HEAD

问题四

刚才提到了rebase,请问rebase和merge的区别是什么,使用时机有什么不同?

我期望的答案

  • 使用merge合并代码,会保留开发分支上的提交记录,这有利于之后定位问题和改bug;
  • 使用rebase不是commit记录的引用,而是对改动的复制,这样的方式不会保留分支上的提交记录;
  • 使用merge的缺点是会产生非常多的无用的提交日志;而使用rebase则恰好相反,没有足够多的提交信息;
  • 正如上面三个问题所述,在开发分支上使用rebase合并了自己不想要别人看到的revert提交记录,而合并到主分支main上的时候,总是以merge的方式;
  • 于是rebase主要用在私有分支内部,而merge主要用在私有分支向主分支合并的时候;
  • 总之,不论是使用merge还是rebase,核心依据是为了方便其他开发者,当然这也是为了方便自己。

最后

这就是我平时工作中遇到的问题,以及我希望我的同事在遇到这些问题之后的处理方式,并且我会把这个当成面试题积累下来,那么您有没有更好的做法呢?欢迎留言和吐槽~

相关推荐
真的很上进9 小时前
【Git必看系列】—— Git巨好用的神器之git stash篇
java·前端·javascript·数据结构·git·react.js
小小安于乱10 小时前
git 更换远程地址的方法
git
高林雨露13 小时前
git 空项目初次提交项目命令记录
git
liu83418944714 小时前
git 本地分支误删,怎么恢复?误删本地已提交未推送的分支!
git
+码农快讯+14 小时前
Git clone远程仓库没有其他分支的问题
git
多恩Stone15 小时前
【Hugging Face 下载中断】Git LFS 如何下载指定文件、单个文件夹?
git·stable diffusion·huggingface·diffusers
佚明zj16 小时前
如何配置ssh key 到gitlab, 实现git push
git·ssh·gitlab
半糖112216 小时前
git配置SSH
git·ssh
橘色的喵20 小时前
git 如何基于某个分支rebase?
git·rebase
未来可期LJ20 小时前
【Git 操作】Git 的基本操作
git