Skip to main content

Git

介绍

分布式管理工具 git 是本地管理工具和集中式管理工具的结合, 既可以支持代码集中管理,多人团队中每一个成员又拥有一个完整仓库 任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜像出来的本地仓库恢复

支持分支,能进行并行开发,可以恢复到任意时间点

fork 表示克隆出一个仓库的新拷贝,包含了原来仓库(upstream repository)的所有分支,tag,历史,issue 和提交 clone 克隆出一个仓库,但是下载到本地 git branch --list 列出该仓库的所有分支 git diff 查看当前代码 add 后,会 add 哪些内容 git status 查看当前分支状态 git pull origin 远程:本地 如果没有:本地则默认和当前分支合并 git commit --amend [file1] [file2]可以重做上一次 commit

git log查看提交历史
git reset --hard HEAD撤销工作目录中所有未提交文件的修改历史
git checkout HEAD <file>撤销指定未提交文件的修改内容
git revert <commit ID>撤销指定提交

概念

HEAD 指针就是你所在的位置,指向分支指针 分支指针则指向当前分支最新的一次 commit 提交

工作树的代码通过 git add 添加到 git 索引中 commit 则是将索引中的文件提交到 git 仓库中

git fetch 是将远程主机的最新内容拉到本地,用户在检查了以后决定是否合并到工作本机分支中 而 git pull 则是将远程主机的最新内容拉下来后直接合并,即:git pull = git fetch + git merge,这样可能会产生冲突,需要手动解决

git stash 会同时缓存 staged changes 和 unstaged changes 相当于一个栈 ● git stash ● git pull ● git stash pop

● git stash:保存开发到一半的代码 ● git commit -m '修改问题' ● git stash pop:将代码追加到最新的提交之后

git rebase 和 git merge 的区别

