Git一句话简介
没错,就如标题一般,Git是地球上最先进的分布式版本控制系统。
何为版本库(repository)
版本库又称为代码仓库,其实就是放项目源文件的地方,仓库里面的所有文件都将被Git管理起来,每个文件的修改、删除都会被Git所记录,方便后续需要时,进行项目回滚。
创建仓库
$ mkdir gitdir
$ cd gitdir
$ git init
此后git会在gitdir文件夹下自动生成一个后缀名为git的文件目录,这个目录是用于跟踪管理仓库的。
把文件添加进仓库
例如我们在gitdir目录下创建一个名为Git.txt的文本文件。
把大象放进冰箱需要三个步骤,而Git只需要两步。
第一步,使用git add
命令将文件添加到仓库中
$ git add Git.txt
执行完这一步,如果git没有任何提示就说明文件添加成功了。
第二步,使用git commit
命令提交到仓库中
$ git commit -m "add a new file"
-m参数是本次提交的说明,一般输入本次提交相关的简单说明,方便以后更加方便的找到自己的更改记录。
git commit
命令运行成功后,git会输出如下信息:
[master (root-commit) eaadf4e] wrote a readme file
1 file changed, 2 insertions(+)
create mode 100644 Git.txt
1 file changed:1个文件被改动(我们新添加的Git.txt文件)
2 insertions:插入了两行内容(Git.txt有两行内容)。
git commit
命令只会提交git add
成功的文件,我们可以add不同的文件,然后commit一次性提交。
$ git add a.txt
$ git add b.txt c.txt
$ git commit -m "add 3 files"
查看仓库当前状态
之前我们添加了Git.txt文件到仓库中,我们对文件内容进行一些修改
修改之前的原内容
this is a txt file
and this is a git test
修改之后的内容
this is a very good txt file
and this is a git test
我们可以使用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: Git.txt
no changes added to commit (use "git add" and/or "git commit -a")
git status
命令可以让我们时刻掌握仓库当前的状态,上面的命令输出告诉我们,Git.txt被修改过了,但还没有提交修改。
但是这样仅仅知道Git.txt被修改了,但是却无法知道具体修改的内容,此时我们需要git diff
这个命令来查看了
$ git diff Git.txt
结果如下:
diff --git a/test.txt b/test.txt
index 21094ae..0876bad 100644
--- a/Git.txt
+++ b/Git.txt
@@ -1,2 +1,2 @@
-this is a txt file
+this is a very good txt file
and this is a git test
\ No newline at end of file
从上面的输出我们可以看到我们在第一行中添加了very good两个单词
确认文件修改无误后,我们便可以提交文件到仓库了,步骤和之前一样共两步:
$ git add Git.txt
在git commit
之前,我们可以先查看一下仓库状态git status
输出结果如下:
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: test.txt
确认即将被提交的文件为我们修改文件之后,就可以提交仓库了。
$ git commit -m "add very good"
[master 977ad7a] add very good
1 file changed, 1 insertion(+), 1 deletion(-)
为确保提交成功,我们可以再查看一下git status
$ git status
On branch master
nothing to commit, working tree clean
输出表示目前已经没有东西需要提交了,工作树是空的。
版本回滚
我们不断的修改文件并提交。每次的commit
就是一个版本快照,当将来误删除文件、或者文件丢失等问题,我们可以通过git的版本回滚,回滚到任意之前的提交版本。
使用git log
命令来查看历史版本信息
$ git log
commit 977ad7a0e30563457ce1499bf26e174b3ad918ac (HEAD -> master)
Author: lan.gao <[email protected]>
Date: Tue Oct 16 09:37:10 2018 +0800
add very good
commit c6fef09e01a87bee355e67d169de5a858b40d1ba
Author: lan.gao <[email protected]>
Date: Mon Oct 15 14:06:56 2018 +0800
add new file
我们可以从输出看到我们之前所commit
的两个版本。git log
会显示规则是从近到远的。值得一提的是输出的信息每个commit之后都会有一个Hash值,表示commit版本的id号,由于Git是分布式版本控制系统,当多人协作时,并不能使用1、2、3…作为版本id。
想要回滚到之前的版本,我们必须要让Git知道,我们要回滚到哪个版本,在Git中,HEAD
表示当前版本,也就是我们最新提交的版本(id号为9977ad…),上个版本我们使用HEAD^
,上上个版本为HEAD^^
,上50个版本我们可以使用HEAD~50
现在我们试着把当前版本(add very good)回滚到上个版本(add new file),使用git reset
命令
$ git reset --hard HEAD^
HEAD is now at c6fef09 add new file
打开Git.txt
文件查看内容:
this is a txt file
and this is a git test
可以看到版本已经回滚到了之前的add new file的版本了,此时我们在使用git log
查看下历史版本信息:
$ git log
commit c6fef09e01a87bee355e67d169de5a858b40d1ba (HEAD -> master)
Author: lan.gao <[email protected]>
Date: Mon Oct 15 14:06:56 2018 +0800
add new file
之前最新的 add very good的版本已经消失了,假如我们后悔了,想要再回到之前的版本怎么办?我们只需要找到之前版本的id号就可以了,Git提供了git reflog
命令供我们查看历史命令
$ git reflog
c6fef09 (HEAD -> master) HEAD@{0}: reset: moving to HEAD^
977ad7a HEAD@{1}: commit: add very good
c6fef09 (HEAD -> master) HEAD@{2}: commit (initial): add new file
我们可以看到add very good的版本id号为977ad7a,我们可以再次通过git reset
命令回到之前版本:
$ git reset --hard 977ad7a
HEAD is now at 977ad7a add very good
OK,果然Git总是提供了后悔药给我们吃,我们的add very good版本恢复成功。
工作区和暂存区
Git有工作区和暂存区的概念,其他的版本控制工具如SVN是没有的。
工作区
工作区也就是我们的项目目录,例如我们创建的的gitdir文件夹
版本库
在工作区中,存在一个隐藏的文件夹为.git
,它不算是工作区的一部分,我们之前提到过,它是Git版本库的目录
Git的版本库中有个非常重要的概念,叫暂存区(stage),还有Git为我们自动创建的主分支master,还有一个指向master分支的指针HEAD
回忆之前我们将修改提交到仓库的步骤,其实是:
第一步:修改项目,使用git add
将工作区的文件添加到暂存区
中
第二步:使用git commit
将修改从暂存区提交到当前分支
我们当前分支为Git为我们自动创建的主分支master
撤销修改
我们现在给Git.txt增加一行新的内容:
this is a very good txt file
and this is a git test
this is a new line
如果我们想要撤销之前的修改,我们怎么办?我们先使用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: Git.txt
no changes added to commit (use "git add" and/or "git commit -a")
其实我们可以看到在输出中,Git有告诉我们,可以使用git checkout -- <file>
命令放弃修改文件修改内容
$ git checkout -- Git.txt
执行完这段命令,我们就可以撤销Git.txt在工作区
的所有修改,存在两种情况:
第一种:文件修改后未添加入暂存区,撤销后和版本库保持一致。
第二种:文件添加到暂存区之后再次做修改,撤销后和暂存区保持一致。
总的来说,只能撤销掉在工作区的修改。
再来看我们的Git.txt撤销后的内容:
this is a very good txt file
and this is a git test
我们已经撤销修改成功了
远程仓库
远程仓库就是一个在线的Git仓库,既可以作为项目备份,也可以多人通过该仓库来协作开发。例如Github、GitLab、码云等平台。
添加远程仓库
以Github平台为例,现在我们本地有一个名为GitTest的仓库了,我们在Github上也创建一个名为GitTest的仓库。
登录Github --> 右上角 + 号--> New repository
Repository name: 仓库名
Description: 仓库描述
Public/Private: 仓库私有 or 开源
Initialize this repository with a README: 是否为项目添加说明文档
我们填入仓库名GitTest其余保持默认即可,点击Create repository创建仓库。
接下来我们就可以将本地仓库与线上仓库进行关联了
$ git remote add origin [email protected]:michaelliao/learngit.git
其中的origin是Git对远程仓库的默认叫法。关联成功后,我们就可以将本地的仓库同步到线上仓库了,使用git push
命令把当前分支推送到线上仓库
$ git push -u origin master
Enumerating objects: 6, done.
Counting objects: 100% (6/6), done.
Delta compression using up to 4 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (6/6), 496 bytes | 248.00 KiB/s, done.
Total 6 (delta 0), reused 0 (delta 0)
remote:
remote: Create a pull request for 'master' on GitHub by visiting:
remote: https://github.com/ZerGen/GitTest/pull/new/master
remote:
To github.com:ZerGen/GitTest.git
* [new branch] master -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.
由于线上仓库是空的,所以第一次推的时候加上了-u
参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。
从远程仓库克隆项目
一般常规来说,我们从头开发项目的步骤是先在远程仓库上新建仓库,然后将线上的仓库克隆到本地。我们用刚才新建的GitTest仓库为例(提前已经删除了之前本地的GitTest仓库)
在需要建立本地仓库的目录下鼠标右键Git Bash
使用git clone
命令进行克隆
$ git clone [email protected]:ZerGen/GitTest.git
Cloning into 'GitTest'...
Warning: Permanently added the RSA host key for IP address '192.30.253.112' to the list of known hosts.
remote: Enumerating objects: 6, done.
remote: Counting objects: 100% (6/6), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 6 (delta 0), reused 6 (delta 0), pack-reused 0
Receiving objects: 100% (6/6), done.
查看目录,我们的项目已经成功的克隆到了本地仓库中。
分支管理
我们之前的全部操作,都在一个主分支master上进行,Git还可以新建其他的分支进行操作
分支用来做什么
我的理解是,为了方便维护和多人协作开发,我们需要不同的分支来同时进行开发,如果大家都用master分支一起开发,十分不便于管理,并且maste分支一直处于修改状态,并不是能够稳定运行的代码,所以我们需要把不同的功能模块或者不同的开发人员分配不同的分支,待分支开发完成后,测试无误之后再直接合并到主分支中,这样就可以保证主分支永远是稳定可用的版本。并且十分利于后期维护。
创建分支与合并
首先我们通过git checkout
命令进行分支的创建
$ git checkout -b dev
或者
$ git branch dev
$ git checkout dev
这两段命令是等同的,checkout
命令加上-b
的参数意思是 创建分支并切换分支
可以使用git branch
命令查看当前分支
$ git branch
* dev
master
Git会输出所有的分支,当前的分支前面会加上*
这时候我们在对Git.txt进行修改,添加一行新内容:
this is a very good txt file
and this is a git test
this is a new branch line
然后我们进行提交:
$ git add Git.txt
$ git commit -m "new branch commit"
[dev 4caf816] new branch commit
1 file changed, 2 insertions(+), 1 deletion(-)
OK,dev分支的提交完成了,我们再切回到master
分支上,查看Git.txt文件内容
$ git checkout master
查看文件内容为:
this is a very good txt file
and this is a git test
因为刚才我们的提交是在dev分支上的操作,所以master分支并没有改变。
然后我们可以通过git merge
命令来将dev
的修改合并到master
分支上
$ git merge dev
Updating 977ad7a..4caf816
Fast-forward
test.txt | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
合并成功了,我们再查看下master分支下文件的内容:
this is a very good txt file
and this is a git test
this is a new branch line
合并完成后,如果需要的话,我们也可以愉快地删除dev
分支了
$ git branch -d dev
Deleted branch dev (was 4caf816).
在查看下当前分支的情况:
$ git branch
* master
可以看到,我们只剩下master分支了
分支冲突处理
然而,合并分支操作并不能每次都非常顺利,有些时候会出现一些冲突,需要我们自己处理。
我们先新建一个分支,叫pay分支
$ git checkout -b pay
然后我们在pay分支下修改Git.txt文件
this is a very good txt file
and this is a git test
this is a new branch line and this is one
然后提交
$ git add Git.txt
$ git commit -m "pay branch one"
在切回到master分支
$ git checkout master
并修改文件内容如下:
this is a very good txt file
and this is a git test
this is a new branch line and this is first
然后提交内容
$ git add Git.txt
$ git commit -m "master branch first"
此时我们合并分支就会出现冲突,如下:
$ git merge pay
Auto-merging test.txt
CONFLICT (content): Merge conflict in Git.txt
Automatic merge failed; fix conflicts and then commit the result.
从Git的输出信息可知,它告诉我们 在合并Git.txt文件时存在冲突,让我们解决冲突后再提交结果。
我们可以先输出下目前Git.txt的内容:
$ cat Git.txt
this is a very good txt file
and this is a git test
<<<<<<< HEAD
this is a new branch line and this is first
=======
this is a new branch line and this is one
>>>>>>> pay
Git用<<<<<<<,=======,>>>>>>>标记出不同分支的内容,我们将冲突部分手动修改为:
this is a very good txt file
and this is a git test
this is a new branch line and this is 1
再次提交
$ git add Git.txt
$ git commit -m "conflict fix"
[master 0ace348] conflict fix
OK 合并成功。
强制性删除分支
一般来说,项目每次增加新的功能,我们总是增加一个feature分支来进行开发,假如开发到一半了,突然不需要这个功能了,我们正常删除这个分支是没办法做到的,假设我们先创建一个feature分支
$ git checkout -b feature_list
我们在该分支下新建文件list.js然后提交该分支内容
$ git add list.js
$ git commit -m "add feature list"
然后我们切换为master分支,准备合并,可是如果突然该功能不需要了,我们需要删除该分支
$ git checkout master
$ git branch -d feature_list
error: The branch 'feature_list' is not fully merged.
If you are sure you want to delete it, run 'git branch -D feature_list'.
Git告诉我们删除失败,因为feature_list分支还没有合并,如果需要删除的话 使用-D
参数强行删除
$ git branch -D feature_list
Deleted branch feature_list (was b6b4e20).
这样就可以强行删除这个分支了。
多人协作
在实际的项目开发中,一个人开发是不可能的,一般情况是几个开发人员共同开发一个项目,那么多人协作开发是个非常重要的点
推送分支
推送分支就是把本地该分支的所有提交推送到远程仓库,推送时要制定本地分支,这样Git就会把本地的这个分支推送到远程仓库上对应的分支。例如我们推送dev
分支
$ git push origin dev
抓取分支
多人协作的时候,大家往往都在往dev
分支上推送自己的修改,假如本地并没有dev
分支,如何从远程仓库中拉取本地不存在的分支呢?
第一步:使用git fetch
拉取远程数据到本地
第二步:使用git checkout
拉取对应分支到本地
$ git fetch
From github.com:ZerGen/GitTest
* [new branch] dev -> origin/dev
$ git checkout -b dev origin/dev
Switched to a new branch 'dev'
Branch 'dev' set up to track remote branch 'dev' from 'origin'.
这样就可以拉取本地不存在的远程分支了。
这个时候小伙伴们就可以在dev
分支上进行开发,并push到远程的仓库了。
但是存在这样一种情况,例如A同学对dev
分支下的app.js
进行了修改,并push到了远程仓库中,此时你也修改了app.js
,将要push到远程仓库中,这时候我们的推送会失败,因为我们的推送和A同学推送的最新数据存在冲突。
我们可以先使用git pull
命令把最新的提交从 origin/dev
上拉取下来,然后在本地合并,解决冲突,然后再推送到远程仓库。
多人协作小结
总而言之,我们多人协作时,我们大致的流程如下:
首先从远程仓库拉取开发分支,git checkout -b branchName origin/branchName
然后本地推送到远程仓库 git push orgin branchName
如果推送失败 先git pull
最新的提交到本地
然后解决冲突,本地提交,然后push到远程仓库。
总结
本篇博客目前只是整理Git一些常用的操作,Git十分的强大,但是实际使用其实也就是常用的那几个命令。希望在工作中能够更加灵活的加以运用,提高工作效率。