注:本笔记全然参考廖雪峰老师的git教学网站所记,关于更详细的教程请参考廖雪峰的官方网站。
Git是一种分布式版本控制系统
版本控制系统分集中式和分布式。
集中式版本控制系统版本库存放于中央服务器,先从中央服务器取得最新版本,改动完毕后再送回中央服务器,而集中式版本控制系统的最大弊端在于联网才能工作。
分布式版本控制系统没有中央服务器,每个人都有一个完整的版本库,因此工作时无需联网。而如果两个人工作在同一个文件,可以把各自的修改部分推送给对方,即可互相知道对方做出了哪些更改。
相较于集中式版本控制系统,分布式版本控制系统安全性很高,每个人电脑都有完整的版本库,而集中式版本控制系统的中央服务器如果出现问题,后果要严重许多。其实分布式版本控制系统也有充当中央服务器的电脑,服务器的作用主要是方便大家的修改,但是没有它并不会有多大的问题
在安装完毕git之后,还需要最后的设置:
$git config --global user.name "name"
$git config --global user.email "email@example.com"版本库
版本库即为仓库,仓库的所有文件都可以被Git管理,每个文件的修改、删除都会被Git跟踪。
# 通过git init命令可以将这个目录变成git可以管理的仓库
$git init仓库中一般包含.git目录,目录默认隐藏,可以使用ls -ah命令查看。
将文件添加到版本库
所有的版本控制系统,其实只能跟踪文本文件的改动,txt、html、程序代码等。
对于文本文件,版本控制系统可以显示每次的改动细节
而图片、视频这些二进制文件,没法跟踪文件的变化只能知道文件大小的变动(Micresoft的word即为二进制文件)
将一个文件添加到git仓库只需要两步:
# 将文件添加到仓库
$git add readme.txt
# 将文件提交到仓库,-m后面是提交说明
$git commit -m "readme file"可以一次性add多个文件,然后依次commit全部提交。
如果我们提交文件后,继续修改了文件,我们可以执行git status查看结果
$git statusgit status可以查看当前仓库状态,比如修改后尚未提交的文件
$git diffgit diff可以查看到具体修改了哪些内容(difference)
版本回退
当文本文档已经被多次修改了,我们可以使用git log查看
$git loggit log可以查看从最近到最远的提交日志

