接上篇 Git汇总–对象及版本库存储

版本库操作

日志–log

显示提交历史! 当不使用任何参数调用,相当于使用了缺省的参数HEAD,即显示当前HEAD能够访问到的所有历史提交。可以指定某个远程或者分支进行查看:

$ git log upstream/master
参数 说明
--oneline 最精简的日志输出
--graph 分支图显示
-<n> 显示最近的几条日志
--stat 显示每次提交的变更概要
--all 显示所有分支的历史记录

提交–commit

commit 分为两种:一种是常规的 commit,也就是使用 git commit 提交的 commit;另一种是 merge commit,在使用 git merge 合并两个分支之后,你将会得到一个新的 merge commit。

merge commit 和普通 commit 的不同之处在于 merge commit 包含两个 parent commit,代表该 merge commit 是从哪两个 commit 合并过来的。

# cdc4a1为merge生成的commitID
$ git show cdc4a1
commit cdc4a1c252171c24b7c98b92a6fb94010637de44 (HEAD -> hotfix-inspection, origin/hotfix-inspection)
Merge: 81cf95f5 41cc17e6

使用命令git describe 将提交显示为一个易记的名称。

  • 这个易记的名称来自于建立在该提交上的里程碑;
  • 如果提交没有对应的里程碑,但是在其祖先版本上建有里程碑,则使用类似<tag>-<num>-g<commit>(“基础版本号” - 距离“基础版本”的数字 - 该提交的SHA1哈希值缩写)的格式显示;
  • 如果提交本身没有包含里程碑,其祖先版本上也没有里程碑,可以通过传递--always参数显示精简提交ID,否则出错。
$ git describe
v2.0.0-143-gcffed5c2

补充:最后一次的提交信息,会存储在.git/COMMIT_EDITMSG 中,这对于对提交信息格式校验很有帮助, 具体可以查看:Git提交信息规范化

$ cat .git/COMMIT_EDITMSG
feat(git): git总结

可以在commit命令后加参数-s,为在提交说明的最后添加“Signed-off-by:”签名。

$ git commit -s -m "提交说明"

没有对工作区的文件进行任何修改,Git默认不会执行提交,参数--allow-empty 允许执行空白提交。

# 重新修改最新的提交,改正作者和提交者的错误信息
$ git commit --amend --allow-empty --reset-author

提交空文件夹: 默认情况下,Git不能对空文件夹进行提交。所以,我们可以在相关文件夹下创建一个文件.gitkeep来进行占位。

建议:

  • 一次提交只干一件事
  • 每次提交尽量完整,可以使用git stash或其他分支保持当前进度
  • 尽量保持暂存区和HEAD一致(即add后的内容,及时commit)

对比变更

上述提到的工作区、暂存区、HEAD,如何做比较呢?

