Android开发之路工具篇:版本控制工具(Git)

一:简介

未经作者本人同意谢绝转载!!!!

未经作者本人同意谢绝转载!!!!

未经作者本人同意谢绝转载!!!!

非要转载请标明出处。违者追究。

       Git是一种最初应用在Linux上的一种分布式版本控制系统。Git它与常用的cvs、svn的不同,在于它采用了分布式的控制方式。而cvs和svn都是集中式的版本控制系统。那么这两个系统有什么区别呢?

1:集中式版本控制系统:它将整个项目库存放在服务器上,在工作的时候,我们需要从服务器上获取最新的版本,然后开始工作,工作完成后,交给服务器保存。服务器就是一个仓库,我们的工作都是建立在这个仓库上进行的。而与仓库建立连接必须进行联网操作,因此如果网络不好,工作效率就很受影响。

2:分布式版本控制系统:他并没有统一的版本库,这里的统一是和集中式的服务器版本库相对比而言的。分布式版本控制系统,每个电脑都有完整的版本库,某个人的电脑出现问题,可以从其他人那里复制一份就可以了,这样就提高了安全性,不像集中式的只要中央服务器出现问题,整个项目就没法工作。而实际上分布式控制系统通常也有一台中央服务器,只不过这台中央服务器仅仅用于方便交换大家的修改而已。

 本文只介绍Git的使用,至于它的原理及实现我们不做深究。因为它只是我们android开发者使用的其中一个工具。在as中的相应操作都会有与之相对应的命令行。

二:Git的基础知识

  1、文件区域划分: 

 

我们先了解一下git管理时我们的项目的内部区域划分:

工作目录(Workspace):就是我们电脑上的本地工作文件夹。

暂存区(IndexStage):Git内部的一块存储区域,用于存储文件的改动。我们通过git add 将文件改动添加到这块区域。

本地仓库(HEAD):就是Git仓库,我们将文件永久保存到的区域。

 

2、文件状态:

 对于任何一个文件,在Git内只有四种状态:

    unmodified(未修改):表示该文件已经被安全地保存到本地的仓库中。

    untracked(未被跟踪):表示文件没有与git进行关联,不被git所管理。

    modified(已修改):表示用户修改了文件,但是没有提交保存。

    staged(暂存):表示把已修改的文件存放在下次提交时要保存的清单中。

    

一个文件提交到本地仓库中一个简单的流程如下图所示。

3、工作流程:

一个简单的git工作流程:

 

从图1可以看到我们要想将我们工作区中的文件添加到本地仓库中,分三步走:

        1、git init 通过git创建一个本地仓库,关联我们的文件,让git管理我们的项目。

        2、git add:就是将文件添加到暂存区中。

        3、git commit 是将暂存区中的文件提交到master分支上。

              这里的HEAD指向master,HEAD就是一个指向当前分支的一个指针。

如果我们要与远程仓库(Github、Gitlab、码云、公司服务器等)建立连接,就必须将自己的仓库push到远程仓库中,与远程仓库建立连接,同步分支。

 

3.Git的安装

关于Git的安装:以mac系统为例介绍:

由于Mac系统自带有Git,我们不需要进行下载安装了。但是如果Git的版本过低,我们需要升级。可以采用以下方法来做。命令Git—version 查看当前Git版本。which git或者whereis git查看git的安装路径。

附下载链接:http://git-scm.com/download/

4.Git 的相关配置

4.1基础配置:配置姓名及邮箱,必须要配置供生成秘钥使用,也是为了区分不同的用户。

$ git config --global user.name "Your Name"

$ git config --global user.email "email@example.com

 

查看你的配置

$ git config  user.name

$ git config  user.email

 

在as中的配置:

 

这里如果不知道Git的路径可以在terminal中输入which git 或者whereis git查看

 生成密钥

   与远程仓库建立连接,一般有两种方式:一类是https(每次建立连接都要输入密码),一类是ssh路径(要配置秘钥)。

如果要采用SSH连接远程仓库、必须得生成密钥;一个公钥交给服务端配置和一个私钥放在本地。

那么如何生成密钥呢?

 

1:首先查看本地是否生成过SSH key

在默认情况下,用户的SSH秘钥存储在~/.ssh目录下。进入这个目录并列出其中的内容,就可以确认自己是否已拥有密钥。如果你找不到这样的文件(或者根本就没有.ssh目录),你可以通过ssh-keygen来创建。会确认密钥的存储位置(默认是.ssh/id_rsa)。

 

   $ cd ~/.ssh

   $ ls 

 

可以看到本地已经生成了rsa的公钥了(id_rsa.pub)。

 

2:生成key和生成多个key

 

如何生成一个key?

$ ssh-keygen -t rsa -C "你的邮箱地址”

 

第一次回车确认你保存key的文件名及其路径。

第二次回车是key是否要密码,输入你的密码,如果不需要密码直接回车即可。

