一些常规操作
一、分支操作
1.1、拉取远程的某个分支的几种方式
拉取之前,可以使用git branch -a查看所有分支(或者使用git branch -r 查看所有远程分支)。
- git checkout -b lBranch origin/rBranch 【在本地新建名为 lBranch 的分支,并追踪远程的 rBranch 分支】
- git checkout --t origin/rBranch 【在本地新建名为 rBranch 的分支,并追踪到远程的 rBranch 分支,其中的-t,是 -track 的缩写】
- git fetch之后,git checkout 远程分支
目前来说,我使用的比较多的是最后一种,这种方式可以直接在本地建立一个与远程分支同名的本地分支,并追踪到远程分支
1.2、本地新建分支并提交到远程
git checkout -b feature/my-feature
git push origin feature/my-feature
1.3、删除本地分支并推送到远程
git branch -d feature/my-feature
git push origin --delete feature/my-feature
1.4、分支合并
1.4.1、git merge的三种用法以及缺陷
- git merge branchName【fast-forward 方式】
将当前分支 与 本地 叫“branchName”分支的代码合并(branchName代码合并到当前分支),这种方式下,会将feature所有的commit点加到baseline上,不会额外生成一个merge 的commit点; - git merge --no-ff branchName
将当前分支 与 本地 叫“branchName”分支的代码合并(branchName代码合并到当前分支),并且显示合并细节,这种方式下,会将feature所有的commit点加到baseline上,但会额外生成一个merge 的commit点; - git merge --squash branchName
合并新分支代码时, 只将分支新改动放入暂存区,然后baseline提交一个新的commit点。
两次 squash merge:
git merge 和 git merge --no-ff的区别:
默认情况下,git执行"快进式合并"(fast-farward merge),会直接将master分支指向dev分支。使用–no-ff参数后,会执行正常合并,在master分支上生成一个新节点.
三种方式的缺点:
- fast-forward merge会将所有feature上的commit点完整的呈现在baseline,如果feature上commit非常冗杂,将会导致baseline的commit信息爆炸多
- none-fast-forward merge会丢失merge 信息
- git merge --squash branchName 会将多个压缩点合并成baseline上的一个commit点,且会丢失feature分支上所有的提交信息(提交人变成git仓库的container)
1.4.2、git rebase + git merge方式(仅做了解,日常工作中并未做过rebase操作,目前只知道如果在本地仓库单人时,非常好用,如果多人,需要仓库管理员统一rebase,然后通知所有开发人员,删除该分支,重新拉取,否则会很麻烦)
rebase会把你当前分支的 commit 放到公共分支的最后面,所以叫变基。就好像你从公共分支又重新拉出来这个分支一样。
举个栗子:
以一般的gitflow中feature分支的操作为例子:
全部使用merge方式:
- 从分支master新建两个分支 f1 和 f2。
- f1 修改test.txt文件并提交
- master merge --no-ff f1
- f2 merge --no-ff master
- f2修改test.txt并提交
- master merge --no-ff f2
使用merge+rebase方式:
- 从分支master新建两个分支 f1 和 f2。
- f1 修改test.txt文件并提交
- master merge --no-ff f1
- f2 rebase master
- f2修改test.txt并提交
- master merge --no-ff f2
两种方式相比,明显后者的提交信息更加清爽。
rebase的工作原理可以看下git官方文档:https://git-scm.com/book/zh/v2/Git-%E5%88%86%E6%94%AF-%E5%8F%98%E5%9F%BA
核心原理就是将feature的提交点放在baseline的最后面。
rebase的黄金守则:
绝不要在公共的分支上使用它!
在你运行 git rebase 之前,一定要问问你自己「有没有别人正在这个分支上工作?」。如果答案是肯定的,那就不能rebase
个人理解:只对尚未推送或分享给别人的本地修改执行变基操作清理历史;从不对已推送至别处的提交执行变基操作
git rebase的缺点:
- 安全性,如果你违反了 rebase 黄金法则,重写项目历史可能会给你的协作工作流带来灾难性的影响
- 可跟踪性,rebase 不会有合并提交中附带的信息——你看不到 feature 分支中并入了上游的哪些更改
1.5、撤销提交
由于日常开发中,为了提交方便,一般直接使用idea进行commit操作,而idea会直接将文件提交到暂存区和本地仓库。所以,这里讨论的是,如何把将工作区撤销到某个 commit 点。
1.5.1、如果提交没有push到远程
- git reset --hard 某个commit点 git reset 可以直接将 head 指针指向这个commit点(–hard 是将暂存区和工作区都重置到指定的 commit 点 --soft 将暂存区重置到指定的 commit 点,工作区不受影响)
- git checkout head . 将工作区所有文件撤销到本地仓库最新的一次提交
1.5.2、git revert撤销已经push到远程的commit
因为已经push到远程仓库了,有可能别人已经拉取了最新的 commit 点,这个时候就不能使用 checkout 或者 reset 命令直接撤销commit点了(这样 push 的时候会冲突),这个时候我们可以用git revert方法,revert会提交一个新的commit点,用来撤销我们选择的 commit 点的内容。
git revert HEAD 撤销前一次 commit
git revert HEAD^ 撤销前前一次 commit
git revert fa042ce57 撤销指定的版本,撤销也会作为一次提交进行保存。
下面附张图:
1.6、git statsh 工作区暂存
如果,开发到一半,突然需要切换到另外一个分支,提交代码,但是当前分支代码又没完成,怎么办?使用 git stash ! git stash 操作会将 工作区 和 暂存区 的改动放到 工作现场。
一般使用顺序是:
- git stash save “这些是注释啦”
- 切换到其他分支处理
- 其他分支代码处理完后,切换到git statsh 操作所在分支
- git stash pop / git stash apply
1.7、重写历史
以下需要重写的历史 commit 都默认为未 push 到远程的本地commit历史。
1.7.1、git commit --amend 修改最后一次提交
修改最后一次提交的message
git commit --amend 后,通过文本编辑器来修改
最后一次提交,忘记提交了文件
如果你已经完成提交,又因为之前提交时忘记添加一个新创建的文件,想通过添加或修改文件来更改提交的快照,也可以通过类似的操作来完成。 通过修改文件然后运行 git add 一个已追踪的文件,随后运行 git commit --amend 拿走当前的暂存区域并使其做为新提交的快照。
git add 需要add的文件
git commit --amend
注意事项
使用这个技巧的时候需要小心,因为修正会改变提交的 SHA-1 校验和。 它类似于一个小的变基——如果已经推送了最后一次提交就不要修正它。
1.7.2、git rebase -i 修改提交历史中较远的提交
选中当前头指针之前的3个提交
git rebase -i HEAD~3
进入交互界面:
这张图,可以分两个部分看:
- 主要内容:选定的提交们,以及对它们的处理。(编辑区默认的提交顺排列序是按提交历史上的顺序排列的,由前到后,顺序执行)
- 带#的注释内容:关于对这些提交你能操作的命令,理解了它们,就可以开心地为所欲为了。
先看注释内容,理论知识大概掌握先:
- p,pick
使用该提交,也是默认操作,这个从上面的编辑区域可以看出。这个命令的含义是拿到这个命令,但是什么都不做。 - r,reword
拿到提交,修改提交的提交信息。 - e,edit
拿到提交,修改这个提交的内容。使用这个命令的时候,rebase 操作会停在操作提交处,等待修改完毕,使用git add .和 git commit --amend修改提交,git rebase --continue继续 rebase 进程。 - s,squash
合并到前一个commit上面去。 - f,fixup
和 squash 命令的作用一样,不同的是,squash 命令会把融合的提交的提交信息都保存融合后的提交信息中,但是 fixup 会放弃被融合的提交。 - d,drop
删除提交
交互步骤:
- 对需要修改的历史 commit ,设置操作
- 保存退出
- 如果中间出现冲突,解决冲突后,进行 git rebase --continue.
- 如果中间任何一个换件出现问题,均可以使用 git rebase --abort 放弃此次变基
1.8、一些tips
1.8.1、每次commit代码时,首先从远程拉取下代码
这是因为,如果远程仓库如果有新的 commit ,本地仓库也有新的 commit ,这个时候如果git pull,本地会多一个 merge 的 commit 点。这种情况,其实可以通过 git pull --rebase 来解决,但考虑到变基操作学习成本较高,故不做介绍。
二、日常开发中,你需要记住下面的基础命令(包含参数)
2.1、git branch命令
用户分支的管理工作
- git branch branch1 在当前分支(本地)下,创建branch1分支
- git branch -d branch1 删除本地的branch1分支
- git branch 列出本地分支
- git branch -a 列出本地分支和远程分支
- git branch -r 列出远程分支
2.2、git checkout 命令
git checkout主要有下面两个用处:
- 工作区的文件回退;(从暂存区、从本地仓库)
- 切换分支(包括新建、切换)
回退文件时的常用命令:
- git checkout – a.txt 【用 暂存区 的 a.txt 文件,替换工作区的 a.txt 文件】
- git checkout – . 【用暂存区的所有文件,替换工作区的文件】
- git checkout head a.txt 【用 本地仓库 的a.txt 文件,替换工作区的 a.txt 文件】
- git checkout head . 【用 本地仓库 的所有文件,替换工作区的文件】
分支操作时的常用命令
分支切换:
- git checkout branch1 将分支切换到本地分支branch1
本地新建分支:
- git checkout -b dev 在本地新建名为dev的分支,并切换过去,如果本地已经存在dev分支,则会报错
相当于git branch dev 和 git checkout dev两个命令
本地新建分支,并track到远程分支:
- git checkout -b lBranch origin/rBranch 【在本地新建名为 lBranch 的分支,并追踪远程的 rBranch 分支】
- git checkout --t origin/rBranch 【在本地新建名为 rBranch 的分支,并追踪到远程的 rBranch 分支,其中的-t,是 -track 的缩写】
2.3、git pull
- git pull
拉取与当前分支关联的远程分支代码(并自动合并当前改动的代码, 如本地已有commit会产生一个新的commit) - git pull --rebase
拉取与当前分支关联的远程分支代码(并自动合并当前改动的代码, 如本地已有commit不会产生新的commit)
2.4、git add
- git add .
提交当前路径下的所有文件到暂存区(包括子目录,但不包括父级以上目录) - git add -A
最常用的git 指令, 提交所有 新增、删除、修改到暂存区(包括子目录,且包括父级以上目录)
2.5、git commit
- git commit -m
提交暂存区
2.6、git push
- git push
推送代码至与当前分支关联的远程分支 - git push -f
将当前分支的commit强制推送到远程分支(不处理 更新、合并等, 非常危险的指令,谨慎操作) - git push origin --delete [branch-name]
删除远程分支
2.7、git stash
- git stash
- git stash save “这些是注释啦”
新增工作现场(将当前的所有改动全部放入工作现场), git stash的默认注释为当前分支上一次commit的注释 - git stash list
显示工作现场列表 - git stash apply
- git stash apply --index stash@{0}
恢复工作现场的代码(不删除),默认恢复最新工作现场:git stash apply = git stash apply --index stash@{0}, --index 参数:不仅恢复工作区,还恢复暂存区
2.8、 git merge
- git merge branchName
将当前分支 与 本地 叫“branchName”分支的代码合并(branchName代码合并到当前分支); - git merge --no-ff branchName
将当前分支 与 本地 叫“branchName”分支的代码合并(branchName代码合并到当前分支),并且显示合并细节,具体表现在 提交线路图会出现交叉线; - git merge --squash branchName
合并新分支代码时, 只将分支新改动放入暂存区,不产生commit;(合并分支减少commit)
2.9、git log
- git log
查看commit提交历史, 查看commit id方便回退; - git log --oneline --graph --decorate --all
查看分支树
2.10、git revert
- git revert
撤销某个提交带来的修改
2.11、git clone
- git clone https://github.com/xxxxx
此方式拷贝项目不需密码;
但以后使用git pull 、git push指令都得输入账号密码;
2.12、git config
- git config --global alias.co checkout
设置别名,这样可以直接使用 git co 来 代替 git checkout
三、插件&工具
3.1、一个支持交互的git checkout 分支切换工具
https://github.com/royeo/git-checkout-branch
安装命令(本地需要安装git):
curl -sSL https://github.com/royeo/git-checkout-branch/releases/download/v0.4.0/git-checkout-branch-`uname -s`-`uname -m` -o /usr/local/bin/git-checkout-branch && chmod +x /usr/local/bin/git-checkout-branch
git config --global alias.cb checkout-branch
使用:
- git仓库目录下,直接键入git cb即可选择相关分支,↑、↓可以选择,←、→可以翻页。
- git cb 执行后,按 “/”,支持模糊搜索
- control + c 退出交互
四、引用 & 常用链接
- https://git-scm.com/book/zh/v2/Git-%E5%9F%BA%E7%A1%80-%E6%92%A4%E6%B6%88%E6%93%8D%E4%BD%9C
- git常用命令大全 https://www.kancloud.cn/wteamxq/git_rank/277268