git 放弃当前修改_<Git> Git 学习笔记

一. Git 介绍

ce3bd230d48537b2735a623ae8c13285.png

Git作为一款分布式的 版本控制 工具,作为一名程序员,是必须要掌握的。

Git最初由林纳斯·托瓦兹(Linus Torvalds)创作,于2005年以GPL发布。最初目的是为更好地管理Linux内核开发而设计。后来git内核已经成熟到可以独立地用作版本控制,使的很多著名的软件都开始使用git进行版本控制。

了解更多,可点击:
维基百科 - Git 和 廖雪峰的Git博客

原文链接 《旻天:<Git> Git学习笔记》:https://zhuanlan.zhihu.com/p/159035868

Git虽然是文件的版本控制工具,但它所管理的并不是文件,比较贴切的说,它控制的应该是文件的修改。

虽然目前 Git 已经有很多桌面应用,可以方便实现各种功能,比如我推荐的GitKraken,但是如果要更好使用桌面应用,对于下文中的概念和命令还是很有必要掌握的。

1.1 Git和SVN的对比

Git                          |   Svn 
:---:                        |   :---: 
分布式的                       | 集中式的 
把内容按元数据(记录改动)方式存储  | 按文件 
下载后,脱网也可查看全部log       | 需要联网需要联网查看log 
没有一个全局的版本号             | 有 
内容存储使用的是SHA-1哈希算法,内容完整性要优于SVN | 差于Git

二. Git入门

2.1 基础概念介绍

git共有四个

  • - 工作区(Working Area)
  • - 暂存区(Stage)
  • - 本地仓库(Local Repository),仅自己可见
  • - 远程仓库(Remote Repository),全组成员可见

同时还有五种状态

  • - 未修改(Origin)
  • - 已修改(Modified)&未追踪(Untracked)
  • - 已暂存(Staged)
  • - 已提交(Committed)
  • - 已推送(Pushed)

状态之间的关系如下图:

b1cb19be04678ab2d164e9982986a99f.png

对于图上的所有命令,之后都会有详细的介绍,各位不要捉急。

2.2 Git的安装和GitHub的使用

Git的安装就不介绍了,网上很多。
GitHub是通过Git进行版本控制的软件源代码托管服务,并且它是免费的,在小组开发时,我们可以将代码托管到GitHub上,非常方便。官网https://github.com/。并且目前 Github 支持免费创建私有仓库,或将已有的公有仓库私有化,提高了代码的安全性。

2.3 创建版本库

版本库,说白了就是我们要交给Git管理的项目根目录。

$ cd ~/workspace/git/
$ git init

命令行进入到目标目录,然后输入git init,就会在当前目录下生成一个.git的文件夹,此时这个版本库就创建好了。所有在此目录和子目录下的文件改动,都会被 git 发现。.git文件夹就是这个工程的本地版本库。

我们也可以直接在GitHub clone代码到本地,方法如下:

$ git clone git@github.com:michaelliao/bootstrap.git

2.4 基本使用

>问<: 此时在git目录下,新建文件helloWorld.scala。然后想继续修改,但是怕最近的修改出错,想可以随时回到当前状态,那要怎么做呢?如果我想让这个开发的文件,在小组内的其他成员也可见,又要怎么做呢?<问>

>答<

  1. git add => 暂存区
  2. git status 状态查看器
  3. git commit => 本地仓库
  4. git push => 远程仓库
  5. git pull => 同步远程仓库

<答>

git add => 暂存区

第一步就是先将要保存的文件加入暂存区:

$ git add helloWorld.scala
注意, add可以一次提交多个文件,如 git add a.scala b.scala,也可以多次提交,如 git add a.scala git add b.scala
如果使用 git add --all,提交当前工作区的全部更改到暂存区 如果使用 git add .,提交当前目录下的全部更改到暂存区

git status 状态查看器

使用下面命令,可以查看当前工作区的修改情况:

$ git status

Git非常清楚地告诉我们,helloWorld.scala还从来没有被添加过,所以它的状态是Untracked。如果我们已经添加过helloWorld.scala文件,在对其进行修改,那么它就是modified状态。

git checkout 放弃修改

如果想放弃现在没有add的改动,可以使用下面命令,将工作区的改动还原

$ git checkout -- helloWorld.scala
注意,这个 --是必须要有的,不然它就会切换分支了,分支概念后面说。

可是,如果add之后,又想放弃目前暂存区的更改呢?就要使用下面的语句,先将文件改动先从暂存区移到工作区,然后重复上面的步骤将工作区的改动还原。

git reset HEAD helloWorld.scala
关于 reset 和 HEAD 的概念,之后会讲到.

git commit => 本地仓库

第二步,将缓存区的内容提交到本地仓库中:

$ git commit -m "wrote a hello file"

