常用Git基本命令

浏览: 1754
git

Git本身是一个命令行的工具,因此,掌握Git命令成为我们使用Git版本控制的第一道障碍。好在常用的Git命令只有几个,并且参数都比较简单,因此,我们会很容易地跨越这个障碍。而刚开始就直接使用GUI工具并不是我们推荐的方式,因为使用GUI不仅效率慢,还会使得你根本不了解Git本身的工作机制,一旦出现问题你将不能手动进行解决。因此,要使用GUI也要建立在能够熟悉Git基本命令的前提下。

进行版本控制的第一步—Git init

使用Git进行版本控制的第一步就是通过在你的项目根目录执行Git init命令,该命令会在你的根目录下创建了一个隐藏的.Git目录,该目录中包含了该项目在Git中的相关配置和信息,Git就是根据里面的数据对你的项目进行版本控制。例如,我们在git-project根目录运行git init命令,然后再查看根目录下的文件,结果如图8-6所示。

Clipboard Image.png

常用的版本控制命令—Git status

在初始化了需要版本控制的项目之后,我们就可以继续进行后续的工作。在我们使用Git进行版本控制的过程中,Git status命令是我们最为常用的命令之一,它用于检查本地项目的状态。现在我们就来学习该命令,首先我们在git-project项目中创建一个新的文件,我们命令为SayHello.java,它的功能就是输出Hello字符串。然后执行Git status命令,如图8-7所示。

Clipboard Image.png

此时我们看到在命令行中给出了一些提示信息,比较显眼的就是红色区域(运行中可看到)的SayHello.java文件。咋一看会觉得不知所措,下一步到底要做什么呢?但是仔细看上面的提示我们会发现一些关键的信息,在SayHello.java的上、下一行都含有有用的信息,例如,SayHello.java上一行是use git add <file> … to include in what will be commited。这就是告诉我们下一步可以使用Git add 命令将下面的文件添加到下次要提交的文件列表中。因此,我们下一步要做的就是执行Git add 命令。

添加到追踪列表中—Git add

Git add 命令的作用是将一个或者多个文件添加到Git追踪列表中,只有通过Git add 添加了的文件才会被版本控制管理。从上面的Git status中得知,我们下一步要做的就是Git add命令。Git add命令并不像Git init 、Git status这样的无参数命令,完整的命令参数复杂,我们只说最常见的两种用法。一种用法是添加某个文件,另一种是添加某个目录下的所有文件。示例如下:

git add SayHello.java    # 添加SayHello.java这个文件gitadd .     # 添加当前目录下的所有文件

通常由于Android的项目文件比较多,一次性可能会修改多个文件,因此,最为常用的也就是Git add .命令,一次性将所有文件都添加到下次要添加的列表中。执行该命令之后我们再次执行Git status命令查看当前状态(执行完一些重要命令之后通过Git status查看状态应该是你使用Git的习惯,这样避免出现遗漏等问题)。如图8-8所示。

Clipboard Image.png

执行Git add命令之后可以看到当前项目的修改已经被提交,项目状态变成了前文说的staged(已暂存)状态,此时SayHello.java会在下次提交时被提交到本地仓库。需要注意的是,Git add 命令并不是执行一次就可以的,每次修改项目中的内容之后你都需要执行Git add命令进行更新。

假设我们是误操作将不需要追踪的文件进行了add操作,那么如何移除呢?答案还是仔细看Git status给出的提示信息,这也是Git体现人性化的一点,它会在你执行命令时给出下一个你可以要用到的命令,因此,查看Git状态就变得更为重要。在图8-8中我们看到一句提示: use “git rm –cached <file>…” to unstage 。意思是我们可以通过git rm –cached 命令将文件从追踪列表中移除,不用担心,这个命令不会将你的文件从本地目录删除,而只会从你的Git追踪列表中删除,这样在提交中就不会包含被移除的文件。

提交—Git commit

执行Git add 命令之后,你的文件已经添加到追踪列表。执行这个操作的时间节点应该是你已经完成了一个功能,并且想将这个功能提交到本地仓库中。此时,还需要Git commit命令将你的改动真正的提交。Git commit命令格式如下:

git commit -m "这里写你的提交说明"  # 形式1 : 通过-m提交简短的信息
git commit        # 形式2 : 通过git commit提交,会跳转到编辑器

使用形式1相对来说比较方便、快捷,但是,当你的提交信息有一定格式或者需要提交的文字内容较多时,使用形式2会是一个更好的选择。执行Git commit之后,如图8-9所示。

Clipboard Image.png

从图8-9中可以看到,我们通过git commit -m 将这次修改添加到本地仓库,提交信息为“add SayHello.java”。成功之后我们再通过git status查看状态,得到的结果是“nothing to commit, working directory clean“。至此,我们就将这次修改提交到本地仓库了。

查看项目历史记录—Git log

有的时候我们需要查看某个项目的提交历史,那么我们可以通过Git log命令实现。该命令会列出所有的提交记录,这些信息包括提交人、时间、信息,最重要的就是这次提交对应的信息指纹,也就是该项目的目录和文件的整体SHA-1值,它代表了这次提交的唯一标识。我们在git-project项目中执行Git log,结果如下:

commit 07408ceedfa52473107efc7daa4d7af6c363e192    # 信息指纹Author: MrSimple <bboyfeiyu@gmail.com>               # 提交人Date:   Fri Aug 14 12:43:11 2015 +0800                # 时间
   add SayHello.java                                    # 提交信息

由于我们的项目就提交了一次,因此,也就是输出了这次提交的相关信息。

下载程序—Git clone

