Detailed Git version control tools

A, Git and SVN difference?

This is a school Git can not bypass the topic, the common theme of the interview, and I guess a lot of people the answer is on the back of directly Baidu, SVN has understood the realization of the principle underlying it?

SVN is a centralized version control tools, SVN architecture as shown:

A, B, C three developers If you need to submit your code to the remote repository, must be networked (upload), after uploading the SVN repository inside what has been done?

Suppose user A document submit code, the user A will be altered in A.java submitted to SVN repository, the repository only record change (increment) for B.java, C.java h no other operation is performed, the no increment.

So come out of two issues

1, assuming that the Internet does not how to do?

2, assuming SVN repository bad hard drive, how to do?

 

Git is a distributed version control, its structure as shown:

 local computer1, the local computer2 is essentially a local repository, Git without networking can be achieved submit other operations in local development, Server, local computer1, computer2 the content is the same. And it is different from the local computer1 SVN and local computer2 can communicate directly.

The underlying principle Git version control:

For the modified files, as shown in the A.java, will save a copy of the file after the modification in the new version, it can be understood as a Snapshot (note: not a delta file). For no modified files, then saved in the new version is a reference to the old version.

 

Second, the work area and the staging area

Git and other version control systems such as SVN One difference is that the concept of the temporary area.

Workspace (Working Directory): what you can see in the computer catalog.

Repository (Repository): the work area has a hidden directory .git, this is not the work area, but Git repository.

Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD

我们把文件往Git版本库里添加的时候,是分两步执行的:

第一步是用git add把文件添加进去,实际上就是把文件修改添加到暂存区;

第二步是用git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支。

因为我们创建Git版本库时,Git自动为我们创建了唯一一个master分支,所以,现在,git commit就是往master分支上提交更改。

你可以简单理解为,需要提交的文件修改通通放到暂存区,然后,一次性提交暂存区的所有修改

俗话说,实践出真知。现在,我们再练习一遍,先对readme.txt做个修改,比如加上一行内容:

Git is a distributed version control system.
Git is free software distributed under the GPL.
Git has a mutable index called stage.

然后,在工作区新增一个LICENSE文本文件(内容随便写)。

先用git status查看一下状态:

$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

	modified:   readme.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)

	LICENSE

no changes added to commit (use "git add" and/or "git commit -a")

Git非常清楚地告诉我们,readme.txt被修改了,而LICENSE还从来没有被添加过,所以它的状态是Untracked

现在,使用两次命令git add,把readme.txtLICENSE都添加后,用git status再查看一下:

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	new file:   LICENSE
	modified:   readme.txt

现在,暂存区的状态就变成这样了:

所以,git add命令实际上就是把要提交的所有修改放到暂存区(Stage),然后,执行git commit就可以一次性把暂存区的所有修改提交到分支。

$ git commit -m "understand how stage works"
[master e43a48b] understand how stage works
 2 files changed, 2 insertions(+)
 create mode 100644 LICENSE

一旦提交后,如果你又没有对工作区做任何修改,那么工作区就是“干净”的:

$ git status
On branch master
nothing to commit, working tree clean

现在版本库变成了这样,暂存区就没有任何内容了:

本文第二章节以上部分参考自《工作区和暂存区——廖雪峰的官方网站》 

git中包含四种状态:Untracked、Unmodified、modified   [可以通过git status查看当前状态]

1、Untracked一般出现在新建文件时候,表示新建的文件处于未被追踪的状态

2、将新建文件add之后,此时新建文件处于暂存区(Stage),状态为Staged状态

3、当用户commit提交暂存区域的文件到分支时,所有文件将处于Unmodified状态,此时Stage(暂存区是完全干净的)

4、当用户对文件进行修改后,被修改的文件将处于Modified状态,等待add 【重复2-4步骤】

 

三、Git最常用的几个命令

  • remote
  • fetch/pull/push
  • reset
  • checkout
  • log
  • merge

当然还包括我们上一章节所说的git add <file>    和  git commit -m '信息'    和 git status  命令,下面我们将一个个介绍。

3.1  git remote(建立远端连接)

因为我们会存在远端的分支,比如使用gitlab举例来说。

假设我们本地已有一个项目,但是GitLab/GitHub上没有,我现在想将该项目推送上去,该怎么做呢?

1、这是一个比较笨的方法,在远端建立一个项目,从远端仓库clone到本地,将本地代码拷贝到该项目,再分别执行三个命令add->commit->push。

