阅读视图

发现新文章,点击刷新页面。

Git指令及相关原理

Git 常见命令汇总

  1. 初始化

    git init : 初始化代码仓库,生成.git目录。在根目录下的 .gitconfig 中会包含配置信息,如用户email、用户名等

  2. git config

    git默认使用全局的用户和邮箱信息

    # 设置
    # 全局
    git config --global user.name <user_name>
    git config --global user.email <user_email>
    # 当前
    git config user.name <user_name>
    git config user.email <user_email>
    
    
    # 获取
    # 全局
    git config --global user.name
    git config --global user.email
    # 当前
    git config user.name
    git config user.email
    
    # 解决每次提交和拉取代码都需要输入用户名和密码
    git config --global credential.helper store
    
  3. git add

    将文件的更改添加到暂存区(Staging Area)。跟踪指定的文件,将其添加到 Git 的索引中。索引包含了将在下次提交中包含的文件列表。

    • Git 会计算文件的哈希值,生成文件的唯一标识符(SHA-1 值),更新Objects目录以及index文件。对于生成的objects中的文件可以查看详细信息。

      git cat-file -t <filename> # 文件类型
      git cat-file -s <filename> # 内容字节大小
      git cat-file -p <filename> # 文件内容
      
    • 新建一个同内容不同名的文件,可以发现.git下的文件目录没有变化,说明objects中保存的是文件类型和文件内容,不包括文件名。 echo "hello git">hello.txt

    • Git 用到的hash算法是SHA1算法

      echo "hello git" |  shasum    # d6a96ae3b442218a91512b9e1c57b9578b487a0b
      
    • Git的计算方式

      echo "blob 10\0hello git" | shasum  # 这里就是objects中使用的hash算法
      
  4. git commit

    在objects目录下生成一个commit类型的对象,一个tree类型的对象。

    1. 树对象(Tree Object):树对象代表了该次提交时整个项目目录结构的快照。它记录了当前提交状态下的文件和目录的组织结构。树对象保存了每个文件或子目录的名称、类型(blob 或 tree)和相应的哈希值。

      • 文件(blob):文件类型的树对象表示一个具体的文件,它包含文件名、文件模式(如文件权限)和文件内容的哈希值。文件内容的哈希值在 Git 中以 blob 对象的形式进行存储。
      • 目录(tree):目录类型的树对象表示一个子目录,它包含子目录或文件的引用。每个子目录都对应一个树对象,而文件对应的是 blob 对象。
    2. 提交对象(Commit Object):提交对象代表了一次具体的提交操作。它包含了该次提交的作者、提交时间戳、父提交引用和提交消息等信息。

      • 作者和时间戳:提交对象记录了该次提交的作者信息和提交时间。

      • 父提交引用:除了第一次提交外,每个提交对象都包含一个或多个父提交的引用。这些引用指向了该次提交的直接前导提交。这样形成了提交历史的有向无环图(DAG)结构,记录了提交的衍生关系。

      • 提交消息:提交对象包含了提交时输入的提交消息,用于描述该次提交的目的和变更内容。

  5. git 分支管理

  • HEAD是一个特殊指针,始终指向当前分支的最新commit

    image.png

  • 分支操作

    git branch  //列出当前所有本地分支
    git branch -r // 查看所有的远程分支
    git branch -a // 查看所有分支
    git branch <branch_name>  // 创建分支,如过已经存在,报错
    git branch -D <branch_name>  // 删除分支,不能删除当前分支
    
    git checkout <branch_name> // 切换分支,也可以直接checkout到特定的commit(detached Head)
    
    git branch -m <new-branch-name> // 分支重命名
    git branch -v // 查看每个分支的最后一次提交信息
    git branch -vv // 用于查看分支列表及其对应的追踪信息
    
    git switch <branch> // 切换到已存在的分支
    git switch -c <new-branch> // 创建并切换到新的分支,等价于branch + switch
    git switch -f <branch>  // 强制切换分支(丢弃当前更改)
    git switch <commit/branch/tag> --detach // 切换到某个提交或标签:
    

假设删除了一个分支,可以通过detached Head去找回删除分支的commit

