Git: 多人协作的开源版本管理工具
git的4个核心区域
工作区(Working Directory):
电脑上的工作目录
暂存区(Staging Area):
类似于草稿箱,本质上是一个叫index的二进制文件。{工作目录/.git/index}
本地仓库(Local Repository):
本地的.git目录,包含了项目的所有文件、提交历史、分支、标签等信息。通过git init就能在工作区生成.git目录
远程仓库(Remote Repository):
存储在远程服务器(github/gitlab)上的远程仓库。通过远程仓库,可以共享代码,协同工作
git的三种基本状态
已修改(modified)
工作区的文件已经被修改了,但还未进入暂存区
已暂存(staged)
修改的文件进入了暂存区,等待被提交到本地仓库
已提交(committed)
暂存区的文件已经被提交到本地仓库
git基础
git init # 初始化工作目录
git status # 显示当前状态
git add [filename] # add file to staing area
git commit -m "commit" # 一次提交
git config
配置用户名和邮箱
- 可以通过git config命令配置
- 可以通过配置config文件,然后保存着本地目录/家目录/系统目录下,对应本地/用户/系统级的config。
- 可在config文件中配置添加常用缩略语。
[alias]
co = checkout
br = branch
ci = commit
st = status
git常用命令
git show # 展示上一个commit的详细信息
git log # 展示当前分支提交历史记录,和对应commit的哈希值
git log --graph # 图形化展示
git diff # 未暂存(工作区) 和 暂存区 的差异
git diff --cached
git diff --staged # 显示已暂存但未提交的改动
git diff <file> # 查看指定文件的差异
git diff <commit1> <commit1> # 查看指定的两个commit的差异
git clone [url] # 下载并关联远程仓库
git remote # 远程仓库
.gitignore 文件 # 让git不跟踪这些文件 通用模版: https://github.com/github/gitignore
git的分支
git branch <branch-name> # 从当前分支新建一个分支 (未进行切换)
git checkout <branch-name> # 切换到分支branch-name上
git checkout -b <branch-name> # 新建并切换到新分支
git switch <branch> # 现在用switch单纯进行切换分支 # checkout既可以用于切换commit(也保留了切换分支的能力)
git branch # 显示本地所有分支 当前分支用*标记
git branch -r # 显示远程所有分支
git branch -vv # 显示当前分支关联的远程分支
分支合并 merge vs rebase
git merge
// 在目标分支main上,合入feature分支的代码
git merge branch-feature
-
如果无冲突,默认快速合并(fast-forward)。如果分支main是分支feature的子集,git会将当前分支指向feature分支的最新提交。
-
如果有冲突(three-way merge),git会创建一个新的提交merge commit,包含两个分支的所有变更内容,我们需要手动解决冲突后提交。
git rebase
git rebase 将当前分支变基到分支branch上.
以target-branch的最新提交为基准,将本分支的提交移动到target-branch的最新提交后。过程中可能有冲突需要解决。
merge的优点是不会修改merge前的历史提交,而rebase或多或少会修改了历史。
merge的缺陷是引入了很多的merge commit,这些commit没有太多的意义,如果想保持工作历史干净推荐用rebase
黄金准则:不要rebase一个共享分支。 例如分支两人公共开发feature分支,最终要合入main分支,对feature分支使用rebase操作会打乱提交历史造成很多混乱。
git rebase创建干净的commit
日常开发中对于开发一个feature我们可能会多次commit,这些commit并非都是有意义的,可能只是加上几个log,修复一些简单的bug...
这时可以用rebase命令创建一个干净的commit
git log # 查看commit历史记录
git rebase -i <hash-commit> # 以 hash-commit 这条commit 为基准
git rebase -i HEAD~5 # 以前5条commit为基准
pick c32e46da 废弃埋点SDK对外暴露的事件分发接口
pick 3ecabc77 Merge: 张梦: 版本号自动升级,从4.12240.0升级到VERSION=4.12240.1
pick fdb100f9 简单功能实现
pick 91431a79 test
-->
pick c32e46da 废弃埋点SDK对外暴露的事件分发接口
squash 3ecabc77 Merge: 张梦: 版本号自动升级,从4.12240.0升级到VERSION=4.12240.1
s fdb100f9 简单功能实现
s 91431a79 test
下一阶段类似,可以修改commit message。即可完成变基操作。
此时再通过git push就能提交一个只包含一个commit的干净的提交了。
如果远程仓库中已经有了这些无意义的commit,可以通过git push -f 将本地的干净的分支强制推送到远程分支。
(注意⚠️禁止对线上分支这样操作)
fetch vs pull
都是从远程抓取代码
git fetch # 更新本地的远程分支
git pull # == fetch + merge
有时间并不想直接合入远程的最新提交,因此可以先fetch,再考虑合入这些最新的更改。
git stash
在开发过程中,会遇到开发到一半需要临时切到其他分支的情况,这时git add + git commit 就会产生一条无意义的commit
通过git stash可以暂存当前的修改,然后切换分支去忙别的事。
当切回原来的分支后,通过git stash apply就能恢复原来的代码了
git reset
有时需要一些撤销操作
git reset [file] # 撤销暂存的文件,但不会撤销更改
git reset <commit>
git reset --soft <commit> # 撤销 commit 后的提交,但本地保留这些修改
git reset --hard <commit> # 撤销 commit 后的提交并清除修改,回到指定commit的状态
一些学习资料
在线学习(闯关)网站
learngitbranching.js.org/?locale=zh_…
一本书 ProGit
一节课