静看光阴荏苒,借我喑哑无言
前言
此文用于记录学习git,学自廖雪峰老师的教程,有需要者可看这:Git教程
Git简介
1.Git是目前世界上最先进的分布式版本控制系统
2.CVS和SVN都是集中式的版本控制系统
3.CVS作为最早的开源而且免费的集中式版本控制系统,直到现在还有不少人在用。由于CVS自身设计的问题,会造成提交文件不完整,版本库莫名其妙损坏的情况。同样是开源而且免费的SVN修正了CVS的一些稳定性问题,是目前用得最多的集中式版本库控制系统。
初始化一个Git仓库
首先,先上一张图,方便大家记忆:
1.初始化一个Git仓库,使用git init
命令。
2.添加文件到Git仓库,分两步:
- 使用命令
git add <file>
,注意,可反复多次使用,添加多个文件 - 使用命令
git commit -m <message>
,完成。
3.git status
命令可以让我们查看仓库当前的状态
4.git diff
是查看difference,显示的格式是Unix通用的diff格式
5.git log
命令显示从最近到最远的提交日志
6.关于版本控制:
HEAD
指向的版本就是当前版本
,上一个版本就是HEAD^
,上上一个版本就是HEAD^^
,当然往上100个版本写100个^
比较容易数不过来,所以写成HEAD~100
- 因此,Git允许我们在版本的历史之间穿梭,使用命令
git reset --hard commit_id
即可。 - 穿梭前,用
git log
可以查看提交历史,以便确定要回退到哪个版本。 - 要重返未来(回退后又后悔了),用
git reflog
查看命令历史,以便确定要回到未来的哪个版本。
Git暂存区
1.Git和其他版本控制系统如SVN的一个不同之处就是有暂存区的概念。
2.关于Git的三个区:
- 工作区(Working Directory)就是在电脑里能看到的目录(即项目的目录)
- 暂存区(starge)
- 仓库分支(master)
版本库(Repository):工作区有一个隐藏目录.git
,这个不算工作区,而是Git的版本库。
Git的版本库里存了很多东西,其中最重要的就是称为stage
(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master
,以及指向master
的一个指针叫HEAD
。
3.关于git diff
和git diff --cached
区别:
1.git diff比较的是
工作目录中当前文件
和暂存区域快照
之间的差异, 也就是修改之后还没有暂存起来
的变化内容。若要查看已暂存的将要添加到下次提交里的内容,可以用git diff --cached
命令。
2.请注意,git diff
本身只显示尚未暂存的改动
,而不是自上次提交以来所做的所有改动。 所以有时候你一下子暂存了所有更新过的文件后,运行git diff
后却什么也没有,就是这个原因。
经过尝试,理解为:
git diff
比较的是工作区文件
与暂存区文件
的区别(上次git add
的内容)(因为可能有多次git add
,每次修改后没有进行git add
的内容和上次进行git add
的内容进行比较)git diff --cached
比较的是暂存区的文件
与仓库分支里
(上次git commit
后的内容)的区别
这个点引起了评论区的热烈讨论,经过自己尝试,发现上面的理解好像才是对的。
4.每次修改,如果不用git add
到暂存区,那就不会加入到commit中
5.git checkout -- file
可以丢弃工作区的修改,具体运用有:
场景1:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令
git checkout -- file
。
场景2:当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令git reset HEAD <file>
,就回到了场景1,第二步按场景1操作。
场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,参考版本回退一节,不过前提是没有推送
到远程库。
6.关于删除
- 先删除文件夹(工作目录)下的文件,然后用
git status
查看(不是必要的,如果对命令很熟的话)然后根据提示和自己的想法看是真的删除还是撤销。 - 命令git rm用于删除一个文件。如果一个文件已经被提交到版本库,那么你永远不用担心误删,但是要小心,你只能恢复文件到最新版本,你会丢失最近一次提交后你修改的内容。
远程仓库
本地仓库的内容推送到GitHub仓库
1.创建SSH Key
- 先执行以下语句来判断是否已经存在本地公钥(git中执行):
cat ~/.ssh/id_rsa.pub
- 如果你看到一长串以
ssh-rsa
或ssh-dsa
开头的字符串, 则可以跳过ssh-keygen
的步骤。否则 需要用下面的命令来生成ssh key:ssh-keygen -t rsa -C "youremail"
- 这个指令会要求提供一个位置和文件名去存放键值对和密码,可以点击Enter键去使用默认值。
- 用以下命令获取生成的公钥:
cat ~/.ssh/id_rsa.pub
或者在用户主目录的.ssh
文件夹中找到,一般在C:\Users\Administrator\
下
2.在github上创建仓库(这是在本地已经存在仓库的情况下,不可以勾选Initialize this repository with a README
,不然会出现很多错误。这样可以立即克隆这个仓库到自己电脑,但这不是我们需要的)如果本地无相应仓库,则可以勾选(下面说)。
3.根据提示,使用git remote add origin git@server-name:path/repo-name.git;
关联远程库,然后使用git push -u origin master
把本地库的所有内容推送到远程库上
注:第一次推送master分支时,加上了-u
参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。
4.此后,只要本地作了提交,可直接用git push origin master
把本地master分支的最新修改推送至GitHub,现在,就拥有了真正的分布式版本库。
5.总结:
- 要关联一个远程库,使用命令
git remote add origin git@server-name:path/repo-name.git;
- 关联后,使用命令
git push -u origin master
第一次推送master分支的所有内容 - 此后,每次本地提交后,只要有必要,就可以使用命令
git push origin master
推送最新修改
从远程库克隆
1.在github上创建仓库时,勾选Initialize this repository with a README
,这样GitHub会自动为我们创建一个README.md
文件。
2.克隆即可:使用git clone git@server-name:path/repo-name.git;
(git@开始都是直接复制即可)这样便克隆到了本地库(多个人协作开发,那么每个人各自从远程克隆一份就可以了)
3.Git支持多种协议,包括https,但通过ssh支持的原生git协议速度最快。
分支管理
使用分支:
1.查看分支:git branch
2.创建分支:git branch <name>
切换分支:git checkout <name>
或直接
创建+切换分支:git checkout -b <name>
3.合并某分支到当前分支:git merge <name>
4.删除分支:git branch -d <name>
解决冲突
1.当Git无法自动合并分支时(比如同时在两个分支上做了修改并都已经commit),就必须首先解决突。解决冲突后,再提交,合并完成。
2.解决冲突就是把Git合并失败的文件手动编辑为我们希望的内容,再提交。
3.用git log --graph
命令可以看到分支合并图。
4.合并分支时,加上--no-ff
参数就可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并,而fast forward合并就看不出来曾经做过合并。
5.命令一般为:git merge --no-ff -m "about information" dev
因为合并要创建一个新的commit,所以加上-m
参数,把commit描述写进去。
Bug分支
1.修复bug时,我们会通过创建新的bug分支
进行修复,然后合并,最后删除
2.当手头工作没有完成时,先把工作现场git stash
一下,然后去修复bug,修复后,再git stash pop
,回到工作现场。
3.回到现场也可以用git stash apply
恢复,但是恢复后,stash内容并不删除,还需要用git stash drop
来删除
Feature分支
1.每添加一个新功能,最好新建一个feature分支,在上面开发,完成后,合并,最后,删除该feature分支。
2.如果要丢弃一个没有被合并过的分支,可以通过git branch -D <name>
强行删除。
多人协作
1.多人协作的工作模式通常是这样:
- 首先,可以试图用
git push origin <branch-name>
推送自己的修改; - 如果推送失败,则因为远程分支比你的本地更新,需要先用
git pull
试图合并; - 如果合并有冲突,则解决冲突,并在本地提交;
- 没有冲突或者解决掉冲突后,再用
git push origin <branch-name>
推送就能成功! - 如果
git pull
提示no tracking information
,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream-to <branch-name> origin/<branch-name>
(出错会有提示)
2.小结
- 查看远程库信息,使用
git remote -v
; - 本地新建的分支如果不推送到远程,对其他人就是不可见的;
- 从本地推送分支,使用
git push origin branch-name
,如果推送失败,先用git pull
抓取远程的新提交; - 在本地创建和远程分支对应的分支,使用
git checkout -b branch-name origin/branch-name
,本地和远程分支的名称最好一致; - 建立本地分支和远程分支的关联,使用
git branch --set-upstream branch-name origin/branch-name
; - 从远程抓取分支,使用
git pull
,如果有冲突,要先处理冲突。
3.分支
- master分支是主分支,因此要时刻与远程同步;
- dev分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步;
- bug分支只用于在本地修复bug,就没必要推到远程了,除非老板要看看你每周到底修复了几个bug;
- feature分支是否推到远程,取决于你是否和你的小伙伴合作在上面开发。
- 更多:
Rebase
1.rebase操作可以把本地未push的分叉提交历史整理成直线;
2.rebase的目的是使得我们在查看历史提交的变化时更容易,因为分叉的提交需要三方对比。
3.关于原理,可参考这篇文章:Git Community Book 中文版
4.文中的例子:
执行(mywork和origin分别为两个分支)
1 | $ git checkout mywork |
这些命令会把你的”mywork”分支里的每个提交(commit)取消掉,并且把它们临时保存为补丁(patch)(这些补丁放到”.git/rebase”目录中), 然后把”mywork”分支更新到最新的”origin”分支,最后把保存的这些补丁应用到”mywork”分支上。
5.在rebase的过程中,也许会出现冲突(conflict). 在这种情况,Git会停止rebase并会让你去解决 冲突;在解决完冲突后,用git add
命令去更新这些内容的索引(index), 然后,你无需执行 git commit,只要执行:git rebase --continue
这样git会继续应用(apply)余下的补丁。
6.在任何时候,你可以用--abort
参数来终止rebase的行动,并且”mywork” 分支会回到rebase开始前的状态。
简而言之,就是把mywork分支提交先撤销,然后指向到最新节点,然后再提交(如果有冲突,需要手动处理,用git add
命令去更新这些内容的索引(index), 然后执行:git rebase --continue
这样git会继续应用(apply)余下的补丁)
标签管理
1.创建标签
- 命令
git tag <tagname>
用于新建一个标签,默认为HEAD,也可以指定一个commit id; - 命令
git tag -a <tagname> -m "blablabla..."
可以指定标签信息,-a
指定标签名,-m
指定说明文字 - 命令
git tag
可以查看所有标签。用命令git show <tagname>
可以看到对应的说明文字
2.命令git push origin <tagname>
可以推送一个本地标签;
3.命令git push origin --tags
可以推送全部未推送过的本地标签;
4.命令git tag -d <tagname>
可以删除一个本地标签;
5.命令git push origin :refs/tags/<tagname>
可以删除一个远程标签(得先删除本地对应标签)
自定义Git
让Git显示颜色
让命令输出看起来更醒目,使用:git config --global color.ui true
忽略文件
1.忽略某些文件时,需要编写.gitignore
。在Git工作区的根目录下创建一个特殊的.gitignore
文件,然后把要忽略的文件名填进去,Git就会自动忽略这些文件。
2.所有配置文件可以直接在线浏览:gitignore 找到自己需要的加入即可。
3.忽略文件的原则是:
- 忽略操作系统自动生成的文件,比如缩略图等
- 忽略编译生成的中间文件、可执行文件等,也就是如果一个文件是通过另一个文件自动生成的,那自动生成的文件就没必要放进版本库,比如Java编译产生的.class文件
- 忽略你自己的带有敏感信息的配置文件,比如存放口令的配置文件。
4.可以用-f
强制添加到Git,如git add -f App.class
5.若觉得规则写错了,可以用git check-ignore
命令检查。或者直接打开.gitignore
文件检查。
配置别名
1.使用alias
设置别名,如git config --global alias.st status
2.一些常用别名设置
1 | git config --global alias.st status |
3.使用git config --global --list
查看用户的配置信息,若想看当前仓库的,用git config --local --list
3.配置文件
- 配置Git的时候,加上
--global
是针对当前用户起作用的,如果不加,那只针对当前的仓库起作用。 - 每个仓库的Git配置文件都放在
.git/config
文件中 - 当前用户的Git配置文件放在用户主目录下的一个隐藏文件
.gitconfig
中
致谢
很感谢廖雪峰老师的教程。多的就不说了,强烈推荐初学者通过此教程学习。