git
工做区(Working Directory)github
就是你在电脑里能看到的目录,git init所在的目录。缓存
版本库(Repository)安全
工做区有一个隐藏目录.git,这个不算工做区,而是Git的版本库。Git的版本库里存了不少东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为咱们自动建立的第一个分支master,以及指向master的一个指针叫HEAD。
服务器
第一步是用git add把文件添加进去,实际上就是把文件修改添加到暂存区;第二步是用git commit提交更改,实际上就是把暂存区的全部内容提交到当前分支。由于咱们建立Git版本库时,Git自动为咱们建立了惟一一个master分支,因此,如今,git commit就是往master分支上提交更改。你能够简单理解为,须要提交的文件修改统统放到暂存区,而后,一次性提交暂存区的全部修改。app
因此,git add命令实际上就是把要提交的全部修改放到暂存区(Stage),而后,执行git commit就能够一次性把暂存区的全部修改提交到分支。ssh
什么是版本库呢?版本库又名仓库,英文名repository,你能够简单理解成一个目录,这个目录里面的全部文件均可以被Git管理起来,每一个文件的修改、删除,Git都能跟踪,以便任什么时候刻均可以追踪历史,或者在未来某个时刻能够“还原”。分布式
选择一个合适的地方,建立一个空目录。post
bangdeMacBook-Pro:~ bang$ mkdir gitlocal bangdeMacBook-Pro:~ bang$ cd gitlocal/ bangdeMacBook-Pro:gitlocal bang$ pwd /Users/bang/gitlocal bangdeMacBook-Pro:gitlocal bang$
注意:若是你使用Windows系统,为了不遇到各类莫名其妙的问题,请确保目录名(包括父目录)不包含中文。学习
经过git init命令把这个目录变成Git能够管理的仓库。
bangdeMacBook-Pro:gitlocal bang$ git init Initialized empty Git repository in /Users/bang/gitlocal/.git/ bangdeMacBook-Pro:gitlocal bang$ ls -a . .. .git bangdeMacBook-Pro:gitlocal bang$
瞬间Git就把仓库建好了,并且告诉你是一个空的仓库(empty Git repository),.git的目录是Git来跟踪管理版本库的,没事千万不要手动修改这个目录里面的文件,否则改乱了,就把Git仓库给破坏了。也不必定必须在空目录下建立Git仓库,选择一个已经有东西的目录也是能够的。不过,不建议你使用本身正在开发的公司项目来学习Git,不然形成的一切后果概不负责。
首先这里再明确一下,全部的版本控制系统,其实只能跟踪文本文件的改动,好比TXT文件,网页,全部的程序代码等等,Git也不例外。版本控制系统能够告诉你每次的改动,好比在第5行加了一个单词“Linux”,在第8行删了一个单词“Windows”。而图片、视频这些二进制文件,虽然也能由版本控制系统管理,但无法跟踪文件的变化,只能把二进制文件每次改动串起来,也就是只知道图片从100KB改为了120KB,但到底改了啥,版本控制系统不知道,也无法知道。不幸的是,Microsoft的Word格式是二进制格式,所以,版本控制系统是无法跟踪Word文件的改动的,若是要真正使用版本控制系统,就要以纯文本方式编写文件。由于文本是有编码的,好比中文有经常使用的GBK编码,日文有Shift_JIS编码,若是没有历史遗留问题,强烈建议使用标准的UTF-8编码,全部语言使用同一种编码,既没有冲突,又被全部平台所支持。
咱们建立一个文件。
文件必定要放到learngit目录下(子目录也行),由于这是一个Git仓库,放到其余地方Git再厉害也找不到这个文件。
bangdeMacBook-Pro:gitlocal bang$ vi text1.txt bangdeMacBook-Pro:gitlocal bang$ ls text1.txt
用命令git add告诉Git,把文件添加到仓库
bangdeMacBook-Pro:gitlocal bang$ git add text1.txt
git add * 能够把全部文件添加到本地仓库。
用命令git commit告诉Git,把文件提交到仓库
bangdeMacBook-Pro:gitlocal bang$ git commit [master (root-commit) ed7560b] text1建立 1 file changed, 1 insertion(+) create mode 100644 text1.txt
git commit * 提交全部文件到本地仓库。
git commit -a -m “全部文件提交"
简单解释一下git commit命令,-m后面输入的是本次提交的说明,能够输入任意内容,固然最好是有意义的,这样你就能从历史记录里方便地找到改动记录。git commit命令执行成功后会告诉你,1个文件被改动(咱们新添加的text1.txt文件),插入了1行内容。
查看仓库状态。
git status查看仓库状态
bangdeMacBook-Pro:gitlocal bang$ 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: text1.txt no changes added to commit (use "git add" and/or "git commit -a")
仓库无任何改动状态:
bangdeMacBook-Pro:gitlocal bang$ git status On branch master nothing to commit, working tree clean
git diff 查看具体修改
bangdeMacBook-Pro:gitlocal bang$ git diff diff --git a/text1.txt b/text1.txt index 368785c..3760d94 100644 --- a/text1.txt +++ b/text1.txt @@ -1 +1,2 @@ test1_1 +test1_2
git diff head -- 文件名 查看工做区和版本库里面最新版本的区别
bangdeMacBook-Pro:gitlocal bang$ git diff head -- text4.txt diff --git a/text4.txt b/text4.txt index 35f7725..f2383f8 100644 --- a/text4.txt +++ b/text4.txt @@ -1 +1,2 @@ text4_1 +text4_2
查看提交的历史记录
bangdeMacBook-Pro:gitlocal bang$ git log commit f0c55f361fdd3d61f2a7a1f3ca40375f470c78ff (HEAD -> master) Author: wangzhenbang <wangzhenbang@100tal.com> Date: Wed Jan 3 11:30:58 2018 +0800 text2_2 commit 0996e4e77c5002cf45e96f1d99841acba24cdf6f Author: wangzhenbang <wangzhenbang@100tal.com> Date: Wed Jan 3 11:28:04 2018 +0800 text1_2 commit 66ce043a24be29d5093515282c4e850aaf162022 Author: wangzhenbang <wangzhenbang@100tal.com> Date: Wed Jan 3 11:21:59 2018 +0800 commit all text commit ed7560bddcbd275cdb570fc63b9e086ba1b7200b Author: wangzhenbang <wangzhenbang@100tal.com> Date: Wed Jan 3 11:13:27 2018 +0800 text1建立
或者
bangdeMacBook-Pro:gitlocal bang$ git log --pretty=oneline f0c55f361fdd3d61f2a7a1f3ca40375f470c78ff (HEAD -> master) text2_2 0996e4e77c5002cf45e96f1d99841acba24cdf6f text1_2 66ce043a24be29d5093515282c4e850aaf162022 commit all text ed7560bddcbd275cdb570fc63b9e086ba1b7200b text1建立
须要友情提示的是f0c55f361fdd3d61f2a7a1f3ca40375f470c78ff是commit id(版本号),和SVN不同,Git的commit id不是1,2,3……递增的数字,而是一个SHA1计算出来的一个很是大的数字,用十六进制表示,并且你看到的commit id和个人确定不同,以你本身的为准。为何commit id须要用这么一大串数字表示呢?由于Git是分布式的版本控制系统,后面咱们还要研究多人在同一个版本库里工做,若是你们都用1,2,3……做为版本号,那确定就冲突了。
显示最后一次的提交
git log -1
版本回退
在Git中,用HEAD表示当前版本,也就是最新的提交f0c55f361fdd3d61f2a7a1f3ca40375f470c78ff(注意个人提交ID和你的确定不同),上一个版本就是HEAD^
,上上一个版本就是HEAD^^
,固然往上100个版本写100个^
比较容易数不过来,因此写成HEAD~100。咱们使用git reset进行版本回退。
bangdeMacBook-Pro:gitlocal bang$ git log --pretty=oneline f0c55f361fdd3d61f2a7a1f3ca40375f470c78ff (HEAD -> master) text2_2 0996e4e77c5002cf45e96f1d99841acba24cdf6f text1_2 66ce043a24be29d5093515282c4e850aaf162022 commit all text ed7560bddcbd275cdb570fc63b9e086ba1b7200b text1建立 bangdeMacBook-Pro:gitlocal bang$ git reset --hard head^ HEAD is now at 0996e4e text1_2 bangdeMacBook-Pro:gitlocal bang$ git log --pretty=oneline 0996e4e77c5002cf45e96f1d99841acba24cdf6f (HEAD -> master) text1_2 66ce043a24be29d5093515282c4e850aaf162022 commit all text ed7560bddcbd275cdb570fc63b9e086ba1b7200b text1建立
从以前版本恢复到最新版本,注意须要记住当前版本的commit id,版本号不必写全,前几位就能够了。
bangdeMacBook-Pro:gitlocal bang$ git reset --hard f0c55f HEAD is now at f0c55f3 text2_2 bangdeMacBook-Pro:gitlocal bang$ git log --pretty=oneline f0c55f361fdd3d61f2a7a1f3ca40375f470c78ff (HEAD -> master) text2_2 0996e4e77c5002cf45e96f1d99841acba24cdf6f text1_2 66ce043a24be29d5093515282c4e850aaf162022 commit all text ed7560bddcbd275cdb570fc63b9e086ba1b7200b text1建立
若是你忘记了commit id,也是能够恢复的。git reflog 能够查看以前的操做命令,经过命令能够查找到当前版本的commit id
bangdeMacBook-Pro:gitlocal bang$ git reflog f0c55f3 (HEAD -> master) HEAD@{0}: reset: moving to f0c55f 0996e4e HEAD@{1}: reset: moving to head^ f0c55f3 (HEAD -> master) HEAD@{2}: reset: moving to head f0c55f3 (HEAD -> master) HEAD@{3}: commit: text2_2 0996e4e HEAD@{4}: commit: text1_2 66ce043 HEAD@{5}: commit: commit all text ed7560b HEAD@{6}: commit (initial): text1建立
丢弃工做区的修改
git checkout -- file能够丢弃工做区的修改
bangdeMacBook-Pro:gitlocal bang$ git status On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: text4.txt 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: text1.txt bangdeMacBook-Pro:gitlocal bang$ git checkout -- text1.txt bangdeMacBook-Pro:gitlocal bang$ git status On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: text4.txt bangdeMacBook-Pro:gitlocal bang$ bangdeMacBook-Pro:gitlocal bang$ git checkout -- text4.txt bangdeMacBook-Pro:gitlocal bang$ git status On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: text4.txt
命令git checkout -- text1.txt意思就是,把text1.txt文件在工做区的修改所有撤销,这里有两种状况:一种是text1.txt自修改后尚未被放到暂存区,如今,撤销修改就回到和版本库如出一辙的状态;一种是readme.txt已经添加到暂存区后,又做了修改,如今,撤销修改就回到添加到暂存区后的状态。总之,就是让这个文件回到最近一次git commit或git add时的状态。git checkout -- file命令中的--很重要,没有--,就变成了“切换到另外一个分支”的命令。
若是想把上面已经存入暂存区的文件删除可使用git reset
bangdeMacBook-Pro:gitlocal bang$ git status On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: text4.txt bangdeMacBook-Pro:gitlocal bang$ git reset Head -- text4.txt Unstaged changes after reset: M text4.txt bangdeMacBook-Pro:gitlocal bang$ 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: text4.txt no changes added to commit (use "git add" and/or "git commit -a") bangdeMacBook-Pro:gitlocal bang$ git checkout -- text4.txt bangdeMacBook-Pro:gitlocal bang$ git status On branch master nothing to commit, working tree clean bangdeMacBook-Pro:gitlocal bang$
删除文件git rm
注意删除的文件直接git add也能够
bangdeMacBook-Pro:gitlocal bang$ rm text3.txt bangdeMacBook-Pro:gitlocal bang$ git rm text3.txt rm 'text3.txt' bangdeMacBook-Pro:gitlocal bang$ git status On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) deleted: text3.txt
能够本身搭建一台运行Git的服务器,不过现阶段,为了学Git先搭个服务器绝对是小题大做。好在这个世界上有个叫GitHub的神奇的网站,从名字就能够看出,这个网站就是提供Git仓库托管服务的,因此,只要注册一个GitHub帐号,就能够免费得到Git远程仓库。
因为你的本地Git仓库和GitHub仓库之间的传输是经过SSH加密的,因此,须要一点设置:
建立SSH Key。在用户主目录下,看看有没有.ssh目录,若是有,再看看这个目录下有没有id_rsa和id_rsa.pub这两个文件,若是已经有了,可直接跳到下一步。若是没有,建立SSH Key:
bangdeMacBook-Pro:.ssh bang$ ssh-keygen -t rsa -C "youremail@qq.com"
你须要把邮件地址换成你本身的邮件地址,而后一路回车,使用默认值便可,因为这个Key也不是用于军事目的,因此也无需设置密码。若是一切顺利的话,能够在用户主目录里找到.ssh目录,里面有id_rsa和id_rsa.pub两个文件,这两个就是SSH Key的秘钥对,id_rsa是私钥,不能泄露出去,id_rsa.pub是公钥,能够放心地告诉任何人。
登录GitHub,打开“Account settings”,“SSH Keys”页面添加:
点“Add SSH Key”,填上任意Title,在Key文本框里粘贴id_rsa.pub文件的内容

