用只狼教你学Git (中)

整体介绍:

在学习了Git相关的概念之后,我们正式开始学习如何使用Git

这篇文章主要分为两个部分:

  • 基础使用
  • 进阶使用

中篇负责讲述基础的使用liux


基础使用

Git诞生:安装

Git 支持在 Windows、MacOS、Linux、Unix

MacOS安装:

MacOS有一个强大的包管理器:HomeBrew

  • 包管理器简单的认为是一个应用商店,你可以下载,安装,删除,看应用相关信息,升级应用(后面我会专门写一篇包管理器的文章)

  • 它能够简化很多操作,尤其是对于程序员需要的一些工具的安装:

    • Python解释器
    • GCC
    • Git
    • JDK
    • …..

    如果是在搜索引擎搜索的话,可能需要安装,并且配置环境变量,相对来说麻烦很多,所以会使用包管理器相当重要

所以,Git 也能够 通过HomeBrew安装

  1. 首先安装HomeBrew,打开终端,输入:
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

安装结束就可以使用了(详细不在这里展开,后面会写一篇专门介绍HomeBrew的文章)

  1. 然后在终端中,输入命令行:
brew install git
  1. 安装结束,输入命令验证一下:
git --version
  1. 打印出版本信息既是安装成功

Windows安装:

Windows我使用不多,上面也有包管理器(Scoop、Chocolatey),但是我感觉不好用,我们就用传统的方法来进行Git的下载吧

直接点击这里,在官方网站下载,安装完成后在,菜单里面找到Git 打开Git Bash,就能跳出一个类似于这样的窗口(我身边没win的机器,只有在网上找的图):

最后也是对git进行验证

GNU/Linux安装:

使用包管理器安装:

Linux因为有太多的发行版本,不同的比如Debian、CentOS里面的默认的包管理器就不同,常见的有:

  • yum
  • apt-get

所以对应安装的方法就是:

yum install git

apt-get install git

玩Linux的应该都懂~

安装好Git之后开始下一步


Git启动:初始化

git的启动首先需要创建仓库,或者说版本库,什么意思呢,就是在指定文件夹下面,输入命令,让它拥有git的能力,能在里面进行版本控制

如果你不会一些基础命令,建议你先学习一些基本的命令,不过这里面用的最多的是 cd 这个命令,就是到指定路径下面,就是你想创建仓库的地方

到了指定路径下面,输入:

git init

你就让你的文件夹变成了一个版本库了

So easy~ 这样Git初始化这个步骤就完成了,我们继续下一步


Git穿越时空:版本控制

工作区、暂存区、版本库、分支:

Git 工作中,有两个区域:

  • 工作区

  • 版本库:

    又分为:

    • 暂存区
    • 分支
    • …..

我们来看看四者之间的区别。

工作区 就是你初始化之后,把文件夹变成版本库,这个文件夹,就是工作区

版本库 就是工作区里面的一个隐藏文件夹.git,版本控制就是通过它实现

暂存区 是版本库的一部分

分支 是版本库的一部分,创建版本库默认的分支就是master

补充一个概念: 目录树 ,目录树是指由容器和对象构成的层次结构。树的叶子、节点往往是对象,树的非叶子节点是容器

图片这些元素的解释:

在版本库中标记为 “index” 的区域是暂存区(也叫stage),在 “.git/index”文件中 ,是一个目录树

标记为 “master” 的是 master 分支所代表的目录树。在 “.git/refs/master” 文件中

图中我们可以看出此时 “HEAD” 实际是指向 master 分支的一个指针,在.git/HEAD 文件中,它记录着目前指向的是什么分支

图中的 objects 标识的区域为 Git 的对象库,实际位于 “.git/objects” 目录下,里面包含了创建的各种对象及内容。

基本工作流

  • 当对工作区修改(或新增)的文件执行 “git add” 命令时,工作区的文件被存入暂存区:
    • 暂存区目录树被更新,同时工作区修改(或新增)的文件内容被写入到对象库中的一个新的对象中,而该对象的ID被记录在暂存区的文件索引中。
  • 当执行提交操作(git commit)时,缓存区的文件被提交的当前的分支(master)
    • master 指向的目录树被提交时暂存区的目录树所替换。

可能上面这部分有点枯燥,主要是想一定的说明git的原理,不过适可而止,毕竟原理解释不是这篇文章主要目的,主要是为了使用git。

