Bo2SS

Bo2SS

2 独自使用Git时的常见场景

本机测试环境:macOS 11

14 | 怎么删除不需要的分支?#

git branch -d <BRANCH_NAME>

  • -d--delete
  • 有条件地删除一个本地分支
    • ❗️条件:当该分支被合并到上游分支(本地分支对应的远端分支,可设置)或者 HEAD(当前分支)时,才能成功执行删除

git branch -D <BRANCH_NAME>

  • -D--delete --force
  • 强制删除一个本地分支
    • 当确定删除分支没有风险时,可以使用

PS:

  • 不能删除当前的分支,如需删除,可通过 git checkout <BRANCH_NAME> 先切换分支
  • 删除远程分支: git push <REMOTE> --delete <BRANCH_NAME>
    • 通过 git fetch -p / --prune 同步分支列表,此时就不会显示远程已被删除的分支了

15 | 怎么修改最新 commit 的 message?#

输入 git commit --amend ,弹出文本编辑器,修改新的 commit message,如红框所示:

image

输入 :wq 保存并退出后,终端显示修改结果:

image

再次查看 commit 信息:

image

修改成功!

PS:git commit --amend

  • 本质上是替换上一次提交,不局限于修改 message
  • 一般用于修改未 push 到远端之前的 commit 操作

16 | 怎么修改老旧 commit 的 message?#

git rebase -i 可以用来修改前几次的 commit 信息, -i 为使用交互模式

—— 具体步骤 ——

先使用 git log 查看当前的版本历史:

image

我们想修改顺数第 3 个 commit 的 message,那么需要基于它的父 commit 来操作。

使用git rebase -i d8796c00719323800976e6c7fcfe6b02627ec6b2 命令,末尾添加父 commit 的 hash 值(如果要对最开始的 commit 进行修改,可使用 git rebase -i --root ) ,弹出编辑界面:

image

commit 的顺序倒置了一下;从 Commands 部分可以看到有很多用法。

我们使用 reword / r 命令,保留某次 commit,但修改其 message,如下:

image

:wq 保存退出后,又弹出一个新的编辑界面:

image

修改 commit 的 message,再:wq 保存退出。

image

修改成功,❗️可以看到这里使用了分离头指针,修改完成后,还更新了 master 分支的指向,说明 commit 的 hash 值很可能发生了改变。

那么验证一下,再次通过 git log 查看版本历史:

image

可以发现顺数第 3 个 commit 的 message 修改成功,前 3 个 commit 的 hash 值都发生了改变,除了第 3 个 commit 的 message 都没有改变,其他信息其实也都没有改变,可自行验证。

⚠️:

  • 一般基于自己的分支,用在还没有提交到集成分支(团队)之前,否则一定要慎用,其会对集成分支造成影响。
  • rebase 常用于变基,可关注其和 merge 的相同点和不同点,参考

17 | 怎样把连续的多个 commit 整理成 1 个?#

同样使用 git rebase -i

—— 具体步骤 ——

先使用 git log 查看当前的版本历史:

image

现在想合并上面红框内的 3 个 commit,减少分支里的 commit 数。

使用 git rebase -i --root 命令,末尾添加父 commit 的 hash 值(因为要对最开始的 commit 进行修改,所以使用--root ) ,弹出编辑界面:

image

要合并的 3 个 commit 见上面红框内,顺序与 git log 展示的顺序相反。

使用 Commands 中的 squash / s 命令,可以将某个 commit 融合到前一个 commit 中,修改如下:

image

:wq 保存退出后,又弹出一个新的编辑界面:

image

添加第 2 行,作为融合 3 个 commit 的 message,保留下面每个 commit 的 message,再:wq 保存退出。

image

整合成功,❗️可以看到这里使用了分离头指针,修改完成后,还更新了 master 分支的指向。

git log 也验证了整合的结果,可以发现 2 个 commit 的 hash 值都发生了改变,因为 commit 的 message 或者父 commit 的指向发生了改变。

PS:

  • 整合后会导致一些 commit 没有用了,git 会进行清理。
  • 通过 gitk --all 观察此时的分支情况:

image

  1. 可以发现出现了两棵树,两个分支之间已经没有关联
  2. 这是因为 master 分支的根 commit 已经改变

18 | 怎样把间隔的几个 commit 整理成 1 个?#

命令: git rebase -i

通过 git log 命令查看版本历史:

image

想合并如红框所示的间隔的几个 commit,同样使用 git rebase -i 76e5c9ca 命令,后面添加的是父 commit 的 hash 值,弹出如下熟悉的窗口:

image

调整要合并的 commit 位置,并使用 s 命令,修改如下:

image

:wq 保存退出后,提示存在合并冲突,需要解决。

image

上面蓝框中提示了接下来可以进行的操作,这里我们尝试第一种方式:解决冲突。

PS:还可以借助 git status 查看当前建议的操作:

image