为何GitHub须要SSH Key呢?由于GitHub须要识别出你推送的提交确实是你推送的,而不是别人冒充的,而Git支持SSH协议,因此,GitHub只要知道了你的公钥,就能够确认只有你本身才能推送。固然,GitHub容许你添加多个Key。假定你有若干电脑,你一下子在公司提交,一下子在家里提交,只要把每台电脑的Key都添加到GitHub,就能够在每台电脑上往GitHub推送了。
最后友情提示,在GitHub上免费托管的Git仓库,任何人均可以看到喔(但只有你本身才能改)。因此,不要把敏感信息放进去。
若是你不想让别人看到Git库,有两个办法,一个是交点保护费,让GitHub把公开的仓库变成私有的,这样别人就看不见了(不可读更不可写)。另外一个办法是本身动手,搭一个Git服务器,由于是你本身的Git服务器,因此别人也是看不见的。这个方法咱们后面会讲到的,至关简单,公司内部开发必备。
建立远程仓库

注意:
Add a license 添加一个证书,证书选择标准参考:
.gitignore失效的状况
Git忽略规则
在git中若是想忽略掉某个文件,不让这个文件提交到版本库中,可使用修改根目录中 .gitignore 文件的方法(若是没有这个文件,则需本身手工创建此文件)。这个文件每一行保存了一个匹配的规则例如:
# 此为注释–将被Git忽略 *.sample # 忽略全部.sample 结尾的文件 !lib.sample #但lib.sample除外 /TODO # 仅仅忽略项目根目录下的 TODO 文件,不包括subdir/TODO build/ # 忽略build/目录下的全部文件 doc/*.txt # 会忽略doc/notes.txt 但不包括 doc/server/arch.txt
gitignore规则不生效的解决办法
把某些目录或文件加入忽略规则,按照上述方法定义后发现并未生效,缘由是.gitignore只能忽略那些原来没有被追踪的文件,若是某些文件已经被归入了版本管理中,则修改.gitignore是无效的。那么解决方法就是先把本地缓存删除(改变成未被追踪状态),而后再提交,进入.git所在目录,执行如下命令:
git rm -r --cached . git add . git commit -m 'update .gitignore'
.gitignore未生效

