git常见指令

230 阅读7分钟

git常见指令

1. stash

官方解释:当您想记录工作目录和索引的当前状态,但又想返回一个干净的工作目录时,请使用git stash。该命令将保存本地修改,并恢复工作目录以匹配头部提交。

应用场景:你正在 feature 分支进行开发,这个时候你需要紧急切换到master 分支去解决bug,但是因为当前有文件更改了,需要提交commit保持工作区干净才能切分支。由于情况紧急,你只有急忙 commit 上去,commit 信息也随便写了个“暂存代码”,于是该分支提交记录就会显得很不整洁。

# 切换分支前暂存本地修改但未commit的代码,清空工作区
git stash
​
# 修改完后切换回feature分支恢复代码
git stash apply
​
# 保存当前未commit的代码并添加备注
git stash save "备注的内容"# 列出stash的所有记录
git stash list
​
# 删除stash的所有记录
git stash clear
​
# 应用最近一次的stash
git stash apply
​
# 应用最近一次的stash,随后删除该记录
git stash pop# 删除最近的一次stash
git stash drop

当有多条 stash,可以指定操作stash,首先使用stash list 列出所有记录:

$ git stash list
stash@{0}: WIP on ...
stash@{1}: WIP on ...
stash@{2}: On ...

应用第二条记录:

$ git stash apply stash@{1}
$ git stash apply pop@{1} # 应用指定的stash,随后删除该记录
$ git stash apply drop@{1} # 删除指定的stash记录

stash在 vscode 图形化界面实际上就是暂存代码,暂存的代码会在暂存区,在STASHES菜单中可以看到保存的stash

1.1 add和stash的区别与联系

git add 只是把文件加到 git 版本控制里,并不等于就被 stash 起来了,git add 和 git stash 没有必然关系,但是执行 git stash 能正确存储的前提是文件必须在 git 版本控制中才行。

常规 git stash 的一个限制是它会一下暂存所有的文件。有时,只备份某些文件更为方便,让另外一些与代码库保持一致。一个非常有用的技巧,用来备份部分文件:
  1. add 那些你不想备份的文件。
  2. 调用 git stash –keep-index。只会备份那些没有被 add 的文件。
  3. 调用 git reset 取消已经 add 的文件的备份,继续自己的工作。

2. reset --soft(回退版本)

完全不接触索引文件或工作树(但会像所有模式一样,将头部重置),这会使您的所有更改的文件更改为“要提交的更改”。

回退你已提交的 commit,并将 commit 的修改内容放回到暂存区。

一般我们在使用 reset 命令时,git reset --hard 会被提及的比较多,它能让 commit 记录强制回溯到某一个节点。而 git reset --soft 的作用正如其名,--soft (柔软的) 除了回溯节点外,还会保留节点的修改内容。

还未 push 的commit可以通过git reset --soft回退,对于已经 push 的 commit,也可以使用该命令,不过再次 push 时,由于远程分支和本地分支有差异,需要强制推送 git push -f 来覆盖被 reset 的 commit。

还有一点需要注意,在 reset --soft 指定 commitId时,会将该 commit 到最近一次 commit 的所有修改内容全部恢复,而不是只针对该 commit。

3. cherry-pick

描述:给定一个或多个现有提交,应用每个提交引入的更改,为每个提交记录一个新的提交。这需要您的工作树清洁(没有从头提交的修改)。即将已经提交的 commit,复制出新的 commit 应用到分支里

应用场景:开发分支中的代码记录被污染,导致开发分支合到线上分支有问题,这时需要新建一条开发分支,再从旧的开发分支中,把 commit 复制到新分支。

使用:

3.1 单个复制

现在有一条feature分支,通过commit log查看提交记录,需要把 某条记录(称之为a)复制到另一个分支,首先把 commitId 复制下来,然后切到 master 分支。

$ git cherry-pick commitId

再次使用命令git log查看提交记录可以看到master分支下的最新提交记录已经变成了记录a