第三次回车确认密码,不需要密码直接回车。在这里你的key就生成好了。

 

如何生成多个key

有时我们在本地利用我们的私人账户(这里用我的qq好注册的邮箱为例)已经产生了一对key,但是这个key是我们访问github所用的秘钥。

现在公司需要我们用公司提供给我们的邮箱(这里用我的163邮箱为例)生成的密钥去连接公司的服务器,而我又不想让原来访问github的密钥失效怎么办呢?我们就需要再生成一个key。

 

注意:这里生成的第二个key一定要重新命名一下,防止被覆盖了。

生成好密钥之后我们需要进行密钥的配置

切换到.ssh文件夹下,touch config

查看是否具有config文件,如果没有就创建。

有的话直接配置就可以了,配置的格式如下:

 

 

# 配置文件参数

# Host : Host可以看作是一个你要识别的模式,对识别的模式,进行配置对应的的主机名和ssh文件(可以直接填写ip地址)

# HostName : 要登录主机的主机名(建议与Host一致)

# User : 登录名(如gitlab的username)

# IdentityFile : 指明上面User对应的identityFile路径

# Port: 端口号(如果不是默认22号端口则需要指定)

你可以将配置好的公钥复制到远程服务器上进行配置,通过

 

ssh-t “git@github.com”

ssh-t “git@gitee.com”

测试一下即可

如果发生公钥拒绝的情况,是因为你没有在远程服务端把公钥加入进去。如何加入公钥后文我们再说。

这里就配置完成了。

通过ssh -t 连接远程仓库进行测试即可.

 

三:创建仓库提交并代码

        

        在前文Git的工作流程中我们知道,我们要用Git管理我们的项目,要分三步走战略:创建仓库、添加到暂存区、提交到master分支中。

1、创建仓库

先介绍一个命令 git status 主要是用来查看仓库的当前状态。

我们先在terminal中运行一下 

这句话的意思是我们的项目还没有git仓库。

现在通过在 terminal中 输入git init 命令 初始化一个仓库:

 

可以看到控制台已经提示我们成功初始化了一个空的仓库。

我们在运用 git status 查看一下状态

 

这里的 Untracked files 中的内容,就是我们没有将文件添加到缓存区里的文件。

 

那么在AS中的操作先初始化一个仓库:

 

紧接着在项目弹框中选择创建仓库的位置在你的项目所在的文件夹中。

 

可以看出仓库已经创建成功,可以观察到我们项目文件的变化:

                

这个.git文件夹默认是隐藏的(可以通过ls -ah或者la或者在项目的根目录下按住command和句号查看) 。这个.git文件不要删掉,否则项目与git建立的关联就失效了。

此时as关联本地仓库文件成功之后,文件的颜色变为红色。

注意:

文件的颜色为白色(普通文件的颜色、成功提交到仓库后文件的颜色)

文件的颜色变为红色(表示已经关联到本地仓库,但文件没有天添加到本地仓库中)

文件的颜色变为绿色(表示已经添加到本地仓库中,但文件没有提交到服务器)

文件的颜色变为蓝色(表示文件已经被修改)

 

在我们项目中有个.gitignore文件这个文件是我们提交到git仓库上所忽略的文件。

会有两个,一个文件在项目中,一个在App目录下我们打开文件工程的.gitignore文件

