前语

本文首要讲Git的相关常识,特别是关于rebase、revert指令的一些个人了解,欢迎我们纠正。articles/2023-03-14-GIt韶光机(简单小例子).md at main slshsl/articles (github.com)

Git 与其他版别控制体系的差异

Git 直接记录快照,而非差异比较。

Git 完整性

Git 中一切的数据在存储前都核算校验和,然后以校验和引证Git 用以核算校验和的机制叫做 SHA-1 散列(hash,哈希)。

Git 怎样存储数据

Git存储数据有点像 key-value storekey能够以为是datasha1哈希,value以为是数据本身。

value是经过ZLib紧缩过的

Git 根底概念

Working Space / Working Directory作业区/作业目录,便是你平时存放项目代码的地方,本文一致运用作业区

Index / Stage暂存区/索引区,用于暂时存放你的改动,本文一致运用暂存区

Local Repository本地库房本地版别库)本文一致运用本地库房

Stash储藏区

Remote Repository长途库房长途版别库)本文一致运用长途库房

<remote_name>/<branch_name>本地长途分支引证/本地长途盯梢分支,本文一致运用本地长途盯梢分支

Git 时光机,一只调皮的猫

常用指令

git xxx -h

检查某个指令的帮助信息。

git config

# 检查git装备
$ git config -l`
# 检查体系装备
$ git config --system --list
# 检查用户装备
$ git config --global --list
# 检查项目装备
$ git config --local --list
# 设置用户称号
$ git config --global user.name xxx
# 设置用户邮箱
$ git config --global user.email xxx
# 启动的编辑器一般为 vim。 当然也能够指令设置你喜欢的编辑器。
# 我一般习惯设置成vscode
$ git config --global core.editor xxx
# 项目启用rerere
$ git config rerere.enabled true
# 设置log -1 HEAD的别名为last
$ git config --global alias.last 'log -1 HEAD'
# 运用last别名
$ git last

每一个等级会掩盖上一等级的装备

git init

初始化一个库房。

git clone

# 克隆一个库房
$ git clone <url>

git clone 指令做了什么?

  1. 增加一个盯梢的长途库房remote,主动将其命名为 origin,拉取它的一切数据
  2. 创立一个origin/master本地长途盯梢分支
  3. 创立一个 master本地分支
# 克隆一个库房
$ git clone —depth=1 <url>

一般我们直接运用 git clone 即可克隆项目,假定仅仅运用一个库房项目,这是参加–depth=1参数能够使我们只下载当时的最新提交即可。

git add

增加作业区的内容至索引区。

git status

显现当时的状况。

$ git status
On branch dev
Your branch is ahead of 'origin/dev' by 2 commits.
  (use "git push" to publish your local commits)
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   a.txt
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   a.txt
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        c.txt
  1. 显现当时分支与其本地长途盯梢分支(假定有)的关系 能够经过git push推到长途的commit
  2. 显现暂存区和本地库房有差异的文件 经过运转git commit会增加到本地库房的文件
  3. 显现作业区和暂存区有差异的文件 经过运转git add能够增加到暂存区的文件
  4. 显现作业区中不被git追寻的文件(也不被.gitignore忽略) 经过运转git add能够增加到暂存区的文件

git commit

# 提交变更到本地库房
$ git commit -m "xxx"
# 修补提交:修补终究的提交
$ git commit --amend
# 修补提交:修补终究的提交,不修正提交信息
$ git commit --amend --no-edit

Git 时光机,一只调皮的猫

git commit --amend:修补终究的提交时,是彻底用一个新的提交替换旧的提交。修补提交最明显的价值是能够略微改进你终究的提交,例如一些小的修补,笔误等等;能够像下面这样操作:

# 第一次提交
$ git commit -m 'initial commit' 
# 修正笔误等
$ git add forgotten_file
# 第2次提交
$ git commit --amend

终究你只会有一个提交;第2次提交将代替第一次提交的结果。

假定你的代码现已 push 了的话,git commit --amend要慎用,因为会修正提交前史。

# 带签名的提交
git commit --signoff -m 'xxxx'

git log

# 基本用法
$ git log
# 仅显现最近的 n 条提交
$ git log -<n>
# 按补丁格局显现每个提交引入的差异
$ git log -p
# 显现每次提交的文件修正计算信息
$ git log --stat
# 在日志旁以 ASCII 图形显现分支与兼并前史
$ git log --graph
# 每条日志一行显现
$ git log --pretty=oneline
# 仅显现 SHA-1 校验和一切 40 个字符中的前几个字符
$ git log --abbrev-commit
# --pretty=oneline --abbrev-commit 合用的简写。
$ git log --oneline
# 仅显现作者匹配指定字符串的提交。
$ git log --author='xxx'
# 
$ git --no-pager log
# Log files that have been moved or renamed
$ git log --name-status --follow -- file

git diff

# 比较作业区与暂存区之间的不同
$ git diff
# 比较暂存区与本地库房之间的不同
$ git diff —cached(git diff —staged)
# 比较作业区和暂存区(即一切未提交到本地库房的修正)与本地库房当时的HEAD之间的不同
$ git diff HEAD
# 比较作业区和暂存区(即一切未提交到本地库房的修正)与本地库房dev分支最新commit之间的不同
$ git diff dev
# 比较作业区和暂存区(即一切未提交到本地库房的修正)与本地长途盯梢dev分支最新commit之间的不同
$ git diff origin/master
# 比较两次提交之间的不同
$ git diff [commit_sha1_value] [commit_sha1_value] 

git tag

有两种tag,一种是lightweight轻量标签;一种是annotated tag附注标签

# 显现一切
$ git tag
# 创立lightweight tag(轻量标签)
# 假定没有写commit_sha1_value,则会主动把tag放到现在的这个commit上
$ git tag <tag_name> [commit_sha1_value]
# 创立annotated tag(附注标签)
# 假定没有写commit_sha1_value,则会主动把tag放到现在的这个commit上
$ git tag -a <tag_name> -m <tag_message> [commit_sha1_value]
# 删去tag
$ git tag -d <tag_name>
# 检查某个commit上的标签
$ git tag --points-at <commit>

轻量标签很像一个不会改动的分支——它仅仅某个特定提交的引证

附注标签是存储在 Git 数据库中的一个完整git的tag类型的objects方针, 它们是能够被校验的,其中包括打标签者的姓名、电子邮件地址、日期时刻, 此外还有一个标签信息。

git show

# 显现tag对应的commit所提交的内容,假定是附注标签,仍是显现附注标签的信息
$ git show <tag_name>
# 显现某次commit提交的内容
$ git show <commit_sha1_value>

git branch

# 检查本地库房分支
$ git branch
# 检查长途库房分支
$ git branch -r
# 检查本地库房和长途库房分支
$ git branch -a
# 创立本地库房分支
$ git branch <branch_name>
# 强制删去本地库房分支
$ git branch -D <branch_name>
# 删去本地库房分支
$ git branch -d <branch_name>
# 检查分支详细信息,包括分支终究一个commit的hash、message等
$ git branch -v
# 同git branch -v
$ git branch -vv
# 修正本地库房分支称号,假定省掉old_branch_name,则更改的是当时分支的称号
$ git branch -m <old_branch_name> <new_branch_name>
# 强制修正本地库房分支称号
$ git branch -M <old_branch_name> <new_branch_name>
# 检查哪些分支现已兼并到当时分支
$ git branch --merged
# 检查哪些分支未兼并到当时分支
$ git branch --no-merged

git branch -d <branch_name>假定该分支还未合入master或许main,会提示报错,不让删去

git branch -vv一起还会显现每一个分支正在盯梢哪个长途分支

git checkout

# 切换到新分支
$ git checkout <branch_name>
# 创立并切换到新分支 
$ git checkout -b <branch_name>
# 重置分支,删去已存在的分支且从头创立,分支不存在也不会报错称
$ git checkout -B <branch_name>
# 将head指向一个commit
$ git checkout <commit_sha1_value>
# 从某个本地长途盯梢分支中检出一个新分支(并设置该分支的上游是长途盯梢分支)
$ git checkout -b <new_branch_name> <remote_name>/<old_branch_name>
# 是 git checkout -b <new_branch_name> <remote_name>/<old_branch_name>的简写
$ git checkout --track <remote_name>/<branch_name>
# 让作业区中的一切文件吊销更改
$ git checkout -- .
# 让作业区中的某些文件吊销更改
$ git checkout -- <file_name> <file_name> 

git checkout -b <new_branch_name> <remote_name>/<old_branch_nameh>

git checkout --track <remote_name>/<branch_name>

git checkout <branch_name>

git checkout -b <new_branch_name> <remote_name>/<old_branch_nameh>的意思是从某个本地长途盯梢分支中检出一个新分支,并设置该新分支的上游是该本地长途盯梢分支; 因为git checkout -b <new_branch_name> <remote_name>/<old_branch_nameh>经常用,且检出的新分支姓名和其上游分支的姓名一般相同,不太会取不同的姓名;所以出了一个简写指令git checkout --track <remote_name>/<branch_name>git checkout --track <remote_name>/<branch_name>该指令从某个本地长途盯梢分支中检出一个新分支,并设置该新分支的上游是该本地长途盯梢分支,一起该新分支的姓名不能指定,只能是该本地长途盯梢分支的姓名; git checkout --track <remote_name>/<branch_name>仍是太长;所以 git checkout branch_name 切换分支时,先从本地库查找分支,在本地库没找到时,会去本地长途盯梢分支中查找,假定本地长途盯梢分支中有相同称号的分支,则也会检出分支并设置其上游为同名的本地长途盯梢分支;假定本地长途盯梢分支里也没有找到就会报错;

git checkout <commit_sha1_value>:这样会产生detached head,即head不再指向一个分支,而是指向一个commit; 运用场景是比方从之前的commit或许误删的commit(经过给git reflog检查);拉出一个新分支;

# 检查一切操作的日志
$ git reflog
# 检出需求检出的commit
$ git checkout <ommit_sha1_value>
# 检出一个新的分支
$ git checkout -b <new_branch_name>

git checkout --的吊销功用:git checkout吊销的是作业区的内容,即铲除作业区 场景一、本地库中已有 user.txt在作业区修正了该文件,可是没有提交到暂存区,此刻吊销更改是从本地库房中康复内容 场景二、本地库中已有 user.txt在作业区修正了该文件,而且之前按已提交到暂存区,此刻吊销更改是从暂存区中康复内容

git restore

代替git checkout的吊销功用。

# 放弃在作业区的修正
$ git restore <file_name> <file_name>
# 放弃一切文件在作业区的修正
$ git restore .
# 将暂存区的内容,移动作业区中,便是git add的反向操作
$ git restore  —staged <file_name> <filen_ame>

git restore <file_name> <file_name>代替git checkout -- <file_name> <file_name>

git restore .代替git checkout -- .

it restore —staged <file_name> <filen_ame>git add 的反向操作

git switch

代替git checkout的切换分支功用。

# 假定本地库房或许本地长途盯梢分支有这个分支,则切成功,不然失利
$ git switch <branch_name>
# 创立并切换到新分支 
$ git switch -c <branch_name>
# 重置分支,删去已存在的分支且从头创立,分支不存在也不会报错称
$ git switch -C <branch_name>

git switch <branch_name>代替git checkout <branch_name*>

git switch -c <branch_name>代替git checkout -b <branch_name>

git switch -C <branch_name>代替git checkout -B <branch_name>

git switch -能够快速切换上一个分支,来回切换,与 cd -相同

git remote

# 显现长途库房的姓名
$ git remote
# 显现长途库房的姓名及url
$ git remote -v
# 检查本地长途盯梢分支与长途库房中分支的同步情况
$ git remote show <remote_name>
# 能够删去(在长途库房中被删去的分支)对应的本地长途盯梢分支
$ git remote prune <remote_name>

git remote show <remote_name>:一般运用场景便是在git fetch之前检查一下分支同步情况

git fetch —prunegit remote prune的作用相同,实际上删去(长途库房中被删去的分支)对应的本地长途盯梢分支。

git rebase

变基

$ git rebase <upstream_name>
# 当时分支为dev
$ git rebase main
# 假定有冲突,处理冲突后继续编辑
$ git rebase —continue
# 当时分支为main
$ git merge dev

Git 时光机,一只调皮的猫

git rebase <upstream_name>做了什么? git rebase maindev)把dev分支的提交重放(从头运用)到main分支的顶部。

Git 时光机,一只调皮的猫

git rebase --onto main server client做了什么? 关于这个指令,每次看到都头大,需求自己用文字描绘一下,以方便了解

Git 时光机,一只调皮的猫

# newbase_name\upstream_name\branch_name既能够是分支名,也能够是commit_sha1_value
$ git rebase [--onto <newbase_name>] [<upstream_name> | [branch_name]]

怎样了解上面这条指令各个参数是啥意思?列出详细指令来尝试解说

  1. 场景及指令一:
    场景:假定dev是从master检出的分支,要在dev分支上变基,当时地点分支不是dev分支
    指令:git rebase <upstream_name>git rebase master

    # 切换到dev分支
    git checkout dev
    # rebase master,这个master是对应upstream_name;怎样了解这里的上游分支
    # 实际上便是dev是从master检出的,是dev的上游分支,依此来找到两个分支的穿插点
    # 把在dev分支上以这个穿插点为起点,以当时HEAD为结尾(dev最新commit),把这两点之间的
    # commit在master分支顶部(最新commit),从头来一遍,得到一个新的dev分支。
    git rebase master
    
  2. 场景及指令二:
    场景:假定dev是从master检出的分支,要在dev分支上变基,当时地点分支不是dev分支
    指令:git rebase <upstream_name> [branch_name]git rebase master dev

    # git rebase master dev 是 git checkout dev + git rebase master 这两条指令的简写
    # 便是我先切到dev分支,再rebase master分支
    git rebase master dev
    
  3. 场景及指令三:
    场景:假定当时地点分支是dev分支,其本地长途盯梢分支是origin/dev
    指令:git rebase

    # git rebase 是 git rebase origin/dev 指令的简写
    git rebase
    

    简写的条件是

    1. 当时不是detached headhead状况
    2. 当时分支有对应的本地长途盯梢分支(即上游分支)
  4. 场景及指令四:
    场景:

    Git 时光机,一只调皮的猫
    指令:git rebase --onto main server client
    # 第一步:git checkout client
    # 第二步:找到client与其上游分支server的穿插点的之后的一切commit
    # 第三步:把这些commit根据--onto参数的值main顶部(最新的commit),重放这些commit
    # 了解分为两部分,第一部分找server client穿插之后的提交,
    # 第二部分,以--onto参数的值为基,重放这些提交
    git rebase --onto main server client
    
  5. 场景及指令五:
    场景:master分支,共6个提交,每个提交都创立一个txt文件 指令:git rebase --onto HEAD~5 HEAD~3 HEAD

    # 第一步:git checkout HEAD,处于detached headhead状况
    # 第二步:找到HEAD~3与HEAD之间一切的commit
    # 第三步:把这些commit根据HEAD~5,重放这些commit
    # 实际效果便是删去第2次与第3次提交
    # 能够从当时游离的head检出一个分支代替master,或许直接git branch -D master
    git rebase --onto HEAD~5 HEAD~3 HEAD
    

    Git 时光机,一只调皮的猫

  • 运用场景
    1. 在兼并分支前,不想分叉,能够先rebase方针分支,再合入方针分支
    2. 同步长途分支时,不运用git pull,运用git fetch,再运用git rebase

同享分支:当一个分支会被push到长途库房,且有或许其他人会进行pull操作时,这便是一个同享分支

Do not rebase commits that exist outside your repository and that people may have based work on.

永久、永久不要对一个同享分支进行变基

原因便是:变基操作的实质是丢掉一些现有的提交,然后相应地新建一些内容相同但实际上不同的提交。

根据变基的实质,假定是多人协作对同享分支允许变基;假定A在本地变基操作后推到了长途同享的分支,一起也丢掉了一些现有的提交;

而B在拉去长途同享分支时,因为依靠了之前A丢掉的提交,所以假定再merge后推送到长途,就会造成重复的提交。

处理办法:那便是永久不要对同享分支进行变基;

交互式变基

# start_commit_sha1_value不包括,end_commit_sha1_value包括
# end_commit_sha1_value能够没有,则默许为当时分支的HEAD
$ git rebase -i [start_commit_sha1_value] [end_commit_sha1_value]
# 假定你异常退出了变基选择操作的窗口,运用以下指令从头翻开
$ git rebase --edit-todo
# 放弃变基
$ git rebase --abort
# 保存,啥也不动
**p, pick <commit> = use commit**
# 只修正提交信息
**r, reword <commit> = use commit, but edit the commit message**
# 不仅仅修正提交信息
**e, edit <commit> = use commit, but stop for amending**
# 并入前一个提交
**s, squash <commit> = use commit, but meld into previous commit**
# 并入前一个提交,并丢掉该提交信息
**f, fixup [-C | -c] <commit> = like "squash"
       but keep only the previous commit's log message,
       unless -C is used,in which case keep only this commit's message; 
       -c is same as -C but opens the editor
# 删去该提交
**d, drop <commit> = remove commit**

主张运用vscode中的GitLens插件来进行交互式变基,如下图

Git 时光机,一只调皮的猫

git fetch

会拉去数据,一起会同步一切长途库房分支本地长途盯梢分支,关于本地长途盯梢分支,实际上便是为了区分本地库房分支,前面加了remote_name的分支引证

git fetch 指令做了什么?

  1. 拉取它的一切数据
  2. 更新你的长途盯梢分支
  3. 对与长途库房中有而本地没有的分支,只会创立长途盯梢分支,不会创立本地分支

当抓取到新的长途盯梢分支时(这句话的意思是比方长途库房新建了一个分支dev,当git fetch时就会拉取新长途分支到本地的长途盯梢分支origin/dev),但不会创立一个本地dev分支

  1. 怎样仅仅想兼并到你的分支,能够履行git merge origin/dev
  2. 假定想在本地分支的作业,能够从origin/dev检出一个本地的dev分支,履行git checkout -b dev origin/dev
# 从长途库房中拉去一切分支数据到本地,同步一切长途库房分支和本地长途盯梢分支,假定缺省长途库房名,默许为origin
$ git fetch <remote_name>
# 从长途库房中只拉取一个分支数据到本地
$ git fetch <remote_name> <remote_branch_name>
# 从长途库房中只拉取一个分支数据到本地,并在本地库房中创立一个分支
$ git fetch <remote_name> <remote_branch_name>:<local_branch_name>
# 首要会同步长途库房分支与本地长途盯梢分支,一起会将本地长途盯梢分支中存在而长途库房分支没有的分支删去。
$ git fetch —prune
# 显现fetch的详细信息
$ git fetch -v

git fetch —prune:比方初始状况时长途库房分支和本地长途盯梢分支现已同步; 此刻,在长途库房中删去某个分支a,再运用git fetch时,本地长途盯梢分支中的分支a不会删去; 此场景下能够运用git fetch —prune,也能够运用git remote prune <remote_name>

  • 运用
    1. 运用一
      git fetch origin master //从长途origin库房拉取master分支的数据,一起同步本地长途盯梢分支 master git log -p master origin/master //比较本地库房master分支和本地长途盯梢分支master的差异
      git merge origin/master //将本地长途盯梢分支中的master分支合入本地库房master分支
    2. 运用二
      git fetch origin master:temp //从长途的origin库房拉取master分支的数据,并在本地库房中新建一个分支temp git diff temp //比较本地库房当时分支和本地库房temp分支的不同
      git merge temp //兼并本地库房temp分支到本地库房master分支
      git branch -d temp //删去本地库房temp分支

git merge

Git 时光机,一只调皮的猫

# 默许选用fast forward
$ git merge
# 选用fast forward
$ git merge -ff
# 强行封闭fast forward
# 个人觉得运用场景是:拉取长途分支,检出自己的分支上开发,然后push前rebase一下长途分支,提个pr,选用git merge --no--ff的办法merge到长途分支。
$ git merge --no-ff
  1. fast forward:这时候bugfix合入master是一次fast forward
  2. 3 way merge

假定现已分叉了,还想完结fast-forwardmerge,能够运用git rebase

git pull

git fetch + git merge

# git fetch + git merge
$ git pull
# git pull的简写
$ git pull --merge
# git fetch + git rebase
$ git pull --rebase
# 显现详细信息
$ git pull -v

git push

将本地库房当时分支推出送长途分支

# 完整指令,关于没有设置上游的本地分支推送至长途选用的办法
$ git push <remote_name> <local_branch_name>:<remote_branch_name>
# 假定本地分支名和长途分支名相同的情况下,能够省掉:<remote_branch_name>
$ git push <remote_name> <local_branch_name>>
# 设置当时的分支的上游分支是
$ git push —set-upstream <remote_name> <remote_branch_name>
# git push -u origin是git push —set-upstream origin的简写
$ git push -u <remote_name> <remote_branch_name>
# 删去长途分支
$ git push <remote_name> -d <remote_branch_name>
# 删去长途分支
$ git push <remote_name> :<remote_branch_name>
# 推送某个标签
$ git push <remote_name> <tag_name>
# 一次性推送很多标签
$ git push origin —tags
# 删去长途标签的办法
$ git push origin --delete <tag_name>

git push简写指令运用条件条件是:

  1. 长途库房有这个分支
  2. 而且经过git branch -vv检查,本地库房当时分支与本地长途盯梢分支是关联的
  3. 而且当时只要一个originremote

git push <remote_name> <local_branch_name>:将本地库房分支推送到长途库房;这样操作,虽然会一起更新本地长途盯梢分支;并没有将本地的该分支与对应的本地长途盯梢分支进行关联(经过git branch -vv检查)

新建本地分支后push到长途库房,但并没有将本地分支与对应的本地长途盯梢分支相关联,下次本地分支有新的commit后,再push到长途,仍然要git push <remote_name> <local_branch_name>,不能直接用git push这样的简写指令

git push -u <remote_name> <remote_branch_name>:将新建的本地分支推送到长途分支,并将该分支与对应的本地长途盯梢分支相关联,下回再推送时就能够运用git push这样的简写

git revert

git revert <commit_sha1_value>
git revert HEAD
git revert HEAD^
git revert HEAD~

下图是在C5为当时HEAD,别离对C5C4C3C2C1C0进行revert

Git 时光机,一只调皮的猫

差异:HEAD^首要是控制merge之后回退的方向;HEAD~才是回退的步数 个人了解:假定某个节点只要一个父节点,那就用~,不要用,因为不太直观,简单混乱;只针对有多个父节点的回退操作选用。

git revert -m <commit_sha1_value>
git revert -m HEAD
git revert -m HEAD^
git revert -m HEAD~

revert首要分两类,一类是针对只要一个父节点的commit,一类是针对有两个父节点的commit(merge分支产生的)

什么时候加-m,当该节点是merge产生的节点的时候,它会有2个父节点(之前老是记不清,一个commit节点是不或许有多于2个父节点的,经过这个-m的参数才想起来,所以这个-m后边跟的数字只能是1和2,1代表我保存自己的分支,2代表保存合入的分支)

revert或许带来的问题如下图描绘

Git 时光机,一只调皮的猫

关于此问题官网给出的处理方案是在masterrevert掉之前的revert,然后再merge

git reset

# 更改HEAD和当时分支顶部指向哪个commit,并掩盖暂存区
git reset —mixed <commit_sha1_value>
# 只更改HEAD和当时分支顶部指向哪个commit
git reset —soft <commit_sha1_value>
# 更改HEAD和当时分支顶部指向哪个commit,并掩盖暂存区和作业区
git reset —hard <commit_sha1_value>
# git reset —mixed <commit_sha1_value>简写
git reset <commit_sha1_value>

git reset —soft

Git 时光机,一只调皮的猫

git reset —mixed

Git 时光机,一只调皮的猫

git reset —hard

Git 时光机,一只调皮的猫

下图是在C5为当时HEAD,别离resetC4C3C2C1C0能够运用的指令

Git 时光机,一只调皮的猫

revertreset的差异是什么
git revert是用一次新的commit来回滚之前的commit,此次提交之前的commit都会被保存;git reset是回退到某次提交,提交及之前的commit都会被保存,可是此之后的commit都会被删去;所以能够说revert是以新增commit的办法回滚某个commit;而reset回退到某个commit

单从用法上来讲,运用场景能够参考以下: 找出有问题的commit,假定从HEAD一直到有问题的commit之间都不要,那就用reset;假定从HEAD一直到有问题的commit之间,只想回滚有问题的commit,中心其他的commit还要保存,那就用revert

以上过于啰嗦了,简单点,便是回滚某个commitrevert回退到某个commitreset;所以关于git reset HEAD这个指令是无意义的,当时就在这个commit,要回退到这个commit岂不是无用功;关于git revert HEAD这个指令是有意义的,假定你的确想回滚当时的commit

git stash

# 保存作业区暂存区中的内容
git stash
# 保存作业区暂存区中的内容,并增加注释,不引荐运用
git stash save 'message'
# 保存作业区暂存区中的内容,并增加注释,引荐运用
git stash push -m 'message'
# 康复后一起弹出 stash
git stash pop
# 康复后stash内容并不删去
git stash apply
# 删去stash
git stash drop
# 清空`stash`
git stash clear
# 显现一切的stash
git stash list
# 显现最新缓存修正的计算信息
git stash show

在运用git stash pop代码时,经常会碰到有冲突的情况,一旦出现冲突的话,体系会以为你的stash没有结束。导致的结果是git stash list 中的列表仍然存在,实际上代码现已pop出来了。

  • 运用场景
    1. 正常dev分支上开发,紧迫bug或许功用来时,能够先将在dev分支做的作业用git stash save存下,然后切换到紧迫分支,修正或许完结commit之后,在切回dev分支,用git stash pop将之前的作业内容回复

Git中的其他概念及指令

本地长途盯梢分支 上游分支

从一个长途盯梢分支检出一个本地分支会主动创立所谓的盯梢分支(它盯梢的分支叫做上游分支,即盯梢的是长途库房的分支); 盯梢分支是与长途分支有直接关系的本地分支; 假定在一个盯梢分支上输入 git pullGit 能主动地识别去哪个服务器上抓取、兼并到哪个分支。

ORIG_HEAD

ORIG_HEAD 记录了reset或许merge操作之前的HEAD

运用场景:

  1. 使用ORIG_HEAD吊销resetgit reset ORIG_HEAD
  2. 使用ORIG_HEAD吊销mergegit reset --merge ORIG_HEAD

use –merge flag to preserve any uncommitted changes

FETCH_HEAD

记录了长途一切分支对应的最新的commit

git ls-files -s

检查索引区内容

git cat-file

# 检查git object内容
git cat-file -p <sha1_value>
# 检查git object类型
git cat-file -t <sha1_value>
# 检查git object巨细
git cat-file -s <sha1_value>

git objects

有四种类型:blobcommittreetag

通用数据结构为:

Git 时光机,一只调皮的猫

blob

# echo -n输出的内容不换行
echo -n 'Hello, World!' | git hash-object --stdin
b45ef6fec89518d314f546fd6c3025367b721684
# echo -e转义
echo -e -n 'blob 13\0Hello, World!' | openssl sha1
(stdin)= b45ef6fec89518d314f546fd6c3025367b721684

git add .会生成blob方针

Git 时光机,一只调皮的猫

blob方针存储文件内容信息,包括sha1、字节巨细、文件内容数据

tree

git commit会生成tree方针(或许有多个)

Git 时光机,一只调皮的猫

tree方针中嵌套tree以来表明文件的嵌套

blob方针不存储文件的称号,文件的称号存储在tree方针中

commit

git commit会生成一个commit方针(包括)、tree方针(可有有多个),不会生成blob方针

Git 时光机,一只调皮的猫

tag

git tag -a tagname会创立一个tag方针,方针中的object会指向某一个committag方针会包括一些作者和时刻的信息等等

Git 时光机,一只调皮的猫

git tag <tag_name>不会创立一个tag类型的git object

git references

git中的引证实际上是指向某个commit的指针

Tags

Lightweight tags的引证是指向某个commit类型的git object方针的指针

ANNOTATED tags的引证时指向某个tag类型的git object方针的指针

Branches

Branches的引证是指向某个commit类型的git object方针的指针

HEAD

一般是指向当时分支的引证,可是它也能够指向某个commit类型的git object方针(detached HEAD

git show-ref

# 检查当时一切的tag,约同等与 git tag
git show-ref --tags
# 检查当时一切的分支,约同等与 git branch
git show-ref --heads

git gc

因为git是全量快照,每一次commit都会对应一个版别的悉数数据,这样会造成库房很大,为了处理该问题,引入了紧缩算法,举例,git clone在拉取长途库房时,就会紧缩成pack后再传递;在本地履行gc后,也会把.git/objects文件夹下的方针紧缩到pack文件夹下。

参考文献

  • Git – Book (git-scm.com)
  • Git In-depth

本文发布内容来自个人关于Git-scm网站关于Pro Git book的阅览及实践后的了解,一起参考了Git In-depth视频,文章未经授权禁止任何形式的转载。