基本操作

Git 的工作就是创建和保存你项目的快照及与之后的快照进行对比。本章将对有关创建与提交你的项目快照的命令作介绍。


获取与创建项目命令

git init

用 git init 在目录中创建新的 Git 仓库。 你可以在任何时候、任何目录中这么做,完全是本地化的。

在目录中执行 git init,就可以创建一个 Git 仓库了。比如我们创建 test 项目:

$ mkdir test
$ cd test/
$ git init
Initialized empty Git repository in /Users/liuxunzhuo/top/liuxunzhuo/.git/
# 在 /top/liuxunzhuo/.git/ 目录初始化空 Git 仓库完毕。

现在你可以看到在你的项目中生成了 .git 这个子目录。 这就是你的 Git 仓库了,所有有关你的此项目的快照数据都存放在这里。

ls -a
.    ..    .git

git clone

使用 git clone 拷贝一个云端的Git 仓库到本地,让自己能够查看该项目,或者进行修改。

如果你需要与他人合作一个项目,或者想要复制一个项目,看看代码,你就可以克隆那个项目。 执行命令:

 git clone [url]

[url] 为你想要复制的项目,就可以了。

例如我们克隆 Github 上的项目:

$ git clone git@github.com:Xunzhuo/SpringBoot-in-Action.git
Cloning into 'SpringBoot-in-Action'...
remote: Counting objects: 13, done.
remote: Total 13 (delta 0), reused 0 (delta 0), pack-reused 13
Receiving objects: 100% (13/13), done.
Resolving deltas: 100% (2/2), done.
Checking connectivity... done.

克隆完成后,在当前目录下会生成一个SpringBoot-in-Action 目录:

$ cd SpringBoot-in-Action/
$ ls
README   src 

上述操作将复制该项目的全部记录。

$ ls -a
.        ..       .git     README   Rakefile lib
$ cd .git
$ ls
HEAD        description info        packed-refs
branches    hooks       logs        refs
config      index       objects

默认情况下,Git 会按照你提供的 URL 所指示的项目的名称创建你的本地项目目录。 通常就是该 URL 最后一个 / 之后的项目名称。如果你想要一个不一样的名字, 你可以在该命令后加上你想要的名称。


Git 的工作就是创建和保存你的项目的快照及与之后的快照进行对比。本章将对有关创建与提交你的项目的快照的命令作介绍。

git add

git add 命令可将该文件添加到缓存区,如我们添加以下两个文件:

$ touch README
$ touch hello.py
$ ls
README        hello.py
$ git status -s
?? README
?? hello.py
$ 

git status 命令用于查看项目的当前状态。

接下来我们执行 git add 命令来添加文件:

$ git add README hello.py

现在我们再执行 git status,就可以看到这两个文件已经加上去了。

$ git status -s
A  README
A  hello.py
$ 

新项目中,添加所有文件很普遍,我们可以使用 git add . 命令来添加当前项目的所有文件。

现在我们修改 README 文件:

$ vim README

在 README 添加以下内容:然后保存退出。

再执行一下 git status:

$ git status -s
AM README
A  hello.py

“AM” 状态的意思是,这个文件在我们将它添加到缓存之后又有改动。改动后我们再执行 git add 命令将其添加到缓存中:

$ git add .
$ git status -s
A  README
A  hello.py

当你要将你的修改包含在即将提交的快照里的时候,需要执行 git add。

git status

git status 以查看在你上次提交之后是否有修改。

我演示该命令的时候加了 -s 参数,以获得简短的结果输出。如果没加该参数会详细输出内容:

$ git status
On branch master

Initial commit

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

    new file:   README
    new file:   hello.py

git diff

执行 git diff 来查看执行 git status 的结果的详细信息。

git diff 命令显示已写入缓存与已修改但尚未写入缓存的改动的区别。git diff 有两个主要的应用场景。

  • 尚未缓存的改动:git diff
  • 查看已缓存的改动: git diff –cached
  • 查看已缓存的与未缓存的所有改动:git diff HEAD
  • 显示摘要而非整个 diff:git diff –stat

在 hello.py 文件中输入以下内容:

print("hello world")

git status 显示你上次提交更新后的更改或者写入缓存的改动, 而 git diff 一行一行地显示这些改动具体是啥。