这里的忽略文件信息可以按照官方给的填写方式(https://github.com/github/gitignore)根据自己的项目情况填写。

 

 

2、将我们的项目添加到暂存区:

 

在命令行中输入

$ git  add  <file> 添加到仓库中

在as中vcs-git-add即可

 

我们查看一下git status

 

我们可以看到git 多了一段提示:Changes to be committed(改动已经被提交了)

这里的文件表示我们已经将文件的修改添加到暂存区里中了,但是还没有提交到分支上。

 

git  rm -r —cached 你的项目名 从工作缓存区中移除

 

3、将项目提交到master分支上:

$ git  commit  -m <message>

后面的message 代表你的提交日志”

注意git 提交一定要输入日志,否则你提交不上去。

 

在as中vcs--git--commit即可

到这里我们的三步走战略已经完成了。

 

我们通过 git status 查看仓库目前的状态

这表明我们工作区很干净,没有要提交的文件了。所以暂存区中的内容相当于提交所有的修改到了分支上。

可以通过git log 查看我们提交的日志.

 

log信息显示出了:提交的id(commitedId)(这个id是SHA1计算出来的一个非常大的数字,用十六进制来进行表示),作者和日期。

如果你想只显示id和日志信息可以加上—pretty=oneline 漂亮的显示出了一行

或者 你直接输入 git lg

 

这里总结一下:

        1:我们要将文件提交到本地代码仓库,要分三步走:创建仓库(init)、添加(add)、提交    

              (commit)。

        2:我们可以通过git  status查看版本库状态信息,对应了三种状态:

              Untracked files: 在工作区中的文件,没有提交到暂存区中的,通常是新建的文     

              件。工作区中有但暂存区中没有。

              Changes not staged for commit:工作区中发生改动了,但是改动的部分没有提交        

              到暂存区中的文件,通常是修改了的文件。

               Changes to be committed:存在暂存区里,但是还没有提交到分支上。

        3:我们可以通过git log 查看我们提交的日志信息。

 

至此代码已经提交到了本地git仓库中,这里要说明一下,根据git工作流图可以看出,我们本地的git仓库并没有与远程仓库建立连接。那么如何建立连接呢?这个后文我们再说。

到这里我们一个最基本的将文件提交到本地仓库的工作我们已经完成了。接下来我们介绍git的一些常用的其他操作。

 

4、修改文件:

开发过程无法避免去修改文件,那么针对修改的文件我们同样采用 git add <file>这种操作,其实git保存的就是文件的修改,这是与svn不同的(后文对文件管理的操作更能体现)。至于原理不做深究。下面我们对mainactivity进行修改,查看git 仓库的状态发生了哪些变化。在as中最明显的变化是文件变为蓝色。

 

git status

 

 

可以看到有两个文件已经被修改,但是被修改的内容还没有被提交到暂存区中。

 

我们如何知道文件修改了哪些内容发生了哪些变化呢?

git diff <file> 

这个指令是工作区的文件和暂存区的文件作对比;

 

这里绿色的部分就是我们增加的内容,红色的内容就是我们删除的。

此外还有另外两个指令:

git diff —cached <file> 是指暂存区的文件和分支的作比较

git diff HEAD <file> 工作区中的文件和分支作比较(注意这个命令没有--)

在as中我们通过选择Version Control 里的LocalChanges 选择Default,选择蓝色变化的文件右击选择Show Diff同样可以知道文件的变化。

 

在VersionControl中有两个根目录:

Default  就是我们前面提到的Changes not staged for commit对应的文件,也即是修改但是还未提交的文件

UnVersioned Files 代表的意思是没有添加到暂存区中的文件,也即是处在工作区中的文件。

关于git的添加的另外几种,可以通过输入git add -help 查看

 

这里就介绍三种,除非特殊情况,不要使用git add -f这种强制添加文件。

git add .  将文件的修改和新增文件添加到暂存区中(这里不包括删除的文件)

git add -u 这里的u是update的意思,将文件的修改、删除添加到暂存区中。

git add -A 这里A的意思是All,它是将所有修改信息添加到暂存区中(包括修改、删除、新增是上面两个的合集)。

 

我们通过git add 已经将文件的修改提交到暂存区中,之后再用git commit 将文件提交到分支上就行了。

 

5、版本回退

  有时候我们需要回退到指定的版本该怎么去做呢?我们还记得第一部分文件状态图吗?图中清楚的标记了文件在Git工作过程中的状态。我们说版本回退,那张图可以帮助我们很好的理解。

在Git中,HEAD 表示当前版本,HEAD^表示上一个版本,HEAD^^表示上上一个版本,指定到往上n个版本HEAD~n.

比如我们把当前版本回退到上一个版本可以使用命令:

git reset --hard HEAD^ 

—hard是一个参数,有什么意义呢?在这里git reset 表示重置版本,它有三种用法:

5.1  git reset — mixed    回退的版本会将暂存区里面的内容和本地已提交的内容全部恢复到未暂存的状态(也就是初始状态对应的Untracked files),但是他不会覆盖掉没有提交的文件,只影响暂存区和已提交的文件。举个例子说明一下:

先获取一下当前git的状态,在我们的工程目录下,

可以看到我们

   暂存区中有一个新增的readme_fixbug和一个已提交的readme文件。

工作区里有一个.idea/vcs.xml文件和一个在修改的readme文件。画个图直观一点:

 

 

我们看一下readme中的内容。

看一下日志:

 

这时候我们采用git reset —mixed HEAD^回退到上一个版本。

在用git status查看一下git仓库的状态;

 

git log

查看本地readme 中的内容:

查看本地readme文件和master分支上的文件有什么不同:

可以看到和上面git diff HEAD readme 的结果一致

查看暂存区中的readme文件和master分支上的文件有什么不同:

没有不同

git diff 比较的是暂存区和工作区的不同,但是暂存区的文件已经提交到分支上了,那么它比较的就是工作区和分支上的不同了。

 

通过log可以看到已经回退到上一个版本上(第一个版本)。

可以看出已提交到暂存区中(readme_fixbug)的变为未提交状态,未提交的(处在工作区中的)和已经修改的(分支和工作区不同的文件)未受影响。上个版本已经提交到分支上的,变为Untacked  files状态即处在工作区的初始状态。

 

5.2  git reset —hard

回到初始状态也就是我们采用git reset —mixed之前的状态。

git状态如下:

 

采用 git reset —hard :

log信息:

git status:

看一下readme 的信息:

我们发现git已经恢复到上一个版本第一个版本,但是我们发现暂存区里面的内容没有了,工作区中改变的文件也没有了。此时的状态如下图:

 

可以很清楚的看出git reset —hard 命令它表示回退一个版本,会清空暂存区,而且将已提交的内容恢复到本地,本地的文件也会被替换(文件你已经修改了,也会被替换)。

5.3  git reset — soft

接下来我们执行git soft 命令会发生什么情况?我们先让版本状态恢复最初的状态:

 

执行git reset —soft HEAD^

reame里的内容

 

此时的目录结构:

 

 

可以看出这个指令:回退一个版本,不清空暂存区,将已提交的内容恢复到暂存区,不影响原来本地的文件(未提交的也不受影响)。

在AS中的操作:

找到VersionControl-在log中你可以操作已提交到分支上的版本,在LocalChanges中可以操作暂存区和工作区的版本。

 

总结:

    git reset —mixed  HEAD^:回退一个版本,且会将暂存区的内容和本地已提交的内容全部恢复到工作区,不影响原来本地文件(未提交的也不受影响).重置暂存区和分支到工作区

     git reset —soft HEAD^:回退一个版本,不清空暂存区,将已提交的内容恢复到暂存区,不影响原来本地的文件(未提交的也不受影响).重置分支到暂存区

    git reset —hard HEAD^:回退一个版本,清空暂存区,将已提交的内容的版本恢复到本地,本地的文件也将被恢复的版本替换。全部重置

 

这三中版本重置已经介绍完了,但是如果我们又后悔重置到上一个版本了那该怎么办呢?

我们接下来继续说

 

6、撤销修改

git 保存的是文件的修改不是文件本身这是与svn不同的地方。

修改是指新增、删除、改动。

    6.1   现在有个文件你已经提交到本地版本库上,但是你又进行了修改,还没来得及添加到暂存区里,你发现改动的部分是错的。那么如何撤销修改呢?我们可以采用git checkout — <file> 命令中的--很重要,没有--,就变成了“切换到另一个分支”的命令,我们在后面的分支管理中会再次遇到git checkout命令.举个例子说明:

现在目录结构如下:

readme 在工作区和分支上的状态一致。

现在我们修改readme的内容,并不提交。看看采用git checkout —readme操作后的状态

我们看到结果本地工作空间恢复到了与分支状态一致。

 

6.2  现在有个文件你不但修改了,还提交到了暂存区中,如何撤销修改呢?

 

 

执行撤销操作:

 

 

我们发现执行git checkout — <file>并没有撤销;

该怎么做呢?

我们需要分两步:1:把提交到暂存区的内容改为未提交状态;2:执行checkout操作。

这里 git rest HEAD 表示的是恢复到当前未提交的状态

 

执行第二步操作:

 

我们可以看出git checkout --<file>这个命令只能将未添加到暂存区改动的部分撤销掉。

6.3 文件已提交到了分支上但是没有push到远程仓库如何撤销?

 

根据6.2的思想我们可以了解到,我们必须将文件重置到未提交状态,才能使用git checkout -- <file>撤销,而让文件处于未提交状态,这就是我们第5点所说的版本回退。

还是拿上个例子来说:

可以看出新增的修改已经提交到仓库上了,但是我想这新增的修改是没用的,怎么撤回呢?

我们仍需要两步操作:

6.3.1:恢复到上个版本

其实还是用第5步的git reset 这个指令。后面的加上commitid(也就是log前面的id),git reset <commitid> 是不是和之前的git reset HEAD~ n 命令一样相当于git reset — mixed,回到指定版本提交之前的状态。但是如果你不记得那个id怎么办呢?可以使用git reflog来获取我们之前提交的id.

这里也解决了第5步遗留下的后悔版本回撤的问题。

 

git reset <commitID>之后

其实就是HEAD指针的移动,这个速度非常快。

可以看出 已经恢复到版本2之后的未提交状态,此时我们再执行checkout操作

6.3.2、执行git checkout —<file>

 

可以看到文件已经恢复了。

 

上面我们说的是在命令行中的操作工,现在说一下在AS中的操作:

项目->Git—>Repository->Reset HEAD 

 

 

这个弹框我们可以很好的理解:Type:我们上面所说的三种类型,Mixed、soft和hard 、,To Commit是要提交到的版本也就是我们所说的commiteID。Validate是查看影响的目录.

相比命令行git checkout —<file>,AS操作更为简单。

在AS中

 

点击对比按钮,观察不同直接合并。

 

总结: 

 1:如果文件没有提交到暂存区中我们可以通过git checkout —<file>的命令撤回修改

 2:如果文件已经提交到暂存区或者已经提交到了分支上,我们必须分成两步操作:

    2.1、将文件撤回到未提交状态;

    2.2、执行git checkout —<file>的命令;

3:如果你将文件提交到本地仓库后,又push到远程仓库中,那就没什么办法了;

4:我们可以通过git reflog查看以往的操作信息来获取commitID;

5:git checkout —<file>其实就是用版本库里的版本来替代我们本地仓库的版本。

6.4、如何撤销删除

 有时候我们操作删除了某个文件该如何处理呢?只要我们删除的文件改动没有提交到版本库中,我们就可以通过git checkout —<file>的命令将文件从版本库中检出。如果你想彻底删除的话,那就是删除后,再提交就可以了。git checkout 后面一定要加上“--”否则就变成切换分支。

 

三、本地仓库与远程仓库建立关联:

我们接下来介绍一个关键的知识点,本地仓库与远程仓库建立关联。

因为我们的电脑可能会出故障,导致项目代码丢失,但是我们将项目上传到远程服务端就能很好的解决这个问题。git关联到远程服务端通常采用两种协议:SSH和Https协议。我们先介绍一下如何将本地的项目push到远程仓库,然后再接着介绍如何将远程已有的项目pull到本地。

    1、Github

    1.1 SSH协议连接Github

    1.1.1 生成密钥对

             具体方法见前面第二部分的内容

     1.1.2 配置公钥

 

公钥可以给别人看,但是注意私钥要保存好。配置完成后我们测试一下连接

在terminal中输入

SSH -T git@github.com

输入密码之后可以看出已经测试成功了。

 

1.1.3创建远程仓库

1.1.4连接远程仓库

添加到远程仓库的命令如下:

git remote add [options] <name> <url>

name就是我们远程仓库的名称,一般采用origin,git默认的叫法

url就是我们项目的地址。

建立连接:

    

git remote 用于查看已配置的远程服务器。

指定参数-v,会显示需要读写远程仓库使用的Git保存的简写与其对应的URL.

我们如果想删除已有的远程仓库,或者对远程仓库进行重命名:

例如我们将 origin 重命名为myorigin

可以这样做:git remote rename origin myorigin

删除已有的远程仓库:git remote rm origin 

查看远程仓库的信息:git remote show <remote-name> :例如 git remote show origin

 

在AS中,可以通过以下操作:

 

 

添加即可。这里报错的同学可以看后面的解决方法;

 

1.1.5 把本地仓库的内容push到远程仓库

git push [options] <remotename> <branchname>

这里remotename对应的就是我们远程仓库的名称也就是origin

branchname是分支的名称

在我们的仓库中可以输入以下指令:

git push origin master 或者加个参数-u (git push -u origin master)

-u参数的意思其实就是一个验证,指定远程特定的分支,把本地的master分支内容推送到远程新的master分支上,还会把本地的master分支和远程的master分支关联起来。在以后推送或者拉取的时候就可以简化命令直接push就行了。注意这里我们的远程仓库是空的,而且是第一次推送。

关于这个参数说法不一:

知乎上的:https://www.zhihu.com/question/20019419

stackoverflow:https://stackoverflow.com/questions/5697750/what-exactly-does-the-u-do-git-push-u-origin-master-vs-git-push-origin-ma

我们知道大概意思就可以了。

git push -u origin master    

 

可以看出我么已经成功推送到远程仓库上了。现在远程仓库上的目录就和我们本地工程的目录一样了。

 

当然与push相对应的是pull即将远程仓库的内容更新到本地工作空间中。

这个我们前面第二部分的Git的工作流程很清晰的表达出了。

 

在AS中的操作:

项目 -> VCS ->Git ->push

 

总结:

我们来总结一下与远程建立连接的步骤:

1:首先要通过git remote add <remote> <url>与远程仓库建立连接。

2:客户端我们通过$ ssh-keygen -t rsa -C "你的邮箱地址”生成密钥对,服务端创建仓库,配置公钥

3:通过git push -u <remote> <brach>将本地仓库推送到远程仓库上。

 

以上所说的是通过ssh协议与Github建立连接,接下来我们说一下通过https协议建立连接所需要的配置。

 

1.2通过Https连接Github

 

 

采用Https的方式与远程仓库建立连接和采用SSH步骤是差不多的(这里我就不做演示了):

简单的说一下步骤

1.2.1 建立连接 git remote add origin <url>,这个url就是https的地址。地址的获取方式见上图。

1.2.2 git push到Github上 git push和pull都需要输入密码,不过AS很方便的为我们提供了这个管理密码的设置,我们需要配置一下即可使用。具体配置方法如下:

 

点击Add account 

这里有个两种方式登录:

1:用户名和密码

直接输入用户名密码登录即可。

2:token登录

在github上生成token复制到token栏即可。

token生成步骤:

 2.1:setting—Developer settings

 

 

2.2:

 

2.3:全选,自定义token名称即可。

 

生成完毕后,复制粘贴。即可登录。

 

注意:

Clone git repositories using ssh 勾上即采用SSH协议,不勾即采用https协议。

本地仓库推送到远程仓库上。

 

之后的push和pull和之前的SSH操作类似。

 

2、克隆

上面我们说的是如何将已有项目上传到远程仓库上面,下面介绍如何将远程仓库的内容clone到本地。我们先在Github上创建一个工程叫LearGit,然后克隆到本地。

 

 

创建好项目之后我们在工程中添加一个readme文件。远程仓库已经准备完毕,接下来就是git clone一个本地仓库。

git clone [options] [--]<remote-url><local-directory>

remote-url:就是远程仓库的地址,

local-directory:仓库存放的目录。

git clone git@github.com:xuchangqing/LearnGit.git

可以看到已经clone到本地了

 

在AS中的操作:

 

2、码云

项目上传到码云上和github是类似的,这里介绍码云是为了解决这样一个问题:

一个本地仓库关联到了Github上,能否关联到码云上呢?答案肯定是可以的啊。

但是要注意远程仓库的名称不能重复,比如我们上传到github上的远程仓库名称叫origin,那么我们再上传到码云上仓库名称不能叫origin,因为使用同一个名字我们就无法区分到底是上传到哪个仓库上。

还记的我们之前生成了两对密钥吗?一对用于Github,那么我们尝试用另一对密钥把我们关联到github上的项目关联码云试一下。

首先看一下我们工程关联的远程项目状态:

接下来我们关联到码云,先在码云上创建一个仓库,配置我们的另一个公钥。

配置公钥

见我们的另一个公钥配置到码云上

 

 

添加完毕后,我们开始重复之前的步骤:

git remote add gitee_origin git@gitee.com:xcq_123/GitDemo.git

 

可以看出已经关联到码云上了。

在执行push操作:

 

可以看出项目已经上传成功了。

四、分支操作

接下来我们说一下Git中最重要的一个功能,分支操作。可以说分支是git里的核心了。

有了分支操作可以说是给项目开发带来了极大的便利、提高了开发速度。

1、简介:git针对每一次提交都会把它们串成一条时间线,这条时间线就是我们所说的分支,而在git中只有一条线,这条线称为master分支也就是主分支。master分支是默认的分支,Git保存了一个名为HEAD的指针,它指向当前所在的分支,每次的提交它都会随着分支一起向前移动。一开始的时候,master分支是一条线,Git 用master 指向最新的提交,再用HEAD指向master。当我们创建新的分支,例如dev,Git就会创建一个新的指针dev,指向master相同的提交,再把HEAD指向dev,这样当前开发就在dev上进行,那么提交修改都是针对的dev分支。而master分支是保持不变的。等我们开发完成后,我们就可以将分支合并到master上,也就是将指向dev分支的指针切换到指向master。

 

2、创建分支、查看分支、

在命令行里我们可以通过命令:

git check out -b <brach_name>

-b表示创建并切换,branch_name就是分支名。

这个命令会创建一个分支并且换到该分支上。根据前面的简介,我们可以知道其实就是创建了一个指针,用HEAD指针指向这个指针。

这个命令包含两步:创建和切换,因此也可以分开使用

git branch dev   //创建

git checkout dev //切换

然后用

git branch //查看当前分支(本地分支),当前分支前会标*,

git branch -a //查看所有分支

git branch -r //查看远程分支

 现在所在的分支处在dev上,然后我们修改mainactivity中的内容然后提交。

之后我们切换到master分支上。

我们会发现之前在dev修改的内容,master分支上并不存在。

因此我们需要将dev分支上的内容合并到master分支上来。

git merge <branch_name> //合并某分支到当前分支上

 

我们再查看所在的工程目录发现变成了dev所在的分支一样的内容。

注意到上面的Fast-forward信息,Git告诉我们,这次合并是“快进模式”,也就是直接把master指向dev的当前提交,所以合并速度非常快。

当然,也不是每次合并都能Fast-forward,我们后面会讲其他方式的合并。

 

合并完成后我们怎么删除dev分支呢?

git branch -d <branch_name> //删除dev分支

 

我们查看brank发现,dev已经被删除了。

 

在AS中的操作:

查看分支:

 

创建分支:

 

总结:

    

git branch <branch_name> //创建分支

git checkout <branch_name> //切换分支

git checkout -b <branch_name> //创建并切换到分支

git merge <branch_name> //合并某分支到当前分支

git branch -d <branch_name> //删除分支

 

注意不能删除当前分支,删除当前分支前,先切换到别的分支

分支的切换我们使用git checkout <branch_name>,要注意如果我们没有保存提交的修改,用命令行切换分支会报错,而用AS切换会弹出如下对话框,AS会自动给你存储起来,而命令行中git会提醒我们要把改动贮藏起来。(git stash)可以保存当前所有改动,到需要的时候我们再恢复到工作区。

 

 

3  git stash命令

3.1 新增保存

git stash

在默认情况下它会把所有的未提交的修改(包括暂存的和非暂存的)保存起来,它不会保存在工作目录中新的文件(untracked files)和被忽略的文件(ignored files)。我们如果想保存新增的文件可以使用 git stash -u ,如果想保存全部文件可以使用git stash -a.这个保存是保存到本地上,不会push到远程服务上。总之就是分支会重新恢复到未修改之前的状态,而已经修改的会保存起来。

 

git stash save <message>  // 例如:git stash save “修改主题颜色”

给stash加一个message,用于保存的版本信息,这也是我们开发中经常使用的。

3.2 查看保存

git stash list  //列出贮存区中保存的信息清单

git stash show -p <index> //查看指定的stash全部修改

3.3 恢复保存

git stash pop <index> //例如git stash pop stash@{0},如果增加了index参数会恢复指定idex下保存的修改信息。如果未指定index默认会恢复第一条保存的信息。

用于恢复保存的缓存目录,但是这个命令恢复的同时会把将stash list中的保存记录清除掉。

如果你不想清除可以采用下一个命令

git stash apply <index> //恢复保存的缓存目录,但是这个命令不会清除保存清单中的记录。

3.4 删除保存

git stash drop <index> //删除指定的index保存

 

3.5 stash 分支

有时候会出现这种情况:我们在分支上进行了修改并将修改保存到stash中去,一段时间过后我们又在分支上进行了开发工作。而我们又想将保存到的stash中的文件合并过来就会产生冲突这个该怎么做呢?

我们可以通过创建一个stash 分支来保存当前的修改,再与stash保存的文件进行合并即可。

git stash branch <branch_name>//创建一个stash 分支

当然还有另外一种方法就是我们将当前分支的修改提交,之后在进行stash pop,再解决文件的冲突也可以。

相比命令行的操作,在AS中stash的操作就显得很直观了。

保存修改到贮存区中:VCS--Git--StashChanges

查看、删除、恢复修改:VCS--Git--UnStashChanges

4 分支的合并

   在上一部分中我们已经知道如何进行简单的分支合并了。其实Git中的合并通常被叫做三方合并。合并时会确定三个提交,当前分支对应的提交,被合并分支对应的提交,和两条分支的共同祖先提交。我们所关心的是两条分支合并后的共同提交。Git会把其他两个提交相对于共同祖先提交的改动提取出来,如果这两份改动里对同一个文件进行了改动,那么Git就会提示自动合并失败,让我们手动修改冲突的文件,在修改完后,使用git commit把所有改动提交,如果没有对同一个文件进行改动,Git就会自动帮我们添加所有改动到新提交中。如果当前分支没有出现改动,而被合并分支上有改动,x就会把分支的指针指向改动的部分,这就是我们上一部分所说的快进模式(fast-forward模式)。

 

有的时候我们不想要用快进模式来合并,我们想看保留我们的工作轨迹——在哪开始开发这个功能,在哪这个工作完成,中间有哪几步。我们可以用--no-ff来关闭快进模式。让我们用--no-ff重新来一遍。

//创建一个分支

git checkout -b dev2

git commit -am “修改mainacitvity的布局”

git checkout master

git merge —no-ff dev2 -m "合并提交分支"

 

可以看出无快进模式清楚的显示我们提交合并到master分支上的轨迹。

 

分支的合并过程中难免会出现合并冲突的现象,下面我们来模拟冲突,看一下如何去解决:

创建两个分支,两个分支都修改main_activity然后与master分支合并。

我们已经创建了两个分支dev、和dev2都修改了main_activity

我们切换到dev2并与dev进行合并结果:

自然产生了冲突

冲突产生的文件已经被标记出来,我们手动修改需要的内容,再次提交。

 

 

成功合并到master分支上。

 

在AS中的操作:

 

如果产生冲突会弹出一个对话框;

 

我们双击冲突的文件左边框显示的是当前所在的分支的文件、中间的是我们合并后要提交的结果

右边是分支上的改变的内容。选择我们需要的信息合并到中间就可以了。

冲突解决完毕后,我们点击apply即可完成合并,但是这种方式不能够记录提交信息,如果要填写提交信息,我们可以使用VSC—Git—MergeChanges

关于这个表格中的参数,网上有篇博客介绍的很详细,不做赘述了。

https://www.jianshu.com/p/58a166f24c81

4 变基操作(rebase)

 

整合分支主要有两种方法:合并(merge)和变基(rebase).合并我们前一节已经说过将已有的分支合并到当前分支上(三方合并),这样必然会产生新的节点和分支上的提交日志信息。而变基的操作,它是将提交某一分支上的修改全部移交到了另一分支上。因此rabase命令可以使分支变得更加简洁、干净。可能会很难理解,上图表示一下:

通过meger命令experiment分支合并到master分支上生成了一个新的节点C5.我们发现有点凌乱,如何让它变成一条直线呢?这就引出了rebase命令,我们使用rebase命令将experiment分支合并到master分支上:

$ git checkout experiment

$ git rebase master

First, rewinding head to replay your work on top of it...

Applying: added staged command

 

 

它是首先找到这两个分支(即当前分支 experiment、变基操作的目标基底分支 master)的最近共同祖先 C2,然后对比当前分支相对于该祖先的历次提交,提取相应的修改并存为临时文件,然后将当前分支指向目标基底 C3, 最后以此将之前另存为临时文件的修改依序应用。

$ git checkout master

$ git merge experiment

 

 

这两种整合方法的最终结果没有任何区别,但是变基使得提交历史更加整洁。 你在查看一个经过变基的分支的历史记录时会发现,尽管实际的开发工作是并行的,但它们看上去就像是串行的一样,提交历史是一条直线没有分叉。

 

注意:无论是通过变基,还是通过三方合并,整合的最终结果所指向的快照始终是一样的,只不过提交历史不同罢了。 变基是将一系列提交按照原有次序依次应用到另一分支上,而合并是把最终结果合在一起。

 

不要对已经push到远程的分支进行变基操作

不要对已经push到远程的分支进行变基操作

不要对已经push到远程的分支进行变基操作

重要的话说三遍!!

 

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

 

为什么会不要对远程分支进行变基操作,官方文档给出了很好的解释:

假设你从一个中央服务器克隆然后在它的基础上进行了一些开发。 你的提交历史如图所示:

Figure 44. 克隆一个仓库,然后在它的基础上进行了一些开发

然后,某人又向中央服务器提交了一些修改,其中还包括一次合并。 你抓取了这些在远程分支上的修改,并将其合并到你本地的开发分支,然后你的提交历史就会变成这样:

Figure 45. 抓取别人的提交,合并到自己的开发分支

接下来,这个人又决定把合并操作回滚,改用变基;继而又用 git push --force 命令覆盖了服务器上的提交历史。 之后你从服务器抓取更新,会发现多出来一些新的提交。

Figure 46. 有人推送了经过变基的提交,并丢弃了你的本地开发所基于的一些提交

结果就是你们两人的处境都十分尴尬。 如果你执行 git pull 命令,你将合并来自两条提交历史的内容,生成一个新的合并提交,最终仓库会如图所示:

Figure 47. 你将相同的内容又合并了一次,生成了一个新的提交

此时如果你执行 git log 命令,你会发现有两个提交的作者、日期、日志居然是一样的,这会令人感到混乱。 此外,如果你将这一堆又推送到服务器上,你实际上是将那些已经被变基抛弃的提交又找了回来,这会令人感到更加混乱。 很明显对方并不想在提交历史中看到 C4 和 C6,因为之前就是他把这两个提交通过变基丢弃的。

上面的内容我们已经了解了变基的基本概念和简单的操作方法,下面我们介绍两个变基常用的命令能够使我们的提交的历史变得更加简洁:

git rebase -i <startCommitID> <endCommitID>

其中-i的意思是--interactive,即弹出交互式的界面让用户编辑完成合并操作,[startCommitID] [endCommitID]则指定了一个编辑区间,如果不指定[startCommitID],则该区间的终点默认是当前分支HEAD所指向的commit(注:该区间指定的是一个前开后闭的区间)。

简单的git操作我们就介绍这么多。至于另外一些复杂的操作,我们可以参考官方文档。

注意:

采用ssh 作为远程项目的路径时,有时会报以下错误:

 

 

 

解决办法:

 1:查看复制的路径地址有没有正确。尝试用terminal连接试一下。

  ssh 地址

1:ssh add 关联

2:转换native

显示欢迎页表示连接正确.

我这个问题很奇怪。

git remote add orgin git@github.com:xuchangqing/GitDemo.git 用命令行添加可以成功,而用AS添

加。血与泪的教训。

 

3.gi关联远程仓库码云不成功原因:

是因为我们本地创建了一个readme文件,而远程也有个readme 

先进行git pull再push

 

git pull gitee_origin master 仍然报错

这个问题出现的原因是因为本地仓库和远程仓库实际上是独立的两个仓库,然后本地要推送到远程,远程仓库觉得这个本地仓库和自己不相干,所以无法合并。假如我之前是直接clone的方式在本地建立起远程github仓库的克隆本地仓库就不会有这问题了。但是我们本地已经建立好项目了,所以只能采用强制的方法:git pull <remote> master --allow -unrelated-histories

然后进入vi编辑,输入以#号开头提交的日志,结束后按esc:wq结束。注意按esc后紧接着输入冒号。

之后再执行push操作

 

如果远程仓库仍然连接不成功的话,可以重新删除url重新尝试。

如果你对于git还有什么疑问,推荐几个学习的网站,希望能够帮到你。

 廖老师Git教程

https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000

个人公众号:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值