Git

2022-05-15/2022-05-15

一切皆引用

Git 仓库数据结构

Git 仓库由一个个的 commit 组成

commit 代表当前时刻下 Git 仓库的完整快照,记录了距离上⼀次 commit 之间的改动。

某些 commit 上会有⼀些 branch 指向它们,这些 branch 的本质是引用

有⼀个特殊的引用叫做 HEAD,它始终指向当前我们正要工作的位置,这个位置可以是 commit,也可以是 branch(一般来说head引用都是指向一个branch引用)

当每次 commit 的时候,HEAD 不仅随着新的 commit ⼀起移动,⽽且如果它指向了某个 branch,那么它也会带着 branch ⼀起移动

改动区和staging area

当我们在一个Git工程项目中改变了一个文件,Git会监测到并将改动的内容加入到改动区,我们可以通过git add filename 将其加入到staging area,staging area:待提交的修改内容暂时存放的地⽅。主要⽤于和已经改动但不打算提交的内容区分开来。

branchmaster

branch指分支,而branch的本质还是引用

image-20220514224530820

master是一种特殊的branch,它是git的默认分支

并且在执⾏ push 命令把本地内容推送到远端仓库的时候,远端仓库的 HEAD 永远跟随默认 branch,⽽不是和本地 HEAD 同步。换句话说,只有 push master 分⽀到远端的时候,远端的 HEAD 才会移动。

此外要注意的是,因为某些国外政治敏感的原理,master分支被改名为main分支

clone,pull,merge,push原理

clone

clone 命令把远端仓库中的所有 branch 取下来,并同步所有的commit信息

image-20220514225303332

其中origin/feature1 指的是远端仓库feature1分支所指向的commit,origin/master,origin/HEAD同理

origin/这样的分支在本地被更改只存在俩种情况:

  1. 在执⾏ push 的时候,push 成功后,push 成功的 branch 会把它对应的origin/ branch 更新到当前 commit
  2. 在执⾏ pull 或者 fetch 的时候,由于从远端拿到了所有最新的 branch 状态,所以也会⼀同更新所有的 origin/ branch

merge

merge 就是合并,它会把当前 commit 和指定 commit合并成一个新的commit

image-20220514225803878

如果要merge进来的分支完全领先于master分支,就会fase-forward,此时不会产生一个新的commit,只是将master分支和head分支所指向的commit移动到了那个领先的分支所指向的commit

pull

pull = fetch + merge

pull具体做的事:

  1. 把远端所有 branch 的最新位置更新到本地的 origin/xxx 镜像
  2. 要到达这些 branch,本地所缺少的所有 commit,也取到本地
  3. 把 origin/当前branch 的内容合并到当前 branch

image-20220514230012578

image-20220514230030233

image-20220514230044811

push

具体做这些事:

  1. 把 HEAD 所指向的 branch 引用推送到远端仓库
  2. 从这个 branch 向前回溯,远端仓库缺少的每⼀个 commit 也推送到远端仓库。
  3. 将 push 的 branch 的本地镜像 origin/xxx 更新

注意,push只是改变了本地head所指向的分支在远端所对应的分支

而pull会改变所有远端分支在本地的指向,但只会合并head所指向的当前分支

Feature Branching

Feature Branching是我们平时团队合作项目开发最常用的模式

指的是每开发⼀个新的功能做⼀个修复,都使⽤单独的分⽀,在做完之后 merge 到master

通常合并我们有俩种方式

1.将本地的master分支推到远端的master分支,此时我们需要保证本地master分支是持平或者是远远领先与远端的master分支的,因为远端master分支并不知道处理冲突,所以必须要能ff(fast-forward),所以我们要先从github上拉去master的最新信息,然后merge feature分支,再将master分支推上去

2.使用 pull request 指的是我们将我们的feature分支直接推到远端,需要合并的时间创建一个pr将我们的feature1分支合并到master分支,如果出现冲突是创建不了pr的,此时我们要先在本地处理好冲突后再推到我们的feature1分支然后再继续