接下来查看 readme 文件,解决里面的冲突,删除红框位置的代码即可:

image

再运行 git add readme 添加刚才的修改记录。

然后按前面的提示运行 git rebase --continue 命令,弹出编辑框,输入 message 信息, :wq 保存退出即可(可能还需要解决冲突,重复上述步骤即可)

最后 git log 查看版本历史:

image

可以看出:如果被间隔的 commit 和要合并的 commit 有关联,很可能不符合预期,导致它们被合并成一个 commit,所以自己要对这几个 commit 的内容非常清楚。

PS:个人认为不太实用,容易产生冲突。

19 | 怎么比较暂存区和 HEAD 所含文件的差异?#

命令: git diff --cached

别忘了这张图:

image

  • HEAD 指向的是当前分支,分支指向的则是一个 commit。

演示:

修改 readme.md 文件后,输入 git add readme.md 将修改添加到暂存区;

再输入git diff --cached 比较暂存区和 HEAD 的差异:

image

可以看到添加了两行文本,确认符合预期后就可以 commit 了。

20 | 怎么比较工作区和暂存区所含文件的差异?#

命令: git diff

还可以在命令后添加文件名,从而比较指定文件在工作区和暂存区的差异,如 git diff readme.md ,当然也可以添加多个文件名。

21 | 如何让暂存区恢复成和 HEAD 的一样?#

场景:暂存区的内容不想要了,暂存区👉HEAD。

命令: git reset HEADHEAD 后面什么也不加,则将所有文件恢复成和 HEAD 一致

可以通过 git status 观察 reset 前后的变化,见下图:

image

reset 之后,修改的操作又放到了工作区,可以通过 git add 命令又将它们添加到暂存区。

PS:

git diff --cached 可以验证暂存区和 HEAD 内容的一致性。

git reset HEADgit restore --staged . 的效果是一样的,后者是 git 2.23 + 后新增的。

22 | 如何让工作区的文件恢复为和暂存区一样?#

场景:工作区做了修改,但是不想要了,想恢复为和暂存区一样。

命令: git checkout <FILENAME>

再提醒下这张图:

image

过程演示:

首先通过 git add ,将修改后的 readme.md 文件,从工作区添加到暂存区:

image

观察操作前后 git diff --cached 的结果,即暂存区与 HEAD 差异的变化,可知 git add 成功。

然后,再来修改readme.md 文件,通过 git diff 观察工作区和暂存区的差异:

image

红框部分为此次的修改。

通过 git status 查看工作区和暂存区的情况:

image

图中上半部分是暂存区中待 commit的内容;下半部分是工作区中待添加到暂存区的内容。

可以看到两个部分都有对 readme.md 的修改,分别对应刚才的两次修改。


❗️此时,如果想把 readme.md 文件在工作区的内容恢复回暂存区状态,使用 git checkout readme.md 即可。

image

可以看到工作区的 readme.md 文件已经不在待添加状态了。


PS:

  • 慎用git checkout ,可能导致文件找不回。
  • Git 2.23 之后,用 git switchgit restore 来替代 git checkout 功能:git switch 替换 git checkout 切换分支的功能; git restore 替换对工作区文件进行恢复的功能。
  • git checkout <FILENAME>git restore <FILENAME> 的效果是一样的,后者是 git 2.23 + 后新增的。

23 | 怎样取消暂存区部分文件的更改?#

命令: git reset HEAD [FILENAME] ,类似第 21 节,在命令后面多添加了具体的文件名,也可以指定多个文件,用空格隔开。

下面示例展示了暂存区中的修改被一个一个退回到工作区中:

image

如果想把工作区中的修改再添加到暂存区,使用 git add 命令即可。

24 | 消除最近的几次提交#

命令: git reset --hard <HASH_OF_COMMIT> ,可以改变 HEAD 的 commit 指向,并且暂存区和工作区的内容都回到该 commit。

请看下面的例子:

image

观察 git reset --hard 前后的两个点:

1)通过 git log 可以看出 HEAD 的指向后退了两个 commit;

2)通过 git diff 可以看出工作区和暂存区从存在差异到没有差异。

25 | 看看不同提交的指定文件的差异#

命令: git diff <HASH_OF_COMMIT> <HASH_OF_COMMIT> [-- FILENAME]

最后添加指定的文件, 如果不添加,则会展示所有文件的差异;

<HASH_OF_COMMIT> 可以用直接换成分支名,分支名本质上也是指向一个 commit。

PS:加--会使 Git 更明确你的意图。

26 | 正确删除文件的方法#

命令: git rm <FILENAME>

效果如下:

image

本质上相当于删除了文件,并把这个删除操作同步到了工作区和暂存区里,等同于:

image

先通过 git reset --hard HEAD 让工作区和暂存区都恢复到 HEAD 的状态;

通过 git status ,分别观察 rm 文件以及 git rm 文件后,工作区和暂存区的状态:

