由于昨天码云宕机,今天要提交代码。
刚才进行了如下操作:

如果直接 pull merge 的话提示没有冲突
使用 pull --rebase 以后有冲突,但是发现前两天的本地提交都没了。。。这种时候还能找回吗?

这两天遇到好几个非正常的 git 问题,都蒙了

git clone 远程分支到一个新文件夹,然后把旧文件夹里修改的代码手动复制粘贴进新文件夹。最后使用新文件夹继续开发,旧文件夹删了。

直接 push 的问题是?

你领先远程分支就是因为你有开发啊. 最终都是要 push 到远端的.

#2
push 之前不都是先 pull 的吗?不知道这次为什么 pull rebase 以后本地的代码也没了。rebase 不是会生成新的 commit 吗?

#1
您这个是一个好办法,如果代码改动太多的话应该也不小工作量吧。有没有更好的办法呢?

  1. 如果是多人开发,你 push -f 。恰好团队没人做分支管理,你会被骂得很惨。
  2. 一般来说,你应该先 git pull 你现在所在的分支(例如 dev )。 如果你是单人开发,那么一般不会报错。不报错就 commit ,push 到远端。
    2.1 pull 出错了,这时候说明远端和你本地存在修改同一个文件的问题。这时候有几种做法。这里只介绍我的分支做法
    2.2 将当前本地开发好的代码,commit 到一个新的分支。如:dev-20220809 。然后切回远端的分支。pull 一次最新代码。
    2.3 在当前的远端分支,再开一个 dev-test-merge 分支并切换过去。然后合并 dev-20220809 ,看看有没有报错。
    2.4 由于不清楚你的分支管理策略,一般来说,没啥问题,我就 dev 和 dev-20220809 合并,然后推送到远端的 dev 分支.
  3. 这时候其他人 pull dev 分支,也得到你的代码了。

2.3.1 补充一点。你 pull 报错的话,你在做 dev-test-merge 和 dev-20220809 合并,有一定可能会提示冲突。这时候你要手动合并代码并解决冲突。也可能 git 帮你合并了同一个文件了。

所以最好从开始就只有你一个人用这个分支。如果需要合作,另外搞一个公共分支。不要几个人在一个分支上直接干活儿。

#5
pull merge 没冲突,pull rebase 有冲突,这是为啥啊。
您说的这种新建分支再合过去我觉得是合理的,也好理解。

#7
我们都是 dev 开发,然后每个人都有自己的 dev-xx 分支,然后去往 dev 合,就很乱。。。

合代码不是应该通过 merge request 吗

push --force ,你是想死吗。你的 1 和 2 都可以,2 并不是本地提交没了,而是因为冲突(本地和远程改了同一个地方),需要你先解决冲突。新手的话,还是老老实实 pull merge 吧。

git fetch remote-branch
fit checkout -b local-branch remote-branch
然后慢慢 cherry-pick

第二种情况你的本地提交应该是还在的,如果你不想解决冲突的话,用 git rebase --abort 来中止 rebase 。

如果你不清楚底层发生了什么。就不要用 cherry pick, rebase 。
如果你不清楚同事的身手脾气。就永远不要--force, --hard 。

common -> remote-1 -> remote-2 -> ... remote-branches
|-> local-1 -> local-2 -> ... local-branches
你的这种情况,merge 没冲突,rebase 有冲突,我猜测是 common 后面的前几个本地分支有冲突,后面改过之后没有冲突了,但是 rebase 的时候,git 从 common 一个 commit 一个 commit 比较过去,在前面就发生了冲突。

如果你的本地分支落后的几个 commit 不重要的话,直接 reset --soft 到本地 common commit ,再 rebase ,就不会有冲突了

#9
同一个分支的本地和远程

#10
push --force 是因为远程分支被回滚了,落后了本地分支。用 2 以后本地的提交好多都没了

#12
他们已经解决完冲突 commit 了,所以没法 abort 了,git log 也没找到前几天的本地 commit

#13
rebase 教程都是合并分支时候,这种远程分支落后的情况下 pull rebase 我确实是蒙了