.gitignore已生效

本地库关联远程库
bangdeMacBook-Pro:gitlocal bang$ git remote add origin git@github.com:luoleiwuhen/gitlocal.git
请千万注意,把上面的git@github.com:luoleiwuhen/gitlocal.git替换成你本身的远程库地址,不然,你在本地关联的就是个人远程库,关联没有问题,可是你之后推送是推不上去的,由于你的SSH Key公钥不在个人帐户列表中。会报下面的错误
bangdeMacBook-Pro:gitlocal bang$ git push -u origin master git@github.com: Permission denied (publickey). fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists.
添加后,远程库的名字就是origin,这是Git默认的叫法,也能够改为别的,可是origin这个名字一看就知道是远程库。
推送修改到远程库
因为远程库是空的,咱们第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在之后的推送或者拉取时就能够简化命令。
bangdeMacBook-Pro:gitlocal bang$ git push -u origin master To github.com:luoleiwuhen/gitlocal.git ! [rejected] master -> master (non-fast-forward) error: failed to push some refs to 'git@github.com:luoleiwuhen/gitlocal.git' hint: Updates were rejected because the tip of your current branch is behind hint: its remote counterpart. Integrate the remote changes (e.g. hint: 'git pull ...') before pushing again. hint: See the 'Note about fast-forwards' in 'git push --help' for details.
上面报错缘由分析:
问题(Non-fast-forward)的出现缘由在于:git仓库中已经有一部分代码,因此它不容许你直接把你的代码覆盖上去。因而你有2个选择方式:
一、强推,即利用强覆盖方式用你本地的代码替代git仓库内的内容
git push -f
二、先把git的东西fetch到你本地而后merge后再push
git fetch
git merge
这2句命令等价于
git pull
bangdeMacBook-Pro:gitlocal bang$ git pull There is no tracking information for the current branch. Please specify which branch you want to merge with. See git-pull(1) for details. git pull <remote> <branch> If you wish to set tracking information for this branch you can do so with: git branch --set-upstream-to=origin/<branch> master
上面代码说明2件事:
一、当你处于master branch, 默认的remote就是origin。
二、当你在master branch上使用git pull时,没有指定remote和branch,若是要让git采用默认的remote(也就是origin)来merge在master branch上全部的改变,配置以下
bangdeMacBook-Pro:gitlocal bang$ git branch --set-upstream-to=origin/master
继续git pull
bangdeMacBook-Pro:gitlocal bang$ git pull fatal: refusing to merge unrelated histories
若是报上面错误,可使用:
bangdeMacBook-Pro:gitlocal bang$ git pull --allow-unrelated-histories origin master From github.com:luoleiwuhen/gitlocal * branch master -> FETCH_HEAD Merge made by the 'recursive' strategy. .gitignore | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 1 + 2 files changed, 64 insertions(+) create mode 100644 .gitignore create mode 100644 README.md bangdeMacBook-Pro:gitlocal bang$ git pull Already up-to-date.
推送本地代码到远程成功:
bangdeMacBook-Pro:gitlocal bang$ git push -u origin master Counting objects: 26, done. Delta compression using up to 8 threads. Compressing objects: 100% (17/17), done. Writing objects: 100% (26/26), 2.20 KiB | 1.10 MiB/s, done. Total 26 (delta 4), reused 0 (delta 0) remote: Resolving deltas: 100% (4/4), done. To github.com:luoleiwuhen/gitlocal.git b60bdaf..d83ba97 master -> master Branch master set up to track remote branch master from origin.

