赞
踩
如果是没有接触过 Git 的同学,推荐 廖雪峰 Git 教程,超级详细,就是内容比较多。
本篇精华版,去掉了很多废话,用于快速唤醒记忆。
目录
3)概念:工作区、版本库 (Respository)、暂存区 (stage)
4)撤销工作区的修改:git checkout,git reset
1)添加远程库,推送已提交内容:git push origin master
3)分支管理策略:git merge --no-ff -m "merge with no-ff" dev
集中式版本控制系统:
版本库是集中存放在中央服务器的,而干活的时候,用的都是自己的电脑,所以要先从中央服务器取得最新的版本,然后开始干活,干完活了,再把自己的活推送给中央服务器。
最大的毛病就是必须联网才能工作。
分布式版本控制系统:
首先,分布式版本控制系统根本没有“中央服务器”,每个人的电脑上都是一个完整的版本库,这样,你工作的时候,就不需要联网了,因为版本库就在你自己的电脑上。
分布式版本控制系统通常也有一台充当“中央服务器”的电脑,但这个服务器的作用仅仅是用来方便“交换”大家的修改。
1. 进入想要创建 git 的文件夹,右键 -> Git Bash,此时进入对应目录的 git
2. 配置身份:
git config --global user.name "Your Name"
git config --global user.email "email@example.com"
Notes:
① 查询语句:git config --global user.name,然后回车,得到当前用户名;
② --global参数,表示你这台机器上所有的Git仓库都会使用这个配置
3. 创建代码仓库(.git是隐藏文件夹)
git init
4.添加文件或目录
git add readme.txt
git add . //添加所有
5.提交代码,-m 用来加上描述信息:git commit -m
git commit -m “wrote a readme file”
Notes:
① -m 后面输入的是本次的提交说明;
② 一个文件改变,插入3行;
1. 修改文件后,查看改动文件:git status
git status
Notes:
① 在 master 分支上,修改但未提交:
git add <file>... 更新即将要被提交的内容
git checkout --<file>... 放弃工作目录的改变
② 没有需要提交的修改,而且,工作目录是干净(working tree clean)的
2. 查看修改的内容:git diff
git diff readme.txt
git diff
在第一行添加了一个distributed单词。
3. 查看提交历史记录 log:git log
版本1:wrote a readme file
Git is a version control system.
Git is free software.
版本2:add distributed
Git is a distributed version control system.
Git is free software.
版本3:append GPL
Git is a distributed version control system.
Git is free software distributed under the GPL.
Notes:
① git log命令显示从最近到最远的提交日志,我们可以看到3次提交;
② 如果嫌输出信息太多,可以加上 --pretty=oneline 参数:只看一行
git log --pretty=oneline
833ca... 长串 是版本号(commit id)
4. 版本回退:git reset
git reset --hard HEAD^
Notes:
① HEAD 表示当前版本,上一个版本就是 HEAD^,上上一个版本就是 HEAD^^,往上100个版本HEAD~100。
② --hard
③ 最新的那个版本 append GPL 已经看不到了!
④ 再返回 append GPL 版本:
只要上面的命令行窗口还没有被关掉,还可以顺着往上找到 append GPL 的commit id 是 833ca1...,于是就可以指定回到未来的某个版本:
git reset --hard 833ca
⑤ 查看命令历史:git reflog
若命令行窗口关闭,使用命令可以查看到 commit id
工作区(Working Directory)
就是你在电脑里能看到的目录,比如我的 learngit 文件夹就是一个工作区:
版本库(Repository)
工作区有一个隐藏目录 .git,是 Git 的版本库。
Git的版本库里存放称为 stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向 master 的一个指针叫 HEAD。
文件往Git版本库里添加的时候,
① git add把文件修改添加到暂存区(stage);
② git commit 把暂存区的所有内容提交到当前分支(master)。
提交后版本库变成了这样,暂存区就没有任何内容了:
Git跟踪并管理的是修改,而非文件。
每次修改,如果不用 git add 到暂存区,那就不会加入到 commit 中。
场景1:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令git checkout -- file。
场景2:当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令git reset HEAD <file>,就回到了场景1,第二步按场景1操作。
场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,参考版本回退一节,不过前提是没有推送到远程库。
把 readme.txt 文件在工作区的修改全部撤销,这里有两种情况:
场景1. 修改在工作区还未 add:git checkout -- readme.txt
直接丢弃工作区修改,回到和版本库(Respository)一模一样的状态;
git checkout -- readme.txt
Notes:
① git checkout -- file命令中的--很重要,没有--,就变成了 “切换到另一个分支” 的命令。
场景2. 已经添加到暂存区(stage)后,又作了修改:
现在,撤销就回到添加到暂存区(stage)的状态。撤销分两步
用git status查看一下:
在 master 分支上,修改即将被提交: 用命令 git reset HEAD <file> 可以把暂存区的修改撤销(unstage)
第一步:
git reset HEAD readme.txt
git reset 既可以回退版本,也可以把暂存区的修改回退到工作区。
HEAD 表示最新的版本。
第二步:丢弃工作区的修改
场景3. 提交了不合适的修改到版本库,想要撤销本次提交:版本回退
先添加一个新文件 test.txt 到Git并且提交,然后在文件管理器中删除 test.txt,或者用rm命令删了:
$ rm test.txt
这时,Git知道你删除了文件,因此,工作区和版本库就不一致了,git status 命令会立刻告诉你哪些文件被删除了:
现在你有两个选择:
① 从版本库中删除该文件,那就用命令git rm删掉,并且git commit:
Note:
先手动删除文件,然后使用git rm <file>和git add<file>效果是一样的。
② 另一种情况是删错了,因为版本库里还有,所以可以把误删的文件恢复到最新版本:
$ git checkout -- test.txt
git checkout 其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。
由于你的本地Git仓库和GitHub仓库之间的传输是通过SSH加密的,所以,需要一点设置:
第1步:创建SSH Key。
打开Git Bash,创建SSH Key:
$ ssh-keygen -t rsa -C "youremail@example.com"
把邮件地址换成你自己的邮件地址,然后一路回车,使用默认值即可,无需设置密码。
这两个就是SSH Key的秘钥对,id_rsa是私钥,不能泄露出去,id_rsa.pub是公钥。
第2步:登陆GitHub,打开“Account settings”,“SSH Keys”页面:
然后,点“Add SSH Key”,填上任意Title,在Key文本框里粘贴id_rsa.pub文件的内容:
点击:New SSH key,进入以下界面
为什么GitHub需要SSH Key呢?因为GitHub需要识别出你推送的提交确实是你推送的。
当然,GitHub允许你添加多个Key。假定你有若干电脑,你一会儿在公司提交,一会儿在家里提交,只要把每台电脑的Key都添加到GitHub,就可以在每台电脑上往GitHub推送了。
首先,登陆GitHub,然后,在右上角找到“New repository”按钮,创建一个新的仓库:
GitHub告诉我们:
可以从这个仓库克隆出新的仓库;
or 把一个已有的本地仓库与之关联,然后,把本地仓库的内容推送到GitHub仓库;
or 从另外的库导入代码。
这里使用第二种方式:copy 命令,然后粘贴到 git Bash 执行即可
把本地库的内容推送到远程,用git push命令,实际上是把当前分支master推送到远程。
由于远程库是空的,我们第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。
推送成功后,可以立刻在GitHub页面中看到远程库的内容已经和本地一模一样:
从现在起,只要本地作了提交,就可以通过命令:
git push origin master
把本地master分支的最新修改推送至GitHub,现在,你就拥有了真正的分布式版本库!
选取一个远程仓库,克隆地址,然后去本地文件夹执行克隆命令即可。
git clone https://github.com/WensonLuo/learngit.git
在Git里,主分支(master)分支指向提交,HEAD指向的就是当前分支。
一开始的时候,master分支是一条线,Git用master指向最新的提交,再用HEAD指向master,就能确定当前分支,以及当前分支的提交点:
当我们创建新的分支,例如dev时,Git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上:
从现在开始,对工作区的修改和提交就是针对dev分支了,比如新提交一次后,dev指针往前移动一步,而master指针不变:
假如我们在dev上的工作完成了,就可以把dev合并到master上。Git怎么合并呢?最简单的方法,就是直接把master指向dev的当前提交,就完成了合并:
所以Git合并分支也很快!就改改指针,工作区内容也不变!
合并完分支后,甚至可以删除dev分支。删除dev分支就是把dev指针给删掉,删掉后,我们就剩下了一条master分支:
下面开始实战。
首先,我们创建dev分支,然后切换到dev分支:
git checkout -b dev
git checkout命令加上-b参数表示创建并切换,相当于以下两条命令:
git branch dev git checkout dev
然后,用git branch命令查看当前分支:
git branch
git branch命令会列出所有分支,当前分支前面会标一个*号。
比如对readme.txt做个修改,加上一行,然后提交
Creating a new branch is quick.
现在,dev分支的工作完成,我们就可以切换回master分支:
git checkout master
切换回master分支后,再查看一个readme.txt文件,刚才添加的内容不见了!因为那个提交是在dev分支上,而master分支此刻的提交点并没有变:
现在,我们把dev分支的工作成果合并到master分支上:
git merge dev
git merge命令用于合并指定分支到当前分支。
Notes:
Fast-forward 这次合并是“快进模式”,也就是直接把master指向dev的当前提交,所以合并速度非常快。
合并完成后,就可以放心地删除dev分支了:
$ git branch -d dev
删除后,查看branch,就只剩下master分支了:
小结
Git鼓励大量使用分支:
查看分支:git branch
创建分支:git branch <name>
切换分支:git checkout <name>
创建+切换分支:git checkout -b <name>
合并某分支到当前分支:git merge <name>
删除分支:git branch -d <name>
准备新的feature1分支,修改readme.txt最后一行,改为:
Creating a new branch is quick AND simple.
在feature1分支上提交,然后切换到master分支,把readme.txt文件的最后一行改为:
Creating a new branch is quick & simple.
提交后,master分支和feature1分支各自都分别有新的提交,变成了这样:
这种情况下,Git无法执行“快速合并”,只能试图把各自的修改合并起来,但这种合并就可能会有冲突:
readme.txt文件存在冲突,必须手动解决冲突后再提交。
git status也可以告诉我们冲突的文件:
我们可以直接查看readme.txt的内容:
Git用<<<<<<<,=======,>>>>>>>标记出不同分支的内容,我们修改如下后保存:
Creating a new branch is quick and simple.
再提交:
现在,master分支和feature1分支变成了下图所示:
用带参数的git log也可以看到分支的合并情况:
git log --graph --pretty=oneline --abbrev-commit
最后,删除feature1分支:
git branch -d feature1
通常,合并分支时,如果可能,Git会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。
如果要强制禁用Fast forward模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息。
首先,创建并切换dev分支,修改readme.txt文件,并提交一个新的commit。现在,我们切换回master,准备合并dev分支。
请注意--no-ff参数,表示禁用Fast forward:
$ git merge --no-ff -m "merge with no-ff" dev
Merge made by the 'recursive' strategy.
readme.txt | 1 +
1 file changed, 1 insertion(+)
因为本次合并要创建一个新的commit,所以加上-m参数,把commit描述写进去。
合并后,我们用git log看看分支历史:
$ git log --graph --pretty=oneline --abbrev-commit
* e1e9c68 (HEAD -> master) merge with no-ff
|\
| * f52c633 (dev) add merge
|/ * cf810e4 conflict fixed
...
可以看到,不使用Fast forward模式,merge后就像这样:
分支策略
在实际开发中,我们应该按照几个基本原则进行分支管理:
首先,master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;
干活都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本;
你和你的小伙伴们都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了。
所以,团队合作的分支看起来就像这样:
小结
Git分支十分强大,在团队开发中应该充分应用。
合并分支时,加上--no-ff参数就可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并,而fast forward合并就看不出来曾经做过合并。
每个bug都可以通过一个新的临时分支来修复,修复后,合并分支,然后将临时分支删除。
当你接到一个修复一个代号101的bug的任务时,很自然地,你想创建一个分支issue-101来修复它,但是,当前正在dev上进行的工作还没有提交。
并不是你不想提交,而是工作只进行到一半,还没法提交,预计完成还需1天时间。但是,必须在两个小时内修复该bug,怎么办?
幸好,Git还提供了一个stash功能,可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作:
$ git stash
Saved working directory and index state WIP on dev: f52c633 add merge
现在,用git status查看工作区,就是干净的(除非有没有被Git管理的文件),因此可以放心地创建分支来修复bug。
首先确定要在哪个分支上修复bug,假定需要在master分支上修复,就从master创建临时分支:
$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 6 commits.
(use "git push" to publish your local commits)
$ git checkout -b issue-101
Switched to a new branch 'issue-101'
现在修复bug,修复完成后,切换到master分支,并完成合并,最后删除issue-101分支:
$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 6 commits.
(use "git push" to publish your local commits)
$ git merge --no-ff -m "merged bug fix 101"issue-101
Merge made by the 'recursive' strategy.
readme.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
现在,回到dev分支干活!
用git stash list命令看看:
$ git stash list
stash@{0}: WIP on dev: f52c633 add merge
工作现场还在,Git把stash内容存在某个地方了,但是需要恢复一下,有两个办法:
① 用git stash apply恢复,但是恢复后,stash内容并不删除,你需要用git stash drop来删除;
② 用git stash pop,恢复的同时把stash内容也删了:
$ git stash pop
On branch dev Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: hello.py
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
Dropped refs/stash@{0} (5d677e2ee266f39ea296182fb2354265b91b3b2a)
再用git stash list查看,就看不到任何stash内容了:
$ git stash list
你可以多次stash,恢复的时候,先用git stash list查看,然后恢复指定的stash,用命令:
$ git stash apply stash@{0}
小结
修复bug时,我们会通过创建新的bug分支进行修复,然后合并,最后删除;
当手头工作没有完成时,先把工作现场git stash一下,然后去修复bug,修复后,再git stash pop,回到工作现场。
使用GitHub时,国内的用户经常遇到的问题是访问速度太慢,可以使用国内的Git托管服务——码云(gitee.com)。
项目名称最好与本地库保持一致:
然后,我们在本地库上使用命令git remote add把它和码云的远程库关联:
git remote add origin git@gitee.com:wenson_luo/learngit.git
之后,就可以正常地用git push和git pull推送了!
如果在使用命令git remote add时报错:
git remote add origin git@gitee.com:liaoxuefeng/learngit.git
fatal: remote origin already exists.
这说明本地库已经关联了一个名叫origin的远程库,此时,可以先用git remote -v查看远程库信息:
git remote -v
可以看到,本地库已经关联了origin的远程库,并且,该远程库指向GitHub。
我们可以删除已有的GitHub远程库:
git remote rm origin
再关联码云的远程库(注意路径中需要填写正确的用户名):
git remote add origin git@gitee.com:liaoxuefeng/learngit.git
此时,我们再查看远程库信息:
git remote -v
现在可以看到,origin已经被关联到码云的远程库了。通过git push命令就可以把本地库推送到Gitee上。
有的小伙伴又要问了,一个本地库能不能既关联GitHub,又关联码云呢?
答案是肯定的,因为git本身是分布式版本控制系统,可以同步到另外一个远程库,当然也可以同步到另外两个远程库。
使用多个远程库时,我们要注意,git给远程库起的默认名称是origin,如果有多个远程库,我们需要用不同的名称来标识不同的远程库。
仍然以learngit本地库为例,我们先删除已关联的名为origin的远程库:
git remote rm origin
然后,先关联GitHub的远程库:
git remote add github git@github.com:WensonLuo/learngit.git
注意,远程库的名称叫github,不叫origin了。
接着,再关联码云的远程库:
git remote add gitee git@gitee.com:wensonluo/learngit.git
同样注意,远程库的名称叫gitee,不叫origin。
现在,我们用git remote -v查看远程库信息,可以看到两个远程库:
git remote -v
如果要推送到GitHub,使用命令:
git push github master
如果要推送到码云,使用命令:
git push gitee master
这样一来,我们的本地库就可以同时与多个远程库互相同步:
┌─────────┐ ┌─────────┐
│ GitHub │ │ Gitee │
└─────────┘ └─────────┘
▲ ▲
└─────┬─────┘
│
┌─────────────┐
│ Local Repo │
└─────────────┘
一整理下来发现内容还挺多,暂写这么多,其实主要用到的还是远程库,不论是 GitHub 还是 码云,对于工作来说都是必不可少需要掌握的内容。想要看到更全面的介绍内容,推荐去 廖雪峰 的网站逛逛。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。