1)前者改变了工作区,但没有暂存;

2)后者同步了暂存区,此时可以 commit 这次修改了。

27 | 开发中临时加塞了紧急任务怎么处理?#

临时加塞了紧急任务,当前工作还只是半成品,该怎么办呢?

git stash :将当前工作区和暂存区的内容迁移到一个额外的栈上,只对被跟踪的文件有效。

完成了紧急任务,此时要恢复刚刚的半成品,先查看 stash 了哪些内容。

git stash list :显示 stash 的记录列表。

然后,将最近的一次 stash 内容恢复到工作区内。

git stash apply :恢复栈顶的保存记录,且记录列表里还保留该记录。

git stash pop :恢复栈顶的保存记录,并把记录列表里的该记录删除

  • PS:也可以指定某一个记录恢复。

过程展示:

来了紧急任务,先将暂存区里未完成的内容 stash 起来。

image

此时 stash 记录列表里添加了一个记录 {0},并且当前工作区和暂存区里已经干净。

忙完了,恢复 stash 里最近的一个记录。

image

可以看到 apply 是不会清除 stash 记录的,并且被恢复的内容放到了工作区,而之前 stash 的是暂存区的内容。

再来另一种方式的恢复,使用 pop 并且添加 --index 参数。

image

可以看到 pop 会清除该 stash 记录,并且被恢复的内容放到了与 stash 时一样的暂存区, --index 其实就代表还会恢复暂存区。


PS:

WIP 全称 Work in progress,表示正在工作过程中,引申含义为 “目前工作区中的代码正在编写中,这部分代码不能独立运行,是半成品”。

28 | 如何指定不需要 Git 管理的文件?#

方法:在 .gitignore 文件中声明文件类型或文件名即可(必须是 .gitignore

声明 doc / 和 doc 的区别演示

1)doc/:忽略文件夹,但不会忽略同名的文件

创建 doc 文件夹,在里面添加 readhim 文件。

image

.gitignore 文件里添加 doc/ 后,Git 将忽略对 doc 文件夹的跟踪。

但是,将 doc 文件夹换成 doc文件后,Git 将不会忽略跟踪 doc 文件。

image


2)doc:同时忽略文件夹和同名文件

而对于忽略规则 doc,不管是文件夹还是同名文件,都会让 Git 忽略对其跟踪。

image


⚠️:

  • 常用通配符 * 忽略同类的文件
  • 文件已经被跟踪后, .gitignore 文件就不起作用了
    • 如果提交 commit 后,想再忽略一些已经提交的文件呢?
    • 可以把想忽略的文件先添加到 .gitignore 文件中,然后通过 git rm --cached FILENAME 的方式忽略掉无需跟踪的文件。
  • 在 Github 上新建仓库时,可以选择添加一份合适的.gitignore 文件:(很贴心❤️)

image

PS:对于不同的语言或项目,常见的 .gitignore 文件可参考github/gitignore库。

29 | 如何将 Git 仓库备份到本地?#

相关命令: git clonegit remotegit push


常用传输协议:本地协议、http/https 协议、ssh 协议,后两者在工作中最常用。

传输协议又可以分为两类:哑协议和智能协议,这里以本地协议为例:

1)/Path/to/.git;2)file:///Path/to/.git

前者为哑协议,后者为智能协议。


那么两者在 Git 备份时有什么区别呢?

智能协议相比哑协议,1)传输进度可见,2)并且传输速度更快。


智能协议和哑协议的效果对比:

通过 pwd 获取到了之前演示用的仓库地址为: /Users/double/Desktop/test

现在通过两种协议,将仓库备份到另外的地方:test_remote 目录下。

哑协议

image

⚠️: --bare 代表创建裸仓库,即不带工作区的仓库,其方便作为服务端;备份的是.git 文件夹,所以地址要添加 /.git ;最后的 ya.git 表示仓库名。

智能协议

回到 test.remote 目录下,使用智能协议,即添加 file:// 前缀。

image

对比可以看到直观的区别:哑协议不带进度条,而智能协议有进度条。


上面展示的是从远端克隆 (clone )仓库到本地的过程,那如何推送 (push ) 本地仓库到远端呢?

回到原仓库(这里原仓库的角色从远端转变成了本地),新建一个名为 new 的分支。

image

此时远端 intel.git 仓库还只有 3 个分支:

image

在本地添加远端服务器:

git remote add intel file:///Users/double/Desktop/test_remote/intel.git

PS: intel 为服务器别名,后面是服务器地址,使用智能协议。

image

通过 git remote -v 可以查看详细的服务器信息。

接下来进行推送: git push REMOTE_NAME 命令

image

⚠️:直接推送会报错,需要先设置上游。

再次查看下远端 intel.git 仓库的分支情况:

image

可以看到分支 new 已经被推送过来了~

学到这里,有哪些是你之前不知道的呢?欢迎交流~

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.