此时,我们已经将本次更改保存到本地仓库,现在就可以放心大胆的继续开发hello了。因为我们已经有了一个现在时间的代码快照,随时可以回到快照。

-m 后面的String,是对于本次commit的备注,可以没有,也可以是任何内容。但建议是一段可描述本次修改的语言,方便日后自己追溯,也方便其他人可以了解本次提交。方便他人大胆的更新或合并你本次的代码。关于更新和合并下文讲。

现在可以使用git status查看一下当前什么状态。

git push => 远程仓库

当前的hello文件只有你自己可见,要想小组的其他人也能看到并且编辑,需要将它同步到远程。方法如下:

$ git push origin master

这样就将本地仓库中提交的代码 push 到远程的 master 分支上了。此时,其他小组成员就可以看到你之前编写的文件并且可以同步和修改了。

git pull => 同步远程仓库

那么其他成员如何下载你的最新代码呢?使用如下命令:

$ git pull
如果git pull提示 no tracking information,则说明本地分支和远程分支的链接关系没有创建,用命令 git branch --set-upstream-to <branch-name> origin/<branch-name>

三. 版本穿越

如果想要回到之前的某个版本,应该如何做呢?

3.1 git 历史书

首先应该查询我之前的所有操作,通过命令:

$ git log

查看最近的操作,但是内容有些多,可以加上参数--pretty=oneline简化输出信息。

输出信息类似下面:

f078079284c567571286ef7a168f095af9acdd03 (HEAD -> Clock-0704, tag: v1.0, origin/Clock-0704) Merge remote-tracking branch 'origin/alex-0704' into Clock-0704
bbb87262b8d8d61d85fc6579ab46527e431ee176 (origin/alex-0704) 修复无限bug
4f0a047023f8a4902f40f03fb5f6040775a9e1ee Merge remote-tracking branch 'origin/alex-0704' into Clock-0704
第一个空格前面的一串数字,就是那次commit的commit id(提交版本号),和SVN不一样,Git的commit id不是1,2,3……递增的数字,而是一个SHA1计算出来的一个非常大的数字,用十六进制表示。而且你看到的commit id和我的肯定不一样,以你自己的为准。>问<: 为什么commit id需要用这么一大串数字表示呢?<问>>答<因为Git是分布式的版本控制系统,后面我们还要研究多人在同一个版本库里工作,如果大家都用1,2,3……作为版本号,那肯定就会导致版本号冲突。<答>

知道了历史记录,我们就可以定位具体的穿越位置,之后使用

$ git reset --hard 4f0a047023f8a4902f40f03fb5f6040775a9e1ee

我们就穿越成功了。

reset 的 --hard参数后面讲解
最后跟的commit id不用写全,git会自动查询,但也不要写的太少,推荐写七位左右

此时有个语法糖,如果我们只是想返回最近的上一次提交,可以使用

$ git reset --hard HEAD^

返回上上次呢?git reset --hard HEAD^^,上三次呢?没错,就是你想的那样,但是有别的方法git reset --hard HEAD~3,不然100次不是很累。

使用git log查询一下历史,已经看不到 3f0a 之后的提交了。我们穿越成功了,但是git log没有了之后的commit id,如果我们反悔了,岂不是回不去了。

3.2 git 万年历

不要怕,在Git中,总是有后悔药可以吃的,Git提供了一个命令git reflog用来记录你的每一次命令:

$ git reflog

输出信息类似下面:

f078079 (HEAD -> Clock-0704, tag: v1.0, origin/Clock-0704) HEAD@{0}: commit (merge): Merge remote-tracking branch 'origin/alex-0704' into Clock-0704
4f0a047 HEAD@{1}: commit (merge): Merge remote-tracking branch 'origin/alex-0704' into Clock-0704
89529a2 HEAD@{2}: commit: report over

再次穿越:

$ git reset --hard f078079

没错,我又回到了原来的时间线

这里要说一下,git切换分支的速度非常快,因为 git 把你的每次 commit 变成了链表的一个点。内部有个指向当前版本的 HEAD头指针,当你回退版本的时候,Git仅仅是把HEAD换个指向而已。

3.3 代码回滚的讲解

代码回滚的方式分三种Reset、Checkout、Revert 那么应该如何使用和选择呢?

reset 详解

reset 是移动HEAD指针,如果HEAD指针指向了之前提交的commit id,就等于放弃了近期的代码更改,回到了某一时刻快照,如上面的例子。但是它比想象的要强大,同时支持几个参数,如下:

  • --mixed – 默认选项。缓存区和你指定的提交同步,但工作目录不受影响,也就是缓存区移入工作区,然后 工作区 > 本地仓库
  • --soft – 缓存区和工作目录都不会被改变,也就是 最近修改优先
  • --hard – 缓存区和工作目录都同步到你指定的提交,也就是 本地仓库优先

checkout 详解

主要是处理工作区的修改

revert 详解