```
git checkout <commit_code>
git checkout -b <branch_name>
```
  • git diff

    比较文件或提交之间差异,例如当前工作目录和最新提交之间的差异,或者两个提交之间的差异。

    # 比较工作目录和最新的commit的差异
    git diff
    
    # 比较指定文件在工作目录和最新提交之间的差异
    git diff <file-name>
    
    # 比较两个提交之间的差异:
    git diff <commit1> <commit2>
    
    # 比较指定分支和当前分支之间的差异
    git diff <branch-name>
    
    # 比较指定提交和当前工作目录之间的差异
    git diff <commit>
    
    # 比较指定提交和当前工作目录之间的差异(包括未暂存的更改
    git diff <branch1> <branch2>
    
    # 比较两个分支之间的差异
    git diff <commit> -- <file-name>
    
    # 对比索引区和代码 仓库
    git diff —cached
    

    image.png

  1. 仓库管理

    1. 新建一个仓库

    2. 将远程仓库添加本地:

      1. git remote add origin url

      2. 查看配置:cat .git/config ,发现出现了remote origin相关信息

      3. 上传到远程仓库:git push -u origin master

      4. 查看.git文件目录:出现了origin目录。

      5. 此时,查看heads和origin远程master和head对应的版本号一致。

      cat ..git\refs\remotes\origin\master cat ..git\refs\heads\master

  2. 压缩、解压

    每次修改都会生成新的bolb对象,通过压缩可以提高传输效率。将object中的文件压缩,全部放入pack中

    git gc  // 压缩
    git verify-pack -v ..git\objects\pack\pack-c992458971df8d681e44771882f19e49298fc75b.idx  //  查看具体的压缩情况
    git unpack-objects < .git/<pack_url> // 解压缩
    
  3. 垃圾回收

    当我们将同一个文件的多次修改,分别add到索引区时,会产生3个对应的blob,在进行commit,会生成对应的tree和commit文件,但是前两次修改产生的blob就是垃圾对象。git gc会将一个blob、一个commit、一个tree压缩,但是多余的blob不会删除

    git prune  // 删除多余的对象
    

    分支删除之后遗留的垃圾对象

    git -c gc.reflogExpire=0 -c gc.reflogExpireUnreachable=0 \
      -c gc.rerereresolved=0 -c gc.rerereunresolved=0 \
      -c gc.pruneExpire=npw gc "$@"
    
  4. git merge

    1. fast forward:如果目标分支在源分支的前进历史中没有额外的提交,那么 Git 将执行快进合并。这种合并模式可以产生一个干净的、线性的提交历史。切换回master分支进行merge,生成一个ORIG_HEAD可以用于回滚。 git merge bugfix

    2. 3 way merge

      • 工作原理:3-way merge比较目标分支、源分支和共同祖先之间的差异,并尝试自动合并这些更改。

      • 优势:3-way merge能够自动处理没有冲突的更改,因此对于大多数情况下的合并是简单且有效的。

      • 适用场景:3-way merge适用于多人协作的项目,特别是当多个人在同一个分支上工作并推送更改时,以及当存在冲突时需要手动解决。

      • 分叉的merge会导致parent出现两个,如果c3、c4 修改了同一个文件会出现冲突。

        image.png

        冲突,会保存三个不同版本的blob,冲突解决commit之后会只剩一个。

    3. Rebase merge(合并衍合):

      • 工作原理:Rebase merge将源分支的每个提交重新应用到目标分支上,形成一系列新的提交。它不会创建合并提交,而是重演源分支的提交历史,并将它们放在目标分支的顶部。
      • 优势:Rebase merge可以产生一个干净、线性的提交历史,不会产生合并提交。它使得提交历史更易于理解、回溯和维护。
      • 适用场景:Rebase merge适用于个人分支或仅自己使用的分支上的合并
  5. Rebase

    要实现fast-forward,必须让新建分支用于master分支最新的commit。要实现这个功能需要使用git rebase

    rebase存在的问题:

    1. 一般不会在master分支上rebase
    2. master的commit(EC5BE)可能和dev分支上的commit在rebase的时候存在冲突。
    3. 如果之前dev分支已经上传到仓库,协作人员拉在本地进行修改,这时再进行rebase会影响他人工作。
  6. Tag

    使用带message的tag会生成一个新的类型为tag的objects,且删除tag之后会残留垃圾。同时在refs/tags中会生成新的文件指向commit对象。

    如果只是生成一个tag,不会生成对应的object,只会在refs/tags中会生成新的文件指向commit对象

    git tag <tag_name>  // 执行commit的hash
    git tag -a <tag_name> -m <tag message>
    git tag -a <tag_name> <commit value>
    git tag  // list
    git tag -d <tag_name> -M <tag message>
    
  7. 本地分支和远程分支

    远程分支的信息被压缩在packed-refs中,不实时

    // 克隆远程代码
    git clone <remote_url>
    // 同步远程分支
    git fetch 
    // 远程仓库的名字和url
    git remote -v
    // 联网检查远程分支和本地分支的一个连接关系
    git remote show origin
    
  8. git fetch

    检查远程仓库的代码情况,更新本地分支,对于远程分支删除的情况是不被处理的。

    git fetch —prune : 先剪枝再同步

    fetch结束可以通过merge让本地分支和远程分支保持一致

    情况1:

    git clone url
    // someone push new commit to github
    git fetch 
    git merge origin/master
    

    image.png

    情况2:

    git clone url
    // someone push new commit to github
    // local master have a new commit
    git fetch 
    git merge origin/master
    

    image.png

  9. git pull

    FETCH_HEAD记录执行git fetch/ git pull分支的对应远程分支的最新的commit

    ORIG_HEAD 记录git pull之前对应的commit

    git pull  // 默认远程仓库获取并合并更改,origin
    
    git pull <remote>  // 从指定远程仓库获取并合并更改
    
    git pull --rebase  //获取并在合并前进行变基(rebase)操作
    
    git pull --no-commit   // 获取并忽略远程仓库的更改
    
  10. git push

    git push // 没有分支关联的时候会报错
    
    git push origin newBranch  // 推送
    
    git push -u origin newBranch  // 推送且将远程分支和本地分支相连 
    
    git push origin -d branch_name // 删除远程分支
    
  11. 类似指令对比

  • git fetch & git pull

    1、git pull:从远程获取最新版本并merge到本地,会自动合并或修改当前的工作。相当于git fetch与git merge两条命令

    2、git fetch :会将数据拉取到本地仓库 ,它并不会自动合并或修改当前的工作

    3、在实际使用中,git fetch更安全一些,因为在merge前,我们可以查看更新情况,然后再决定是否合并

  • git pull & git clone

    1、git clone是将整个工程复制下来所以,不需要本地是仓库(没有.git文件夹),第一次拉取项目不需要使用git init 初始化本地仓库

    2、git pull需要使用git init初始化本地仓库,

    3、git clone 可以直接切换远程分支,git pull需要切换到当前分支

    4、git clone 可以直接指定远程分支推送,git pull需要关联远程仓库(git add origin 远程仓库地址)才能push

  • git switch & git checkout

    • git switch 命令提供更直观和一致的分支切换语义。它的主要用法是 git switch <branch>,用于切换到已存在的分支或创建并切换到新的分支(使用 -c 参数)。git checkout 命令在早期版本的 Git 中,它的语义较为复杂且多样化。除了切换分支外,git checkout 还用于切换提交、还原文件等。
    • git switch 在切换分支时具有更高的安全性。如果存在未提交的更改或未保存的工作目录状态,git switch 会拒绝切换分支,以避免意外丢失或混淆更改。git checkout 在切换分支时较为宽松,它不会检查工作目录的状态,因此可能会在存在未提交的更改时执行切换,潜在地导致更改的丢失。
  • git log & git reflog

    git log 用于查看提交历史记录,显示了当前分支上的所有提交。

    git reflog 用于查看引用日志,显示了当前仓库的引用(如分支、HEAD)的移动历史记录。git reflog 对于恢复误操作、找回丢失的提交等非常有用。

  • git rm & git reset & git restore & git revert

    • git rm 用于从 Git 仓库中删除文件或目录。

      git rm <file>  // 删除已跟踪的文件,从 Git 仓库中删除指定的文件放入暂存区,下一次提交时从仓库中彻底删除。
      
      git rm -r <directory>  // 递归删除目录
      
      git rm -f <file/directory>  // 强制删除,即使它们处于修改或未跟踪状态
      
      git rm --cached <file>  // 删除 Git 仓库中跟踪的文件,但保留本地工作目录中的文件
      
      git rm <pattern> // 使用通配符或正则表达式指定一个模式来删除多个文件
      
    • git reset 用于重置 Git 仓库状态的命令,它可以在不同的模式下修改 HEAD 和分支指针,以及更改索引和工作目录的内容。

      git reset [--hard] <commit>  // 将当前分支的 HEAD、索引和工作目录全部重置为指定的 <commit>。丢弃当前的所有更改,慎用。
      
      git reset [--mixed] <commit> // 将当前分支的索引重置为指定的 <commit>,但保留工作目录中的更改。这意味着您可以重新提交工作目录的更改。
      
      git reset [--soft] <commit> // 将当前分支的 HEAD 指针移动到指定的 <commit>,但不更改索引和工作目录。这样可以重新提交以前的提交或将它们合并为单个提交。
      
      git reset [--hard] HEAD@{<n>}  // 使用引用(reflog)中的记录恢复到以前的提交状态
      
    • git restore 用于还原文件的修改,恢复到先前的状态。它可以撤销工作目录和索引中的更改,或恢复已删除的文件。

      git restore <file>  // 恢复工作目录到最近一次提交的状态,丢弃在工作目录中的任何修改。
      
      git restore --staged <file> // 将指定的文件恢复到最近一次提交的状态,同时将其从索引中移除。这可以撤销 git add 操作。
      
      git restore --source=<commit> <file>  // 恢复已删除的文件
      
      git restore .   // 使用 . 可以批量恢复整个工作目录中的所有文件,将它们恢复到最近一次提交的状态。
      
    • git revert <commit>:使用指定的提交哈希 <commit> 来创建一个新的提交,该提交撤销了指定提交的更改。这种回滚方法会保留原始提交历史,并在回滚提交后生成一个新的提交来撤销先前的更改。

❌