命令 说明
git diff 工作区和暂存区比较
git diff --cached/--staged 暂存区和HEAD(master)比较
git diff HEAD/master 工作区和HEAD(当前工作分支,注意非远程

获取–fetch or pull

fetch

从另一个存储库下载对象和引用。

在执行git fetch命令的时候,可以通过 --no-tags 参数设置不获取里程碑只获取分支及提交

$ git fetch --no-tags

或在注册远程版本库的时候,使用--no-tags 参数避免将远程版本库的里程碑引入本地版本库

$ git remote add --no-tags

获取的引用名称及其指向的对象名称将写入.git / FETCH_HEAD 中。

$ cat .git/FETCH_HEAD
7ccd4971011fe8b0df6599efb38d011f25975979 branch 'master' of x.x.x.x:namespace/project-name

git fetch origin 就相当于执行了下面的命令,将远程版本库的所有分支复制为本地的远程分支

$ git fetch origin +refs/heads/*:refs/remotes/origin/*

示例:合并upstream/master提交到本地

获取到的提交会更新到本地跟踪共享版本库(远程)master分支的本地引用.git/refs/remotes/upstream/master

$ git fetch upstream master
# 合并操作
$ git merge upstream/master

pull

git pull 又都做了哪些操作?

$ git config --list
remote.origin.url=git@x.x.x.x:project-namespace/project-name.git
remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
branch.master.remote=origin
branch.master.merge=refs/heads/master
# 另外一个分支
branch.feature-v2.1.remote=origin
branch.feature-v2.1.merge=refs/heads/feature-v2.1
# 另外一个远程
remote.upstream.url=git@y.y.y.y:project-namespace/project-name.git
remote.upstream.fetch=+refs/heads/*:refs/remotes/upstream/*
$ git pull
  • 不带参数执行git pull 相当于执行了git pull <remote>
  • 当前分支未设置 branch.<branchname>.remote,则为origin
  • 获取的远程版本库的URL地址由 remote.<remote>.url给出
  • 如果为注册的远程版本库设置了fetch参数,即通过 remote.<remote>.fetch 配置了一个引用表达式,则使用该引用表达式执行获取操作
  • 合并的分支,如果设定了branch.<branchname>.merge,则对其设定的分支执行合并,否则报错退出

所以,上述fetch示例可以通过下述命令替代

$ git pull upstream master

推送–push

$ git push <remote> <branchname>
  • 不带参数执行git push相当于执行了git push <remote>
  • 当前分支未设置 branch.<branchname>.remote,则为origin
  • 如果为注册的远程版本库设置了push参数,即通过remote.<remote>.push配置了一个引用表达式,则使用该引用表达式执行推送
  • 否则使用“:”作为引用表达式。该表达式的含义是同名分支推送,即对所有在远程版本库有同名分支的本地分支执行推送。
$ git push branch.<branchname>.remote branchname

个人建议:

push默认的规则使得git push 可以像 git push origin <currentBranch> 一样的效果,但是个人并不建议这种操作(你要明确你的确是想向origin提交;然后你的本地分支和远程分支名称必须一致<当然强烈建议创建分支本地和远程保持一致!>),以上,还是希望提供完整的命令!

重置–reset or reflog or revert

.git/refs/heads/<branch> 中记录了其分支中对应的最新提交ID,下述为master分支最新提交ID:

$ cat .git/refs/heads/master
e695606fc5e31b2ff9038a48a3d363f4c21a3d86

reset

重置命令git reset 的一个用途就是修改引用(如master)的游标。可以将“游标”指向任意一个存在的提交ID。

$ cat .git/HEAD
ref: refs/heads/master

在执行重置命令的时候没有使用任何参数对所要重置的分支名进行设置,这是因为重置命名实际上所针对的是头指针HEAD。

方式一:不会重置引用
$ git reset [-q] [<commit>] [--] <paths>...

包含了路径<paths>的用法。不会重置引用,更不会改变工作区,而是用指定提交状态(<commit>)下的文件(<paths>)替换掉暂存区中的文件。

$ git reset HEAD/commitID [--] <filePaths>

注意: 为了避免路径和引用(或者提交ID)同名而冲突,可以在<paths>前用两个连续的短线作为分隔。

方式二:重置引用
$ git reset [--soft | --mixed | --hard | --merge | --keep] [-q] [<commit>]

不使用路径<paths>的用法。会重置引用。根据不同的选项,可以对暂存区或者工作区进行重置。会彻底的丢弃历史(git log查看不到提及历史)。

参数 影响范围
–hard 引用指向新的提交ID,替换暂存区和工作区
–soft 只更改引用的指向,不改变暂存区和工作区
–mixed(缺省即为--mixed 更改引用的指向以及重置暂存区,但是不改变工作区
$ git reset --hard HEAD^
$ git reset --hard <commitID>

!!!注意: 使用重置命令很危险,会彻底的丢弃历史。那么还能够通过浏览提交历史的办法找到丢弃的提交ID,再使用重置命令恢复历史么?不可能!因为重置让提交历史也改变了。在一个共享的仓库中这会造成问题的。如果其他人已经有你将要重写的提交,你应当避免使用 reset;如果有任何其他提交在合并之后创建了,那么这个方法也会无效;移动引用实际上会丢失那些改动。

reflog

显示操作历史!

上述reset的第二种方式会丢失历史,如果真的做了上述操作,该如何还原呢?

$ ll .git/logs
-rw-r--r--  1 ligang  staff   111K 11 30 15:02 HEAD
drwxr-xr-x  5 ligang  staff   160B 11 29 09:44 refs

通过.git/logs 目录下日志文件记录了分支的变更。默认非裸版本库(带有工作区)都提供分支日志功能,这是因为带有工作区的版本库都有如下设置。

$ git config core.logallrefupdates

Git提供了一个**git reflog** 命令,对这个文件进行操作。使用show子命令可以显示此文件的内容。

$ git reflog show HEAD
61f26bdb (HEAD -> master) HEAD@{0}: commit: camile.txt
622c9bd0 HEAD@{1}: reset: moving to HEAD^
4e0e3777 HEAD@{2}: commit: camile.txt
622c9bd0 HEAD@{3}: reset: moving to HEAD^

注意: 使用git reflog 的输出和直接查看日志文件最大的不同在于显示顺序的不同,即最新改变放在了最前面显示,而且只显示每次改变的最终的SHA1哈希值

# 还原某个提交!!
$ git reset --hard HEAD@{2}

git loggit reflog 区别:

  • git log 显示提交历史;
  • git reflog 显示操作历史(包括已经被删除的 commit 记录和 reset 的操作)。

revert

revert 命令十分直观易用,相当于做一次被 revert 的提交的「反操作」并形成一个新的 commit。

上面commit中提到了,commit分为常规commit和merge的commit两种。所以,revert也对应两种方式:

常规commit

使用 git revert <commit id> 即可,git 会生成一个新的 commit,将指定的 commit 内容从当前分支上撤除

merge的commit

revert merge commit 这时需要添加 -m 选项以代表这次 revert 的是一个 merge commit,-m 选项接收的参数是一个数字,数字取值为 1 和 2,也就是 Merge 行里面列出来的第一个还是第二个。

$ git log
commit e6930af365f89b2bdc47d4e190b0e7e1c10bc0b8
Merge: e215da30 fb5baba1
# 具有merge标识,是从e215da30和fb5baba1两个commit合并而来
$ git revert -m 1 e6930af365f89b2bdc47d4e190b0e7e1c10bc0b8

注意: revert后的代码想在合并进来,必须进行反向revert,否则会丢掉相关内容!http://blog.psjay.com/posts/git-revert-merge-commit/

检出–checkout

git checkout 会重写工作区。

方式一:包含了路径<paths>的用法

不会改变HEAD头指针,主要是用于指定版本的文件覆盖工作区中对应的文件

$ git checkout [-q] [<commit>] [--] <paths>...

<commit>是可选项,如果省略则相当于从暂存区(index)进行检出。这和上一章的重置命令大不相同:重置的默认值是 HEAD,而检出的默认值是暂存区。因此重置一般用于重置暂存区(除非使用--hard参数,否则不重置工作区),而检出命令主要是覆盖工作区(如果<commit>不省略,也会替换暂存区中相应的文件)。

方式二:不使用路径<paths>的用法

改变HEAD头指针。之所以后面的参数写作<branch>,是因为只有HEAD切换到一个分支才可以对提交进行跟踪,否则仍然会进入“分离头指针”的状态。在“分离头指针”状态下的提交不能被引用关联到而可能会丢失。

$ git checkout [<branch>]

关于 ”分离头指针“

HEAD指向的提交将作为新提交的父提交,查看当前HEAD的指向。

$ cat .git/HEAD

分离头指针,指的就是HEAD头指针指向了一个具体的提交ID,而不是一个引用(分支)。

$ git log --pretty=oneline -1
6f44ded81092794fc186e7869eadb4ca5ef225bb (HEAD -> master) test2
$ git checkout 6f44de
# reflog是HEAD头指针的变迁记录,目前是非master分支
$ git reflog -1
6f44ded8 (HEAD, master) HEAD@{0}: checkout: moving from master to 6f44de
$ cat .git/HEAD
6f44ded81092794fc186e7869eadb4ca5ef225bb

方式三:创建和切换到新的分支

新的分支从<start_point>指定的提交开始创建。新分支和我们熟悉的master分支没有什么实质的不同,都是在refs/heads命名空间下的引用。

$ git checkout [-m] [[-b|--orphan] <new_branch>] [<start_point>]

注意,这里不能对远程分支进行checkout,远程分支不是真正意义上的分支,是类似于里程碑一样的引用。如果针对远程分支执行检出命令,会看到大段的错误警告。

分支–branch

# 基于远程分支创建本地分支的过程中
$ git checkout feature-2.2
$ git checkout -b feature-2.2 origin/feature-2.2
  • 删除本地分支

    $ git branch -d/-D develop
    
  • 删除远程分支

    冒号前面的空格不能少,原理是把一个空分支push到server上,相当于删除该分支。

    $ git push origin :develop
    
  • 删除本地仓库相对于远程origin不存在的仓库

    $ git remote prune origin
    

merge

会保留修改内容的历史记录。--no-ff(non fast-forward)总会生成一个merge commit,不添加该参数时,只有冲突时才会生成merge commit。

rebase

rebase 是在原有提交的基础上将差异内容反映进去。这个时候可能会有冲突,当出现冲突时,解决冲突后的提交不是使用 commit 命令,而是执行 rebase 命令指定 --continue 选项。若要取消 rebase,指定 --abort 选项。

注意: 变基操作的 实质是丢弃一些现有的提交,然后相应地新建一些内容一样但实际上不同的提交。 如果你已经将提交推送至某个仓库,而其他人也已经从该仓库拉取提交并进行了后续工作,此时,如果你用 git rebase 命令重新整理了提交并再次推送,你的同伴因此将不得不再次将他们手头的工作与你的提交进行整合,如果接下来你还要拉取并整合他们修改过的提交,事情就会变得一团糟。

merge还是rebase?

有一种观点认为,仓库的提交历史即是 记录实际发生过什么。 它是针对历史的文档,本身就有价值,不能乱改,这些痕迹就应该被保留下来,让后人能够查阅。从这个角度看来,改变提交历史是一种亵渎。

另一种观点则正好相反,他们认为提交历史是 项目过程中发生的事。 没人会出版一本书的第一版草稿,软件维护手册也是需要反复修订才能方便使用。

总的原则是,只对尚未推送或分享给别人的本地修改执行变基操作清理历史,从不对已推送至别处的提交执行变基操作,这样,你才能享受到两种方式带来的便利。

cherry-pick

$ git cherry-pick <commitID>

从众多的提交中挑选出一个提交应用在当前的工作分支中。操作过程相当于将该提交导出为补丁文件,然后在当前HEAD上重放形成无论内容还是提交说明都一致的提交。对于从一个分支单独一个或者两个提交而不是合并整个分支的所有变更是非常有用的。可以通过git cherry-pick --abort 取消cherry-pick操作。

里程碑–tag

https://blog.csdn.net/ligang2585116/article/details/46468709

配置–config

版本库级别的配置文件 ~/.gitconfig,对应.git/config

$ git config -e

全局配置文件--global(用户主目录下) ~/Documents/github/Blog/.git/config

$ git config -e --global

系统级配置文件--system(/etc目录下) /private/etc/gitconfig

 $ git config -e --system

git config 使用INI文件格式。

  • 使用命令$ git config <section>.<key>,来读取INI配置文件中某个配置的键值;
  • 使用命令$ git config <section>.<key> <value>,来更改和设置INI配置文件中某个配置的值。

欢迎关注个人微信公众号「Super 前端」

Git汇总--版本库操作相关推荐

  1. 关于git远程版本库的一些问题之解决

    Part1:CentOS6.5免密码登录 修改/etc/ssh/sshd_config RSAAuthentication yes PubkeyAuthentication yes Authorize ...

  2. GIT创建版本库及版本的迭代

    学习目标: GIT学习一. 学习内容: 1.如何创建版本库 2.版本追溯和跳转 3.git的工作区和暂存区 1.版本库 版本库可以理解为一个目录,里面的所有文件都可以被Git管理起来,每个文件的修改. ...

  3. 01《穿越时空的git》科幻小电影-Git创建版本库和常用命令操作-提交、回退、撤销、删除

    小时候看过一部印象很深的剧叫做<穿越时空的爱恋>,今日也厚着脸皮导演一部<穿越时空的git>,不上映,纯属自嗨! 1.创建版本库 what is 版本库?无论我们平常使用git ...

  4. Git(创建版本库)

    什么是版本库呢?版本库又名仓库,英文名repository,你可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改.删除,Git都能跟踪,以便任何时刻都可以追踪历史,或 ...

  5. Git创建版本库详尽教程

    什么是版本库呢?版本库又名仓库,英文名repository,你可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改.删除,Git都能跟踪,以便任何时刻都可以追踪历史,或 ...

  6. Git 初始化版本库

    创建带工作区的版本库 在开始一个新项目时,首先就要创建并初始化代码库.如果是在本机的工作目录中,那么: $ git init 也就够用了.如果想要初始化的版本库不在当前目录,需要为 git init ...

  7. Git创建版本库和添加文件

    创建版本库: 首先新建一个目录,然后通过 $ git init命令把这个目录变成Git可管理的仓库,例如: 在"C:\AmyPersonal\AmyGit"路径下新建文件夹Git1 ...

  8. git创建版本库(1)

    git add命令把文件添加到库,就好比把商品添加到购物车 git commit命令把文件提交到库,就好比购物车里面的东西一起结账 第一步创建git版本库 $ mkdir learngit $ cd ...

  9. Git——创建版本库【git init】

    创建版本库   版本库又名仓库,英文名repository,可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改.删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者 ...

  10. git 清除版本库中的忽略文件

    一.在已经提交的git代码管理里,删除不想提交的目录或文件 1.在 .gitignore 里面删除想要删除的文件*(没有就不用)(我以app/build 文件夹为例子) git add app/bui ...

最新文章

  1. Zookeeper系列(十)zookeeper的服务端启动详述
  2. Android studio 刷新文件状态
  3. queued frame 造成图形性能卡顿
  4. 华为荣耀5cvs华为v9play_华为荣耀v9play和荣耀9哪个好_华为荣耀v9play和荣耀9对比评测_飞翔教程...
  5. Spring 事务初始化源码分析
  6. 礼橙专车、青菜拼车今日起改名啦!
  7. java中怎么把数字打印在屏幕上_java中如何打印出蜗牛形状的数字
  8. Javascript总结(全)
  9. [收藏]深入浅出的《网络socket编程指南》4
  10. Cent OS 7 配置静态ip
  11. Effective Java 经典学习(一)
  12. table元素无法固定列宽,width设置无效
  13. 阿里云-数据仓库-全链路大数据开发治理平台-DataWorks的数字世界
  14. Differentiable Scaffolding Tree for Molecule Optimization(论文解读)
  15. 【密码学探秘】EVM链和并行执行交易
  16. 《惢客创业日记》2021.05.16(周日)需要用钱吱一声
  17. 『题解』洛谷P3958 奶酪
  18. 分布式环境Raft一致性共识算法解读
  19. PMP证书如何续证?PMP证书续证步骤和注意事项
  20. smbus协议的command_SMBus协议总结

热门文章

  1. Spring 最常用的几大类常用注解总结,史上最强整理!
  2. Flink 源码笔记01—DataStream 和 Transformation
  3. 优矿-获取商品期权数据
  4. [ZZ]什么是Google Urchin:了解Urchin与Google Analytics差异
  5. 2018年10月29日英语学习
  6. C# 中的 delegate, Lambda 表达式 和 event
  7. 【java实现定时自动发送QQ消息】
  8. css3练习——手风琴图片
  9. 电子计算机按钮说明,电子计算器常用按键功能说明
  10. 揭开Docker的神秘面纱