接下来我们来查看下 git diff –cached 的执行效果:

$ git add hello.py
$ git status -s
A  README
A  hello.py
$ git diff --cached

diff --git a/README b/README
new file mode 100644
index 0000000..e69de29
diff --git a/hello.py b/hello.py
new file mode 100644
index 0000000..8cde782
--- /dev/null
+++ b/hello.py
@@ -0,0 +1 @@
+print("hello world")

git commit

使用 git add 命令将想要快照的内容写入缓存区, 而执行 git commit 将缓存区内容添加到仓库中。

Git 为你的每一个提交都记录你的名字与电子邮箱地址,所以第一步需要配置用户名和邮箱地址。

$ git config --global user.name 'xunzhuo'
$ git config --global user.email 981242367@qq.com

接下来我们写入缓存,并提交对 hello.py 的所有改动。在首个例子中,我们使用 -m 选项以在命令行中提供提交注释。

$ git commit -m "init"

[master(根提交) 39aeab6] init
 2 files changed, 1 insertion(+)
 create mode 100644 README
 create mode 100644 hello.py

现在我们已经记录了快照。如果我们再执行 git status:

$ git status

位于分支 master
无文件要提交,干净的工作区

以上输出说明我们在最近一次提交之后,没有做任何改动,是一个”working directory clean:干净的工作目录”。

如果你没有设置 -m 选项,Git 会尝试为你打开一个编辑器以填写提交信息。 如果 Git 在你对它的配置中找不到相关信息,默认会打开 vim。屏幕会像这样:

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
# modified:   hello.py
#
~
~
".git/COMMIT_EDITMSG" 9L, 257C

如果你觉得 git add 提交缓存的流程太过繁琐,Git 也允许你用 -a 选项跳过这一步。命令格式如下(注意,只适合修改,如果新创建了文件,还是得先add,来修改缓存区的文件树):

git commit -a
git commit -am

我们先修改 hello.py 文件为以下内容:

for i in range(100):
    print("hello world")

再执行以下命令:

git commit -am '修改 hello.py 文件'

[master 5f2df9d] 修改 hello.py 文件
 1 file changed, 2 insertions(+), 1 deletion(-)

git rm

如果只是简单地从工作目录中手工删除文件,运行 git status 时就会在 Changes not staged for commit 的提示。

要从 Git 中移除某个文件,就必须要从已跟踪文件清单中移除,然后提交。可以用以下命令完成此项工作

git rm <file>

如果删除之前修改过并且已经放到暂存区域的话,则必须要用强制删除选项 -f

git rm -f <file>

如果把文件从暂存区域移除,但仍然希望保留在当前工作目录中,换句话说,仅是从跟踪清单中删除,使用 –cached 选项即可

git rm --cached <file>

如我们删除 hello.py文件:

$ git rm hello.py 
rm 'hello.py'
$ ls
README

不从工作区中删除文件:

$ git rm --cached README 
rm 'README'
$ ls
README

可以递归删除,即如果后面跟的是一个目录做为参数,则会递归删除整个目录中的所有子目录和文件:

git rm –r * 

进入某个目录中,执行此语句,会删除该目录下的所有文件和子目录。

git mv

git mv 命令用于移动或重命名一个文件、目录、软连接。

我们先把刚移除的 README 添加回来:

$ git add README 

然后对其重名:

$ git mv README  README.md
$ ls
README.md

git log

在使用 Git 提交了若干更新之后,又或者克隆了某个项目,想回顾下提交历史,我们可以使用 git log 命令查看。

针对我们前一章节的操作,使用 git log 命令列出历史提交记录如下:

$ git log
commit d5e9fc2c811e0ca2b2d28506ef7dc14171a207d9 (HEAD -> master)
Merge: c68142b 7774248
Author: xunzhuo <test@xunzhuo.com>
Date:   Fri May 3 15:55:58 2019 +0800

    Merge branch 'change_site'

commit c68142b562c260c3071754623b08e2657b4c6d5b
Author: xunzhuo <test@xunzhuo.com>
Date:   Fri May 3 15:52:12 2019 +0800

    修改代码

commit 777424832e714cf65d3be79b50a4717aea51ab69 (change_site)
Author: xunzhuo <test@xunzhuo.com>
Date:   Fri May 3 15:49:26 2019 +0800

    changed the xunzhuo.py