2、这是一个比较明智的做法,步骤如下:

(1)将需要提交项目的目录的项目初始化,打开Git Bash,比如我要将我的目录/User/itcats_cn/git_test项目提交到Gitlab,就cd到git_test,输入git init命令,初始化该项目为git管理的项目,在执行完该命令后,输入ls -a,应该可以看到.git的隐藏文件。

(2)在本地git add <file> git commit -m 'message' 

(3)在Gitlab中创建项目,项目名需要与第(2)步骤中提交的文件<file>名称一致

(4)复制gitlab中的git协议的地址,如[email protected]:web/test.git

(5)执行命令  git remote add origin [email protected]:web/test.git  【含义是"add" 本地项目与远端建立联系】

(6)执行命令  git config --list  发现[email protected]:web/test.git,已经关联上了

 

输入git remote -v命令,返回的是一个origin集合,说明用户可以对远端的仓库执行fetch和push操作

origin	[email protected]:web/test.git (fetch)
origin	[email protected]:web/test.git (push)

 

3.2  git fetch(版本更新)

从远程仓库获取最新到本地,不会自动merge,Git中从远程的分支获取最新的版本到本地方式如下:

方式一

(1)查看远程仓库

$ git remote -v
eoecn   https://github.com/eoecn/android-app.git (fetch)
eoecn   https://github.com/eoecn/android-app.git (push)
origin  https://github.com/com360/android-app.git (fetch)
origin  https://github.com/com360/android-app.git (push)
su@SUCHANGLI /e/eoe_client/android-app (master)

从上面的结果可以看出,远程仓库有两个,一个是eoecn,一个是origin
(2)从远程获取最新版本到本地

$ git fetch origin master
From https://github.com/com360/android-app
 * branch            master     -> FETCH_HEAD
su@SUCHANGLI /e/eoe_client/android-app (master)

$ git fetch origin master 这句的意思是:从远程的origin仓库的master分支下载代码到本地的origin master

(3)比较本地的仓库和远程参考的区别

$ git log -p master.. origin/master
su@SUCHANGLI /e/eoe_client/android-app (master)

我的本地参考代码和远程代码相同,所以是Already up-to-date

以上的方式有点不好理解,大家可以使用下面的方式,并且很安全

方式二

(1)查看远程分支,和上面的第一步相同
(2)从远程获取最新版本到本地

$ git fetch origin master:temp
From https://github.com/com360/android-app
 * [new branch]      master     -> temp
su@SUCHANGLI /e/eoe_client/android-app (master)

git fetch origin master:temp 这句命令的意思是:从远程的origin仓库的master分支下载到本地并新建一个分支temp

(3)比较本地的仓库和远程参考的区别

$ git diff temp
su@SUCHANGLI /e/eoe_client/android-app (master)

命令的意思是:比较master分支和temp分支的不同
由于我的没有区别就没有显示其他信息
(4)合并temp分支到master分支

$ git merge temp
Already up-to-date.
su@SUCHANGLI /e/eoe_client/android-app (master)

由于没有区别,所以显示Already up-to-date.
合并的时候可能会出现冲突,有时间了再把如何处理冲突写一篇博客补充上。
(5)如果不想要temp分支了,可以删除此分支

$ git branch -d temp
Deleted branch temp (was d6d48cc).
su@SUCHANGLI /e/eoe_client/android-app (master)

如果该分支没有合并到主分支会报错,可以用以下命令强制删除git branch -D <分支名>

总结:方式二更好理解,更安全,对于pull也可以更新代码到本地,相当于fetch+merge,多人写作的话不够安全。

git fetch章节参考自:《git fetch的简单用法》

 

3.3  git pull(版本更新合并)

git pull origin master

 

3.4  git push(版本推送)

git add .

git commit -m 'update .gitignore'

git push origin master  或者  git push -u origin dev
 

 

3.5  git reset(版本回退)

可以通过git log命令查看历史的commit记录,通过选择复制commit后的SHA1 id进行指定的版本回退,如:

localhost:git_test fatah$ git log
commit 617866c48b75d62b8b33a29fc21eb6d32cff3eb1 (HEAD -> master)
Author: itcats_cn <[email protected]>
Date:   Tue Aug 6 23:00:27 2019 -0400

    Add new file

commit 8ea66b2158d45ddd459fc6b538669be5b546bbb0
Author: itcats_cn <[email protected]>
Date:   Wed Aug 7 10:20:37 2019 +0800

    init2