有的时候我们并不是自己创建项目,而是想要将别人的托管在网站上的开源库下载到自己的计算机中,那么此时我们就需要使用Git clone命令。该命令的作用正是将远程项目下载到本地,命令的格式为:Git clone 远程仓库地址。例如,我们要将一个Android事件总线库下载到本地,它的地址为git@github.com:bboyfeiyu/AndroidEventBus.git(网址在这里为http://github.com/bboyfeiyu/ AndroidEventBus),那么我们可以在命令行下执行如下命令:

git clone git@github.com:bboyfeiyu/AndroidEventBus.git

此时,Git就会从该地址下载这个项目,如图8-10所示。


Clipboard Image.png


执行完成之后就会在当前目录下创建一个AndroidEventBus目录来存放这个开源库,项目的所有文件都存放在这个目录中。

不同分支—Git branch

大家看图8-8可以看到,在命令行的末尾总是显示一个“master”,这实际上是我们所在的git-project项目分支名。当你初始化Git之后,默认会创建一个master分支,你的操作也默认会在master分支。不同分支的文件互不影响,因此,当你需要开发一个新的功能时,你可以新建一个新的分支,并且切换到该分支进行开发,当功能完成后你将该分支提交到本地,然后再切换回主分支,并且合并完成新功能开发的分支。例如,我们要创建一个新的类来实现网络聊天,但是,这个我们没有太大的把握能够完成这个功能,为了保险起见,新建了一个net分支进行开发,如果完成了就将net合并到master分支,否则就切换回master分支,并且将net删除。

首先我们通过Git branch 命名创建net分支,命令为Git branch net。

执行后效果如图8-11所示。

Clipboard Image.png


通过Git branch命令可以到当前项目的所有分支,在未执行Git branch net之前我们只有master分之,执行之后我们新增了net分支。注意看master分支之前有一个星号,这代表你当前所处在的分支,目前,我们就处在master分支。那么现在问题来了,我们是要切换到net分支进行开发,分支切换需要用到Git checkout命令。

签出一个分支—Git checkout

checkout命令的作用是签出一个分支或者一个路径。在开发中常用于分支切换和恢复文件。分支切换命令格式为:

git checkout 分支名

执行命令之后就会切换到指定的分支上,如图8-12所示。

Clipboard Image.png

从图8-12中可以看到,此时星号目前在net前面,表明我们顺利地切换到了net分支。这样,我们就可以在net分支进行工作了,我们新建一个Chat.java类实现网络聊天。此时,git-project的net分支就含有SayHello.java、Chat.java两个文件。将Chat.java开发完成之后,我们依次执行如下2条命令将这次修改提交到本地仓库:

gitadd .
git commit -m "add Chat.java"

效果如图8-13所示。

Clipboard Image.png


此时,net分支的网络聊天功能就开发完成了,功能实现在Chat.java中。我们在net分支上的操作不会影响master分支,也就是说master分支目前还是只有SayHello.java一个文件。假设现在经过测试,我们的网络聊天功能出现了验证的Bug,并且不能够被修复,我们只好放弃net分支。那么此时我们可以先checkout回到master分支,然后使用git branch -d 命令删除net分支。依次执行两条命令:

git checkout master         # 切回master分支git branch -d net           # 删除net分支

此时master分支还是只有一个SayHello.java文件,net分支的开发对于master没有产生影响。如图8-14所示。

Clipboard Image.png

checkout的另一个常用的功能是将文件恢复到修改之前的状态。例如,SayHello.java的源码在修改之前如下:

public class SayHello {    // 原来的代码省略
   public static void main(String[] args) {
       System.out.println("Hello");
   }
}

现在需要加一个复杂的功能,经过一轮Coding之后,SayHello.java的代码可能已经变得面目全非,而且由于代码过于混乱,使得原来正确的代码也变得不可用,以前与今天的工作都白干了,此时你两眼早已饱含热泪。修改后的SayHello.java代码如下:

public class SayHello {     // 原来的代码省略
    private static void eat() {          // 省略新增的好多代码
    }     public static void main(String[] args) {
        System.out.println("Hello");
    }     private static void sleep() {          // 又省略新增的好多代码~
    }
}

如何才能回滚到SayHello.java修改之前的状态呢?

还好,Git checkout提供了这样的功能。我们使用如下命令将SayHello.java恢复到修改之前的状态:

git checkout -- SayHello.java

此时,SayHello.java就从已修改状态变为最初的版本了。

合并分支—Git merge

在上一节中我们切换到net分支开发了网络聊天功能,假设开发成功了,那么我们需要将网络聊天功能合并到master分支,也就是我们要将net分支合并到master分支。需要用到的命令为Git merge。我们在net分支提交代码之后,切换到master分支,并且执行Git merge net命令,如果没有冲突,那么master分支将会和net分支合并。如图8-15所示。

Clipboard Image.png



此时,Chat.java就被合并到master分支了,master分支也就有了网络聊天的功能。

解决冲突

在Git merge中没有提到,如果没有冲突才会自动合并,否则将会提出哪些文件产生了冲突。产生冲突的原因是因为有多个开发人员修改了同一个文件的相同地方导致,使得Git系统不知道使用谁的代码,此时就需要开发人员自己来抉择,选择其中一份代码,并且将其他的代码删除。

假设研发-A和研发-B两位同事同时开发网络聊天功能,因此,他们同时修改了Chat.java文件的eat函数。研发-A首先提交了代码到线上的版本控制系统,然后研发-B此时从线上系统更新代码下来,此时就会产生冲突。当然,在不同分支之间切换开发也可能导致发生冲突,或者说只要是代码合并的操作都有可能出现冲突,原因也是同时修改了文件中的同一处代码段。例如Chat.java的原始代码为:

public class Chat {    public static void main(String[] args) {
       System.out.println("Chat with me");
   }
}

研发-A在master分支上修改了Chat.java的main函数的第一行代码,代码如下:

public class Chat {    public static void main(String[] args) {
       System.out.println("Chat with me, I'm RD-A.");
   }
}

研发-B在net分支也修改了同样的地方,代码如下:

public class Chat {    public static void main(String[] args) {
       System.out.println("我和研发-A的代码不一样.");
   }
}

此时,研发-B提交代码到线上系统之后,研发-A将net分支代码同步到本地,并且将net分支通过Git merge合并到master分支。此时就会引发冲突,如图8-16所示。

Clipboard Image.png

从图8-16中可以看到,图中指出自动合并失败,Chat.java产生了冲突。我们看看此时Chat.java文件中的内容是怎样的:

public class Chat {    public static void main(String[] args) {
<<<<<<< HEAD
       System.out.println("Chat with me, I'm RD-A.");
=======
       System.out.println("我和研发-A的代码不一样.");
>>>>>>> net
   }
}

其实很容易看懂这份冲突的文件,它的意思是,在System.out.println()语句这里出现了多份代码,Git不知道如何解决。在我们的示例中,在“<<<<<<< HEAD”与“=======”之间的是研发-A的master分支的代码,而“=======”与“>>>>>>> net”则是研发-B的net分支中的代码。这两份代码到底要哪一份,这需要你来裁决,因此,给出了冲突提示。假设研发-A的代码是正确的,那么需要将“=======”与“>>>>>>> net”之间的代码删除,并且将“<<<<<<< HEAD”、“=======”、“>>>>>>> net”这些冲突标识也删除。最终代码如下:

public class Chat {    public static void main(String[] args) {
       System.out.println("Chat with me, I'm RD-A.");
   }
}

此时,冲突就已经被处理了。重新Git add和commit提交代码即可。

为版本打一个标签—Git tag

在完成了所有功能、并且经过测试之后,我们通常会为这个版本打一个标签,这是一个非常重要的功能,建议大家为每个正式发布的版本都创建一个标签,这样便于后续的版本检索与维护。通常一个标签就代表了一个正式版本,通过Git tag命令就可以列出当前项目的所有标签。新建一个标签的常用命令如下形式:

git tag -a v1.0 -m "这里写相关信息"

上述命令新建了一个名为v1.0的tag,然后再次运行Git tag命令列出所有标签,得到的结果如图8-17所示。

Clipboard Image.png

我们也可以通过“git tag -d 标签名”来删除tag、“git show 标签名”的形式来查看该分支的具体信息,例如执行git tag v1.0,得到的结果为:

tag v1.0Tagger: MrSimple <bboyfeiyu@gmail.com>Date:   Sat Aug 15 08:11:56 2015 +0800版本1.0commit c97418b2a93226296ad0cc4c45b930562ce4261dMerge: 026ca26 1490b54Author: MrSimple <bboyfeiyu@gmail.com>Date:   Fri Aug 14 14:40:26 2015 +0800解决了冲突

当我们的项目托管在远程仓库(如Github)时,我们可以将标签通过Git push命令推送到线上,也可以通过Git pull命令将标签从远程仓库上下载下来。这些功能我们将在后面的章节中为大家演示。

帮助文档—Git help

本章我们讲述的都是常用命令的简单格式,为了避免引入过多的复杂性命令的其他用法,我们并没有全部演示出来。在日常开发中,我们也只会运用到那些基本的命令、形式,而当你想详细了解某个命令时,你可以使用Git help命令来获取完整的使用说明。例如,查看Git tag命令的使用说明可以执行Git help tag命令,得到的结果如下:

NAME
git-tag - Create, list, delete or verify a tag object signed with GPG
SYNOPSIS
git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>]<tagname> [<commit> | <object>]git tag -d <tagname>http://www.worldhello.net/gotgithub/.
git tag
[-n[<num>]] -l [--contains <commit>] [--points-at <object>]
             
[--column[=<options>] | --no-column] [<pattern>http://www.worldhello.net/gotgithub/.]
              [<pattern>http://www.worldhello.net/gotgithub/.]git tag -v <tagname>http://www.worldhello.net/gotgithub/.DESCRIPTION
      Add a tag reference in refs/tags/, unless -d/-l/-v is given to delete, list or verify tags.// 省略OPTIONS// 省略各个参数的说明

重点我们就看上述4项即可,NAME中描述的是Git tag命令的作用简介,SYNOPSIS则是该命令的参数简介,DESCRIPTION是该命令的功能与相关参数的介绍,OPTIONS则是各参数的含义。通常只需要查看这几项说明就能找到所需的功能。

推荐 0
本文由 程序员书屋 创作,采用 知识共享署名-相同方式共享 3.0 中国大陆许可协议 进行许可。
转载、引用前需联系作者,并署名作者且注明文章出处。
本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责。本站是一个个人学习交流的平台,并不用于任何商业目的,如果有任何问题,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

0 个评论

要回复文章请先登录注册