查看远程库已经能够看到推送的内容。
git clone + 仓库地址
bangdeMacBook-Pro:~ bang$ git clone https://github.com/luoleiwuhen/gitlocal.git Cloning into 'gitlocal'... remote: Counting objects: 30, done. remote: Compressing objects: 100% (16/16), done. remote: Total 30 (delta 5), reused 26 (delta 4), pack-reused 0 Unpacking objects: 100% (30/30), done.
GitHub给出的地址不止一个,Git支持多种协议,ssh协议,但也可使用https等其余协议。
ssh:git@github.com:luoleiwuhen/gitlocal.git
https:https://github.com/luoleiwuhen/gitlocal.git
使用https除了速度慢之外,还有个最大的麻烦是每次推送都必须输入口令,可是在某些只开放http端口的公司内部就没法使用ssh协议而只能用https。
在Git里,主分支,即master分支。HEAD严格来讲不是指向提交,而是指向master,master才是指向提交的,因此,HEAD指向的就是当前分支。
一开始的时候,master分支是一条线,Git用master指向最新的提交,再用HEAD指向master,就能肯定当前分支,以及当前分支的提交点:

每次提交,master分支都会向前移动一步,这样,随着你不断提交,master分支的线也愈来愈长。
当咱们建立新的分支,例如dev时,Git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上。

Git建立一个分支很快,由于除了增长一个dev指针,改改HEAD的指向,工做区的文件都没有任何变化!
不过,从如今开始,对工做区的修改和提交就是针对dev分支了,好比新提交一次后,dev指针往前移动一步,而master指针不变:

假如咱们在dev上的工做完成了,就能够把dev合并到master上。Git怎么合并呢?最简单的方法,就是直接把master指向dev的当前提交,就完成了合并。

因此Git合并分支也很快!就改改指针,工做区内容也不变!
合并完分支后,甚至能够删除dev分支。删除dev分支就是把dev指针给删掉,删掉后,咱们就剩下了一条master分支。

git branch 查看当前分支
bangdeMacBook-Pro:gitlocal bang$ git branch * master
git branch xiaoming 建立xiaoming分支
bangdeMacBook-Pro:gitlocal bang$ git branch xiaoming bangdeMacBook-Pro:gitlocal bang$ git branch * master xiaoming
git checkout xiaoming 切换到xiaoming分支
bangdeMacBook-Pro:gitlocal bang$ git checkout xiaoming Switched to branch 'xiaoming' bangdeMacBook-Pro:gitlocal bang$ git branch master * xiaoming
切换并建立分支
git checkout -b xiaogang 建立xiaogang分支并切换到该分支。
git checkout命令加上-b参数表示建立并切换,至关于
git branch xiaogang
git checkout xiaogang
bangdeMacBook-Pro:gitlocal bang$ git checkout -b xiaogang Switched to a new branch 'xiaogang' bangdeMacBook-Pro:gitlocal bang$ git branch master * xiaogang xiaoming
合并分支git merge
若是咱们在xiaogang分支上修改text1.txt提交,而后切换到master分支上查看text1.txt内容是没有修改的。由于修改提交到了xiaogang分支上