常用指令的原理

git checkout

移动 HEAD,让它指向某个 commit 或某个 branch。

checkout --detach :让 HEAD 脱离当前 branch,直接指向下⾯的commit。

如果是让HEAD去指向某个origin/branch则会直接指向其所对应的commit

这是因为origin/镜像分支无法被指向

git rebase

即为变基

把当前 commit(以及它之前的 commits)变基到指定的需要 rebase 的 commit上。

Git 中的每⼀个 commit 都是不会改变的,所以 rebase 之后的每个 commit 都是新产⽣的,⽽不是对原先的 commit 进⾏「修改」

image-20220515132700404

比如这里就是让4,5 commit变基到了a上从而让整个commit记录向是一条直线

rebase 的冲突解决⽅法和 merge 冲突⼀样,只是把 git merge --continue

改成 git rebase --continue 就⾏了

git reset

把当前 branch 指向指定的 commit。

git reset 指定commit

移动到指定 commit,并保留 working tree 的内容

如果使用git reset branch 也是会指向到该branch所指向的commit

git reset --hard 指定commit

移动到指定 commit,并重置 working tree

image-20220515152720666

image-20220515152739438

resetcheckout 的区别

它们都是移动 HEAD,但 chekcout 移动的时候是⾃⼰移动,不带着 branch ⼀起;

⽽ reset 会带着 branch ⼀起移动。

提交完发现写错了的补救命令

修改最新提交

最新的⼀条内容需要修改:

git commit --amend

「修改」只是概念⾏为,实质上会产⽣⼀个新的 commit

image-20220515153023000

修改历史提交

使用交互式rebase 可以更精细化的控制rebase的过程

从而可以更改每个commit的内容

其本质是由于rebase是生成了新的commit,而历史无法被修改

image-20220515153504680

git rebase -i HEAD~4

常⽤选项:

pick 或 p :沿⽤

reword 或 r :修改 commit message

edit 或 e :修改 commit 内容

drop 或 d :删除

squash 或 s :和上⼀条融合,并且合并 commit message(可编辑)

fixup 或 f :和上⼀条融合,并且沿⽤上⼀条的 commit message

已经 push 到 master

只能创建一个新的commit

交互式add

可以精细化控制一个文件中那些代码是这次commit想要提交的,从而让一次commit逻辑性更强

git add -i

常⽤选项:

p (patch)

选取块时的常⽤选项:

y:选⽤当前块

n:不⽤当前块

s:把当前块做⾃动切分后再重新询问

e:⼿动选取修改内容

image-20220515154005456

image-20220515154028527

tag

tag是另类的引用,它和branch的区别是tag初始化引用后就无法再修改引用给,方便我们在发版时给最新commit打tag再推到远端仓库,此时在github中也会出现realease的标签

git tag tagname

如果需要给tag标注更多信息(用于realease)

可以使用

git tag tagname -a

cherry-pick

git cherry-pick commit1 commit2

⽤途:应⽤指定的某个或某些 commit 到 HEAD 处

⽐如我想抛弃某个 branch,这个特性不要了,但它的某两个 commit 我希望保留

git add -i

git cherry-pick commit1 commit2git cherry-pick 这两个 commit

git stash

git stash 等同于gitstashsave,能够将所有未提交的修改(工作区和暂存区)快照至堆栈中,用于后续恢复当前工作目录。
git stash list //查看当前stash中的内容
git stash pop //将当前stash中的内容弹出,并应用到当前分支对应的工作目录上。相当于回退
git stash apply [stash名字] //将堆栈中的内容应用到当前目录 如:git stash apply stash@{1}
git stash drop [stash名字]
git stash clear //清空stash列表
git stash show //查看堆栈中最新保存的stash和当前目录的差异

评论
发表评论
       
       
取消