commit c1501a244676ff55e7cccac1ecac0e18cbf6cb00
Author: xunzhuo <test@xunzhuo.com>
Date:   Fri May 3 15:35:32 2019 +0800

我们可以用 –oneline 选项来查看历史记录的简洁的版本。

$ git log --oneline
$ git log --oneline
d5e9fc2 (HEAD -> master) Merge branch 'change_site'
c68142b 修改代码
7774248 (change_site) changed the xunzhuo.py
c1501a2 removed test.txt、add xunzhuo.py
3e92c19 add test.txt
3b58100 第一次版本提交

这告诉我们的是,此项目的开发历史。

我们还可以用 –graph 选项,查看历史中什么时候出现了分支、合并。以下为相同的命令,开启了拓扑图选项:

*   d5e9fc2 (HEAD -> master) Merge branch 'change_site'
|\  
| * 7774248 (change_site) changed the xunzhuo.py
* | c68142b 修改代码
|/  
* c1501a2 removed test.txt、add xunzhuo.py
* 3e92c19 add test.txt
* 3b58100 第一次版本提交

现在我们可以更清楚明了地看到何时工作分叉、又何时归并。

你也可以用 –reverse 参数来逆向显示所有日志。

$ git log --reverse --oneline
3b58100 第一次版本提交
3e92c19 add test.txt
c1501a2 removed test.txt、add xunzhuo.py
7774248 (change_site) changed the xunzhuo.py
c68142b 修改代码
d5e9fc2 (HEAD -> master) Merge branch 'change_site'

如果只想查找指定用户的提交日志可以使用命令:git log –author , 例如,比方说我们要找 Git 源码中 Linus 提交的部分:

$ git log --author=Linus --oneline -5
81b50f3 Move 'builtin-*' into a 'builtin/' subdirectory
3bb7256 make "index-pack" a built-in
377d027 make "git pack-redundant" a built-in
b532581 make "git unpack-file" a built-in
112dd51 make "mktag" a built-in

如果你要指定日期,可以执行几个选项:–since 和 –before,但是你也可以用 –until 和 –after。

例如,如果我要看 Git 项目中三周前且在四月十八日之后的所有提交,我可以执行这个(我还用了 –no-merges 选项以隐藏合并提交):

$ git log --oneline --before={3.weeks.ago} --after={2010-04-18} --no-merges
5469e2d Git 1.7.1-rc2
d43427d Documentation/remote-helpers: Fix typos and improve language
272a36b Fixup: Second argument may be any arbitrary string
b6c8d2d Documentation/remote-helpers: Add invocation section
5ce4f4e Documentation/urls: Rewrite to accomodate transport::address
00b84e9 Documentation/remote-helpers: Rewrite description
03aa87e Documentation: Describe other situations where -z affects git diff
77bc694 rebase-interactive: silence warning when no commits rewritten
636db2c t3301: add tests to use --format="%N"

git放弃修改&放弃增加文件

本地修改了一堆文件(并没有使用git add到暂存区),想放弃修改。

  • 单个文件/文件夹:

$ git checkout -- filename

  • 所有文件/文件夹:

$ git checkout .

本地新增了一堆文件(并没有git add到暂存区),想放弃修改。

  • 单个文件/文件夹:

$ rm filename / rm dir -rf

  • 所有文件/文件夹:

$ git clean -xdf

// 删除新增的文件,如果文件已经已经git add到暂存区,并不会删除!

本地修改/新增了一堆文件,已经git add到暂存区,想放弃修改。

  • 单个文件/文件夹:

$ git reset HEAD filename

  • 所有文件/文件夹:

$ git reset HEAD.

本地通过git add & git commit 之后,想要撤销此次commit

$ git reset commit_id

这个id是你想要回到的那个节点,可以通过git log查看,可以只选前6位
// 撤销之后,你所做的已经commit的修改还在工作区!

$ git reset --hard commit_id

这个id是你想要回到的那个节点,可以通过git log查看,可以只选前6位
// 撤销之后,你所做的已经commit的修改将会清除,仍在工作区/暂存区的代码也将会清除!

好的,基础部分到这里结束了,接下来进行最后的进阶学习!

坚持就是胜利~

Default image
LIU
代码是躯体,思想是灵魂

Leave a Reply