git学习笔记
声明
本文是本人学习Git过程中所做的笔记,以便日后查阅,文中多有错漏之处,不建议用作学习材料,文章内容来自网络,如需学习请移步原文:
Git诞生
2002年BitMover授权Linux社区免费使用BitKeeper版本控制系统
2005年有人试图破解BitKeeper的协议导致BitMover要收回Linux社区的使用权限
Linus花费两周时间使用C语言写了一个分布式版本控制系统,即git
集中式&分布式
什么是集中式版本控制系统
- 集中式版本控制系统的版本库统一存放在中央服务器,每次编程时都要先从中央服务器取得最新版本,完成后再把自己的版本推送给服务器
- 缺陷:需要联网才能工作
分布式版本控制系统(distributed version control system)
-
分布式版本控制系统没有中央服务器,每台电脑都是一个完整的版本库,可以通过推送获取最新版本
-
优点:
- 没有中央服务器,不需要联网
通常分布式版本控制系统中有一台充当服务器的电脑,方便交换大家的修改
- 安全性高:每个人的电脑都是版本库
- Git的分支管理功能强大(branch)
安装git
git命令可以查看系统有没有安装git
$ git
usage: git [--version] [--help] [-C <path>] [-c name=value]
[--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
[-p | --paginate | --no-pager] [--no-replace-objects] [--bare]
[--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
<command> [<args>]
Linux系统安装
- Linux 使用命令即可直接安装
sudo apt-get install git
Windows上安装git
- Windows上安装git需要通过模拟Linux运行环境来完成,这里直接使用msysgit下载地址
至此Git的安装已经完成,下面是Git的学习阶段
Git学习-版本库
-
什么是版本库
版本库(Repository)又名仓库,仓库里的文件都可以由git管理起来,git会对每个文件的修改删除进行跟踪,一遍将来的某个时刻可以还原 -
创建版本库
创建版本库只需要创建一个文件夹然后通知Git讲次文件夹作为仓库管理$ mkdir gitlearn $ cd gitlearn $ pwd /c/Users/lc/learngit //创建git文件夹 $ git init Initialized empty Git repository in C:/Users/lc/learngit/.git/
-
版本控制系统只能跟踪文本的改动,不能跟踪文本的内容,Microsoft Word的格式是二进制的,版本控制系统无法跟踪改动
Git学习-版本提交
- 版本提交分为两步
- 用
git add <file>
命令把文件添加到暂存区 - 用
git commit
命令告知Git,将文件提交到仓库
$ git commit -m "wrote a readme file"
//-m 命令是对本次提交的说明,输入本次提交的内容
- 用
Git学习-时空穿梭
git status
命令可以查看是否有文件被修改过
git status 主要用于查看仓库当前状态,比如哪些文件被修改,是否准备提交
git diff
可以查看修改的内容
只限于文件被添加到暂存区之前,一旦执行了
git add
命令,git diff
就不能查看更改了
git diff 常用的命令
HEAD commit版本
Index staged版本
git diff//比较工作目录和暂存区快照之间的差异
//即修改单还没有暂存的内容
git diff --cached
git diff --staged
//未发现区别
git diff HEAD
//显示工作版本(work tree)和HEAD之间的查表
git diff topic master
git diff topic..master
//显示两个分支最新提交的区别
git diff HEAD^ HEAD
//显示上次提交commit和上上次提交之间的差别
git add
的各种区别
git add -A // 添加所有改动
git add * // 添加新建文件和修改,但是不包括删除
git add . // 添加新建文件和修改,但是不包括删除
git add -u // 添加修改和删除,但是不包括新建文件
在commit前撤销add:
git reset <file> // 撤销提交单独文件
git reset // unstage all due changes
add/commit前撤销对文件的修改:
git checkout -- README.md // 注意, add添加后(同commit提交后)就无法通过这种方式撤销修改
Git学习-版本回退
查看历史记录:
$ git log
//长串的编码是commit id(版本号)
commit 75d2bf408c157c0b5c9255f81a6dd7116670f1cb
Author: Shenglong <liushenglong@wemarklinks.com>
Date: Tue Jun 27 11:45:28 2017 +0800
2.0 version
commit 2b9e2e1c667378bf00662c173d70581724d53bd0
Author: Shenglong <liushenglong@wemarklinks.com>
Date: Tue Jun 27 11:13:53 2017 +0800
find some Syntax Error
commit b193cdc3b9951c23279d45e04aed326ec3a866c5
Author: Shenglong <liushenglong@wemarklinks.com>
Date: Tue Jun 27 09:52:12 2017 +0800
test git
Git中 HEAD表示当前版本,HEAD表示上一个版本,HEAD^ 表示上上个版本
HEAD~100表示向上100个版本
版本回退git reset
$ git reset --hard HEAD^
HEAD is now at 2b9e2e1 find some Syntax Error
//已经回退到上一个版本
再来查看版本库的状态
$ git log
commit 2b9e2e1c667378bf00662c173d70581724d53bd0
Author: Shenglong <liushenglong@wemarklinks.com>
Date: Tue Jun 27 11:13:53 2017 +0800
find some Syntax Error
commit b193cdc3b9951c23279d45e04aed326ec3a866c5
Author: Shenglong <liushenglong@wemarklinks.com>
Date: Tue Jun 27 09:52:12 2017 +0800
test git
回退了一个版本,可以通过之前的版本id恢复版本或者继续回退
$ git reset --hard 75d2bf408c
查看readme.txt内容
$ cat readme.txt
git is a distributed version control System
i'm alittle confuse about how this worked
git is free software
版本回退的原理:Git内部有一个指向当前版本的HEAD指针,回退版本的时候git仅仅是把指针前移了一位
后悔药:git reflog
,回退一个版本之后如果想退回原来的版本必须使用之前版本的commit id,然后使用git reset --hard commit id
即可返回最新提交的版本
Git学习-工作区与暂存区
工作区(Working Directory)工作目录
版本库(Repository)工作区有一个隐藏目录,版本库中包含stage(暂存区也可以称为Index),以及Git创建的第一个分支master,以及指向master的一个指针HEAD
Git学习-管理修改
git commit
的作用是将暂存区中的修改应用到版本库中,未提交到暂存区的修改不会保存
git diff HEAD --readme.txt
可以查看工作区里和版本库里最新版本的区别
Git学习-撤销修改
在修改未被提交到工作区之前可以使用git checkout -- <file>
命令丢弃工作区的修改
exam:
$ cat readme.txt
git is a distributed version control System
i'm alittle confuse about how this worked
git is free software
git is full of fun!
wrong message(i don't wanna this to be commit)
//我在这里犯了个错误,但是修改还没有被提交到暂存区
//于是..
$ git checkout -- readme.txt
//这里看起来什么都没有发生
$ cat readme.txt
git is a distributed version control System
i'm alittle confuse about how this worked
git is free software
git is full of fun!
//但是我错误的修改已经被丢弃了
如果修改被提交到暂存区,可以使用git reset
丢弃暂存区的记录回到上一步,然后丢弃工作区的记录即可
Git学习-删除文件
如果不小心删除了工作区的文件,git status
查看时git 会告诉你哪些文件被删除了
$ git status
On branch master
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
deleted: test.txt
no changes added to commit (use "git add" and/or "git commit -a")
此时有两个选择:
-
从版本库中删除改文件
$ git rm test.txt rm test.txt $ git commit $ git commit [master 502080a] test.txt has been removed 1 file changed, 1 deletion(-) delete mode 100644 test.txt //此时版本库和文件系统中都没有test.txt了
-
git checkout -- <file>
如果误删了文件可以使用这个命令,用版本库中的版本替换工作区中的版本
> `git checkout`命令本质是从版本去检出版本替换掉工作区的版本,虽然可以将文件恢复到最新版本,但是会丢失最近修改的内容
远程仓库
准备工作
-
创建SSH Key
$ ssh-keygen -t rsa -C "email@url.com" Your identification has been saved in /c/Users/lc/.ssh/id_rsa. Your public key has been saved in /c/Users/lc/.ssh/id_rsa.pub. The key fingerprint is: SHA256:R0Qr3PkLDR7RD4Xrn1pUWrzo+TpA+tusnr0eMYT3qB4 liushenglong@wemarklinks.com The key's randomart image is: +---[RSA 2048]----+ | .+. o. | | . o += . | | o B. * +| | + *+ =+.| | S *.o=oo | | o o+o+ | | .Eo=.. | | ..*o= | | .*=O+. | +----[SHA256]-----+
-
登录GitHub(Gitlab),进入Account setting,"SSH Key"页面,在Add SSH Key中填入id_rsa.pub中的内容
添加远程库
-
在git上创建库 new Repository
-
在本地添加远程库
$ git remote add origin https://GitHub.com/Sakura3754/learngit.git //把本地库推送到远程库上 $ git push -u origin master //第一次向远程库推送时使用了-u参数.Git不但把本地的master分支推送到远程新的master分支,还会把本地的master分支和远程的master分支关联起来
提交完成
- 从现在起,只要本地做了提交就可以通过
git push origin master
提交到远程库
从远程库克隆
git clone git@github.com:Sakura3754/gitskills.git
分支管理
分支就是科幻电影里面的平行宇宙,当你正在电脑前努力学习Git的时候,另一个你正在另一个平行宇宙里努力学习SVN。
创建与合并分支
每次提交,git将操作记录串成一条时间线,这条时间线是一个分支,在git里这个分支叫主分支,即master分支.严格来说HEAD不是指向commit,而是指向master,master才是指向commit的
1.png当我们创建分支,例如dev
时,Git新建一个指针叫dev
,指向master
相同的提交,再把HEAD
指向dev
就表示当前分支在dev上
从现在开始,对工作区的修改和提交就是针对dev分支了,比如新提交一次后,dev
指针往前移动一步,master
指针不变
合并分支:将master
指向dev当前的提交就完成了分支的合并
删除分支就是把指针删除掉
实战:
-
创建分支
$ git checkout -b dev//-b 表示创建并切换
Switched to a new branch 'dev'
//上面的命令等价于
git branch dev//创建分支
git checkout dev//切换分支 -
git branch
查看当前分支
- 创建分支`git branch dev`
- 切换分支`git checkout dev`
- 创建并切换分支`git checkout -b dev`
- 查看当前分支`git branch`
- 合并分支到当前分支`git merge dev`
- 删除分支`git branch -d dev`
- 合并冲突时必须手动解决之后再提交
分支管理
- 如果使用Fast forword 模式合并分支,删除分支后会丢掉分支信息,可以使用
--no-ff
参数禁用fast forword
模式
> 使用no-ff模式提交时,由于master不能直接将指针指向dev分支的最新提交,所以master分支只能独立进行一次提交操作,因此有内容一样,但是commit id不同的问题
- 分支管理原则:
* `master`分支应该是非常稳定的,仅用来发布新版本,不能在上面干活
* 所有的操作都在`dev`分支上进行
* 团队成员都在dev上干活,每个人有自己的分支,时不时往`dev`上合并就可以了
BUG分支
- 用临时分支来修复bug时,可以将当前分支未提交的内容储存到stash中,等bug修复完成后继续操作
-
git stash
保存当前工作进度 -
git stash list
读取保存的进度列表 -
git stash apply
将保存的进度恢复到工作区但是保留stash中的存档 -
git stash drop
删除保存的stash -
git stash pop
取出存档,同时删除stash -
git apply stash@{0}
恢复指定的stash
-
Feature分支
- 在添加一个新功能之前,为了防止实验代码影响主分支内容可以创建一个
feature
分支,在上面开发完成后合并 - 丢弃一个没有被合并过的分支可以通过
git branch -D
强行删除
多人协作
-
查看远程库的信息
- git remote
- git remote -v查看更加详细的信息
-
分支推送
- git push origin dev
-
master
分支时主分支,因此要随时与远程库同步 -
dev
时开发分支,所有成员在上面工作,所以也需要同步 - bug分支无需推送
- feature 是否推送取决于是否有多人协同开发
-
抓取分支
-
从远程库克隆时,只能看到远程库的master分支,如果要在dev分支上开发,就必须创建远程的dev分支到本地
$ git checkout -b dev origin/dev $ git pull <remote> <branch>
-
在
dev
上修改并时不时推送到远程$ git push origin dev
-
如果碰巧别人也
push
了对同样文件的修改,则会发生冲突导致提交失败,这是可以用git pull//如果提示no tracking information,说明本地分支尚未与远程分支建立连接 //指定本地dev分支与远程origin分支的链接 $ git branch --set-upstream dev origin/dev $ git pull //手动解决冲突之后commit,push $ git commit $ git push origin dev
-
标签管理
创建标签
-
创建一个标签,总共分三步
- 切换到需要打标签的分支
git checkout <name>
- 打标签
git tag <tagname>
- 查看标签
git tag
git show <tagname>
查看标签信息 - 切换到需要打标签的分支
-
给一个只有id 的commit打标签
-
git log --pretty=oneline --abbrev-commit
找到历史提交的commit id - 打标签
git tag <tagname> <commitid>
-
-
git tag -a <tagname> -m <message> <commitid>
创建带有说明的标签,-a
指定标签名,-m
添加说明文字 -
-s命令可以用PGP签名标签
操作标签
- 删除标签
git tag -d <tagname>
- 推送标签到远程
git push origin <tagname>
- 一次推送全部标签
git push origin --tags
- 删除远程标签
- 先删除本地标签
git tag -d <tagname>
- 然后从远程删除
- 先删除本地标签
自定义Git
忽略指定文件
- 在
.gitignore
文件中配置需要忽略的文件名,可以使用正则 - 把
.gitignore
文件提交到版本库 - 检验
.gitignore
是否生效的标准是git status
命令提示working directory clean
配置别名
-
使用
git config --global alias.<alias> <order>
为命令指定别名 -
花哨的小技巧
//修改git log的字体样式 git config --global alias.log "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
补充
Git clone
-
用法
git clone (-o 主机名) <url> <localdir>
-
git clone 支持多种协议
$ git clone http[s]://example.com/path/to/repo.git/ $ git clone ssh://example.com/path/to/repo.git/ $ git clone git://example.com/path/to/repo.git/ $ git clone /opt/git/project.git $ git clone file:///opt/git/project.git $ git clone ftp[s]://example.com/path/to/repo.git/ $ git clone rsync://example.com/path/to/repo.git/
remote补充
$ git remote show <主机名>
//查看主机信息
$ git remote add <主机名> <网址>
//添加主机
$ git remote rm <主机名>
//删除主机
$ git remote rename <原主机名> <新主机名>
//远程主机改名
git fetch
-
git fetch
通常用于将远程主机的更新(commit)取回本地$ git fetch <远程主机名> //将远程主机上所有分支取回本地 $ git fetch <远程主机名> <分支名> //将指定分支取回本地
-
git fetch
取回的更新要用"远程主机名/分支名"的形式读取 -
git branch -r
查看远程分支 -
git branch -a
查看所有分支 -
取回远程分支后
//可以在远程分支的基础上创建一个新的分支 $ git checkout -b newbranch //也可以在本地分支上合并远程分支 $ git merge origin/master $ git rebase origin/master
-
git pull/push
$ git pull <远程主机名> <远程分支>:<本地分支> $ git pull <远程主机名> <本地分支>:<远程分支> //手动建立本地分支与远程分支的追踪关系 $ git branch --set-upstream <本地分支> <远程主机/远程分支>
-
git push
的特殊用法//省略远程分支,默认推送到与之有"追踪关系"的远程分支 $ git push origin master //向远程推送空分支相当于删除origin主机上的对应分支 $ git push origin :master #等同于 $ git push origin --delete master # 如果当前分支与多个远程主机关联可以使用`-u`指定默认远程分支 $ git push -u origin master
网友评论