一.基础命令说明
1.设置提交作者
git config user.name “qingpeng”
git config user.email “[email protected]”
上述设置表明,是谁在操作之后的git任务提交
2.创建 git仓库(git init 和 git intit –bare的区别)
不使用–bare选项时,就会生成.git目录以及其下的版本历史记录文件,这些版本历史记录文件就存放在.git目录下。
使用–bare选项时,不再生成.git目录,只生成.git目录下面的版本历史记录文件,这些版本历史记录文件也不再存放在.git目录下面,直接存放在版本库的根目录下面。
用户在远端仓库下执行git操作,当前为master分支。另一个用户想把自己在本地仓库的master分支的更新提交到远端仓库的master分支,命令如下:
git push origin master:master
因为远端仓库的用户正在master的分支上操作,而你又更新提交到这个master分支上,所以就会出错。但如果是往远程仓库中的空闲分支上提交还是可以的。比如更新到远程仓库为操作的dev分支上,命令如下:
git push origin master:dev
解决办法: 使用”git init –bare”方法创建一个所谓的裸仓库,之所以叫裸仓库是因为这个仓库只保存git历史提交的版本信息,而不允许用户在上面进行各种git操作,如果你硬要操作的话,只会得到下面的错误(”This operation must be run in a work tree”)
注:所以最好把远端仓库初始化成bare仓库。
3.分支的工作区,分支的暂存区,分支的版本库(git add , git commit)
工作区就是当前能看见,能操作的目录。
git add test.html 此时文件会被提交到暂存区。
git commit -m “update test” 此时在暂存区中的所有文件,均会被提交到当前分支的版本库中。
注:该命令提交的是暂存区所有的文件,例如:如果你先git add a然后又修改了a,此时你修改后未再次进行git add a操作,那么git commit 提交后,当前分支版本库中没有你之后修改a的内容。
注:上述三个区域均要表明在哪个分支下,因为每个分支均有此三个区域。
4.查看当前分支的状态(git status)
$ git status
(1)On branch master
(2)Changes to be committed:
(use “git reset HEAD …” to unstage)
new file: a
modified: b
(3)Changes not staged for commit:
(use “git add …” to update what will be committed)
(use “git checkout – …” to discard changes in working directory)
modified: c
(4)Untracked files:
(use “git add …” to include in what will be committed)
d
上述例子表明:(1)表明在哪个分支上。(2)表明有一个新的文件a,一个老的被修改过的文件b,两者均存放在暂存区中,需要被commit到当前分支版本库中。(3)表明被修改过的文件c在当前工作区中,还未被放到暂存区中。(4)表示文件d为未捕获到的文件,即新文件且还从来未加入到git版本控制中。
注:文件d与文件a都是新文件区别在于,文件a被git add过,表明文件a加入git版本控制了。而文件d就是一个新文件什么都为做过。
5.比较文件差异,比较版本差异(git diff test.txt)
(1)比对文件差异,分为如下三种情况:
git diff test.txt 比较暂存区与工作区该文件的差异。
git diff - - cached test.txt 比较当前版本库与暂存区的文件差异。
git diff HEAD test.txt 比较某个版本与工作区该文件的差异。(其中HEAD可以改为版本号(git log),或者命令号(git reflog))
(2)比较两个版本的差异
git diff 版本号1 版本号2。比较两个版本库中各个文件的差异。
(3)不管比较的是文件还是版本,均按照如下格式显示,统一解释说明。
- - - a/d
+++ b/d
@@ -1,2 +1,6 @@
1
-2
+3
+a
+b
+c
+d
解释如下:(注:下面解释中说的“位置”两字表示,表示可能是工作区,暂存区,版本库,甚至是其他版本)
a位置的文件内容:
1
2
b位置的d文件内容:
1
3
a
b
c
d
- - - a/d :表示a位置的d文件。(—表示一个位置,+++表示一个位置。)
+++ b/d:表示b位置的d文件。
@@ -1,2 +1,6 @@:表示两个位置的哪些行数有所不同,此处是a位置的1-2行,b位置的1-6行。
最后下面显示的内容:表示如果前面没有-,+表示两个文件一样的内容,-表示a位置文件d的内容,+表示b位置文件d的内容。
6.撤销修改(git checkout - - test.txt,git reset HEAD test.txt)
(1)撤销工作区的修改git checkout - - test.txt
意思是把test.txt文件在工作区的修改撤销,有如下两种撤销情况
一种是test.txt自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态。
一种是test.txt已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。
总之,就是让这个文件回到最近一次git commit或git add时的状态。
(2)撤销暂存区的修改:git reset HEAD test.txt
意思是把test.txt文件在暂存区的修改撤销,但是工作区的修改未被撤销,此时需用上面的git checkout - -test.txt撤销工作区修改,这样暂存区和工作区的修改就均撤销掉了。
注:git checkout branchname 是切换分支,git checkout - -test.txt 是撤销修改的作用,注意- -的作用。
git reset是回退到某个版本,同样git reset HEAD test.txt有撤销暂存区内容的作用。
7.重命名文件(git mv test.txt hehe.txt)
使用git mv test.txt hehe.txt后 查看状态如下:
On branch master
Changes to be committed:
(use “git reset HEAD …” to unstage)
renamed: c -> d
可以看出重命名文件c为d,这个操作被放到了暂存区,所以我们还需要用git commit来执行操作到当前分支版本库中。这才完成了版本库,暂存区,工作区,三个区域的文件名称重命名。
git mv test.txt hehe.txt将test.txt重命名为hehe.txt。此时不管test.txt是否被修改还未被提交,我们只是改它的名字而已,然后用git commit -m “fix file name” 讲此改名需求提交。最后版本库,暂存区,工作区,这三个区对应的文件名均被改变。
8.删除文件(git rm test.txt)
使用git rm test.txt后 查看状态如下:
On branch master
Changes to be committed:
(use “git reset HEAD …” to unstage)
deleted: a
可以看出删除文件a这个操作被放到了暂存区,所以我们还需要用git commit来执行操作到当前分支版本库中。这才完成了从版本库中删除文件。
注:删除远程文件,本地分支删除后,直接git push origin master即可删除远程分支文件
注:git rm test.txt 然后 git commit -m “delete test.txt”。如果被删除的文件有修改,只要还未最终提交到版本库,此时是不能使用命令删除。此种情况不能删除文件。如果被删除的文件没有任何的修改,在工作区和暂存区均没有修改,此时会同时删除版本库中的文件和工作区中的文件。
9.版本回退(git reset - -hard versionID,git reset - -hard commandID)
注意一:一次commit就会形成一个版本,分支树上就会形成一个节点。
注意二:commandID就是versionID,只不过为了好描述两种方法所以加以区分。
回退到上一个版本:git reset - -hard HEAD^
回退到某个版本号版本:首先用git log 查询该版本的版本号,然后使用git reset - -hard versionID。也可以使用git reflog查询命令,然后用git reset - -hard commandID。意思回到某个执行命令时候的状态。
重点内容:回退到某个版本号,首先版本号怎么来的,只有当我们git commit的时候才形成一个版本,此时才形成新的版本号。而我们回退到某个git commit的版本号意思是,那次执行git commit后形成的版本内容就是我们要回退后的内容。注意是那次git commit后形成的内容,这个“后”字很重要,注意理解,就是执行了那次版本号的git commit执行后的内容。
回退到某条命令的状态,意思和上述回退到某个版本号差不多,只不过更加细致了,可以回退到某个git commit“后”的内容,也可以回退到其他命令“后”的操作,还是注意后字的含义。
请关注下面日志git log和git reflog的讲解。
注意三:关于修改文件没有 commit而不能执行的操作,只有删除文件不能执行。而撤销修改,重命名文件,版本回退均不管文件修改后是否commit了,这三种操作均能执行。
注意四:版本回退速度非常快,因为版本按照时间顺序形成版本链表,当前版本是由HEAD指针决定,版本回退只是把head指针指向了某个版本节点而已,然后更新工作区即可。
注意五:版本回退git log - -graph,版本回退是跟着多叉树的版本节点先后顺序,而不是commit时间顺序进行版本回退的。
小结:文件增删改查(本地和远程)
本地:增加git add,删除git rm,修改(其实就是直接改文件然后,git add即可),查看直接看。最后都需要用git commit提交除了查看。
远程:增加,删除,修改都现在本地commit后,直接push即可,查看直接pull即可。
——————————————————————————————————————————————————————————————————————
二.分支
首先理解分支相关的知识包括分支建立,分支与其他分支的关系,分支合并,分支冲突等等问题时,脑海里要有整棵分支树。
注:关于分支理解必须要记住下面这张最简单的分支图,只要脑海里有整棵分支树,以及分支指针目前在哪个节点,那么分支的知识就能掌握。
对此图进行一个流程的描述如下:
这个流程的描述就能把分支最重要的一些知识串联起来,一定要仔细阅读这个流程。
父分支从C0开始,经过几次commit来到C2。此时生成了两个分支,这两个分支的文件等等所有分支信息此时和父分支完全相同。然后分支1经过一次commit来到了C4,另一个分支2经过两次commit来到C5。此时一共有三个分支master,dev1,dev2。三个分支分别有两个分支指针,各自指向当前自己的位置。此时dev1中有master的文件等分支信息,同时还有自己一次的commit信息,这次commit可能是添加一个新文件,也可能是修改父分支继承而来的老文件。dev2情况和dev1一样。然后master和dev1合并,使用命令git merge dev1,此时合并的方法默认是- -fast-forward。然后再合并dev2,此时采用- -no-ff方式,表示保留分支dev2的commit信息,即便你这里使用- -fast-forward也会变成- -no-ff的方式。最后可以采用git log - -graph查看当前分支的合并情况,以及git show-branch查看整棵分支树的情况。
- -fast-forward和- -no-ff两者区别查看下面合并内容:如果合并后有问题,可以采用git reset - -hard versionID,进行版本回退。
10.查看历史命令记录(git reflog)
bc477e5 HEAD@{0}: reset: moving to bc477e581a945d40e00e55dcc8b73821c01c33a3
17a10aa HEAD@{1}: commit: update q
bc477e5 HEAD@{2}: commit: add q
c21c6f9 HEAD@{3}: commit: asd
71c1de8 HEAD@{4}: checkout: moving from master to HEAD
解释说明:每行格式是一样的,每行中的第一列表示命令的ID号,用于版本回退到该命令状态所用。第二行表示。
注意:这个也是用于版本回退,其中也有版本号,在特别场景下,比如你先回退了几个版本,如何你想再回去,你发现使用git log找不到之前的版本号信息了,此时可以使用git reflog查看命令记录,其中有之前的commit版本信息,可以由此再回去。
11.创建分支,删除分支,切换分支(git branch name,git branch -d name,git checkout name)
(1)创建分支 (git branch name master):如果最后不写分支的名称,那么默认是从当前分支创建分支,如果写了分支名称,比如master,那么就是从master创建分支。甚至于还可以从远程某分支创建本地的分支比如git branch name origin/master。
(1)删除分支(git branch -d name):强制删除是git branch -D name。
(2)切换分支(git checkout name):如果当前分支有修改,并且还未提交,那么你是不能切换分支的。如果又想切换分支,又想先不提交当前分支的修改,那么可以先在当前分支使用命令git stash,此时会隐藏掉当前的工作区和暂存区的修改内容。然后你在切换分支,如果想返回当前分支的状态,使用命令git stash lsit。
12.分支什么怎么分出来的?,分出来的分支有哪些文件呢?,多个分支情况下整棵树是怎么样的?
(1)新分支的父分支就是你使用git branch name创建新分支时,当前所在的分支。
(2)新分支继承了所有父分支的版本信息(commit信息,git log - -graph可查),还有继承了父分支的所有文件内容。
(3)每多建立一个分支,就是在这整颗多叉树上的某个起点处添加了一个指针,这个指针能走到哪些节点,就要看这个分支的git log - -graph的版本号有哪些,它没有的就不能去。说白了它继承的父节点的所有版本信息它都能前进后退,它自己新开辟的commit版本节点,它也能前进后退。这个新的分支指针能否去其他超出父节点的兄弟节点上,首先他们得合并,而且还要看合并的方式,采用保留所有commit的方式,那么就能到无交集的兄弟分支上去。
(4)使用git log - -graph查询当前分支的情况。使用git show-branch查询整棵分支多叉树的情况
13.显示整棵分支多叉树的情况(git show-branch)
显示所有分支的构成,也就是显示整棵分支多叉树,用于查看各个分支目前的分支指针指向的节点位置定位
解释说明:整个显示结果被中间的横线分割成上下两个部分,上面部分列出所有的分支以及各自最后一次commit信息,每一行就是一个分支,前面的表示当前分支,!表示其他分支,用不同颜色代表不同分支。下面部分就是整棵分支多叉树的情况,第一列两个红色+号,对应上部分的红色!的dev1分支,该红色!分支在下部分有两个红色+号commit版本,也就是两个节点。可以看出它是从master分出来的,然后自己再commit dev1 add b。第二列对应上部分dev2分支,它有三个绿 号,表示有该dev2有三个节点,第一个节点是master,这个节点也是dev2的父节点,然后它还有自己的两个节点,dev2 add c和dev2 add d。第三列也是这个理解。
14.查看日志(git log,get reflog)
(1)git log(git log -2 显示最近两个版本)
commit bc477e581a945d40e00e55dcc8b73821c01c33a3
Author: qingpeng2016 <[email protected]>
Date: Thu Aug 18 10:46:15 2016 +0800
add q
commit c21c6f99c55df475040a78d6fe776074be798c22
Author: qingpeng2016 <[email protected]>
Date: Thu Aug 18 10:45:20 2016 +0800
rm q
解释说明:日志中第一行表示git commit后形成新的版本的版本号,第二行表示此次版本的作者,第三行表示此次版本的上传时间,第四行是由如下命令形成的git commit -m “add q”,该行中显示内容就是-m中的版本说明信息,即add q。
注:每次git commit都会形成一个新的版本号,版本回退,也就是回到某次git commit“后”的版本内容状态,注意后的理解。
(2)git log - -oneline(压缩日志信息显示,便于在很复杂的git中进行查看)
270312d Merge branch ‘dev2’
c470530 master update a
47a6a30 dev add b
996323b dev update a
90970a1 add a
(3)git log - -graph(查看当前分支的合并情况)
* 270312d Merge branch ‘dev2’
|\
| * 47a6a30 dev add b
| * 996323b dev update a
* | c470530 master update a
|/
* 90970a1 add a
解释说明:上面显示的样子是加上了oneline参数的。git log - -onelie - -praph。一个表示一个版本信息,显示中的两列就表示两个分支在合并。这棵二叉树你想去哪就去哪,通过如下命令:git reset –hard 版本号。从下往上是版本树的走向,一开始仅仅是add a,然后在此生成一个子分支,这个子分支做了两个操作dev update a和dev add b然后就形成了两个 也就是两个版本。然后主分支自己走自己的,主分支master update a形成自己分支的一个版本与子分支已经分开了,然后这两分支再合并,最后采用 - no-ff方式合并的,所以保留了子分支的commit信息,也就是保留了子分支的版本信息。- -no-ff方式会把子分支的所有改变内容形成一个次commit提交到主分支中,也就是最后形成的最上面那个版本信息 merge branch ‘dev2’。图中的字符串就是版本号的前缀。
注意一:上述(1)(2)(3)中的命令可以联合使用比如:git - -oneline - -graph -2,意思是显示2次版本日志,并且每次日志内容显示在一行,然后采用图的形式进行显示,最后显示结果如下:
* 270312d Merge branch ‘dev2’
|\
| * 47a6a30 dev add b
注意二:以后查看版本信息都用git log –graph不要用git log。因为用git log的时候 你没有办法掌控该分支的这棵树。
git log的结果:
解释说明:git log是按照commit的提交时间进行从下往上排序的,如果合并也是重新把所有的分支的commit时间(也就是版本时间)进排序的。git log - -graph是按照合并的顺序对commit进行排序的。仔细看两张图的commit版本时间。就能看出上述解释的区别,那么这个区别会有带来什么后果,假设当前分支指针合并另一分支后,分支指针现在只想最上面这个版本节点处。此时使用git reset - -hard versionID进行版本回退,如果查看git log的结果图1,往下回退一个版本,那么看图1应该还有tt e b a这些文件内容,但是其实只有tt了,因为图2中我们发现版本节点tt是先于e b的,所以回退版本后就没有e b文件了。
总结:版本回退git log - -graph,版本回退是跟着多叉树的版本节点先后顺序,而不是commit时间顺序进行版本回退的。
15.分支合并(git merge fast-forward name,git merge - -no-ff name)
图1:
(1)git merge fast-forward name(默认方式,但是不建议使用,看不出合并前两分支的commit轨迹)
图1是fast-forward合并方式,蓝色是master分支,红色是dev分支,fast-forward方式合并后,master指针仅仅是向前移动,和dev分支重合,仅仅是指针移动,并没有commit提交而产生新的版本。
这样合并后git - -graph只有一条路,看不出两条分支合并前的commit轨迹。
(2)git merge - -no-ff name(建议采用的方式,保留了合并前两分支的commit轨迹)
图2是- -no-ff合并方式,黄色分支是当前分支,红色是被合并分支。可以看出,红色分支和黄色分支合并的时候,黄色分支指针不是直接移动到红色分支最好一个节点的位置,而是新建了最下那个黄色节点,然后把红色分支上的所有commit轨迹全部保留,然后通过一次commit提交给到当前的黄色分支中,保留红色分支全部commit信息的这次commit操作,是- -no-ff方式自动执行的。正因为当前黄色分支有了这次保留被合并红色分支的全部commit信息的自动commit操作,所以当前黄色分支就会形成一个版本,也就是形成了一个节点。
这样合并后git - -graph只有一条路,能看出两条分支合并前的commit轨迹。
(3)合并带来的结果
git merge fast-forward:合并两分支所有的文件内容,合并两个分支的commit信息,git show-branch能看出两分支合并的commit信息,但是只有条路,所以看不出来两分支合并前的分支轨迹。
git merge - -no-ff:合并两分支所有的文件内容,合并两个分支的commit信息,并且git show-branch能看出两分支合并的commit信息,并且还能看出两分支合并前的分支轨迹。
下面举例说清楚解释,说明叫做保留了commit信息,但是看出两分支合并前的轨迹。
举例说明:(git merge fast-forward)
* commit 974ecf4d19d0cf1bb595f5fe6428fd08ca2fcbd2
| Author: qingpeng2016 <[email protected]>
| Date: Mon Aug 22 19:07:11 2016 +0800
|
| dev add b
|
* commit 2ecbe3b2378462e40ff44c10974fdb4b1fdb8516
Author: qingpeng2016 <[email protected]>
Date: Mon Aug 22 19:06:46 2016 +0800
master add a
举例说明:(git merge - -no-ff)
* commit 6b5bf011c754c37e06195d5b28a33f2c1456c88e
|\ Merge: 2ecbe3b 974ecf4
| | Author: qingpeng2016 <[email protected]>
| | Date: Mon Aug 22 19:09:33 2016 +0800
| |
| | Merge branch ‘dev’
| |
| * commit 974ecf4d19d0cf1bb595f5fe6428fd08ca2fcbd2
|/ Author: qingpeng2016 <[email protected]>
| Date: Mon Aug 22 19:07:11 2016 +0800
|
| dev add b
|
* commit 2ecbe3b2378462e40ff44c10974fdb4b1fdb8516
Author: qingpeng2016 <[email protected]>
Date: Mon Aug 22 19:06:46 2016 +0800
master add a
(4)冲突解决
产生冲突的原因:如果两个分支是在一同共同节点的两条树枝上,那么当都修改了同一个文件时就会产生冲突。比如最简单的情况就是父分支与其他分支合并后,此时父分支指针指向了其他分支上了,离开了共同父分支节点,此时子分支与之合并如果刚好又修改了同一个文件就会产生冲突。
解决办法:打开冲突文件,修改掉冲突部分,重新提交上传,然后再重新合并即可。也就是说冲突就是让开发者知道有冲突了,最后解决还是人自己来,手动保留你们协商的结果,然后上传,不是说冲突解决有自动的方式。仅仅是让你知道是哪个地方冲突,最后到底保留什么还是你自己决定,git不会说自动帮你解决冲突,它做不到的。
比如有如下冲突:
welcom to git
<<<<<<< master
this is master
= = = = = = =
this is dev1
.>>>>>>>>> dev1
解释说明:
<<<<<<< 与 = = = = =是master版本的,也就是你当前分支的冲突内容。
= = = = = 与>>>>>>>是dev1版本的,也就是被合并分支的冲突内容。
然后你自己删除不保留的,留下你需要的,然后重新提交到该分支,最后再次进行合并。
(5)撤销合并
合并之后可以用git reset –hard 版本号。回退到合并之前的版本节点,以达到消除合并的效果,其实合并分支,以及回退版本可以想成是一个指针在一棵多叉树上的指向节点的切换过程。
小结:分支增删改查(本地和远程)
本地:增加git branch dev,删除git branch -d dev,修改(其实就是在该分支上commit新的节点版本),查看git log –graph查看当前分支情况,或者git show-branch查看整棵多叉树情况。
远程:增加git push origin dev:dev,删除git push origin :dev,修改(修改本地分支,然后git push即可),git branch -r或者git show-branch -r。
——————————————————————————————————————————————————————————————————————
三.远程仓库
注:远程仓库和本地仓库之间最常用的就是git push 和 git pull。其实对这个的理解就是分支合并,git push就是把本地的某分支合并到远程某分支,git pull就是把远程某分支合并都本地某分支。所以git push和git pull就是分支合并,也会有冲突,也需要解决。
建立与远程仓库的连接
1.git clone url
2.git init 和 git remote add origin url
从远程仓库拉取分支
3.git fetch origin master:tmp ,git diff tmp , git merge tmp
4.git pull origin master(相当于3中的两条语句)拉取内容到当前分支
查看远程仓库的分支情况
5.git branch -r git branch -a git show-branch -r
上传分支到远程仓库
6.git push origin master:master(//提交本地master分支(第一个master) 到远程的master分支(第二个master))
删除远程文件
7.git rm filename,git commit -m “”,git push origin master:master
删除远程分支
8.git push –delete origin dev,git push origin :dev
push(总结一句话,和前面讲的分支合并完全一样的思想,分支中讲的二叉树合并在这里也是一样的。) 其实默认是fast-forward的方式。所以只有当远程分支未被别人push过,才可以,如果被别人push了,那么此时远程分支的指针就不在你当前分支的初始父分支节点上了,此时push会报错。所以最保险的方式先pull或者fetch下来看看,然后再push上去,这是最保险的方式。
——————————————————————————————————————————————————————————————————————
四.git flow流程
http://www.open-open.com/lib/view/open1437744406490.html
http://blog.jobbole.com/76867/
找回删除分支,文件
git branch -D cool_branch
git fsck –lost-found
git show 2e43cd56ee4fb08664cd843cd32836b54fbf594a
git merge 2e43cd56ee4fb08664cd843cd32836b54fbf594a
需要补充!!!!!!!!!!!!!!!!!!!!!!!!!!!
1.忽略的文件怎么添加