Unique's Blog

理解Git和实战

2022-10-17 · 2249字 · 9 min read
🏷️  Git

Git 原理

.git 文件夹说明

-rw-r--r--    HEAD    # 当前的头部commit/指向
-rw-r--r--    config  # 本地仓库的配置
drwxr-xr-x    hooks   # hooks模版
-rw-r--r--    index   # 暂存区的索引[被追踪的文件信息](添加到暂存区会持久化)
drwxr-xr-x    logs    # HEAD 的记录[分支记录以及HEAD移动记录]
drwxr-xr-x    objects # 文件对象[commit对象文件,tree对象文件,bob普通文件]
drwxr-xr-x    refs    # 分支的头部和tags(对应的commitID)

commit 对象表示了此次提交的一次快照/版本,而暂存区是当前的修改版本,等到提交时将当前的状态建立一个 commit 保存归档。

例如一个 commit 对象关联的对象:

commit
  • commit 对象包含一个 tree 对象(指针),表示了当前文件树形组织的快照版本

  • commit 对象之间通过 parent 指针联系

  • 暂存区,上次提交+后续添加到暂存的文件修改的文件状态

说明:

  1. commit 之间,相同的文件对象是共享的;

  2. 每次修改添加到暂存区后,只会影响 bob 文件对象【tree 对象等到提交才会生成】

  • 每个文件的权限、文件路径和 Hash存储在.git/index文件
  1. Git 的 hash 指针/内容寻址/DAG 结构被广泛用于 IPFS 的存储架构中。
Git对象简单测试
# git sha-1 hash
echo "Hello" | git hash-object --stdin
# 查看暂存区的内容[由git追踪的文件]
git ls-files --stage
# 查看git对象的类型
git cat-file -t ID
# 查看git对象的内容
git cat-file -p ID

实战

比较命令

  • git diff commitID1 commitID2 [-- file1 ...]
    比较两个提交的[部分]文件差异,可以使用分支名代替 ID

  • git diff[-- file1 ...]
    比较工作区和暂存区的文件差异

  • git diff --cached [-- file1 ...]
    比较暂存区和HEAD/最近提交的文件差异

  • git diff HEAD -- [-- file1 ...]
    比较工作区和HEAD/最近提交的文件差异

分离头指针

分离头指针,即 HEAD 指向了非分支的头部提交,如果新建提交不属于任何分支,不会被 git 管理后续会被清理。

但是,基于该提交进行试验产生新提交是可行的

  • 如果新提交需要保留,应该基于新提交建立新分支/tag

  • 对于基于分离头指针的提交 为 unreachable object 会在默认策略下被清理【分支/tag/index/reflog 不能到达的对象】并且默认 2weeks 不变(不修改)[缓解竞争条件]的话会被清理

    • 如果想要及时删除,例如大文件提交

    将对应的提交变为unreachable 后(注意 ref/reflog 等都不能索引到它),执行 git gc --prune=now

修改本地提交

  1. 修改最新 commit 的 message
    git commit --amend

  2. 使用变基rebase修改、合并提交
    变基,改变当前分支base 提交位置,使用  rebase  命令将提交到某一分支上的所有修改都移至另一分支上,就好像重新播放一样。用于合并分支【会将分支的提交整理成线性】
    git rebase 目标分支 [源分支] (会先切换到源分支[默认为当前分支],并将当前分支指向目标分支的位置,应用源分支上的每个提交)

(1) 修改本分支上的旧 commit 的提交信息
对自己进行变基,重新修改 base 提交后续的提交
git rebase -i commitID commitID 应该选取为需要修改的前一个提交 ID,通过交互式命令操作后续提交的状态,从而修改后续的所有提交
(2) 合并分支上的几个 commit
git rebase -i commitID 同样可以操作不同的 commit

不同场景的恢复

首先需要知道工作区、暂存区和最近提交 commit 三者之间的关系

注意理解:分支 branch 是指向最新提交的指针(main),通过它可以追溯到整个历史记录

git reset 命令的介绍:

# git reset [--soft | --mixed | --hard] <commit>

# --mixed 是默认值,同 git reset <commit>
# 修改当前分支,将分支指向 <commit> 位置,同时重置暂存区内容与 <commit> 相同,但是不修改工作区(还是原来最新的工作区内容)
# 可以用于将工作区的内容重新提交,通过回退分支+重新提交达到变相修改提交的目的

# --soft
# 仅移动分支的头指针到指定的提交,不修改暂存区和工作目录

