git 入门、reset的3种模式、回滚文件、还原文件、变基、merge

git基础知识

盗用网上的一张图,git有工作目录、索引区(也叫暂存区)、历史区,这3个区,一定要记在脑子里,基本上git所有的操作都是操作这3个区。新建一个文件并提交的一般操作是,

  1. 新建文件
  2. git add到索引区
  3. git commit到历史区(添加-a参数会自动提交到索引区,相当于第2步+第3步)

在这里插入图片描述

git reset 有3种模式

git reset 有3种模式,

git reset [--soft | --mixed [-N] | --hard | --merge | --keep] [-q] [<commit>]
git reset –mixed

这是默认的重置方式,重置索引区,保留工作区。
比如,修改了一个文件后,会提示文件被修改了,并提示add提交到索引区或者restore放弃工作目录更改。

 git status
On branch feature1                                                     
Your branch is up to date with 'origin/feature1'.                      
                                                                       
Changes not staged for commit:                                         
  (use "git add <file>..." to update what will be committed)           
  (use "git restore <file>..." to discard changes in working directory)
        modified:   src/main/java/com/example/learnspringboot/LearnspringbootApplication.java
                                                                                             
no changes added to commit (use "git add" and/or "git commit -a")                            


接下来提交到索引区,接着看下状态,会发现有提示,待commit,或者restore索引区。

PS D:\learnspringboot> git add src/main/java/com/example/learnspringboot/LearnspringbootApplication.java
PS D:\learnspringboot> git status
On branch feature1                                 
Your branch is up to date with 'origin/feature1'.  
                                                   
Changes to be committed:                           
  (use "git restore --staged <file>..." to unstage)
        modified:   src/main/java/com/example/learnspringboot/LearnspringbootApplication.java


然后reset(默认是mixed),会重置索引区保留工作目录,所以提示中有Unstaged changes after reset,重置后与提交到索引区之前完全一样。

PS D:\learnspringboot> git reset                                                             
Unstaged changes after reset:                                                    
M       src/main/java/com/example/learnspringboot/LearnspringbootApplication.java
PS D:\learnspringboot> git status
On branch feature1                                                     
Your branch is up to date with 'origin/feature1'.                      
                                                                       
Changes not staged for commit:                                         
  (use "git add <file>..." to update what will be committed)           
  (use "git restore <file>..." to discard changes in working directory)
        modified:   src/main/java/com/example/learnspringboot/LearnspringbootApplication.java

no changes added to commit (use "git add" and/or "git commit -a")

git reset –soft

重置head指向commit,但索引区和工作区都保存,也就是说add后但未commit的和本地工作目录都会保留。这种情况适合,本地工作目录做了更改add或者没add,但现在想回滚到某个版本,并且不想丢弃这些更改,那么就用这种方式。

git reset –hard

重置head指向commit、重置索引区、工作区,如果本地做了变更,add或者没add,最后不想要了,那么就用这种方式。

总结

这3种模式用联想记忆法,比如soft是软的意思,是最软的,重置head指向commit,索引区、工作区都保留;mixed是混合的,那就是中等喽,所以重置索引区,保留工作区;hard是最硬的,重置索引区、工作区;可以看到是包含关系,har包含mixed,mixed包含soft。为什么叫soft?因为它重置的范围最小;为什么叫mixed,因为它是中等,所以重置soft的部分+索引区,为什么是hard?因为重置了mixed部分+工作区。

经常见的问题

  • 新建了文件,但还没git add,想删除,怎么办?
    • 这种情况,因为文件还未纳入索引区,所以直接在磁盘或者ide删除就可以了。
  • 新建了文件,git add了,想彻底删除,怎么办?
    • 根据上图所说,应该是用 git reset --hard或者git reset,重置索引区,然后再物理删除文件就可以了。
  • 新建了文件,commit了,不想要这个文件了,怎么办?
    • 直接删除,然后commit就可以了。

以上问题最关键的在于理解3个工作区(工作目录、索引区、历史区)理解了后,运用之妙存乎一心了。

intellij idea中git操作

还原文件
  • intellij idea中,还原文件,通常是右击git-----Rollback(ctrl+alt+z),通过日志(下方,git----Console)中可以看到使用的命令git -c core.quotepath=false -c log.showSignature=false checkout HEAD -- src/main/java/com/example/learnspringboot/LearnspringbootApplication.java ,它用的checkout,查官方文档
git checkout [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] 
--pathspec-from-file=<file> [--pathspec-file-nul]

Overwrite the contents of the files that match the pathspec. When the (most often a commit) is not given, overwrite working tree with the contents in the index. When the is given, overwrite both the index and the working tree with the contents at the .

