什么是 Git
Git类似于svn的版本控制工具。
Git出现的原因
由于Linux内核开源项目有着为数众广的参与者。绝大多数的Linux核维护工作都花在了提交补丁和保存归档的繁琐事务上,为了满足这个功能的需求就应运而生了Git。
Git相关资料
Pro git 这本书是目前git的官方权威图书,里面详解了git历史,用途以及作用。
下面就介绍下初学git者,应该怎么了解git
如何搭建git环境
环境搭建这里不再赘述网络上有很多教程,官网中也有相关的教程。如何安装git git环境搭建好后,需要客户端生成一个公钥文件,然后增加公钥文件到服务器。 这样客户端就可以访问服务器的仓库了。如果不提供公钥文件,那么客户端就要输入服务器的密码了。 什么是公钥和私钥哪?下面来介绍下。
什么是公钥和私钥
简单的说就是,用公钥加密的数据,只能用私钥解密,反之用私钥加密的数据,只能用公钥解密。 至于公钥和私钥是需要一定的算法规则才能生成, 这里我举一个实际的例子。比如小明写信给朋友小红, 但是为了在信邮递过程中,不被别人看到。他可以这样做,让小红利用一定的规则生成2把钥匙,一把是公钥,一把是私钥。首先小红可以给 小明一把公钥,然后写完信后,小明用被给的公钥加密自己的信,这样给了小红后,小红就可以用自己的私钥进行解密。这个过程就相当于服务器给客户端传输数据。至于刚才讲的利用一定的规则,就是非对称加密的规则,需要用到数论中的知识,想要详细了解可以学习下RSA加密演算法。
git公钥和私钥如何生成
Mac和Linux用户直接用下面的命令生成:
$ ssh-keygen
然后进入的.ssh目录下,.pub文件就是公钥文件
$ cd ~/.ssh
$ ls
然后把公钥文件加入到服务器上的authorized_keys文件中,命令如下:
$ cat xx.pub >> authorized_keys
mac下推荐一个开源的图形化git工具sourcetree windows用户需要安装git的客户端生成公钥下面有2个教程: 1 安装git命令行工具 2 安装git图形界面工具 ps:以上2中方法,都要生成公钥文件,加入到服务器,客户端才能访问服务器。 git的基本搭建方法介绍完之后,重点来看下git的命令如何使用的
git命令的使用
下面就介绍几个最常用的命令,以及遇到的问题
git clone git@xxxx:xxx.git
这条命令是从服务器上把代码仓库拉下来的,然后clone到本地的文件夹下面,会有一个.git的文件夹,这个文件夹是隐藏的,里面放置的都是版本库的控制信息。这里先提前说下使用git一定要理解2个仓库的概念,一个是本地的一个是远程的。下面几条命令我们就会介绍这两个概念。这里先说下使用这条命令经常遇到的问题
- 当使用这条命令后出现如下错误:
ssh: connect to host xxxx port 22: Connection refused fatal: Could not read from remote repository. 这说明你clone的服务器无法访问 R access for xxxx DENIED (Or there may be no repository at the given path. Did you spell it correctly?) fatal: Could not read from remote repository. 代表你没有权限访问服务器,或者服务上不存在这个仓库
- 当输入命令后,需要你输入密码,这说明上一步说的git公钥文件没有加入到服务器上,或者客户端的私钥文件git无法访问
git pull 和 push命令
- pull操作 (语法git pull 服务器 本地分支:远程分支)
git pull orgin develop:develop
origin这个字段表明的就是git服务器的地址,可以在git的config中进行配置,该文件一般在用户目录下.gitconfig。这里是具体的配置方法:git配置。这里的本地分支和远程分支,就对应着本地仓库和远程仓库。其实pull操作就相当于把远程仓库的所有数据取下来,然后同步到本地。
pull操作相当于2步骤,首先会获取服务器的所有索引,然后跟本地的索引合并。相当于fetch和merge操作,之后会了解fetch和merge命令。
pull命令常见的错误! [rejected] master -> master (non-fast-forward)
出现这个错误一般是因为有文件已经提交到本地仓库了,所以本地仓库和远程的无法同步了。这样就需要先通过push操作,把本地仓库的东西提交给远程,这样才可以同步。这里解释下什么叫fast-forward,假如我们从A分支又开了一个B分支,然后在B分支上修改了东西,但是A分支没做任何修改,假如此时A分支要合并B分支的内容,因为B的分支的Parent commit就是A的HEAD,所以这两个分支唯一的差别就是B之后的修改,所以不会有任何的冲突,只要A分支把HEAD移动到B分支的HEAD上就可以了,这就叫fast-forward。很显然non-fast-forward就说明了远端的分支的parent commit和你本地的HEAD不相同所以很可能是本地的提交没有push到远端造成的。 - push操作 (语法git push 服务器 本地分支:远程分支)
git push orgin develop:develop
这个命令跟pull有的相反的意思,是把本地仓库所有改变的内容,放置到远程仓库中,相当于把本地仓库的内容同步到远程仓库了。
push命令常见的错误! [rejected] master -> master (non-fast-forward)
其实上面已经解释过这个错误的产生的原因了。这里push正好和pull的意思相反。是本地的Parent commit和远端的HEAD不相同,也就是远端可能产生了新的提交,所以需要你pull远端的提交,合并好后,在push改变。这里要注意的是pull的时候,如果出现冲突,需要使用git mergetool来合并冲突,我们这篇文章的最后会讲解,如何merge冲突的文件 - 根远程仓库操作相关的命令
检出仓库:$ git clone git://github.com/jquery/jquery.git
查看远程仓库:$ git remote -v
添加远程仓库:$ git remote add [name] [url]
删除远程仓库:$ git remote rm [name]
修改远程仓库:$ git remote set-url –push[name][newUrl]
拉取远程仓库:$ git pull [remoteName] [localBranchName]
推送远程仓库:$ git push [remoteName] [localBranchName]
git用来提交本地仓库的命令
git status 可以用来查看文件的状态,git版本下的文件有一种文件叫Untracked files,是表示该文件有过用户操作,做了修改,但是没有加入到需要提交的列表中。说到这里就要提到git add命令了,这个命令就是用来把Untracked files变成tracked files,然后就可以使用git commit提交到本地仓库了。这里你就了解了如果需要提交一个文件到本地仓库需要做的操作有那些了。 另外还要说下git版本控制下,可以使用忽略文件,这个是用来把文件加入到忽略列表中的,被加入的文件git版本控制器就不会对这个文件做任何的跟踪处理,也就是无论这个文件怎么变化,都不会有上面提到的这些状态。 例如:忽略一些文件、文件夹不提交 在仓库根目录下创建名称为“.gitignore”的文件,写入不需要的文件夹名或文件,每个元素占一行即可。
target
bin
*.db
git 分支和标签的操作
下面我引用了一篇博客,这里面已经对branch和tag的常见操作,和遇到的问题做了详细的描述。博客原文
1 分支(branch)操作相关命令 查看本地分支:$ git branch
查看远程分支:$ git branch -r
创建本地分支:$ git branch [name] —-注意新分支创建后不会自动切换为当前分支
切换分支:$ git checkout [name]
创建新分支并立即切换到新分支:$ git checkout -b [name]
删除分支:$ git branch -d [name] —- -d选项只能删除已经参与了合并的分支,对于未有合并的分 支是无法删除的。如果想强制删除一个分支,可以使用-D选项
合并分支:$ git merge [name] —-将名称为[name]的分支与当前分支合并
创建远程分支(本地分支push到远程):$ git push origin [name]
删除远程分支:$ git push origin :heads/[name]
我从master分支创建了一个issue5560分支,做了一些修改后,使用git push origin master提交,但是显示的结果却是’Everything up-to-date’,发生问题的原因是git push origin master 在没有track远程分支的本地分支中默认提交的master分支,因为master分支默认指向了origin master 分支,这里要使用git push origin issue5560:master 就可以把issue5560推送到远程的master分支了。
如果想把本地的某个分支test提交到远程仓库,并作为远程仓库的master分支,或者作为另外一个名叫test的分支,那么可以这么做。
$ git push origin test:master // 提交本地test分支作为远程的master分支//好像只写这一句,远程的github就会自动创建一个test分支
$ git push origin test:test // 提交本地test分支作为远程的test分支 如果想删除远程的分支呢?类似于上面,如果:左边的分支为空,那么将删除:右边的远程的分支。
$ git push origin :test // 刚提交到远程的test将被删除,但是本地还会保存的,不用担心
2 版本(tag)操作相关命令 查看版本:$ git tag
创建版本:$ git tag [name]
删除版本:$ git tag -d [name]
查看远程版本:$ git tag -r
创建远程版本(本地版本push到远程):$ git push origin [name]
删除远程版本:$ git push origin :refs/tags/[name]
git merge 操作
这个是用来合并代码的操作。这里我需要说一下,如果该命令执行完,然后提示有冲突文件无法解决时,这就需要亲自来合并代码了。git mergetool就可以用来启动合并工具来完成这个工作。这个命令可以在git的config文件中进行配置。下面是贴出来我的配置:
[user]
name = animeng
email = [email protected]
[core]
excludesfile = /Users/animeng/.gitignore_global
editor = /usr/bin/vim
[merge]
tool = extMerge
[mergetool "extMerge"]
cmd = extMerge \"$BASE\" \"$LOCAL\" \"$REMOTE\" \"$MERGED\"
trustExitCode = false
[diff]
external = extDiff
[difftool "sourcetree"]
cmd = opendiff \"$LOCAL\" \"$REMOTE\"
path =
[mergetool "sourcetree"]
cmd = /Applications/SourceTree.app/Contents/Resources/opendiff-w.sh \"$LOCAL\" \"$ REMOTE\" -ancestor \"$BASE\" -merge \"$MERGED\"
trustExitCode = true
这里我说下合并的这条命令,我用extmerge这个工具作为例子 extMerge "$BASE" "$LOCAL" "$REMOTE" "$MERGED"。其中base就相当于文件的parent commit也就是说在修改之前最初相同的那个文件。既然是冲突肯定是远程有别人修改的内容被提交了,本地没有更新,那么LOCAL是代表本地修改的文件,REMOTE就是远程的文件,而MERGED就是代表要合并后的文件了。那么一旦出现冲突如何合并哪?首先我们要了解下出现冲突后,如果git不能解决,那么这个MERGED的文件长什么样子那?如下:
1 This is git merge file
2 <<<<<<< HEAD
3 =======
4 There is a confict content
5 need confict
6 >>>>>>> 3b0f0b65c7ae2eec59467faea13acdf38cbdbbd4
7 The conflict content is coming
8 hello conflict
9 Tell users to how to use git
我们来看冲突的文件的BASE文件
1 This is git merge file
2 There is a confict content
3 The conflict content is coming
4 Tell users to how to use git
再来看下远程的文件
1 This is git merge file
2 There is a confict content
3 need confict
4 The conflict content is coming
5 Tell users to how to use git
最后是本地的文件
1 This is git merge file
2 The conflict content is coming
3 hello conflict
4 Tell users to how to use git
可以看出来«««<HEAD表明冲突开始的位置,»»»> 3b0f0b65c7ae2eec59467faea13acdf38cbdbbd4表示冲突结束的位置,用户就需要把这些冲突合并了,然后移除这些冲突的符号后,就表明合并完毕,然后提交就可以了。再push到服务器上,就解决了冲突了。
git reset 和 revert的区别
- git revert是用一次新的commit来回滚之前的commit,git reset是直接删除指定的commit。
- 在回滚这一操作上看,效果差不多。但是在日后继续merge以前的老版本时有区别。因为git revert是用一次逆向的commit“中和”之前的提交,因此日后合并老的branch时,导致这部分改变不会再次出现,但是git reset是之间把某些commit在某个branch上删除,因而和老的branch再次merge时,这些被回滚的commit应该还会被引入。
- git reset 是把HEAD向后移动了一下,而git revert是HEAD继续前进,只是新的commit的内容和要revert的内容正好相反,能够抵消要被revert的内容。
这里我需要说明下,在reset之后,只是HEAD改变了,但是文件的内容还是没有改变,需要使用checkout把文件内容也恢复,这样提交就不会有冲突了。
最后有一个练习git命令的一个很好的网站,有兴趣可以练习下。git 命令学习网站