git实战网站:https://learngitbranching.js.org/?locale=zh_CN(闯关型的,比较有趣)
廖雪峰的官方网站:https://www.liaoxuefeng.com/wiki/896043488029600(比较容易理解)
工作区(Working Directory)
就是你在电脑里能看到的目录,比如我的learngit文件夹就是一个工作区:
版本库(Repository)
工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库。
Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD。
//两行命令都可以
git reset <file> [好像只能用于撤销被修改的文件的add,被删除的文件尝试失败]
git restore --staged <file>
要在 commit(提交)之前撤销 git add,运行 git reset 或 git reset 取消所有更改即可。
在旧版本的 Git 中,以上两个命令分别是 git reset HEAD 和 git reset HEAD。Git 1.8.2 做了更新。
git checkout <file>
git checkout -- <file>
当文件是修改的状态:
命令git checkout readme.txt
意思就是,把readme.txt文件在工作区的修改全部撤销,这里有两种情况:
一种是readme.txt自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;
一种是readme.txt已经添加到暂存区后,又作了修改,现在,撤销修改就回到和添加到暂存区后的状态。
总之,就是让这个文件回到最近一次git commit或git add时的状态。
当文件是删除的状态:
应用场景:当我们误删了一些文件时,可以通过下面的操作将误删的文件恢复
//首先要保证被删的文件没有在暂存区【使用git status查看】
//如果在暂存区的话,使用撤销add命令先撤销
//之后再使用git checkout
的命令将文件恢复
git checkout其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。
注意:从来没有被添加到版本库就被删除的文件,是无法恢复的!
能够修改最近一次commit没有push的提交记录的内容和文件名【前提是你需要修改的都添加到暂存区了,也就是add了】,最后这两次提交只会有一个提交,也就是后提交的那次
应用场景:你最近的一次提交名字起错了,或者说内容少了或者有错误,又不想提交两次,想合并为一次,就可以使用此命令,注意,只能对最近一次提交进行操作
git commit --amend -m"内容"
可以比较简洁的看git commit记录
git reset --hard HEAD~
将commit提交回退到上一个版本,当前版本保存的内容在工作区和暂存区以及版本库都不复存在,
如果想要再回到当前版本,在git操作页面没有关闭的情况,git reset --hard <当前版本的哈希值>
就可以回到当前的版本。或者说使用git reflog命令,Git提供了一个命令git reflog
用来记录你的每一次命令,commit id
git reset --soft HEAD~
同样是回退到上一个版本,但是工作内容会保留,并且当前版本的内容会放进暂存区。
比如现在是提交1(新增A类),提交11(新增B类),当前工作区还创建了C类和已经加入暂存区的D类,现在要将目前最新的提交记录提交11回退到提交1的话,使用上面的命令,暂存区会存在原先就存在的D类以及这次被回退的提交11的B类,其他不变。
git reset HEAD~
git reset --mixed HEAD~
也是回退到上一个版本,保留工作目录,并清空暂存区(清空的意思不是都没了,而是将暂存区的文件都放进了工作目录,同理,被回退的版本里面进行的修改也会放进工作目录)
总结:工作目录的修改、暂存区的内容以及由 reset 所导致的新的文件差异,都会被放进工作目录
一般是对本地commit进行reset操作,因为git reset对远程分支是无效的,撤销远程更改不会分享给别人,此时就需要使用git revert指令了。
撤销记录,并且保留了提交记录,这个命令会生成一个新的提交记录,里面的内容是和需要撤销的提交记录内容相反的操作
执行操作后,进入vim界面,修改提交名为revert …,之后重新push,就可以分享给别人了
对于远程分支记录的回退或者撤销,
git reset --hard 撤销并舍弃版本号之后的提交记录,使用需要谨慎
git revert 撤销,但是保留了提交记录
【创建切换分支】
//创建一个新分支并切换到此分支上
git checkout -b bugFix
【合并分支】
merge
//把local分支合并到remote分支
git merge bugFix
eg:A:3,B:2
将A合并到B,经历2步
1.git checkout B 2.git merge A
此时:A:3,B:5
rebase:
//rebase:变基,变基到main分支
理解:当前所处分支main,变基到其他分支release,会将main分支有,release分支没有的
复制过去,main分支没有,release分支有的,main分支也会拥有
git rebase main
eg:将A分支变基到main分支
1.git checkout A 2.git rebase main【此时B分支拥有A,B两个分支的所有内容】
merge A :是将A合并到当前主分支
rebase A:是变基到A分支,所以是将当前所处分支的内容复制一份到A分支。
可以理解为指针,指向需要操作的分支和具体提交记录
//这里的C1应该指的是C1这个节点的哈希值吧? 是的
git checkout C1
//切换到main分支,并且将HEAD指向main最新提交记录的上一个记录
git checkout main^
//切换到main分支,并且将HEAD指向main最新提交记录向上移动num个的提交记录
//不加num,则表示只向上移动一个
git checkout main~num
//
//将main分支强制修改到当前引用往前移动3个提交记录
git branch -f main HEAD~3
git cherry-pick
当前分支:main
将release分支的C1,C2和bug分支的C3提交记录切过来,可以使用命令
git cherry-pick C1 C2 C3
//整理提交记录,可以对选中的记录进行删除,移动,合并操作
git rebase -i HEAD~num
之前百度了一个应用场景,如果多次相同内容的commit,可以使用这个命令,
进行多条commit的合并,最后只推一条命令到远程,避免污染远端的提交记录,
当前主分支:main
git rebase main bugFix
:将bugFix分支上的提交变基到main分支
相当于:git checkout bugFix git rebase main
两步操作合二为一
这里的main^2不是说上推2个提交记录,而是指第二个父提交。(第一个父提交记录是指合并记录正上方的那个提交记录)
用来向上移动n个提交记录,^则用来选择哪个父节点,两者配合,在提交树上很好的移动【并且支持链式操作】^不加参数时和的作用一样,默认选择第一个父节点
//创建一个新分支bugWork,并且将bugWork引用指向main分支向上一级,第二个父节点,
//再向上移动一个,此时主分支还是没变,还是main
git branch bugWork main^^2^
//切换至one分支,然后将C4 C3 C2 复制一份放在one分支上
git checkout one
git cherry-pick C4 C3 C2
//强制将three分支指向C2节点
git branch -f three C2
这里指的是本地的远程分支。远程分支反映了远程仓库(在你上次和它通信时)的状态,这会有助于你理解本地的工作与公共工作的差别
远程分支有一个特别的属性,在你检出时自动进入分离HEAD状态,Git这么做是出于不能直接在这些分支上进行操作的原因,你必须在别的地方完成你的工作,(更新了远程分支之后)再用远程分享你的工作成果。【本地的远程仓库的远程分支只有在远程仓库中相应的分支更新了以后才会更新】
git pull都用过,也知道是将远程仓库的代码拉下来与本地代码进行合并。让本地分支代码与远程仓库分支代码同步,这里主要讲Git刚刚出来时,使用两步操作完成这一步操作。[后面因为这两步操作使用场景太多,直接出了git pull指令代替之前的两条指令]
//将本地仓库中的远程分支更新成了远程仓库相应分支最新的状态(本地仓库本地分支不会变化)
git fetch
//之后使用rebase或者merge,将本地仓库的远程分支的代码合并到或者变基到本地仓库的主分支
git merge main /git merge origin/main
//git pull默认是merge方式合并,如果需要rebase方式合并,可以加--rebase
git pull git pull --rebase
应用场景
如果你是在一个大的合作团队工作,很可能是main分支被锁定了,需要一些Pull Request流程来合并修改。如果你直接提交(commit)到本地main,然后试图推送(push)修改,就会收到这样类似的信息:![远程服务拒绝]main->main,不允许推送(push)这个分支,你必须使用pull request来更新这个分支。
实际就是公司将main分支设置成保护分支
,自定义了保护的策略,需要另起分支feature提交,指定人审核,审核通过才能将另起的分支feature合并进main。比较严格。
实际操作:
到gitee,找到仓库的分支,将需要设置的分支,自定义规则,比如任何人不可以推送代码,但是指定人合并Pull request。这样子定义后,之后新建一条{Pull Request,将合并分支指向main分支,这样,我们提交时,就可以另起分支来提交了。
//如果是第一次进行提交,本地以及远程不存在其他分支的情况
//在main分支写好了功能,需要push时,另起分支
git checkout -b branch-name
//第一次推送远程的情况,远程不存在其他分支,使用下面的指令新建并推送到origin/branch-name
git push origin branch-name
//第一次提交成功,之后继续开发,又需要进行提交,
//此时可以将main分支的代码变基或者合并到提交的分支,
//git rebase branch-name只是将main有的新分支变基到branch-name分支上,
//但是branch-name分支并没有指向这个新的提交记录,所以还需要下面的步骤,
//使用git merge,就只有一条 git merge main[当前主分支是branch-name]
git rebase branch-name [当前主分支是main]
git checkout branch-name
git rebase main
git push origin branch-name
//创建一个名为test的分支,它跟踪远程分支o/main
git checkout -b test origin/main
//第二种跟踪的方法,foo分支会跟踪o/main,如果当前就在foo分支上,还可以省略foo
git branch -u origin/main foo
//如果git push后面的分支名写详细了,就不会受HEAD所在位置的影响
//如果直接git push,git会根据当前HEAD指向的分支找到跟踪的远程分支,进行提交
//如果指定的远程分支不存在,会先创建之后再推送
git push origin branch-name
//将本地的source分支推送到远程的destination分支
git push origin <source>:<destination>
//获取远程仓库foo分支,放到本地o/foo上
git fetch origin foo
//下载所有提交记录到各个本地远程分支
git fetch
//将远程仓库的A分支下载到本地远程分支B
git fetch origin A :B
//删除远程仓库的foo分支
git push origin :foo
//在本地创建一个新分支bar
git fetch origin :bar
//等效于 git fetch origin foo ;git merge o/foo
git pull origin foo