2019/12/11更新
git config --system --unset credential.helper 重新输入账号密码
credential: 证明,证件
2019/8/9更新:git rebase ,git cherry-pick
- interactive 交互
https://www.jianshu.com/p/da7d42139012
(一) 简介
Git是目前世界上最先进的分布式版本控制系统(没有之一)。
(1) 集中式和分布式
集中式版本控制系统:
集中式版本控制系统,版本库是集中存放在中央服务器的
集中式版本控制系统最大的毛病就是必须联网才能工作分布式版本控制系统 :
分布式版本控制系统根本没有“中央服务器”
分布式版本控制系统的安全性要高很多,比如服务器挂了,不容任何影响
(2) 安装
(1) 官网下载https://git-scm.com/download/win
(2) 在命令行输入
$ git config --global user.name "Your Name"
$ git config --global user.email "[email protected]"
------------------------
注意git config命令的--global参数,表示你这台机器上所有的Git仓库都会使用这个配置
当然也可以对某个仓库指定不同的用户名和Email地址。
(3) 配置好用户名和邮箱后,可以通过 git config --list
来查看所有配置
(3) 创建版本库
(1) 什么是版本库:
- 版本库又名仓库,英文名repository,你可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。
- repository是仓库的意思
(2) 创建一个版本库:
(1) 创建文件夹
$ mkdir aa
$ cd aa
$ pwd
// mkdir: 创建文件夹 ( make )
// rmdir: 删除文件夹 ( remove )
// touch filename: 在工作区添加文件 ( 比如:touch one.txt )
// rm filename: 在工作区删除文件 ( 比如:rm one.txt )
// cd: 进入文件夹 ( change )
// pwd: 用于显示当前目录
// pwd是print working directory的缩写
如果你使用Windows系统,为了避免遇到各种莫名其妙的问题,请确保目录名(包括父目录)不包含中文。
(2) 通过 git init 命令把这个目录变成Git可以管理的仓库
- 执行 git init 后,可以发现当前目录下多了一个.git的目录,这个目录是Git来跟踪管理版本库的,没事千万不要手动修改这个目录里面的文件
- 如果 .git 目录被隐藏了,可以通过
ls -ah
(ls-a ls-ah) 命令来查看 - ls -a 显示所有的文件,包括隐藏文件(以.开头的文件) -a 是 all 的意思
$ git init
ls :是list的意思
a :是all的意思
ls : 只显示非隐藏的文件夹。
ls -a : 显示所有文件和文件夹,包括隐藏文件和文件夹
ls -al:显示所有文件和文件夹,包括隐藏文件和文件夹,并显示大小,属组,创建时间等详细信息
(3) 把文件放入git仓库
- (1) 在git仓库中新建文件,或者复制过来
- (2) 用命令 git add 告诉Git,把文件添加到仓库暂存区
- (3) 用命令 git commit 告诉Git,把文件提交到仓库,把暂存区的所有内容提交到当前分支
$ git add readme.txt
$ git commit -m "xxxx"
--------------------------------
git commit命令,-m后面输入的是本次提交的说明
- 为什么Git添加文件需要add,commit一共两步呢?因为commit可以一次提交很多文件,所以你可以多次add不同的文件,比如:
$ git add file1.txt
$ git add file2.txt file3.txt
$ git commit -m "add 3 files."
--------------------------
$ git add * 添加所有文件到仓库
(4) 仓库状态
git status命令可以让我们时刻掌握 -- 仓库当前的状态
git diff 命令可以让我们时刻掌握 -- 具体修改了什么内容
( diff是 difference 的缩写 )
( modified 是修改的意思 )
( untracked 未被追踪 )
(5) git diff 用于比较两次修改的差异
- 比较工作区与暂存区
git diff 不加参数即默认比较工作区与暂存区
- 比较工作区与当前分支
git diff HEAD -- 工作区的文件名
例如: git diff HEAD -- one.txt // 比较 工作区的one.txt 和 当前分支中的 one.txt
(6) 提交修改
提交修改和提交新文件是一样的两步,第一步是git add,再运行git status看看当前仓库的状态,第二步是 git commit,再运行git status看看当前仓库的状态
小结:
要随时掌握工作区的状态,使用git status命令。
如果git status告诉你有文件被修改过,用git diff可以查看修改内容。
(7) git log
git log ---- 查看git的commit信息,每次提交的信息包括注视在内,从最新提交到最久提交
- git log --pretty=oneline 命令-------------- // 将commit 信息简化成一行显示
- git log --graph命令可以看到分支合并图。 -------------( graph是图表的意思 )
(8) git reset 版本回退
HEAD 表示当前版本
HEAD^ 表示上一个版本
HEAD^^ 表示上上一个版本
HEAD~100 退回到相对于当前版本的上 100 个版本去
$ git reset --hard HEAD^ 返回上一个版本
或者:
$ git reset --hard ( commit id ) 返回指定版本 // id不需要写全
(9) git reflog 查看到之前的版本的commit id
git reflog 查看到之前的版本的commit id
- 关闭窗口后,仍然有效
- 在退回到旧版本之后可以查看旧版本之前的提交日志
- 当我们想从一个旧版本退回到新版本但是我们关闭了shell窗口,不能查看之前的commit id了,就可以通过 $ git reflog 查看到之前的版本的commit id
总结:
HEAD指向的版本就是当前版本,因此,Git允许我们在版本的历史之间穿梭,使用命令git reset --hard commit_id。
穿梭前,用git log可以查看提交历史,以便确定要回退到哪个版本。
要重返未来,用 git reflog 查看命令历史,以便确定要回到未来的哪个版本。
(10) cat命令 ----用于读取文件的内容并进行输出
- cat 是concatenate 的缩写,链接的意思
$ cat readme.txt // 读取readme.txt文件的内容,并输出到命令行
(11) 工作区和暂存区
Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD。
git版本库中有很多东西,最重要的是下面三个:
- 暂存区 stage
- 第一个分支 master
- 指向master分支的指针 HEAD
git add把文件添加进去,实际上就是把文件修改添加到暂存区;
git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支。
- cmd命令 创建文件one.txt 并写入内容 one content
(1) 新建文件one.txt
> one.txt
(2) 新建文件one.txt 并且 写入内容 “one content”
echo one content > one.txt
- touch命令 在工作区新建文件
touch one.txt
(12) 管理修改
Git管理的是修改,当你用git add命令后,在工作区的第一次修改被放入暂存区,准备提交,但是,在工作区的第二次修改并没有放入暂存区,所以,git commit只负责把暂存区的修改提交了,也就是第一次的修改被提交了,第二次的修改不会被提交。
- 每次修改,如果不add到暂存区,那就不会加入到commit中。
(13) 撤销修改
git checkout -- filename 撤销工作区的修改
git checkout -- filename 的作用是把filename文件在工作区的修改撤销到最近一次git add 或 git commit时的内容
一种是readme.txt自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;
一种是readme.txt已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。
checkout是校验的意思
git checkout -- file命令中的--很重要,没有--,就变成了“切换到另一个分支”的命令
总之,就是让这个文件回到最近一次git commit或git add时的状态。
git reset HEAD filename 撤销暂存区的修改,重新放回工作区
总结:
场景1:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令`git checkout -- filename`。
场景2:当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,
第一步用命令`git reset HEAD filename`,就回到了场景1,
第二步按场景1操作。
场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交。
git reset HEAD^
(14) 删除文件
rm filename 删除工作区文件
git rm filename 删除版本库中的文件
- (1) rm filename 删除工作区的 文件
- (2) 然后 git status 会提示工作区文件被删除
- 接下来
- (3) 如果要从版本库中删除该文件,那就用命令git rm删掉,并且git commit
- (4) 如果要还原工作区删除前的状态 git checkout -- filename 还原到git add 或者 git commit最近一次的状态
(二) 远程仓库
--- 托管远程仓库 github
由于你的本地Git仓库和GitHub仓库之间的传输是通过SSH加密的,所以,需要一点设置
第1步:创建SSH Key。
在用户主目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsa和id_rsa.pub这两个文件,如果已经有了,可直接跳到下一步。如果没有,打开Shell(Windows下打开Git Bash),创建SSH K
$ssh-keygen -t rsa -C "[email protected]"
-
$ssh-keygen -t rsa -C "[email protected]" -f ~/.ssh/filename
生成多个ssh-key
用 Git Bash 输入以下命令:
---
$ ssh-keygen -t rsa -C "[email protected]"
---
---
如果需要创建多个ssh key 的话
$ssh-keygen -t rsa -C '[email protected]' -f ~/.ssh/filename
// ( !!!!不加-f filename就会覆盖 )
---
-t 指定密钥类型,默认是 rsa ,可以省略。
-C 设置注释文字,比如邮箱。
-f 指定密钥文件存储文件名。
你需要把邮件地址换成你自己的邮件地址,然后一路回车,使用默认值即可,
由于这个Key也不是用于军事目的,所以也无需设置密码
ssh-keygen 用于为 ssh(1) 生成、管理和转换认证密钥,包括 RSA 和 DSA 两种密钥。
- 如果一切顺利的话,可以在用户主目录里找到.ssh目录,里面有id_rsa和id_rsa.pub两个文件,这两个就是SSH Key的秘钥对,
- id_rsa是私钥,不能泄露出去,
- id_rsa.pub是公钥,可以放心地告诉任何人。
第2步:登陆GitHub
- 打开“Account settings”,“SSSH and GPG keys”页面:
- 然后,点“New SSH key”,填上任意Title,在Key文本框里粘贴id_rsa.pub文件的内容:
- 点“Add SSH Key”,你就应该看到已经添加的Key:
为什么GitHub需要SSH Key呢?因为GitHub需要识别出你推送的提交确实是你推送的,而不是别人冒充的,而Git支持SSH协议,所以,GitHub只要知道了你的公钥,就可以确认只有你自己才能推送。
当然,GitHub允许你添加多个Key。假定你有若干电脑,你一会儿在公司提交,一会儿在家里提交,只要把每台电脑的Key都添加到GitHub,就可以在每台电脑上往GitHub推送了。
http://blog.csdn.net/binyao02123202/article/details/20130891
(三) 添加远程库
现在的情景是,你已经在本地创建了一个Git仓库后,又想在GitHub创建一个Git仓库,并且让这两个仓库进行远程同步,这样,GitHub上的仓库既可以作为备份,又可以让其他人通过该仓库来协作
第一步:点击+号,new repository 新建仓库
第二步:填写 repository 仓库名称,和描述
第三步:执行以下代码
git remote add origin https://github.com/woow-wu/git.git
第四布:把本地库的所有内容推送到远程库上:
git push -u origin master
// git push -u origin master
// 表示把本地的master分支推送到origin主机master分支,同时指定origin为默认主机
// -u选项会指定一个默认主机,这样后面就可以不加任何参数使用git push。
由于远程库是空的,我们第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。
$ git push -u origin master 上面命令将本地的master分支推送到origin主机,同时指定origin为默认主机,后面就可以不加任何参数使用git push了。
不带任何参数的git push,默认只推送当前分支,这叫做simple方式。此外,还有一种matching方式,会推送所有有对应的远程分支的本地分支。Git 2.0版本之前,默认采用matching方法,现在改为默认采用simple方式。
git push origin 分支名 ------ 将该分支推送到github
git push origin --delete 分支名 ------ 删除远程分支
git branch -d 分支名 ------ 删除本地当前分支xxx
git remote add origin ......... // 添加远程库origin
git remote rm origin // 删除已有的GitHub远程库
git push origin 分支名 ------ 将该分支推送到 github 的 origin仓库 的 xx分支
--------------------------------------------------
git push origin --delete 分支名 ------ 删除远程分支
git push origin :分支名 ------ 删除github远程分支
(这种方法是推送一个空分支到远程,其实就相当于删除远程分支)
--------------------------------------------------
git branch -a ------ 查看本地和远程分支,远程分支用红色表示
git push
git push 命令:把本地库的内容推送到远程,实际上是把当前分支master推送到远程。
-u
- -u选项会指定一个默认主机,这样后面就可以不加任何参数使用git push。
(四) 从远程库克隆
git clone
要克隆一个仓库,首先必须知道仓库的地址,然后使用git clone命令克隆。
Git支持多种协议,包括https,但通过ssh支持的原生git协议速度最快。
git clone https://github.com/woow-wu/git3.git
分支管理
分支的作用
你创建了一个属于你自己的分支,别人看不到,还继续在原来的分支上正常工作,而你在自己的分支上干活,想提交就提交,直到开发完毕后,再一次性合并到原来的分支上,这样,既安全,又不影响别人工作。
主分支
每次提交,Git都把它们串成一条时间线,这条时间线就是一个分支。截止到目前,只有一条时间线,在Git里,这个分支叫主分支,即master分支。HEAD严格来说不是指向提交,而是指向master,master才是指向提交的,所以,HEAD指向的就是当前分支。
- HEAD指向当前分支
- master分支 是 主分支
创建分支
(1) git chechout -b 分支名 ------------创建 并 切换 分支
- git checkout
git checkout -b 分支名
// git checkout -b dev
- -b参数 表示创建并切换,相当于下面两条命令
$ git branch dev
$ git checkout dev
(2) git branch ------------查看本地分支
git branch ---------- 查看本地分支
git branch -r ------- 查看远程分支
git branch -a ------- 查看本地和远程分支所有分支 (远程分支用红色标记,本地当前分支用绿色标记 )
git branch命令查看当前分支
- git branch命令会列出所有分支,当前分支前面会标一个*号。
(3) git branch 分支名 ------------创建分支
- (1) 用
git branch 新分支名
时,需要在本地有commit时,才会成功 - (2) 用
git checkout -b 新分支名
时,本地没有commit时,也会成功
(4) git branch -d 分支名 ------------删除本地分支
(5) git branch -D 分支名------------强行删除分支
(6) git checkout 分支名 ------------切换分支
(7) git merge 指定分支名 ------------合并指定分支到当前分支
- merge 是融入,合并的意思
- Fast-forward信息,Git告诉我们,这次合并是“快进模式”,也就是直接把master指向dev的当前提交,所以合并速度非常快。
查看分支:git branch
创建分支:git branch
切换分支:git checkout
创建+切换分支:git checkout -b
合并某分支到当前分支:git merge
删除分支:git branch -d
https://blog.zengrong.net/post/1746.html
解决冲突
当Git无法自动合并分支时,就必须首先解决冲突。解决冲突后,再提交,合并完成。
用git log --graph命令可以看到分支合并图。
- graph 是图表的意思
分支管理策略
git merge --no-ff -m "merge with no-ff" dev
git merge --no-ff -m "merge with no-ff" dev : 表示将目标分支 dev 合并到 当前分支上,并强制禁用 Fast forward模式,并且提交 commit ,提交说明是 “merge with no-ff”
- 请注意--no-ff参数,表示禁用Fast forward
- 为什么要禁用 Fash forward : 因为Fast forward模式下,删除分支后,会丢掉分支信息
- 合并分支时,加上--no-ff参数就可以用普通模式合并, 合并后的历史有分支,能看出来曾经做过合并,而fast forward合并就看不出来曾经做过合并。
- 如果要强制禁用Fast forward模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息
- 因为本次合并要创建一个新的commit,所以加上-m参数,把commit描述写进去。
git log --graph --pretty=oneline --abbrev-commit
- --graph 分支合并图
- --pretty=oneline 合并到一条信息
- -- abbrev-commit :缩写commit id,仅显示 SHA-1 的前几个字符,而非所有的 40 个字符
- abbrev 是缩写的意思
$ git merge --no-ff -m "merge with no-ff" dev
// --no--ff 表示禁用 Fast forward
// 为什么要禁用 Fash forward : 因为Fast forward模式下,删除分支后,会丢掉分支信息
// 因为本次合并要创建一个新的commit,所以加上-m参数,把commit描述写进去
---------------------------------------------
$ git log --graph --pretty=oneline --abbrev-commit
// --graph 分支合并图
// --pretty=oneline 合并到一条信息
// -- abbrev-commit :缩写commit id,仅显示 SHA-1 的前几个字符,而非所有的 40 个字符
// abbrev 是缩写的意思
在实际开发中,我们应该按照几个基本原则进行分支管理:
首先,master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;
那在哪干活呢?干活都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本;
你和你的小伙伴们每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了。
合并分支时,加上--no-ff参数就可以用普通模式合并
合并后的历史有分支,能看出来曾经做过合并,而fast forward合并就看不出来曾经做过合并。
Bug分支
git stash
Git还提供了一个stash功能,可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作
- stash 是隐藏的意思
git stash list
- 查看之前隐藏的工作现场
如何恢复之前隐藏的工作现场
(1) git stash apply---------恢复后,stash内容不删除
-----------------------------------需要用git stash drop删除
- 一是用git stash apply恢复,但是恢复后,stash内容并不删除,你需要用git stash drop来删除;
(2) git stash pop---------恢复后,stash内容也删除了
- 另一种方式是用git stash pop,恢复的同时把stash内容也删了
修复bug时,我们会通过创建新的bug分支进行修复,然后合并,最后删除;
当手头工作没有完成时,先把工作现场git stash一下,然后去修复bug,修复后,再git stash pop,回到工作现场。
Feature分支
添加一个新功能时,你肯定不希望因为一些实验性质的代码,把主分支搞乱了,所以,每添加一个新功能,最好新建一个feature分支,在上面开发,完成后,合并,最后,删除该feature分支。
git branch -D 强行删除
多人协作
git remote ------- 查看远程库的信息
git remote -v ------- 查看远程库详细信息
$ git remote -v
origin https://github.com/woow-wu/git.git (fetch)
origin https://github.com/woow-wu/git.git (push)
上面显示了可以抓取和推送的origin的地址。
如果没有推送权限,就看不到push的地址。
$ git push origin master
$ git push origin dev
master分支是主分支,因此要时刻与远程同步;
dev分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步;
bug分支只用于在本地修复bug,就没必要推到远程了,除非老板要看看你每周到底修复了几个bug;
feature分支是否推到远程,取决于你是否和你的小伙伴合作在上面开发。----------------------新功能分支
创建标签
git tag ------------ 查看所有标签
git tag ------------ 打一个新标签
git show ------------ 查看标签信息
- 还可以通过-s用私钥签名一个标签:
$ git tag -s v0.2 -m "signed version 0.2 released" fec145a
2018/3/27更
vim命令
(1) vim 文件名 ----------------- 用vim打开文件
vim b.txt // 用vim打开 b.txt 文件
(2) 打开文件后,按 a, i 或 o 进入编辑模式
会在底部命令行显示 --插入--
(3) ESC 推出编辑模式,回退到命令模式
在编辑模式下按下ESC 键,回退到命令模式
(4) 在命令模式下输入 :q 和 :wq 和 :q! 和 :w
:w 保存
:q 退出
:wq 保存并退出
:q! 不保存并退出
:w! 强行保存
2018/4/4更
git log 如何退出
q 键
在 英文状态下 按 q 键 ----------- 可以退出 git log 显示的 commit 记录
git log --pretty=oneline // 精简模式
git log -n // 只显示前 n 条 commit log
git log --stat -n // 显示前 n 条 commit log,并显示每次提交文件的相关数据统计
git log --graph // 用图形显示log,可以看到分支合并情况
git log --pretty=format:"%an %.." // 控制显示的记录格式
选项 说明
%H 提交对象(commit)的完整哈希字串
%h 提交对象的简短哈希字串
%T 树对象(tree)的完整哈希字串
%t 树对象的简短哈希字串
%P 父对象(parent)的完整哈希字串
%p 父对象的简短哈希字串
%an 作者(author)的名字
%ae 作者的电子邮件地址
%ad 作者修订日期(可以用 -date= 选项定制格式)
%ar 作者修订日期,按多久以前的方式显示
%cn 提交者(committer)的名字
%ce 提交者的电子邮件地址
%cd 提交日期
%cr 提交日期,按多久以前的方式显示
%s 提交说明
命令可以组合使用
git log --graph
git log -n
git log --pretty=oneline
git log --graph --pretty=oneline -3
git log --graph --pretty=oneline -3 --abbrev-commit ( abbrev是缩写的意思 )
版本回退
每次( commit )的记录可以通过 ( git log ) 查看
通过 commit id 就可以回退版本 ------> 工作区的文件就能和某次提交commit文件时的文件一致
git reset --hard HEAD^ // 回退到上一个版本
git reset --hard HEAD^^ // 回退到上上个版本
git reset --hard HEAD~3 // 回退到往上的第三个版本 即上上上个版本
git reset --hard commit id // 回退到指定commit id 的版本
git reflog
当关掉电脑后 git log 没有记录就可以用 git reflog 来打印提交记录
git reflog // 查看命令历史
- 生成多个ssh-key
ssh-keygen -t rsa -C '邮箱' -f ~/.ssh/filename
git 新建分支时要注意
(1) 用git branch 新分支名
时,需要在本地有commit时,才会成功
(2) 用git checkout -b 新分支名
时,本地没有commit时,也会成功
(重要)
如果远程分支A上有修改 ( 或者别人有push ),而对应的本地分支A也有修改,这时候 git push origin A 就会报错,如Updates were rejected because the remote contains work that you do not have locally. This is usually caused by another repository pushing to the same ref. You may want to first integrate the remote changes(e.g., 'git pull ...') before pushing again.
原因就是其他本地库有push内容到远程相同的分支,( 或者首次是 readme文件在本地没有,而远程有 )
-------解决办法是-------
git pull
在push之前,先执行 git pull 拉取远程分支内容到本地,然后如果有 conflict 就先解决冲突,然后在push到远程
- conflict 冲突
- integrate 整合,融合
本地分支关联远程分支
$ git branch --set-upstream-to /
// 例如: $ git branch --set-upstream-to origin/dev dev
查看远程库信息,使用 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,如果有冲突,要先处理冲突。