这意思就是指定了commit就会用commit版本覆盖索引区和工作目录,如果没指定,则使用索引区覆盖工作区。

  • 用索引区覆盖工作目录
    • git checkout filepath
  • 某个commit节点覆盖索引区和工作目录
    • git checkout commit filepath,比如git checkout HEAD filepath
更新

intellij idea中更新的快捷键是ctrl+T,其实它包含了两个动作,默认的是fetch+merge,可以通过File----settings----Git----Update进行更改,本人更新喜欢rebase,因为提交历史是一条线,更清晰。
在这里插入图片描述

提交(快捷键ctrl+k)

这个没啥好说的。

推送(快捷键ctrl+shift+k)

这个没啥好说的。

stash暂存

比如正在开发中,来了个紧急bug,需要赶紧修复,但当前功能未开发完,commit很可能造成编译错误或者功能错误,我们就想如果有个地方可以暂存下变更就好了,git stash (vt. 藏匿; 隐藏; 存放; 贮藏;)
就是做这个的。右击git-----stash changes,当想恢复的时候,右击git---- unstash changes–apply changes

git rebase vs merge

  • 什么时候该用rebase?
    • rebase就是变基,只要没提交到远程仓库或者提交到了远程仓库,但别人还未基于此开发就可以使用。援引原文

如果你只对不会离开你电脑的提交执行变基,那就不会有事。 如果你对已经推送过的提交执行变基,但别人没有基于它的提交,那么也不会有事。
如果你对已经推送至公用仓库的提交上执行变基命令,并因此丢失了一些别人的开发所基于的提交, 那你就有大麻烦了,你的同事也会因此鄙视你。

  • 举例
    比如,有两个分支experiment分支、master分支,experiment从master中切出来的,分别在两个分支上做了变更,现在要把experiment合并到master上,使用merge通常是这样的,
    在这里插入图片描述

rebase相当于以master为基础,然后重放在experiment分支上做的变更
在这里插入图片描述
可以看到rebase后的master是一条直线,更加清晰,但是rebase有风险,在你们没弄清楚他的作用之前不要轻易使用。

Merge remote-tracking branch ‘origin/feature1’ into feature1

也许你见过如上的合并,这通常发生在更新代码时,它是怎么发生的呢?发生场景

  1. 本地更改了代码commit了,但未push
  2. 其他人也更改这个分支commit了,并push了
  3. 你打算push,push之前先更新了一下,就会出现上述情况。

这是因为分支分叉了,要合并,默认的fetch+merge就会产生上述情况,提交线不清晰,可以设置使用fetch+rebase来避免这个情况,设置方法同上边intellij idea 更新小节。

使用rebase踩过的坑

比如一个master分支,在此基础上,切出了feature1分支,因为feature1分支是多个同事都要开发所以push到了远程,开发过程中,为了保持feature1比较新,要时不时将master的提交合并到feature1上,我就rebase了master,然后intellij idea就提示要update和push可以做,如果update就会莫名其妙的很多冲突。
这是因为feature1已经变基了master,此时再update,相当于本地feature1分支又要reabse 远程feature1(我的update策略设置的rebase),已经rebase了master就没必要再rebase远程feature1了,所以正确的操作方式是变基master后,直接force push覆盖远程分支,因为是force push所以这里要格外小心,好在intellij idea的force push默认是Force-with-lease,(lease vt. 租用,租借),就好像本地租借了远程分支,但不加锁,如果远程有更新则会被拒绝,可以再次选择强制推送,
在这里插入图片描述

基于以上原因所以git官方才推荐了使用变基的场景只要没提交到远程仓库或者提交到了远程仓库,但别人还未基于此开发就可以使用。…

最佳实践

  • 多个人基于同一分支开发时,更新,怎么操作?
    • 设置git pull --rebase,设置方法同上边intellij idea 更新小节,如果不设置默认是git pull --merge
  • 下游分支更新上游分支的最新提交
    • 在下游分支上执行,git rebase 上游分支,如果下游分支有对应远程分支,则force push,注意跟同事协商好,同事全部都push了,由一个人rebase;如果没有对应远程分支,那就没不用这么麻烦了。
  • 上游分支合并下游分支
    • 先执行上一步,然后切换到上游分支执行,git merge 下游分支,这样的提交线是一条直线。

head

git的命令中经常会用到head,可以将head看做一个指针,head指本地的版本库,可以将head替换为远程库,比如origin/master,origin代表一个地址,master是分支。

origin

origin代表远程仓库的地址 ,在config文件中,如
这里写图片描述
也可以通过intellij idea查看,
右击git—manage remotes
在这里插入图片描述

参考

Why am I merging “remote-tracking branch ‘origin/develop’ into develop”?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值