Search K
Appearance
Appearance
git 工作流程中,文件在各个区域之间的流动关系:
通过上面几条命令,可以在 git 的 3 个区域之间对文件进行流动操作,也可以通过以下命令,进入命令进入交互模式。
git reset -p
git checkout -p
git add -p
将文件放入暂存区
git add <...files>
git add README.md
:将README.md
文件放入暂存区git add .
:将当前目录下的文件放入暂存区git add -A
等同 git add --all
:将项目根目录下所有目录和文件放入暂存区从暂存区删除文件
git rm <...files>
: 删除文件,并添加到暂存区,等于 rm <file>
+ git add .
操作git rm --cached [files]
: 只从暂存区删除文件,工作区保留重命名文件,并添加到暂存区
git mv <filename> <filename_new>
:重命名文件,并添加到暂存区,等于 mv <filename> <filename_new>
外加 git add .
操作git commit
将 暂存区
内容生成 commit快照
,并根据文件内容生成hash
值,然后提交到历史区
。
提交到历史区
git commit -m "commit message"
git commit -am "commit message"
: 等于 git add -A
和 git commit -m
结合git commit --amend
:放弃当前提交,将当前 commit 对象的快照内容和暂存区内的新内容重新进行一次 commit 提交,并附上新的 commit message 生成新的 commit 对象。git commit --amend
只能修改当前提交,如果以前某个提交出现了错误,可以先修正错误并提交到暂存区生成新的 commit 提交,然后将当前提交使用 git rebase -i <commit-hash>
修正到指定的提交上,比如 git rebase -i HEAD^3
将当前提交覆写到 HAED
指针之前的第 3 个父节点上,又或者使用 git reset
命令恢复到 HEAD^3
重新来过。
恢复到暂存区/工作区
git reset <commit-hash>
:主要是移动指针,并将指针引用的 commit 对象快照恢复到暂存区,所以它主要的功能也是修订暂存区,并不会影响到工作区。git reset <commit-hash> --hard
:不仅将 HEAD 指针移动到指定的 commit,还会抛弃被撤销的 commit 提交,连工作区也被充值到对应的 commit。移动指针
git reset
git reset HEAD
git reset
等同于 git reset HEAD
HEAD指针
移动到 HEAD指针
, 即不移动。--mixed
是 默认参数选项
,将 commit 对象快照恢复到暂存区,改动暂存区内容为快照内容,暂存区和历史区指向当前 commit 对象,但是工作区内容保持不变,不会影响用户工作区的工作内容。--soft
参数选项,将 HEAD 指针指向 commit 对象,不改动暂存区和工作区,即暂存区和工作区还是原 HEAD 指针指向的 commit 对象,这会导致暂存区工作区相同,但和历史区不同 --soft 等于 --minxed 之后再 git add 一次。--hard
参数选项,将暂存区和工作区都强制恢复到 HEAD 指向的 commit 快照。git reset <commit-hash>
git reset HEAD~3
--mixed
是 默认参数选项
,git reset HEAD~3 将 HEAD 指针移动到 b325c 快照, 改动暂存区但不改动工作区
,所以工作区的内容还是 c10b9,da985,ed489 提交的内容,但是暂存区已经重置到 b325c 快照的内容了,所以 git status 可以看见这 3 个提交新增和修改的内容,需要手动添加到暂存区,或者放弃修改--soft
参数选项,git reset HEAD~3 将 HEAD 指针指向 b325c,不改动工作区
,所以工作区的内容还是 c10b9,da985,ed489 提交的内容, 既改动暂存区也不改动暂存区
,暂存区还是保留着 b325c 时的内容,但是 --soft 相比于 --mixed 多了一个 git add 步骤,导致 git add 后的暂存区和使用命令之前时的暂存区是一致的,所以看起来 没有改动暂存区
。--hard
参数选项,git reset HEAD~3 将 HEAD 指针指向 b325c,改动工作区和暂存区
都恢复到 b325c 快照git reset -- <...files>
git reset -- README.md
git reset -- README.md
等同 git reset HEAD -- README.md
将当前历史区中的 README.md 文件恢复到暂存区,也就是取消暂存区中的 README.md 文件的改动提交。--
表示命令参数的结束,后续的参数都是文件名称,将 HEAD指针
移动到 HEAD指针
,即不移动--soft
参数选项--mixed
(默认)参数选项,将 HEAD
指向的 commit对象
快照恢复到暂存区--hard
参数选项,将 HEAD
指向的 commit对象
快照既恢复到暂存区,也恢复工作区提示
git reset -- <...files>
这一操作某种程度上等于撤销了在上一个 commit 提交之后,本次准备 commit 提交之前,对于 README.md
文件的 git add
添加到暂存区的操作。
提示
git checkout 是 git 早期的命令,功能比较多,但也相对危险,所以 git 在 2.23 版本之后增加了 git switch,git restore 命令
git checkout <commit-hash | branch> -- <...files>
将 暂存/索引区
的文件回撤到 工作区
,即放弃当前工作区所有修改,回撤到上次 提交(add)
时的状态。
检出文件
git checkout -- README.md
将 暂存区
的 README.md
文件回撤到工作区,抛弃当前工作区 README.md
文件修改。git checkout -- .
将 暂存区
的 所有文件
回撤到工作区,抛弃当前工作区 所有文件
的修改。git checkout HEAD -- README.md
这一点和 git reset 有很大不同,从 历史区
中,将 HEAD
指针指向的 commit对象
对应的 README.md
文件回撤到工作区,同时也恢复到暂存区,这一操作会抛弃 工作区
和 暂存区
对于 README.md
文件的修改。git checkout HEAD~n -- README.md
检出 HEAD
指引引用的 commit对象
的第 n 个父节点的 README.md
文件到暂存区和工作区git checkout HEAD~ -- README.md
等同 git checkout HEAD~1 -- README.md
,检出 HEAD
指引引用的 commit对象
的第 1 个父节点的 README.md
文件到暂存区和工作区 git checkout <branch> -- README.md
从指定的分支检出 README.md
文件到暂存区和工作区git checkout --orphan <branch>
会创建一个没有任何 commit 记录的分支,直到有新的 commit 提交记录后,这个分支才会真正的存在git checkout <branch>
将HEAD指针
引用到分支
上,并将该分支内容检出到暂存区和工作区,切换分支之前记得使用git stash
保存当前文件的修改。
git checkout <commit-hash>
将 HEAD指针
引用到 commit对象
上,这会产生一个游离的 HEAD指针
,即 detached HEAD。
如果在游离的指针上提交了一个 commit对象
,当你切换到其它 commit对象
或 分支
或 tag标签
后,这个新提交的 commit对象
将难以找回。
提示
可以使用 git reflog 找到历史提交记录
所以在提交了新的提交之后,记得使用 git checkout -b <branch> <commit-hash>
,或者 git branch <branch> <commit-hash>
新建一个分支指向这个危险的 commit对象
。
切换分支(检出分支)
# 新建分支,分支指针指向 HEAD,并切换到分支
git checkout -b newbranch
# 等同
git checkout -b newbranch HEAD
# 等同
git branch newbranch HEAD && git switch newbranch
# 等同
git branch newbranch HEAD && git checkout newbranch
# 等同
git switch -c newbranch
git diff
git diff
将工作区内容和暂存区进行 diff 比较git diff <branch>
将工作区内容和分支引用进行比较git diff HEAD
将工作区内容和 HEAD
引用的 commit对象
进行比较git diff <commit-hash>
将工作区内容和 commit对象
进行比较git diff --cached
将 HEAD
引用的 commit对象
和暂存区进行比较git diff <commit-hash> <commit-hash>
将两个 commit对象
进行比较Git 合并分支有多种情况,下面将一一介绍。
默认情况下,git 会按照 fast-forward 快速合并模式进行合并,直接将 stable 分支指向最新的提交,这样整个提交记录就只有一棵树。
git merge main
当前 HEAD 指针 指向 ed489
,main 分支指向 HEAD,stable 分支指向 a47c3
,main 分支和 stable 分支在同一棵树上,这时候 stable 分支合并 main 分支就是 fast-forwad 模式,只需要在合并时将 stable 分支的指针引用更新到 main 分支的指针引用(HEAD 指针)就行了。
提示
这是一张动图,可以将鼠标放上去。
git merge --squash master
当前处在 feature 分支上,--squash 会将 feature 分支上的 commit 提交合并为 1 个新的提交,然后按照 fast-forward 快速合并模式合并到 master 分支上。
git merge --no-ff -m "message" master
non-fast-forward 模式并不会因为当前分支和 master 分支在同一棵树上,就直接将 master 分支或者当前分支的指针移动到二者之间最新的提交,而是会强行分个叉,然后重新提交一个 commit 对象,也就是 3-way merge。
git merge other
当前处在 main 分支上行,other 分支和 main 分支并不在一棵树上,所以合并 other 分支时,进行的是 3 方合并,会生成一个新的提交记录 commit 对象,并且将分支指针指向新的提交记录。
cherry-pick 会选择一个 commit 对象作为新的提交内容进行一次提交, 本质和 git commit --amend
有些类似,amend 操作会将当前的 commit 对象重新提交一次,并修改提交信息, 生成新的 SHA-1 值,而 cherry-pick 操作将选中的 commit 对象在当前 HEAD 上重新提交一次且生成新的 SHA-1 值。
变基也是合并的一种,两个分支的合并可能不是处在一棵树上,所以并不是线性才做, 但是 rebase 会将不同树上的节点合并到同一棵树上去
当前处在 topic 分支,使用变基操作,将 topic 分支挂到 mian 分支所在的树上,和 cherrr-pick 一样会将节点(commit 对象)的内容重新提交生成新的引用,而不是直接移植引用,因为同 SHA1
哈希值的父 commit 对象只有一个。
git rebase main
# 添加到暂存区
git add .
# 会将暂存区再次commit,和 git commit --amend类似
git rebase --continue
如果 rebase 过程中出现错误,可以取消 rebase
git rebase --abort
提示
git merge main
分支,将 main 分支的引用也更新到当前提交,然后推送到远程仓库。从 topic 分支,可以直接变基到 main 分支,但并不希望 topic 上所有 commit 提交都被变基,可以使用 --onto 参数。
git rebase --onto main 169a6
这条命令表示从 169a6 的下一个节点开始,到 topic 分支上最新提交,重新变基到 main 分支上,不仅如此,还会将指针也一起挪动
可以指定变基的起点,从起点向前递归父 commit
# 修改当前commit
git rebase -i master
# 修改master开始往前共3个commit
git rebase -i master~3
HEAD^1
^1
表示当前提交的第一个父提交。通常,一个提交只有一个父提交,(除非是合并提交(Merge Commit),合并提交会有多个父提交)。HEAD^1
就是合并的第一个父提交。HEAD~1
~1
表示当前提交的父提交。它是 Git 中用来指代父提交的一种简化写法。所以,HEAD^1
和 HEAD~1
在大多数情况下是等价的,它们都表示当前提交的父提交。但是在涉及到合并提交时,HEAD^1
可以更加明确地指定第一个父提交。