git merge 和 git rebase 都是用于分支合并,关键在 commit 记录的处理上不同:

  • git merge 会新建一个新的 commit 对象,然后两个分支以前的 commit 记录都指向这个新 commit 记录。这种方法会保留之前每个分支的 commit 历史。 (创建一条新的,然后两个末端指向新的前端)
  • git rebase 会先找到两个分支的第一个共同的 commit 祖先记录,然后将提取当前分支这之后的所有 commit 记录,然后将这个 commit 记录添加到目标分支的最新提交后面。经过这个合并后,两个分支合并后的 commit 记录就变为了线性的记录了。 (直接把自己的接在目标的后面,但是会截取掉自己和目标从前端算起共同的部分,从而防止重复

merge 会新增一个 commit 提交,会导致历史记录更复杂 rebase 不会,直接分支移动,消除

squash 和 rebase 相似,但是线性记录会合并

与 merge 创建合并的区别是不保留原记录

git reset 和 git revert 的区别

git reset 用于回退版本,可以遗弃提交, 指定参数可以影响遗弃的范围,可以指定是否复原索引或工作树 ● --mixed(默认):默认的时候,只有暂存区变化 ● --hard 参数:如果使用 --hard 参数,那么工作区也会变化 ● --soft:如果使用 --soft 参数,那么暂存区和工作区都不会变化

git revert 不会遗弃提交,而是新增一次提交抵消上次提交的变化

reset 指针会往后移动,revert 指针会一直前进

Git 原理

git 任何文件都会通过 SHA-1 散列哈希计算一个 40 位的校验和进行标识

.git 目录下主要的子目录

  • /hooks 管理周期钩子
  • info/exclude 管理 ignore
  • objects 管理实际文件内容(类似数据库)
    • object 里存了所有资源,包括 blob(文件本身) commit branch
  • remote 存远端分支
  • refs 管理分支

commit

一个 commit 内容包括 tree parent author committer size message

通过 tree 记录 blob 的标识

tree 下面存有多个文件的 blob 的 hash 值

parent 串到上一个 commit

checkout

git checkout -b iss53 master 在 master 分支(一个指针)指向的 commit 记录上,创建一个指向该 commit 的 iss53 分支,并把 head 指向 iss53

等同于 git checkout master git checkout -b iss53

等同于 git checkout master git branch iss53 git checkout iss53

merge

有两种情况

fast-forward merge

master 和 iss53, 仅 iss53 有新的 commit,这时将 iss53 合入 master,只需要将 master 指针直接指到 iss53 最新的 commit 就算合并

long fast-forward merge

这时 master 已经和 iss53 一致,再将 iss53(master)和 i18n 合并 git merge i18n

iss53 和 i18n 都有新的 commit,但是两个 commit 没有冲突,生成一个新的 commit 记录,是两个 commit 的并集。

有冲突 使用 git status 得知 xxx.html unmerge

需要 git add , commit 解决冲突

branch -d

前提: 切换到另一条分支,作为当前分支

-d 未 merge 到当前分支的无法删除

-D 可以删除未 merge 分支

push

git push 本地到远端

如果是超集,才能 push 成功

否则会在本地通过(fetch) 创建一条 origin/master 分支,来等待和 master 分支进行 merge 操作

pull

fetch + merge

log

将所有通向当前 commit 的所有 commit 记录展示出来(可以多个分支指向同一个)

log --oneline 只展示一条分支上的

--all 把整个仓库的图完全展示出来

log branchA ^branchB分支 A 中所有不在分支 B 中的 commit, 比如说没有根 commit

rebase

将该分支所有 commit 线性放置到原先分支最新位置,但是 commit 号(因为同时基于内容和父节点)和时间都会发生变动

线性的好处(可以通过二分,在一条线上快速定位产生 bug 的 commit)

通过-add 参数可以自由把 commit 合体/调换顺序


内部存在压缩算法,保证性能,commit 之间有 diff 存储,但是不是按照顺序存储 diff 的,底层通过排序自由找到合适的增量存储内容

常用命令速查

git clone [url] // 将存储库克隆到本地
git init // 创建新的 Git 仓库,在当前路径下生成 .git 目录

git remote -v // 查看连接的远程仓库地址
git remote add origin [gitUrl] // 为本地仓库添加远程仓库地址
git push -u origin master // 将本地仓库的master和远程仓库的master进行关联
git remote origin set-url [gitUrl] // 为本地仓库修改远程仓库地址
git remote rm origin // 为本地仓库删除远程仓库连接

git checkout [branchName] // 切换分支
git checkout -b [branchName] // 新建分支并切换到该分支

git branch //查看本地分支
git branch -r //查看远程分支
git branch -a //查看本地和远程分支
git branch [branchName] //新建本地分支但不切换
git branch -D [branchName] //删除本地分支

// -m 重命名!!!
git branch -m [oldBranchName] [newBranchName] //重新命名分

git tag [tagName] // 新建标签
git tag // 查看标签列表
git tag -d [tagName] // 删除标签
git push origin [tagName] // 推送标签到远程仓库

git add [file1] [file2] // 添加指定文件至暂存区
git add [dir] // 添加指定目录至暂存区
git add . // 添加当前目录下所有文件至暂存区
git add -A // 添加当前仓库下的所有文件改动至暂存区

git commit -m 'xxx' // 将暂存区文件添加到本地仓库,并记录下备注
git commit -m 'xxx' -n // 将暂存区文件添加到本地仓库,并记录下备注,同时跳过 husky hooks 设置的规则校验
git commit -am 'xxx' // 将文件添加到暂存区,再添加到本地仓库,并记录下备注

git push [remoteName] [branchName] // 推送分支
git push --set-upstream [remoteName] [branchName] // 推送分支并建立关联关系

git pull // 从远程仓库拉取代码合并到本地,等同于 git fetch && git merge
git pull --rebase // 使用rebase的模式进行合并

git fetch // 从所有远程仓库拉取当前分支代码
git fetch [remoteName] // 从指定远程仓库拉取当前分支代码
git fetch --all // 获取所有远程仓库所有分支的更新

git cherry-pick [commitId] // 获取指定的commit

git merge [branchName]

git rebase master // 将当前分支变基到 master 分支上

git reset HEAD^ // 回退所有内容到上一个版本
git reset HEAD^ [filename] // 回退某文件到上一个版本
git reset [commitId] // 回退所有内容到指定版本

git reset --soft HEAD~1 // 回退本地仓库到上一个版本
git reset --hard HEAD~1 // 回退本地仓库到上一个版本,并删除工作区所有未提交的修改内容

git stash // 暂存文件
git stash save 'aa' // 暂存文件,添加备注
git stash pop // 应用最近一次暂存文件,并删除暂存记录
git stash apply // 应用最近一次暂存,但不删除该暂存记录
git stash apply stash@{第几次暂存的代码,例如0} // 应用某一次暂存,但不删除该暂存记录;
git stash list // 暂存记录
git stash clear // 删除所有暂存记录

git reflog

git rm [filname]
git rm [dir]

git log // 查看所有 commit 记录
git log --grep 瀑布流 // 搜索 commit msg 有瀑布流关键字的 记录