合并分支:
首先咱们要切换到master分支上,而后合并
bangdeMacBook-Pro:gitlocal bang$ git branch * master xiaogang xiaoming bangdeMacBook-Pro:gitlocal bang$ git merge xiaogang Updating d83ba97..7f2a267 Fast-forward text1.txt | 1 + 1 file changed, 1 insertion(+)
此时查看text1.txt文件能够发现内容已经和xiaogang分支同样了。
git merge命令用于合并指定分支到当前分支。注意到上面的Fast-forward信息,Git告诉咱们,此次合并是“快进模式”,也就是直接把master指向dev的当前提交,因此合并速度很是快。固然,也不是每次合并都能Fast-forward,咱们后面会讲其余方式的合并。
删除分支
bangdeMacBook-Pro:gitlocal bang$ git branch -d xiaogang Deleted branch xiaogang (was 7f2a267). bangdeMacBook-Pro:gitlocal bang$ git branch * master xiaoming bangdeMacBook-Pro
合并冲突
若是咱们同时在master分支和xiaogang分支上都修改了text1.txt文件,合并分支会报错。
bangdeMacBook-Pro:gitlocal bang$ git merge xiaogang Auto-merging text1.txt CONFLICT (content): Merge conflict in text1.txt Automatic merge failed; fix conflicts and then commit the result.

状态以下:

冲突如上,test1_4_branch_master是master分支上的修改,test1_4_branch_xiaogang是xiaogang分支的修改,更具需求进行处理,这里删除xiaogang分支的修改。Git用<<<<<<<,=======,>>>>>>>标记出不一样分支的内容,咱们修改以下后保存.
合并完成以后状态以下:

查看提交状态:
bangdeMacBook-Pro:gitlocal bang$ git log --graph --pretty=oneline --abbrev-commit * 76a3e34 (HEAD -> master) 合并master和xiaogang分支冲突 |\ | * cc71d22 (xiaogang) 分支xiaogang修改text1.txt * | 7e54f09 分支master修改text1.txt |/ * 7f2a267 xiaogang分支修改text1 * d83ba97 (origin/master, origin/HEAD, xiaoming) 合并代码 Merge branch 'master' of github.com:luoleiwuhen/gitlocal |\ | * b60bdaf Initial commit * 4aa2fd6 删除text3 * 62bd4ea 删除text4 * 2444e9f 修改text2 * 47dc252 提交text4.txt * f0c55f3 text2_2 * 0996e4e text1_2 * 66ce043 commit all text * ed7560b text1建立
一般,合并分支时,若是可能,Git会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。
bangdeMacBook-Pro:gitlocal bang$ git log --graph --pretty=oneline * 76a3e3429ff12fdf75181867ab599efc39faba59 (HEAD -> master) 合并master和xiaogang分支冲突 |\ | * cc71d221719013d4c130ebac05185d6dc19a6855 分支xiaogang修改text1.txt * | 7e54f09d75daa45269f72c2b4eb0aa9d23bf6c83 分支master修改text1.txt |/ * 7f2a26765450d2f295c6134993c470ed4e3796d4 xiaogang分支修改text1 * d83ba972a45be71d82dde386aa569693e5b830ca (origin/master, origin/HEAD, xiaoming) 合并代码 Merge branch 'master' of github.com:luoleiwuhen/gitlocal |\ | * b60bdaf38af68593b91236d36c814d14285f46dc Initial commit * 4aa2fd6a460da40cb9d99e9e984dc47f0146932a 删除text3 * 62bd4ea485e2380095eefde95cfda0ba216af3c7 删除text4 * 2444e9f5665dbba5148b7bf289eb2990680a577c 修改text2 * 47dc25236a6a2c36c7d5cfceb3b17f68a7825898 提交text4.txt * f0c55f361fdd3d61f2a7a1f3ca40375f470c78ff text2_2 * 0996e4e77c5002cf45e96f1d99841acba24cdf6f text1_2 * 66ce043a24be29d5093515282c4e850aaf162022 commit all text * ed7560bddcbd275cdb570fc63b9e086ba1b7200b text1建立
cc71d221719013d4c130ebac05185d6dc19a6855 分支xiaogang修改text1.txt再也不是cc71d221719013d4c130ebac05185d6dc19a6855 (xiaogang) 分支xiaogang修改text1.txt
若是要强制禁用Fast forward模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就能够看出分支信息。
下面咱们实战一下--no-ff方式的git merge:
bangdeMacBook-Pro:gitlocal bang$ git merge --no-ff -m "merge with no-ff" xiaogang Merge made by the 'recursive' strategy. text1.txt | 1 + 1 file changed, 1 insertion(+)
本次合并要建立一个新的commit,因此加上-m参数,把commit描述写进去
分支策略
在实际开发中,咱们应该按照几个基本原则进行分支管理:首先,master分支应该是很是稳定的,也就是仅用来发布新版本,平时不能在上面干活;那在哪干活呢?干活都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,好比1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本;你和你的小伙伴们每一个人都在dev分支上干活,每一个人都有本身的分支,时不时地往dev分支上合并就能够了。
因此,团队合做的分支看起来就像这样:

软件开发中,bug就像屡见不鲜同样。有了bug就须要修复,在Git中,因为分支是如此的强大,因此,每一个bug均可以经过一个新的临时分支来修复,修复后,合并分支,而后将临时分支删除。
工做区存储
当你接到一个修复紧急bug的任务时,很天然地,你想建立一个分支来修复它,可是,当前正在dev上进行的工做尚未提交,并且暂时尚未开发完不能提交:
bangdeMacBook-Pro:gitlocal bang$ git status On branch xiaoming 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: text2.txt no changes added to commit (use "git add" and/or "git commit -a")
这时能够git stash功能,能够把当前工做现场“储藏”起来,等之后恢复现场后继续工做。
bangdeMacBook-Pro:gitlocal bang$ git stash Saved working directory and index state WIP on xiaoming: d83ba97 合并代码 Merge branch 'master' of github.com:luoleiwuhen/gitlocal bangdeMacBook-Pro:gitlocal bang$ git status On branch xiaoming nothing to commit, working tree clean bangdeMacBook-Pro:gitlocal bang$
用git status查看工做区,就是干净的(除非有没有被Git管理的文件),所以能够放心地建立分支来修复bug。切换到master分支建立bugfix分支修复bug,等修复完成再合并到master分支上并删除bugfix分支。
修改完成后切换到工做分支继续干活。首先恢复工做区现场。
git stash list查看工做区存放位置
bangdeMacBook-Pro:gitlocal bang$ git stash list stash@{0}: WIP on xiaoming: d83ba97 合并代码 Merge branch 'master' of github.com:luoleiwuhen/gitlocal
恢复工做区:
bangdeMacBook-Pro:gitlocal bang$ git stash apply On branch xiaoming 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: text2.txt no changes added to commit (use "git add" and/or "git commit -a") bangdeMacBook-Pro:gitlocal bang$ git stash list stash@{0}: WIP on xiaoming: d83ba97 合并代码 Merge branch 'master' of github.com:luoleiwuhen/gitlocal bangdeMacBook-Pro:gitlocal bang$ git stash drop Dropped refs/stash@{0} (c718ed368b38350aae172bf2b1d4049ef83df91a) bangdeMacBook-Pro:gitlocal bang$ git stash list bangdeMacBook-Pro:gitlocal bang$
bangdeMacBook-Pro:gitlocal bang$ git stash pop On branch xiaoming 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: text2.txt no changes added to commit (use "git add" and/or "git commit -a") Dropped refs/stash@{0} (b302d48cd814921cc263a5a577cfa95746adf8bf)
你能够屡次stash,恢复的时候,先用git stash list查看,而后恢复指定的stash,用命令:
git stash apply stash@{0}
强行删除分支
若是建立xiaogang分支修改代码而且提交,切换到master分支没有进行merge,此时若是删除xiaogang分支会失败
bangdeMacBook-Pro:gitlocal bang$ git branch -d xiaogang error: The branch 'xiaogang' is not fully merged. If you are sure you want to delete it, run 'git branch -D xiaogang'. bangdeMacBook-Pro:gitlocal bang$ git branch -D xiaogang Deleted branch xiaogang (was fd22ddb).
查看远程分支信息
bangdeMacBook-Pro:gitlocal bang$ git remote origin bangdeMacBook-Pro:gitlocal bang$ git remote -v origin https://github.com/luoleiwuhen/gitlocal.git (fetch) origin https://github.com/luoleiwuhen/gitlocal.git (push)
推送分支
bangdeMacBook-Pro:gitlocal bang$ git push origin master Counting objects: 18, done. Delta compression using up to 8 threads. Compressing objects: 100% (16/16), done. Writing objects: 100% (18/18), 1.70 KiB | 1.70 MiB/s, done. Total 18 (delta 9), reused 0 (delta 0) remote: Resolving deltas: 100% (9/9), completed with 1 local object. To https://github.com/luoleiwuhen/gitlocal.git d83ba97..d907513 master -> master
多人合做场景
如今,模拟一个你的小伙伴,能够在另外一台电脑(注意要把SSH Key添加到GitHub)或者同一台电脑的另外一个目录下克隆。这里选择一个新目录。
bangdeMacBook-Pro:gitlocal_zhenbang bang$ git clone git@github.com:luoleiwuhen/gitlocal.git Cloning into 'gitlocal'... remote: Counting objects: 51, done. remote: Compressing objects: 100% (25/25), done. remote: Total 51 (delta 15), reused 46 (delta 13), pack-reused 0 Receiving objects: 100% (51/51), 5.28 KiB | 1.76 MiB/s, done. Resolving deltas: 100% (15/15), done.
上面会克隆远程分支master到本地,查看本地分支也确实是master。
bangdeMacBook-Pro:gitlocal bang$ git branch * master bangdeMacBook-Pro:gitlocal bang$ git branch -a * master remotes/origin/HEAD -> origin/master remotes/origin/dev remotes/origin/master
如今,你的小伙伴要在dev分支上开发,就必须建立远程origin的dev分支到本地,因而他用这个命令建立本地dev分支:
bangdeMacBook-Pro:gitlocal bang$ git checkout -b dev origin/dev Branch dev set up to track remote branch dev from origin. Switched to a new branch 'dev' bangdeMacBook-Pro:gitlocal bang$ git branch -a * dev master remotes/origin/HEAD -> origin/master remotes/origin/dev remotes/origin/master
git checkout -b dev origin/dev 建立
修改代码并提交到远程dev分支上
bangdeMacBook-Pro:gitlocal bang$ git commit text1.txt -m "zhenbang分支" [dev 9b135df] zhenbang分支 1 file changed, 1 insertion(+) bangdeMacBook-Pro:gitlocal bang$ git push origin dev Counting objects: 3, done. Delta compression using up to 8 threads. Compressing objects: 100% (3/3), done. Writing objects: 100% (3/3), 312 bytes | 312.00 KiB/s, done. Total 3 (delta 1), reused 0 (delta 0) remote: Resolving deltas: 100% (1/1), completed with 1 local object. To github.com:luoleiwuhen/gitlocal.git 23a4112..9b135df dev -> dev
git push origin dev这里origin表明远程库
bangdeMacBook-Pro:gitlocal bang$ git remote -v origin git@github.com:luoleiwuhen/gitlocal.git (fetch) origin git@github.com:luoleiwuhen/gitlocal.git (push)
你的小伙伴已经向origin/dev分支推送了他的提交,而碰巧你也对一样的文件做了修改,并试图推送:
bangdeMacBook-Pro:gitlocal bang$ git push origin dev To https://github.com/luoleiwuhen/gitlocal.git ! [rejected] dev -> dev (fetch first) error: failed to push some refs to 'https://github.com/luoleiwuhen/gitlocal.git' hint: Updates were rejected because the remote contains work that you do hint: not have locally. This is usually caused by another repository pushing hint: to the same ref. You may want to first integrate the remote changes hint: (e.g., 'git pull ...') before pushing again. hint: See the 'Note about fast-forwards' in 'git push --help' for details.
推送失败,由于你的小伙伴的最新提交和你试图推送的提交有冲突,解决办法也很简单,Git已经提示咱们,先用git pull把最新的提交从origin/dev抓下来,而后,在本地合并,解决冲突,再推送
bangdeMacBook-Pro:gitlocal bang$ git pull There is no tracking information for the current branch. Please specify which branch you want to merge with. See git-pull(1) for details. git pull <remote> <branch> If you wish to set tracking information for this branch you can do so with: git branch --set-upstream-to=origin/<branch> dev
git pull也失败了,缘由是没有指定本地dev分支与远程origin/dev分支的连接,根据提示,设置dev和origin/dev的连接:
bangdeMacBook-Pro:gitlocal bang$ git branch --set-upstream-to=origin/dev dev Branch dev set up to track remote branch dev from origin. bangdeMacBook-Pro:gitlocal bang$ git pull remote: Counting objects: 3, done. remote: Compressing objects: 100% (2/2), done. remote: Total 3 (delta 1), reused 3 (delta 1), pack-reused 0 Unpacking objects: 100% (3/3), done. From github.com:luoleiwuhen/gitlocal 9b135df..92847e4 dev -> origin/dev Auto-merging text1.txt CONFLICT (content): Merge conflict in text1.txt Automatic merge failed; fix conflicts and then commit the result.
这回git pull成功,可是合并有冲突,须要手动解决,解决的方法和分支管理中的解决冲突彻底同样。解决后,提交,再push
发布一个版本时,咱们一般先在版本库中打一个标签(tag),这样,就惟一肯定了打标签时刻的版本。未来不管何时,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来。因此,标签也是版本库的一个快照。
Git的标签虽然是版本库的快照,但其实它就是指向某个commit的指针(跟分支很像对不对?可是分支能够移动,标签不能移动),因此,建立和删除标签都是瞬间完成的。
Git有commit,为何还要引入tag?
“请把上周一的那个版本打包发布,commit号是6a5819e...”
“一串乱七八糟的数字很差找!”
若是换一个办法:
“请把上周一的那个版本打包发布,版本号是v1.2”
“好的,按照tag v1.2查找commit就行!”
因此,tag就是一个让人容易记住的有意义的名字,它跟某个commit绑在一块儿。
打标签
首先切换到须要打标签的分支上
bangdeMacBook-Pro:gitlocal bang$ git checkout master Switched to branch 'master' Your branch is up-to-date with 'origin/master'.
而后,敲命令git tag name就能够打一个新标签了
bangdeMacBook-Pro:gitlocal bang$ git tag v1.0
默认标签是打在最新提交的commit上的。有时候,若是忘了打标签,好比,如今已是周五了,但应该在周一打的标签没有打,怎么办?
方法是找到历史提交的commit id,而后打上就能够了:
bangdeMacBook-Pro:gitlocal bang$ git log --graph --pretty=oneline * d907513c086b73970acd81eefe3422642ba5ea0a (HEAD -> master, tag: v1.0, origin/master, origin/HEAD) merge bugfix |\ | * 84d9daf8c69a11e0e8970260b060c7f324b77bcd fixbug * | 4c811ab83e78ea66e6e2eea475fc7760452746ff merge with no-ff |\ \ | * | 776eee31e3ce6b053d1b263fed0b5bd6f916fda4 xiaogang分支修改text1.txt |/ / * | 76a3e3429ff12fdf75181867ab599efc39faba59 合并master和xiaogang分支冲突 |\ \ | * | cc71d221719013d4c130ebac05185d6dc19a6855 分支xiaogang修改text1.txt * | | 7e54f09d75daa45269f72c2b4eb0aa9d23bf6c83 分支master修改text1.txt |/ / * | 7f2a26765450d2f295c6134993c470ed4e3796d4 xiaogang分支修改text1 |/ * d83ba972a45be71d82dde386aa569693e5b830ca 合并代码 Merge branch 'master' of github.com:luoleiwuhen/gitlocal |\ | * b60bdaf38af68593b91236d36c814d14285f46dc Initial commit * 4aa2fd6a460da40cb9d99e9e984dc47f0146932a 删除text3 * 62bd4ea485e2380095eefde95cfda0ba216af3c7 删除text4 * 2444e9f5665dbba5148b7bf289eb2990680a577c 修改text2 * 47dc25236a6a2c36c7d5cfceb3b17f68a7825898 提交text4.txt * f0c55f361fdd3d61f2a7a1f3ca40375f470c78ff text2_2 * 0996e4e77c5002cf45e96f1d99841acba24cdf6f text1_2 * 66ce043a24be29d5093515282c4e850aaf162022 commit all text * ed7560bddcbd275cdb570fc63b9e086ba1b7200b text1建立 bangdeMacBook-Pro:gitlocal bang$ git tag v0.1 4aa2f bangdeMacBook-Pro:gitlocal bang$ git tag v0.1 v1.0
还能够建立带有说明的标签,用-a指定标签名,-m指定说明文字:
bangdeMacBook-Pro:gitlocal bang$ git tag -a v0.2 -m"分支合并" 76a3e3 bangdeMacBook-Pro:gitlocal bang$ git tag v0.1 v0.2 v1.0
查看打过的tag
bangdeMacBook-Pro:gitlocal bang$ git tag v0.1 v1.0
查看分支详情
bangdeMacBook-Pro:gitlocal bang$ git show v0.2 tag v0.2 Tagger: wangzhenbang <wangzhenbang@100tal.com> Date: Thu Jan 4 17:22:48 2018 +0800 分支合并 commit 76a3e3429ff12fdf75181867ab599efc39faba59 (tag: v0.2, tag: show) Merge: 7e54f09 cc71d22 Author: wangzhenbang <wangzhenbang@100tal.com> Date: Wed Jan 3 18:10:22 2018 +0800 合并master和xiaogang分支冲突
删除标签
bangdeMacBook-Pro:gitlocal bang$ git tag show v0.1 v0.2 v1.0 bangdeMacBook-Pro:gitlocal bang$ git tag -d v0.1 Deleted tag 'v0.1' (was 4aa2fd6) bangdeMacBook-Pro:gitlocal bang$ git tag show v0.2 v1.0
推送标签到远程
由于建立的标签都只存储在本地,不会自动推送到远程。因此,打错的标签能够在本地安全删除。
若是要推送某个标签到远程,使用命令git push origin tagname:
bangdeMacBook-Pro:gitlocal bang$ git push origin v1.0 Total 0 (delta 0), reused 0 (delta 0) To github.com:luoleiwuhen/gitlocal.git * [new tag] v1.0 -> v1.0