#14
不明白为啥 pull rebase 会丢掉本地的 commit ,rebase 不是会生成新的 commit 吗

#15 远程分支被回滚,说明远程分支已经被破坏了,这时候就不能做任何 pull ,否则你本地也要跟着被破坏。远程分支回滚后的那个 Head ,它之后的(在回滚前)所有提交,不管是本地的还是远程的,都被搞废了。你们本地需要先留着当前仓库不动,另开位置重新 clone ,然后通过补丁或者复制粘贴,把本地晚于远程 Head 的提交,手动重新提交上去。当然,也可以用 pull --rebase ,它本质上是 rebase -i ,前提是已经对 git 操作尤其是 rebase 相当熟练。

#18 先 fetch ,你现在本地仓库上的远程仓库引用 origin/master 跟真是的远程仓库 master 分支可能都不一样。这事,建议找熟手帮你做。没有话就别 pull 了,只能手动复制粘贴。

where gupav
gupav: aliased to git pull --rebase --autostash -v

对远程分支进行 git push --force 是一定要沟通过的。沟通不是说在 v 站上发贴。

比较保守和简单的操作其实是选一个基准,在本地新建一个分支出来。然后把本地修改过分支和远程分支需要的 commits 都用 cherry-pick 挑出来。

OP 另一个找回的需求,如果 rebase 已经完成,也可以用 git reflog

这种略看一下介绍 git 实现文章,就能自己处理的。

所以说能别用 rebase 就别用 rebase 。要用的话记住一定不要在分支在远端存在的情况下 rebase 。一定不要去 rebase 公共分支

#19
「远程分支回滚后的那个 Head ,它之后的(在回滚前)所有提交,不管是本地的还是远程的,都被搞废了」
远程的被破坏我能理解,为什么说本地的也被破坏了呢?

「你现在本地仓库上的远程仓库引用 origin/master 跟真是的远程仓库 master 分支可能都不一样」
仓库地址我没有改过,为什么 还能不一样呢?

请大佬解惑

#23
以前公共分支拉的时候都 rebase 成一条直线了,这次弄了以后不敢 rebase 了,可是 merge 的话也太乱了吧

Main(主),beta(测), Debug(紧急)。
主叉永远只在测试之后合并,所有人都在 beta 上面拉分叉,debug 叉跟着 main 走。、
各自叉自己 ID 在 beta 上面的叉,各自开发延申,完结了一起合并审查代码。

#26
我们现在是 dev ,每个人都从 dev 拉分支最后再合过去。

pull 是拉线上分支之后再 merge ,当然会丢掉你先前的东西。

解决完冲突后你们有没有 git rebase --continue ,让 rebase 继续走完呢

git pull --rebase ,发现 commit 没了,不要着急,git reflogs 看一下,一般能恢复的。

个人认为,merge 记录也是有价值的记录,对于版本控制系统来说,为了“整洁”而放弃一些版本记录是本末倒置。

实在想用 rebase 来整理提交记录也是可以的,但最好在所要整理的 commit 被 push 之前。

万不得已要用 push --force 必须召集 repo 的所有使用者协商一致。

你试试 git fetch 之后直接 rebase ,不报错就是 bug 。

git pull --rebase origin xxxx ,然后看有没有冲突,有的话解决了就 git add xxx && git rebase --continue ,一步步地去把冲突解决掉

#24 假如远程 master 的 提交顺序是 a,b,c,d,e,f,g ,被回滚到了 d ,变成了 a,b,c,d,e,f,g 。这时候 d 之后的提交 e,f,g 就都丢失了。然后丢失的不光是这些,因为这个 e,f,g 在做过 pull 的所有人的本地还是存在的,这时候这些人本地上的 master 分支,跟远程的 master 分支,是混淆的。

实际上中央服务器被回滚,相当于有人做了 push --force ,是特么相当操蛋的行为。这时候要是有人正好在服务器出问题前做过 pull 还好,他那里再做一次 push --force 就能恢复过来。但要是没有这种正好情况,那么在 d 这个提交时间点之后的所有提交,不管是本地还是中央仓库,不管有没有推送过,都成了离线的提交,需要手动处理才能搞回去。