如果觉得输出信息过于冗杂
# 输出日志,每个日志仅一行
$ git log --pretty=oneline
1094adb7b9b3807259d8cb349e7df1d4d6477073 (HEAD -> master) append GPL
e475afc93c209a690c39c13a46716e8fa000c366 add distributed
eaadf4e385e865d25c48e7ca9c8395c3f7dfaef0 wrote a readme file# 回退至上个版本
$git reset --hard HEAD^
# 回退至上上版本
$git reset --hard HEAD^^
# 往上一百个版本
$git reset --hard HEAD~100
# 更新至某个版本号
$git reset --hard 版本号如果忘记了想要更新至的版本号,可以使用git reflog查看每一次执行的命令
工作区和暂存区
工作区中的.git隐藏目录不算是工作区,而是git的版本库
git的版本库中最重要的便是stage的暂存区,创建的第一个分支master和指向master的指针HEAD
当执行git add命令后,文件会存放在暂存区保管等待提交。
管理修改
Git跟踪并管理的是修改,而非文件。
如果希望将初始文件和修改后的文件都提交,需要执行以下顺序
$git add readme.txt
# 修改
$git add readme.txt
$git commit -m ''撤销修改
$git checkout -- file将文件file在工作区的修改全部撤销。
1.file自修改后还没有放在暂存区,撤销修改即可以回到和版本库一样
2.file已经添加到暂存区后,又做了修改,撤销修改即回到添加到暂存区后的状态
也就是说,回到最近一次git commit或是git add时的状态。
如果是修改之后加入了暂存区,并没有提交:
$git reset HEAD readme.txt可以将暂存区的修改撤销掉,重新放回工作区。
$git checkout -- readme.txt继而执行checkout丢弃工作区的修改。
删除文件
通常我们执行删除命令
$rm readme.txt当删除文件后,工作区和版本库不一致 ,执行git status可以查看哪些文件被删除了
如果我们需要从版本库中删除文件,则
执行命令
$git rm readme.txt
$git commit -m ""版本库中文件即被删除
远程仓库
由于本地Git仓库和GitHub仓库之间的传输是通过SSH加密的,所以,需要一点设置:
1.创建SSH Key
$ ssh-keygen -t rsa -C "youremail@example.com"此时,可以在用户主目录中找到.ssh目录,里面有id_rsa和id_rsa.pub两个文件,这两个就是SSH Key的密钥对,其中,id_rsa是私钥,私钥不可泄露,id_rsa.pub是公钥。
2.在GitHub的SSH Key页面在Key文本框中粘贴id_rsa.pub文件内的内容。
添加远程仓库
# origin即为远程仓库的名字
$ git remote add origin url$git push -u origin master第一次添加远程仓库后,由于远程仓库为空需要加上-u参数
git不但会把本地的master分支内容推送到远程仓库的master分支,还会将本地master分支和远程master分支关联起来。
删除远程仓库
# 查看远程仓库信息
$ git remote -v
# 根据仓库名字删除
$git remote rm name从远程库克隆
$ git clone ssh-url创建与合并分支
在git中,有个主分支即master分支,HEAD指向当前的分支,然后当前分支指向提交。
例如当我们创建新的分支slave时,HEAD会转而指向slave,而salve指向着和master指向相同的提交。
当我们进行新的提交时,slave指针会向前移动,而master指针不变。
如果我们在slave分支上的任务完成了,想把slave合并到分支master上面,可以让master直接指向slave的当前的提交。
合并后,甚至可以删掉slave指针。
# 创建slave分支,切换到slave分支
$git checkout -b slave
# 等同于
$git branch slave
$git checkout slave# 查看当前分支
$git branch
git branch会列出所有分支,当前分支加*如果在slave上新建文件并作出提交,在master分支上不会出现,需要合并分支才可以见到。
# 将slave分支合并到master分支
$git merge slave下面就是删除分支了
$git branch -d slave实际上,切换分支使用switch更加科学:
# 创建并切换到新的分支
$git switch -c slave
# 直接切换到slave分支
$git switch slave解决冲突
当两个分支修改了同一个文件时,合并分支会发生冲突
此时执行git status可以看到冲突的文件
查看文件的内容时可以看到之间不同分支的差异,我们可以做出更改后继而上传提交。
此时执行git log命令可以查看合并情况。
Bug分支
当软件的开发出现bug时,我们可以新建一个临时分支来修复bug,修复后合并分支,然后删除临时分支。
但是,如果当前的工作还没有完成,而且工作需要一天来完成,而bug需要两小时来修复。
# git提供了stash的功能,可以存储当前的工作现场,等恢复现场后继续工作
$git stash
Saved working directory and index state WIP on dev: f52c633 add merge然后切换到需要修复bug的分支,修复bug,提交,合并分支,删除分支
继而回到工作分支继续干活。
$git stash list
stash@{0}: WIP on dev: f52c633 add merge下面有两种恢复工作现场的办法:
# 恢复工作现场后,stash内容不删除
$git stash apply stash@{0}
# 恢复工作现场的同时删除stash
$git stash pop stash@{0}此时,会想到当前工作分支是从master分支分出来的,如果master存在bug,那么当前工作分支也会存在bug。
那么,如何在当前分支修复同样的bug呢?
其实,只需要将在master上提交所做的修改复制到当前工作分支即可,我们只需要复制该提交所需要的修改。
$git cherry-pick 提交号 Feature分支
当我们对新的分支创建了新的功能。
$git switch -c feature-vulcan
Switched to a new branch 'feature-vulcan'
# 开发完毕
$git add vulcan.py
$git status
On branch feature-vulcan
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: vulcan.py
$git commit -m "add feature vulcan"
[feature-vulcan 287773e] add feature vulcan
1 file changed, 2 insertions(+)
create mode 100644 vulcan.py
# 切回主分支准备合并
$git switch dev但是此时因为某些原因,需要将新建分支删除
$git branch -d feature-vulcan
error: The branch 'feature-vulcan' is not fully merged.
If you are sure you want to delete it, run 'git branch -D feature-vulcan'.
# 强制删除
$git branch -D feature-vulcan
Deleted branch feature-vulcan (was 287773e)多人协作
# 查看远程仓库信息
$git remote
# 显示更详细的信息
$git remote -v
# 将分支上的本地提交推送到远程仓库,可以指定本地分支
$git push origin master
#master分支是主分支,因此要时刻与远程同步
#dev分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步
#bug分支只用于在本地修复bug,就没必要推到远程了,除非老板要看看你每周到底修复了几个bug
#feature分支是否推到远程,取决于你是否和你的小伙伴合作在上面开发。多人协作时,大家都会往master和dev分支上推送各自的修改。
当我们从远程仓库clone时,默认情况下,只能看到本地的master分支。
# 现在如果我们想要在dev分支开发,需要创建origin的dev分支到本地才可以
$git checkout -b dev origin/dev现在,可以在dev上继续修稿,然后将dev分支push到远程。
如果我修改了dev分支的文件,而碰巧别人对同样的文件做了修改,这时候推送,会遇到问题:
$git push origin dev
To github.com:michaelliao/learngit.git
! [rejected] dev -> dev (non-fast-forward)
error: failed to push some refs to 'git@github.com:michaelliao/learngit.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.解决方法:我们呢需要先git pull把最新的提交从origin/dev抓下来,然后本地合并,解决冲突,再推送。
$ 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的链接
$git branch --set-upstream-to=origin/dev dev
Branch 'dev' set up to track remote branch 'dev' from 'origin'.然后再git pull,合并,解决冲突即可。
标签管理
切换到需要打标签的分支上
# 打标签
$git tag v1.0# 查看所有标签
$git tag默认来说,标签是打在最新提交的commit上,如果忘记打标签了
# 找出历史提交的commit id
$git log --pretty=oneline --abbrev-commit
# 打标签
$git tag v0.9 f52c633
# 打带说明的标签,-a指定标签名,-m指定说明文字
$git tag -a v1.0 -m "说明"
# 查看标签信息
$git show <tagname>
# 创建的标签都只存储在本地,不会自动推送到远程。
# 删除标签
$git tag -d <tagname>
# 将标签推送至远程仓库
$git push <remote name> <tagname>
# 推送所有的尚未推送的本地标签
$git push <remote name> --tags
# 删除远程标签
$git tag -d <tagname>
$git push origin :refs/tags/<tagname>自定义Git
# 让Git显示颜色,会让命令输出看起来更醒目
$git config --global color.ui true忽略特殊文件
如果在git工作目录中存在必须存在,又无需提交的配置文件。
可以在git的工作区根目录下创建.gitignore文件,将要忽略的文件名填进去,git会自动忽略这些文件。
忽略文件的原则:
1.系统自动生成的文件,如缩略图等
2.编译生成中间文件
3.带有敏感信息的配置文件
# 排除所有.开头的隐藏文件:
.*
# 排除所有.class文件:
*.class
# 不排除.gitignore和App.class:
!.gitignore
!App.class配置别名
# commit设为别名cm
$git config --global alias.cm commit
# 撤销暂存区修改:git reset HEAD file(两个字段用单引号连接)
$git config --global alias.unstage 'reset HEAD'其中,配置文件
每个仓库的git配置都放在.git/config文件中。
当前用户的git配置文件放在用户主目录下的.gitconfig文件中。
搭建Git服务器
GitHub就是一个免费托管开源代码的远程仓库。但是对于某些视源代码如生命的商业公司来说,既不想公开源代码,又舍不得给GitHub交保护费,那就只能自己搭建一台Git服务器作为私有仓库使用。
搭建Git服务器需要准备一台运行Linux的机器,强烈推荐用Ubuntu或Debian,这样,通过几条简单的apt命令就可以完成安装。
# 安装git
$sudo apt-get install git
# 创建git用户,用来运行git服务
$sudo adduser git
# 创建证书登录
# 收集需要登录的用户的公钥,即id_rsa.pub文件,将所有公钥导入/home/git/authorized_keys
# 初始化git仓库,选定目录作为git仓库,假定是/src/sample.git,在/src目录下输入
$sudo git init --bare sample.git
# 此时git会创建裸仓库,裸仓库没有工作区,因为服务器上的git仓库纯粹为了共享,所以不让用户直接登录到
# 服务器上改工作,并且服务器上的git仓库通常以.git结尾,把owner改为git:
$sudo chown -R git:git sample.git
# 禁用shell登录
# 出于安全考虑,第二步创建的git用户不允许登录shell,这可以通过编辑/etc/passwd文件完成
# 将
git:x:1001:1001:,,,:/home/git:/bin/bash
# 改为
git:x:1001:1001:,,,:/home/git:/usr/bin/git-shell
# 这样,git用户可以正常通过ssh使用git,但无法登录shell,因为我们为git用户指定的git-shell每次一 # 登陆自动退出
# 克隆远程仓库
$git clone url