创建一个修改来修改之前的提交,不会影响历史,是最安全的回滚办法。好比Ctrl + Z

文件层面操作

git resetgit checkout 命令也接受文件路径作为参数。这时它的行为就大为不同了。它不会作用于整份提交,参数将它限制于特定文件。

如:

git reset HEAD~2 helloWorld.scala

会把最近前两次提交中的helloWorld.scala文件提取出来放到暂存区。

而:

git checkout HEAD~2 helloWorld.scala

会把最近前两次提交中的helloWorld.scala文件提取出来放到工作区。

总结

  • git revert当做Ctrl + Z,它不会修改历史记录,并且会生成记录。所以执行之前,要先stash
  • git reset HEAD用来撤销没有提交的更改。
  • git checkout主要是处理工作区中没有add的修改。
命令         | 作用域   | 常用情景
:---:        | :---:    | :---:
git reset    | 提交层面 | 在私有分支上舍弃一些没有提交的更改
git reset    | 文件层面 | 舍弃缓存区中的更改
git checkout | 提交层面 | 切换分支或查看旧版本
git checkout | 文件层面 | 舍弃工作目录中的更改
git revert   | 提交层面 | 在公共分支上回滚更改
git revert   | 文件层面 | (然而并没有)

四. 分支概念

如果对于同一个项目,领导要张三去开发新功能的同时,要李四去修复当前版本的一个bug呢?

这时,我们就要做一个比穿越时间更神奇的事情了,就是创建平行宇宙 => 分支。

分支可以将某个时间节点的代码分别放到两个平行线上,这两条线上的开发互不影响,只有在两者需要合并的时候重合。

4.1 分支基础

在版本回退里,你已经知道,每次提交,Git都把它们串成一条时间线,这条时间线就是一个分支。

截止到目前,只有一条时间线,在Git里,这个分支叫主分支,即master分支。HEAD严格来说不是指向提交,而是指向master,master才是指向提交的,所以,HEAD指向的就是当前分支。

就像这样:

470b55e7ebebd09e0f0c516cc2176551.png

当我们创建新的分支,例如dev时,Git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上:

48fe8932d970ecfbb8f6da1c2fe06071.png

你看,Git创建一个分支很快,因为除了增加一个dev指针,改改HEAD的指向,工作区的文件都没有任何变化!

git checkout

首先,我们创建dev分支

$ git branch dev

查看现在都有哪些分支:

$ git branch
* master
  dev
有*号的表示是当前分支

然后切换到dev分支:

$ git checkout dev

也有语法糖,可以二步合一

$ git checkout -b dev
参数-b就是分支不存在,则创建分支

现在我们在dev分支已经开发完了,要把代码统一回master分支。要先切换回 master 并合并分支:

$ git checkout master
$ git merge dev

此时,用

$ git log --graph --pretty=oneline --abbrev-commit

可以查看分支合并过程

合并完成,删除之前的dev分支

$ git branch -d dev

五. 番外

5.1 stash 暂存

可以缓存工作区的修改到stash中,那在什么场景使用呢?

比如,你正在开发新模块,但之前分支中有改动,需要合并分支,可是你们项目中有一些配置文件,如数据库配置等是连接到了自己的数据库上,每次合并分支还要重新修改,很麻烦。

这时就可以先stash,然后merge,再把stash中的文件修改提取出来。

如何提取:

$ git apply
$ git pop
这两句的功能一样,都是拿出刚才stash的文件修改,区别在于:
- apply只是提取,不会删除刚才的stash;
- 而pop就像弹栈一样,在提取的同时删除了stash。

可以使用git stash list查看全部stash列表。使用git stash apply stash@{0}恢复指定stash。

5.2 Rebase 变基

不是很好理解,就当做是最后一次的 merge 吧。
因为rebase 后,两个分支的修改记录都会合并为一个分支的记录,好像另一个分支从来没有出现过一样。

5.3 tag 标签管理

可以理解为commit的收藏功能,通常和版本发布一同使用。

$ git tag v1.0

使用上面命令,就会在最近的commit上创建一个tag,也可以使用git tag v1.0 commitId给指定 commit 打 tag。

删除标签

$ git tag -d v1.0

从远程删除。删除命令也是push,但是格式如下:

$ git push origin :refs/tags/v0.9

5.4 .gitignore 忽略文件

忽略文件的原则是:

  1. 忽略操作系统自动生成的文件,比如缩略图等;
  2. 忽略编译生成的中间文件、可执行文件等,也就是如果一个文件是通过另一个文件自动生成的,那自动生成的文件就没必要放进版本库,比如Java编译产生的.class文件;
  3. 忽略你自己的带有敏感信息的配置文件,比如存放口令的配置文件。

5.5 设置别名

$ git config --global alias.co checkout
$ git config --global alias.ci commit
$ git config --global alias.br branch

《完结》

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值