#29
他们当时应该是已经 continue 了,找我去看的时候已经有 rebase 的 commit 了

#34
所以说远程分支落后本地的话,直接拿本地的代码 push --force 就行了吗?然后别的人再 pull 后解决自己的冲突再 push 就可以了?

不是,我的意思是,如果你本地 commit 不重要的话,直接把本地有分歧的 commit 都 soft reset 掉,然后再 rebase ,应该就没有冲突了(因为你说你 merge 的时候是没冲突的

你这一块,我建议不要自己搞了,搞不定的,还是先找别人帮你处理了。后面有时间了花上半个月去看看 git-scm.com/book/zh/v2 ,git 才能入门。

#36 不是直接 push --force ,是先要确定那个人本地的仓库跟回滚前服务器上仓库是同步过的,才能让那个人 push --force 以覆盖的方式恢复服务器上已经被破坏的仓库。

#37
是,我搞不清楚为啥 pull merge 没冲突 pull rebase 有

#39
最后是找的本地最新的人把代码推上去的,有没有先拉再推,有没有强制推,他们现在也不记得了。。。

rebase 有冲突应该就是远端分支对应你本地分支检出的时候已经发生了改变,rebase 会从你本地分支检出远程的地方开始检查,之后本地提交修改的地方都会提示冲突,这时候应该在一个分离的 head 上,中断 rebase 本地提交就回来了啊,至少我以前是遇到过类似的 rebase 冲突的情况的

默认情况下 git server 不是应该会禁止 force push 吗

你的提交是不是有多个 commits ?如果 merge 的话是用最后一个 commit 去 merge ,rebase 的话从最早的一个 commit 开始 rebase 。所以冲突结果可能不一样。

另外可以使用:fetch -> rebase -> push 的流程,远端禁止 force push 。

#41
他们是解决冲突完了已经并且 commit 了

git pull --rebase

#43
「如果 merge 的话是用最后一个 commit 去 merge ,rebase 的话从最早的一个 commit 开始 rebase 。所以冲突结果可能不一样。」
那我大概知道为啥 merge 没冲突但是 rebase 有冲突了。

我平常都是 pull rebase ,没怎么用过 fetch

#45
今天就是这么搞的,然后本地的 commit 好像丢了(他们说本来要推 20+ 的 commit 都没了

fetch 的话是只同步远端,并不尝试合并本地的 commits 。这样更加安全一些。总之不能 force 。

#48
要不是这事故,一般也不会碰到远端分支回滚

可以先 git stash 然后 git pull --rebase 最后 git stash pop

是不是你之前这个 20+commit 已经是之前 push 过的了?如果是,大概率是前一个人解决冲突的时候在相同的代码位置选择使用了他的代码(旧的),对于 git 来说这块代码 head 已经是最新的了,即使你本地(新的)和远程的不一致,git 也会认为远程的是最新的

git pull --rebase 如果有冲突,可能会卡在 rebase 中,需要手动处理完冲突然后git rebase --continue继续处理下一个提交。
merge 没冲突而 rebase 有冲突很好理解,因为 merge 是把改动直接放回分支,生成一个新提交,而 rebase 是需要先把分支上的改动合并,然后再把本地修改 apply 上,分支上的改动可能引起本地修改不正确了,需要手动调整本地修改。
如果本地 git 搞乱了,可以用 git reflog 命令检查本地操作历史,一般可以找回所有 commit 。

原来这么多人不会 rebase

我发现一个疑问就是为啥都那么喜欢用 rebase ?多一个 merge 又能咋样....

rebase 主要是保持分支的的线性,不是多一个提交这么简单。

少。。

8
rebase 我记得是把别人放在主分支的东西合并进来?可能你俩修改了同一个文件?我是小白瞎猜的

git pull --rebase 本地代码没了应该是你代码冲突了,然后进入解决冲突流程你没注意(然后就停在第一个解决冲突的本地 commit 那里了)。可以考虑直接 git rebase --abort,不行 git reflog 看历史找下最新本地 commit 的提交然后 reset --hard 回去重新搞。
不知道你本地写了多少个提交,rebase 解冲突比较烦,要把本地 commit 从开始冲突的提交起一个接一个都处理了。

丢东西的时候 git reflog 就行了

rebase 是把你的 dev 本地修改变基到远程的 dev 分支上,不会导致代码丢失的。如果是新文件不可能,旧文件修改的话,应该是 OP 解决冲突出问题了。
一般我建议在 dev 上更新代码也是用 rebase ,避免产生一个无谓的 merge commit 。
当然,操作都可以用 reflog 找回来

本地提交你用 git log 看? git log 又看不了。
pull rebase 是正常操作,pull merge 才是作大死。上面甚至有个建议日常作死的大佬我也是服气。
如果你实在想要锻炼自己去用这扭曲的命令行,那也最好先装个 GUI ,像这样不知所措的情况至少 GUI 能正确显示仓库当前的状态。

merge 可以把不正确的仓库改动隐藏在 merge commit 里。

比如你把 master 合并到 feature 上的时候产生了冲突,一顿解决以后合并成功了,然后过几天你把 feature 合并回 master ,结果 master 上某些功能不见了。然而你回溯回去却根本不知道是哪里出了问题。因为 merge commit 里可能会包含任何更改,不仅仅是 master 的更改,也可能是 master 覆盖 feature 后又被手动改回来的更改,甚至还可能包含既不在 master 也不在 feature 上的更改。因为 merge commit 本身就非常大,不可能单独检查,这种操作就等于是在代码提交历史里埋炸弹。

或者换句话说,这种 merge 就相当于把 feature 和 master 的提交揉在一起。不出事我才觉得奇怪。

这种 merge 出问题一般不见得那么麻烦,因为正常人都是遇到很少的 conflict 马上能处理完才会去耐心直接在 merge commit 上改(否则改了一半又有人提交就犯二了),而且 commit 本身不见得就很大。只是做了任何不能自动解决的操作都应该在 commit message 里说清楚。这样真有问题,大不了直接拎过 parents 手动重现。其实效果就是相当于把之前某个 parent 的最近的 commit 给 squash 上来了,如果改动直观到是个人就能看懂就无所谓,反正这种 merge 本来就得人工验证而不可能全自动化。反过来,有时候能自动解决的反而可能是错的,这是更坑的炸弹。
要是真是遇上脑子不大正常的,那就得拖过来教育扣工时了。

就怕有人心大直接在 merge conflict 上瞎基尔改,改完一交,神不知鬼不觉。
squash 完如果有 PR code review 的话倒还好,做个 diff 至少能看到改了点啥,但是像楼主的 team 这样愉快地打算 push -f 的就……

原则上像样的项目所有有实质改动的 commit 都最好走 pr 有别人 review ,再缺人那也得至少涵盖涉及不同 owner 的多个 branch 的 merge ,否则一旦出问题,锅就只能是 merge 的人背了,那就有点……活该了。
横竖都是一个人的项目锅都会自己背(虽说不该有并发提交的冲突),不过这种时候一旦吃亏就很容易长记性。
至于没搞清在干什么就敢 push -f (或者说,就敢允许非仓库配置管理员 push -f ),那是整个 team 在另一个次元意义上的活该(尤其是掉 commit )了。

为啥不用 push --force? 我经常这样用一点问题也没有.

你是认真的吗?
去学下 pull push rebase checkout log diff 这几个命令吧,有冲突解决好冲突,master 分支不要 push -f ,开发分支可以在 rebase master 之后 push -f 使提交好看。针对你的问题,merge 是把远程当前状态合并到本地当前状态,而 rebase 是在远程当前状态上一条条写本地新提交,所以出冲突的概率比较大,可以两个方法都用,然后 git diff 检查冲突解决得是否 OK 。

你一个人开发用 push -f 无所谓,但是多人共同开发,对公共分支 push -f 就可能影响别人,所以最好是主干分支禁止 push ,开发分支在开发阶段要追新就 merge master ,开发好以后要合并代码 rebase master 再 push -f ,然后提一个开发分支到 master 分支的合并请求。

本地有提交 先 git rebase , 合并远程代码。 再 push 就行了。

一个 force push 可能会搞挂整个团队,所以不要给普通开发人员开放 force push 权限

#62 ,个人感觉这种坑即使使用了 rebase 依旧没办法避免啊?也没有在 message 里面说明改动情况吗?

这种问题不应该从提交、分工这边就把所有隐患都处理掉吗,特别是谁都有权限操作 master 的时候。

我都是先把本地 dev 分支更新到最新 develop pull
再 rebase develop --> feature_xxx 个人功能分支
再 merge feature_xxx --> develop
最后 push develop

rebase 的时候解决冲突就行了

你这种情况还是 pull 完了 merge ,然后再 push 吧。

你就不能对下 commit id? 钓鱼?

「本地分支领先远程分支」这个不是很正常的情况吗?不知道是不是描述不准确。

如果本地分支和远程分支在一条线上

  • 本地分支领先远程分支:那说明这个分支只有你的修改,完全不会有冲突,git push 就能把本地代码推到远程;
  • 远程分支领先本地分支,那说明这个分支只有别人的修改,完全不会有冲突,git pull 就能把远程分支的改动拉到本地

如果本地分支和原创分支分叉,那说明你和其他人都进行了修改,并且别人已经把改动推到了远程。

  • git pull 是把本地分支和远程分支做 merge
  • git pull --rebase 是把本地分支 rebase 到远程分支

也有其他的处理方式,不过如果有冲突那不管哪种方式都是要处理冲突的

rebase 以后 master 的变更和个人的变更是分开的,不会像 merge commit 那样既有 master 的变更,又有个人偷偷塞进去的变更。

我感觉码云那边在 bare 里面做个 gc 就好了
至于本地可以复制一份,然后 rebase 解冲突
如果缺少的话就 cherry-pick
丢东西可能性不大

要是人少,可以线下协同,force 也不是不行

我是认真的。当我是一个刚学会 git 几天的新手时,搞不清提交、冲突、变基这些复杂概念,也不知道怎么解决冲突时,显然,复制粘贴是一个简单又易行的解决方案。

建议使用 rebase -i 这样就能知道哪些 commit 会被 rebase
养成良好习惯😃

本地领先远程分支很正常呀,git pull 如果有冲突,可以先 git stash ,然后再 git stash pop

这个是一个典型场景 适合 git pull rebase (git pull origin branch-name --rebase)
stackoverflow.com/questions/2472254/when-should-i-use-git-pull-rebase/28472221#28472221
在这个场景里:两个人基于同一个分支 (记作 base 分支) 各自开了两条分支,然后两个人先后从自己的分支呢 merge 回 base 分支。在第二个人试图 merge 回 base 分支的时候 因为发现了 base 分支的改变, 所以在自己分支呢执行了 pull rebase
在如上情况里 pull rebase 是不会有冲突的。这也是人们根据自己的一套分支安排办法所期待的

lz 说的这个情况里 在 pull rebase 里遇到了冲突,显然情况要更复杂一些 (why? 我认为是分支规划问题, 可能我是错的)。如果是我 我会通过(早些时候)合理安排分支来规避这个问题(而非在现在时候试图解决这个问题),比如 在安排分支的时候,就直接 ... 创建一条分支来"保护"另一条分支 ... 这样两个分支都相安无事。实际上 这形成了一套分支安排办法

人们期待的 “pull rebase 不会冲突” 的情况正是基于(早些时候)合理安排分支的。收益于一套分支安排办法

分支安排办法 + 分支合并策略是对应的,实际上一套分支安排办法就应该包括分支责任 分支创建 分支合并的所有考量,人们根据自己的情况(项目规模 项目人员 主要想保护哪些分支)来安排,且人们按照之前安排好的做 就不会出问题

#62
其实您说的这种场景我还是没太理解。
我找到一篇说是放弃 cherry pick 改用 merge 的:
devblogs.microsoft.com/oldnewthing/20180312-00/?p=98215

两个都不应该用。你这篇文章里提到的 cherry pick 是更差的做法。