或者,一次性推送所有还没有推送到远程的本地标签:
bangdeMacBook-Pro:gitlocal bang$ git push origin --tags Counting objects: 1, done. Writing objects: 100% (1/1), 174 bytes | 174.00 KiB/s, done. Total 1 (delta 0), reused 0 (delta 0) To github.com:luoleiwuhen/gitlocal.git * [new tag] show -> show * [new tag] v0.2 -> v0.2

删除远程标签
若是标签已经推送到远程,要删除远程标签就麻烦一点,先从本地删除:
bangdeMacBook-Pro:gitlocal bang$ git tag -d v0.2 Deleted tag 'v0.2' (was 9f1a177) bangdeMacBook-Pro:gitlocal bang$ git tag show v1.0
而后,从远程删除。删除命令也是push,可是格式以下:
bangdeMacBook-Pro:gitlocal bang$ git push origin :refs/tags/v0.2 To github.com:luoleiwuhen/gitlocal.git - [deleted] v0.2

颜色配置
bangdeMacBook-Pro:gitlocal bang$ git config --global color.ui true bangdeMacBook-Pro:gitlocal bang$ git config --global color.ui false
指令替换
若是敲git st就表示git status那就简单多了,固然这种偷懒的办法咱们是极力同意的。
咱们只须要敲一行命令,告诉Git,之后st就表示status:
bangdeMacBook-Pro:gitlocal bang$ git config --global alias.st status bangdeMacBook-Pro:gitlocal bang$ git status On branch master Your branch is up-to-date with 'origin/master'. nothing to commit, working tree clean bangdeMacBook-Pro:gitlocal bang$ git st On branch master Your branch is up-to-date with 'origin/master'. nothing to commit, working tree clean
打印记录
git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit" bangdeMacBook-Pro:gitlocal bang$ git lg * d907513 - (HEAD -> master, tag: v1.0, origin/master, origin/HEAD) merge bugfix (23 hours ago) <wangzhenbang> |\ | * 84d9daf - fixbug (24 hours ago) <wangzhenbang> * | 4c811ab - merge with no-ff (24 hours ago) <wangzhenbang> |\ \ | * | 776eee3 - xiaogang分支修改text1.txt (24 hours ago) <wangzhenbang> |/ / * | 76a3e34 - (tag: show) 合并master和xiaogang分支冲突 (25 hours ago) <wangzhenbang> |\ \ | * | cc71d22 - 分支xiaogang修改text1.txt (26 hours ago) <wangzhenbang> * | | 7e54f09 - 分支master修改text1.txt (26 hours ago) <wangzhenbang> |/ / * | 7f2a267 - xiaogang分支修改text1 (26 hours ago) <wangzhenbang> |/ * d83ba97 - 合并代码 Merge branch 'master' of github.com:luoleiwuhen/gitlocal (27 hours ago) <wangzhenbang> |\ | * b60bdaf - Initial commit (28 hours ago) <彡天涯灬无忌彡> * 4aa2fd6 - 删除text3 (29 hours ago) <wangzhenbang> * 62bd4ea - 删除text4 (29 hours ago) <wangzhenbang> * 2444e9f - 修改text2 (29 hours ago) <wangzhenbang> * 47dc252 - 提交text4.txt (29 hours ago) <wangzhenbang> * f0c55f3 - text2_2 (32 hours ago) <wangzhenbang> * 0996e4e - text1_2 (32 hours ago) <wangzhenbang> * 66ce043 - commit all text (32 hours ago) <wangzhenbang> * ed7560b - text1建立 (32 hours ago) <wangzhenbang>
配置文件
配置Git的时候,加上--global是针对当前用户起做用的,若是不加,那只针对当前的仓库起做用。
配置文件放哪了?每一个仓库的Git配置文件都放在.git/config文件中:
bangdeMacBook-Pro:.git bang$ cat config [core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true ignorecase = true precomposeunicode = true [remote "origin"] url = git@github.com:luoleiwuhen/gitlocal.git fetch = +refs/heads/*:refs/remotes/origin/* [branch "master"] remote = origin merge = refs/heads/master [branch "dev"] remote = origin merge = refs/heads/dev
而当前用户的Git配置文件放在用户主目录(cd ~)下的一个隐藏文件.gitconfig中:
bangdeMacBook-Pro:gitlocal bang$ cd ~ bangdeMacBook-Pro:~ bang$ cat .gitconfig [user] name = wangzhenbang email = wangzhenbang@100tal.com [http] postBuffer = 524288000 [filter "lfs"] clean = git-lfs clean %f smudge = git-lfs smudge %f required = true [color] ui = true [alias] lg = log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit st = status [core] excludesfile = /Users/bang/.gitignore_global [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
别名就在[alias]后面,要删除别名,直接把对应的行删掉便可。的行删掉便可。