目前版本为617866开头的commit id版本号,如果想回退版本,可以通过指定版本号进行回退

git reset --hear '8ea66b2158d45ddd459fc6b538669be5b546bbb0'

如果嫌输出信息太多,看得眼花缭乱的,可以试试加上--pretty=oneline参数:

localhost:git_test fatah$ git log --pretty=oneline
881667e679a88b557b1014d33e6a46a3c1d0a442 (HEAD -> master, origin/master) add hahaha
617866c48b75d62b8b33a29fc21eb6d32cff3eb1 Add new file

Git的commit id(版本号)和SVN不一样,Git的commit id不是1,2,3……递增的数字,而是一个SHA1计算出来的一个非常大的数字,用十六进制表示,而且你看到的commit id和我的肯定不一样,以你自己的为准。为什么commit id需要用这么一大串数字表示呢?因为Git是分布式的版本控制系统,后面我们还要研究多人在同一个版本库里工作,如果大家都用1,2,3……作为版本号,那肯定就冲突了。

Git必须知道当前版本是哪个版本,在Git中,用HEAD表示当前版本,上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100。

 

3.6 checkout

作用:

1、切换到新的分支: 一般来说master分支上都是最稳定的版本,我们日常开发的时候在分支开发,开发完毕之后再合并到master中,具体操作如下。

$ git checkout -b dev-0807-work
 Switched to a new branch 'dev-0807-work'

$ git checkout -b master
 Switched to a new branch 'master'

2、撤销更改 :只能撤销更改过的文件,不能撤销新增的文件或删除的文件

比如我们修改了3.txt的内容

$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   3.txt

no changes added to commit (use "git add" and/or "git commit -a")

现在我想撤销3.txt的更改,操作如下:

$ git checkout 3.txt
Updated 1 path from the index

此时3.txt的内容就成功被撤销,这样不会影响之前的版本,恢复成非常"干净"的状态

 

3.7  merge

一般我们开发环境都在分支上开发,分支开发完毕时候测试通过则发布,并且在master进行merge合并并发布,这样才能保证master上是最"clean"的状态,但是一般我们将分支合并到Master都是在图形化界面发起的,下面我将展示GitLab中的 Pull Request。

这种merge方法方便code-review,查看改动之处并让参与者、审阅者也可以方便在下面书写评论。 

在确认没有任何问题后,再点击绿色的按钮"Merge',就可以将我们的工作分支合并到master之中。

合并之后,在本地机器执行  git fetch 命令,从远端拉取最新的代码[此时本机处于dev-08-07-work分支]

本机切换到master分支,执行命令 git checkout master

localhost:git_test fatah$ git checkout master
Switched to branch 'master'
Your branch is behind 'origin/master' by 2 commits, and can be fast-forwarded.
  (use "git pull" to update your local branch)

提示远端的master有两处commit,先pull到本机的orgin/master

localhost:git_test fatah$ git pull origin master
Enter passphrase for key '/Users/fatah/.ssh/id_rsa': 
From 192.168.1.103:web/test
 * branch            master     -> FETCH_HEAD
Updating 881667e..b117d8f
Fast-forward
 a.txt | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

整个过程我们发现,本地的master并没有push到远端仓库,而是使用分支push到远端仓库中,再使用Request Merge在远端将分支与Master进行合并,在code-view没有问题之后,在远端仓库执行Merge操作。由于本地在fetch最新代码的时候并不会直接合并,所以在本机切换为master分支的时候会提示pull一下,因为有两处commit,在pull成功之后本机master便拥有了最新的master代码。

在merge的时候如何解决冲突呢?

 

3.7.1  merge解决冲突

模拟场景:

(1)比如修改gitlab中的a.txt文件,本地也修改git管理目录下的a.txt文件

(2)本地进行add 和 commit操作

(3)执行git pull origin master时候,发现冲突文件,因为远端和本地两处修改位置一样,到底选用哪一行?

(4)删除冲突部分,其中<<<<HEAD到=====之间的内容为本地仓库内容,后面的内容为远端仓库的内容,两处冲突地方选用哪个可以自己权衡,再修改完之后,输入git status,发现a.txt变为了unmodified状态,重新执行add -> commit -> push操作,发现完成解决冲突。

 

 

发布了162 篇原创文章 · 获赞 237 · 访问量 26万+

Guess you like

Origin blog.csdn.net/itcats_cn/article/details/98646044
Recommended