一直用Mac开发,使用SourceTree比较多,其实终端命令行才是王者呀。Git操作一直是自己的短板,记录一下自己遇到的关于Git的问题.因为常规操作,可能大家都懂,但是遇到问题的时候,可能你就不懂了,因为不好复盘。
问题一. 工具SourceTree开启“强制推送”功能。这个功能还是很有用的,SourceTree默认是没有开启的,需要我们手动去开启。SourceTree在中文语言下,是无法开启强制推送的,我们首先要做的就是更改它的语言为英文,然后再去开启.
1.1 需要注意的是,开启SourceTree的设置不是点击它的右上角的“设置”按钮,而是选中它后,在Mac系统的状态栏点击SourceTree,然后点击设置。它们里面的内容有很大的不一样。
1.2 选择切换为英文后,重启SourceTree
1.3 看到Advanced
1.4 开启强制推送
1.5 开启了过后,在需要的时候就可以勾选“强制推送”的选项
1.6 事实上“强制推送”也可以通过 git push -f
这个命令行进行执行。
强制推送的方式,它会强制将本地分支推送到远程分支,即使远程分支比本地分支更新。这种方式应该谨慎使用,因为它会覆盖远程分支上的所有更改,包括其他人提交的更改。如果你不确定是否要使用此命令,请先备份你的代码。
问题二:sourceTree“重置提交”和“提交回滚”的区别,为何要使用“强制推送”。
我们举一个例子 : 例如我们已经提交了几次代码了,分别是分支提交记录 1、2、3、4,在这种情况下,我们对比“重置提交”和“提交回滚”的区别。
2.1 提交回滚 : 比如我现在提交回滚到2,操作之后你会发现,3和4的操作还是在,1也在。只是将2的操作还原了,1、3、4得到了保留,本地的2被回滚,推送之后,远端的2也被回滚。需要注意的是,3、4的操作可能会引起提交回滚2操作的代码冲突。
2.2 重置到本次提交 : 比如我现在要重置到2这次提交,SourceTree会让你选择几种合并方式,我几次操作都是使用的“强行合并-丢弃所有工作副本改动”,这么一种高风险的操作。此时本地仓库的改动已删掉,没有文件状态,本地仓库和“2”推送之前的版本是一样的,只需要强制推送当前本地仓库到远程即可。 其实,在重置提交成功,没有推送到远端之前,就可以看到你会发现这个时候历史列表显示落后2个版本,而且显示出了2中所有的文件变更,相当于回到当时准备提交的状态,这个时候如果你去push推送是会报错的,SourceTree意思就是需要拉取的,但是如果你去拉取的话,你会发现又还原了,又回到重置之前,这个时候就需要我们问题一进行的设置后,执行强制推送,才能将个人分支远端进行同步更改.
问题三:git reset origin/uat --hard 这个命令是什么意思呢?
这句话是同事帮我处理问题时,执行的一串命令,我进行的一些学习.
3.1 git reset
命令可以重置本地分支。它有三个参数:--soft
、--mixed
和 --hard
,分别表示重置后的状态不同。其中,--hard
参数表示重置后,本地分支的工作区和暂存区都会被清空,所有改动都会被删除,可以将工作区和暂存区都重置到远程分支的状态。
下面是对hard模式的解释.
3.2 git reset origin/uat --hard
: 这句话的意思是,是将本地分支重置到指定的远程分支的状态,并且强制覆盖本地分支的所有改动。
问题四 :如何将本地Git分支重置为远程?
另外一张图片
问题三和问题四综合操作.
我曾经拉取一个分支,就普通的pull rebase一下,各种冲突,解决了冲突照样是下一个冲突,当时很奇怪的是,其他打包分支又是好的,只有这个叫做uat的打包分支有问题,这个叫做uat的打包分支我们一般是用来打包的,不会在上面直接写代码,都是其他分支在往上面合并代码而已.在我的一顿操作下,这个叫uat的本地分支被我搞乱,呼叫我的命令行大神同事帮忙,操作顺序如下:
git rebase --abort
(撤销我刚刚的rebase操作,输入过后,从SourceTree看,该分支回到了我没有做任何操作的时刻,就像checkout一样)git fetch
(从远程获取最新版本到本地,但不会自动merge ; git pull则是会获取所有远程索引并合并到本地分支中来)git reset origin/uat --hard
(将本地分支重置到指定的远程分支的状态,并且强制覆盖本地分支的所有改动。这相当于重置了本地的该分支,还把该分支的最新代码从远端拉取了下来)
执行了上述三个命令后,本地分支同步到了远端的最新代码信息,并且合并到了本地的该分支,该分支又可以和其他分支进行合并了。但是注意的是,合并冲突我们并没有解决,下次正常拉取该分支代码,依然会冲突! 权宜之计吧,我没有想通该冲突的原因,因为冲突很多,我也没有更改过冲突部分的代码,又要离开这个项目了,就没有机会再深究了.
问题五:删除分支
删除分支其实就注意一点,不要把远端的公共分支给删除了,我遇到过这种小伙伴。你删除分支的目的可能是想重置分支,或者想再拉取一次代码?用上面的reset命令就可以啦.
问题六:Git命令行解决冲突的思想和流程
所有合并中冲突而待解决的文件,都会以未合并状态标识出来。 Git 会在有冲突的文件中加入标准的冲突解决标记,这样你可以打开这些包含冲突的文件然后手动解决冲突。
<<<<<<< HEAD
12345678
=======
abcdefg
>>>>>>> dev
=======为分割线,上半部分是HEAD指向的分支的版本的代码(说白了就是你的本地所在分支的代码),下半部分是dev分支所指向的版本的代码(说白了就是从dev分支带过来的代码,这个代码就可以能是其他同事提交上去的,它和你本地的代码冲突了,Git不知道选谁)。
上述的冲突解决方案仅保留了其中一个分支的修改,并且<<<<<<< , ======= , 和 >>>>>>> 这些行需要被完全删除。
修改完成之后需要操作? 这才是我主要想记录的,因为一直使用SourceTree,忘记了Git的初衷.
6.1 解决冲突,修改完文件过后 使用 git add
命令来将其标记为冲突已解决,SourceTree工具也可以标记文件为“冲突已解决”,位置很好找. SourceTree甚至有选项可以让你选择,选择自己分支的还是其他人的代码.
6.2 然后继续rebase操作: git rebase --continue
6.3 一直循环rebase --continue,直到rebase成功.
6.4 最后push.
最后放上一张上面说的SourceTree工具,‘标记已解决’和‘使用他人版本’或者‘使用我的版本解决冲突’的截图.
问题七:HEAD是什么?
Git 中的分支,其实本质上仅仅是个指向 commit 对象的可变指针。git 是如何知道你当前在哪个分支上工作的呢? 答案也很简单,它保存着一个名为 HEAD 的特别指针。在 git 中,它是一个指向你正在工作中的本地分支的指针,可以将 HEAD 想象为当前分支的别名。
所以HEAD指向的版本就是当前的版本,因此Git允许我们在版本的历史之间穿梭,使用命令 git reset -- hard commit_id
这个叫HEAD的指针,指向一个commit id,就算你以为你的HEAD指向的是一个branch,其实底层也是指向的这个branch的最后、也就是最新的那一个commit id.所以我们需要清楚的一点是:HEAD并非只能指向一个branch,它其实可以指向任何一个commit id.
问题八:Flutter 版本如何升级与降级,以及如何用Git降级.
写下这篇文章的时候,我正在从事Flutter的开发工作。顺便记录一下,Flutter如何升级与降级别.
其实Flutter的SDK是通过Git进行管理的,我们也可以通过Git的操作将版本进行回退。
我们只需要找到Flutter老版本对应的commit_id,复制下来,执行下面的git命令就可以了.
git reset --hard '该版本对应的commit_id'
最后再执行一下flutter doctor重新检查安装完毕就行.
问题九:git reset --hard commit_id 是什么意思,有什么用?
git reset --hard b96b56fd057bfff9fd0e52d635f4d50064f5a782
(后面的这段数字与字母的组合是某一次代码提交的commit id): 它的意思是 彻底回退到某个版本,本地的源码也会变为这一次commit版本的内容,撤销的commit中所包含的更改会被冲掉。
比如你想将当前本地代码重置到 commit b96b56fd057bfff9fd0e52d635f4d50064f5a782,
我们就执行下面的命令
git reset --hard b96b56fd057bfff9fd0e52d635f4d50064f5a782
执行成功后,终端会打印这么一句话:
HEAD is now at b96b56f 5_iconeditor
它表示HEAD 已经在这个commit了,你成功了。HEAD的概念请参考问题七,这也是我们在问题八中,对flutter sdk版本回退执行的命令, 它意思是抛弃一切,彻底回退到某个版本.
作用:有一次我合并的时候,我也将分支搞乱了,想重置回去。但是自己最近的一次代码也有一些代码内容不想丢弃,这次代码已经push了,我就可以重置到这次commit了.
这是另外一份资料对它的解释,这里分割线记录一下:
这段命令,可以回退到指定的commitId 所在位置及commitId 以前的代码.
–hard | 清空工作区与缓存区 | 放弃目标版本后所有的修改 |
---|
执行上面的代码 :git reset --hard c4f43a6,代码会回滚到commitId 所在位置及所在位置之前的所有代码。
1、reset是彻底回退到指定的commit版本,该commit后的所有commit都将被清除;而revert仅是撤销指定commit的修改,并不影响后续的commit。
2、reset执行后不会产生记录,revert执行后会产生记录。
问题十 :commit id是什么,有什么用?
在Git中,每个提交都有一个唯一的标识符,称为“commit ID”或“SHA-1哈希值”。这个标识符是由根据提交的计算出来的,可以用来唯一地标识一个提交。
Git commit ID是一个40个字符长的十六进制字符串,它由Git根据提交的内容计算出来。个字符串可以用来唯一地标识一个提交。
如上图,上面就是一次commit的id,长的和短的都是commitid 短的是:不重复情况下的缩写 长的至少32位.其实我们在使用过程中,长的和短的都可以用,git可以根据这个找到唯一对应的那个节点.
问题十一:detached HEAD 游离状态的HEAD
Git 中的 HEAD 可以理解为一个指针,我们可以在命令行中输入 cat .git/HEAD
查看当前 HEAD 指向哪儿,一般它指向当前工作目录所在分支的最新提交。
当使用 git checkout < branch_name>
切换分支时,HEAD 会移动到指定分支。
但是如果使用的是 git checkout < commit id>
,即切换到指定的某一次提交,HEAD 就会处于 detached 状态(游离状态)。
另外一份资料中对产生detached HEAD这种情况的场景进行了描述,我觉得很好,记录一下:
产生detached HEAD 是因为HEAD回到历史commit,然后对文件进行修改导致的,产生了一个没有名称的分支。
比如:
A(HEAD~2)
B(HEAD~)
C(HEAD)
如果使用以下的命令:
git checkout HEAD~
HEAD会回到B commit,如果此时再修改了某些文件,就会产生一个无名的分支,如果使用:git status 就会出现detached HEAD。
当输入git status指令,终端给出如下,出现detached关键字的时候,那么你现在就在游离状态HEAD了.
-
游离状态的HEAD,它已经不指向任何一个分支,而是指向一个commit.所以你到了这种状态就不能进行类似分支的操作(例如:合并),这肯定是操作不了了.
-
网上资料都说在这种情况下,你可以基于这个commit创建一个分支(出现detached HEAD这种状态的时候,终端也会提醒你可以新建一个分支),将需要的更改提交到这个新分支上面,然后再合并过去。完了最后再删除这个新分支即可.
-
你也可以使用类似
git reset --hard xxx
的指令进行版本回退到指定版本(可能在这之前你需要终止本次merge或者rebase),然后再做图谋.
问题十二:其他重要的Git命令
-
git merge --abort
: 终止本次merge,并回到merge前的状态。 -
git rebase --abort
: 撤销或者说终止rebase操作。 -
git checkout 分支名称
: 切换到另一个分支,这将使您的工作树和索引与所选分支的最新提交匹配。如果您想创建一个新分支并切换到该分支,请使用以下命令:git checkout -b 新分支名
。这将创建一个新的分支,并将其指向当前提交。 -
git checkout commit_id
: 切换到另外一个提交。这将使您的工作树和索引与所选提交的状态匹配。如果您想创建一个新分支并切换到该提交,请使用以下命令:git checkout -b 新分支名称 commit_id
。这将创建一个新的分支,并将其指向当前提交。 -
git fetch --all
: 拉取所有远端的最新代码.