3.2 多个复制
git cherry-pick commit1 commit2
3.3 连续区间复制
# 多个连续的commit,可区间复制,复制从commit1到commitN之间的所有提交,其中commit1是最早的提交
git cherry-pick commit1^..commitN
代码冲突
  1. cherry-pick 多个commit时,可能会遇到代码冲突,这时 cherry-pick 会停下来,让用户决定如何继续操作。
  1. 同时复制a、b、c三个提交,其中b会产生冲突,可以看到 a 被成功复制,当进行到 b时,发现代码冲突,cherry-pick 中断了。这时需要解决代码冲突,重新提交到暂存区。
  2. 然后使用 cherry-pick --continuecherry-pick 继续进行下去。最后 e 也被复制进来,整个流程就完成了。

放弃 cherry-pick

gits cherry-pick --abort # 回到操作前的样子,就像什么都没发生过。

退出 cherry-pick

git cherry-pick --quit # 不回到操作前的样子。即保留已经 `cherry-pick` 成功的 commit,并退出 `cherry-pick` 流程。

4. revert(撤销提交)

描述:将现有的提交还原,恢复提交的内容,并生成一条还原记录。(撤销提交)

4.1 revert 普通提交

git log查看提交记录

git revert <commitHash>

因为 revert 会生成一条新的提交记录,这时会让你编辑提交信息,编辑完后 :wq 保存退出就好了。

再来看下最新的 log,生成了一条 revert 记录,虽然自己之前的提交记录还是会保留着,但你修改的代码内容已经被撤回了。

4.2 revert 合并提交

在官方文档中有解释:

通常无法 revert 合并,因为您不知道合并的哪一侧应被视为主线。此选项指定主线的父编号(从1开始),并允许 revert 反转相对于指定父编号的更改

git revert -m 1 <commitHash>

revert 合并提交后,再次合并分支会失效

还是上面的场景,在 master 分支 revert 合并提交后,然后切到 feature 分支修复好 bug,再合并到 master 分支时,会发现之前被 revert 的修改内容没有重新合并进来。

因为使用 revert 后, feature 分支的 commit 还是会保留在 master 分支的记录中,当你再次合并进去时,git 判断有相同的 commitHash,就忽略了相关 commit 修改的内容。

这时就需要 revert 掉之前 revert 的合并提交。(即撤销掉之前“revert合并提交”的操作)

5. reflog

如果说 reset --soft 是后悔药,那 reflog 就是强力后悔药。它记录了所有的 commit 操作记录,便于错误操作后找回记录。

应用场景:某天你眼花,发现自己在其他人分支提交了代码还推到远程分支,这时因为分支只有你的最新提交,就想着使用 reset --hard,结果紧张不小心记错了 commitHash,reset 过头,把同事的 commit 搞没了。没办法,reset --hard 是强制回退的,找不到 commitHash 了,只能让同事从本地分支再推一次(同事瞬间拳头就硬了,怎么又是你)。于是,你的技术形象又一落千丈。

例如你错误地reset了一个旧的提交,或者rebase,…,这个时候你可以使用reflog去查看在误操作之前的信息,并且使用git reset --hard 去恢复之前的状态。

设置 Git 短命令

方式一

git config --global alias.ps push

方式二

打开全局配置文件

vim ~/.gitconfig

写入内容

[alias] 
        co = checkout
        ps = push
        pl = pull
        mer = merge --no-ff
        cp = cherry-pick

使用

# 等同于 git cherry-pick <commitHash>
git cp <commitHash>

7. rebase(变基)

git checkout feature
git rebase master
​
//这两条命令等价于git rebase master feature

在这里插入图片描述

master分支: A->B->M

feature分支: A->B->C->D

master分支的使用者将M提交并合并到主干上,然后feature分支的使用者将C、D提交并合并,这一步实际上是将C、D复制后删除,将复制后的C‘、D’接到主干的最新提交M上面,他们的提交内容一样,但commit id不同。feature自然最后也是指向D’。(注意,如果master上在B以后没有新提交,那么就还是用原来的B作为基,rebase操作相当于无效,此时和git merge就基本没区别了,差异只在于git merge会多一条记录Merge操作的提交记录)

ps:feature和master分支最开始的基底都是B