# --hard
# 强制代码回滚,参考下节

常见的恢复场景:

  1. 暂存区恢复成 HEAD 一样

git reset HEAD [file1 ...]
含义:使用 git reset —mixed HEAD ,重置了当前的暂存区为最新提交状态。保持最新工作区状态。
类似命令:git restore --staged <file> 必须加文件路径,是一个局部(指定文件)恢复操作,并且不会修改分支指针的状态

  1. 工作区恢复成暂存区一样

git checkout -- '*'

丢弃最近的几次提交【代码回滚】

git reset —hard commitID

说明:由于丢弃的提交处于游离部分/不属于分支或 tag 关联的提交,可能会被清理,想切换分支请使用 checkout 命令。

撤销某次提交

git revert commitID [commitID ...],用于撤销某次特定提交,效果:反向应用某个提交的更改,生成一个新的提交,从而撤销目标提交的影响。它不会删除原始的提交记录。(git reset 功能主要是回滚,通过移动分支的头指针实现,可能丢失提交记录。)

可以使用的选项:

git revert commitID --no-commit
# 不直接生成一个新的提交,而是将反向更改放入工作目录和暂存区,下次手动提交

git revert merge-commitID -m 1
# 用于撤销一次合并提交。因为合并提交有多个父节点,Git 需要知道要保留哪个父节点的更改。(即:基于该父提交反向应用其他分支的更改)
# 通常保留主分支的更改,-m 1 (git show merge-commitID)

cherry-pick 复制提交

与分支合并(merge/rebase)不同,在只需要复制其他分支某一个 commit,使用 cherry-pick
命令,即可复制一个特定的提交到当前分支并生成一次新的提交,避免了相同的工作或分支的合并操作。

git cherry-pick commitID 在当前分支应用特定的提交

贮藏工作区与暂存区

https://git-scm.com/book/zh/v2/Git-工具-贮藏与清理

场景:当正在自己分支上开发,并修改和暂存了部分文件,临时需要切换到其它分支工作,但是此时不想提交自己未完成的工作。需要临时保存自己的工作状态,使用 git stash 来保存。

  • git stash 将工作区和暂存区中尚未提交的修改存入栈中

  • git stash list 查看栈中所有元素

  • git stash pop --index

将栈顶存储的修改恢复到当前分支,同时删除栈顶元素
默认会将先前暂存区的存储的内容撤销到工作区(暂存区修改的内容被清空),使用 --index 恢复暂存区的内容/恢复得和原来一样。

  • git stash apply --index

将栈顶存储的修改恢复到当前分支,但不删除栈顶元素

  • git stash drop 删除栈顶存储的贮藏

远程分支操作

https://learngitbranching.js.org/?locale=zh_CN

.gitignore 配置

添加忽略文件列表到 .gitignore ,让 git 忽略这些文件/不管理

有时一些文件最好不要用 Git 跟踪。这通常在名为  .gitignore 的特殊文件中完成。你可以在  github.com/github/gitignore 找到有用的  .gitignore文件模板。或者:https://www.toptal.com/developers/gitignore

简单示例:

*.class
doc/ # 忽略doc文件夹
doc/*.txt # 非递归
doc/**/*.pdf # 递归,忽略doc/下所有pdf

# 不忽略.gitignore和App.class:
!.gitignore
!App.class

Git 集成使用禁忌

禁止向团队集成的分支强制推送

push -f 强制推送分支,发生冲突会强制覆盖远程分支的内容。会导致原来分支内容全部丢失/或部分丢失。

因此,对团队的集成分支严禁使用 push -f 命令

禁止对团队的集成分支作变基操作

团队的集成分支,是不能修改历史提交的,只能通过增加 commit 提交来改进
如果使用 rebase 修改历史,会导致其他成员与集成分支的冲突。

💡

总的原则是,只对尚未推送或分享给别人的本地修改执行变基操作清理历史, 从不对已推送至别处的提交执行变基操作.

手册

  1. https://git-scm.com/book/zh/v2/Git-分支-变基

  2. 可视化 Git 命令

https://ndpsoftware.com/git-cheatsheet.html#loc=workspace;

Git 相关文章

本文链接: 理解Git和实战

版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。

发布日期: 2022-10-17

最新构建: 2024-12-26

本文已被阅读 0 次,该数据仅供参考

欢迎任何与文章内容相关并保持尊重的评论😊 !

共 43 篇文章 | Powered by Gridea | RSS
©2020-2024 Nuo. All rights reserved.