git 总结
1. 集中式和分布式版本控制系统有什么区别呢?
集中式版本控制系统:版本库是集中存放在中央服务器的,而干活的时候,用的都是自己的电脑,所以要先从中央服务器取得最新的版本,然后开始干活,干完活了,再把自己的活推送给中央服务器。中央服务器就好比是一个图书馆,你要改一本书,必须先从图书馆借出来,然后回到家自己改,改完了,再放回图书馆。
集中式版本控制系统最大的毛病就是必须联网才能工作,如果在局域网内还好,带宽够大,速度够快,可如果在互联网上,遇到网速慢的话,可能提交一个10M的文件就需要5分钟,这还不得把人给憋死啊。
分布式版本控制系统与集中式版本控制系统有何不同呢:首先,分布式版本控制系统根本没有“中央服务器”,每个人的电脑上都是一个完整的版本库,这样,你工作的时候,就不需要联网了,因为版本库就在你自己的电脑上。既然每个人电脑上都有一个完整的版本库,那多个人如何协作呢?比方说你在自己电脑上改了文件A,你的同事也在他的电脑上改了文件A,这时,你们俩之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。
在实际使用分布式版本控制系统的时候,其实很少在两人之间的电脑上推送版本库的修改,因为可能你们俩不在一个局域网内,两台电脑互相访问不了,也可能今天你的同事病了,他的电脑压根没有开机。因此,分布式版本控制系统通常也有一台充当“中央服务器”的电脑,但这个服务器的作用仅仅是用来方便“交换”大家的修改,没有它大家也一样干活,只是交换修改不方便而已。
2. repository
// 创建文件夹
$ mkdir learngit
$ cd learngit
$ pwd
/Users/Michael/learngit
// 把这个目录变成Git可以管理的仓库
$ git init
Initialized empty Git repository in /Users/michael/learngit/.git/
// 查看默认隐藏的目录
$ ls -ah
// 添加文本文件
$ vi readme.txt
$ git add readme.txt // 添加指定文件
$ git add . // 添加所有修改文件
$ git add -I // 查看 add 状态
$ git status // 查看当前git状态
$ git rm --cached readme.txt // 从索引中删除,不改变本地文件
$ git commit -m "message" // commit
$ git diff readme.txt // 修改文件后,查看文件对比
// git add 添加 多余文件
// 这样的错误是由于, 有的时候 可能
git add . // (空格+ 点) 表示当前目录所有文件,不小心就会提交其他文件
// git add 如果添加了错误的文件的话
// 撤销操作
git status // 先看一下add 中的文件
git reset // HEAD 如果后面什么都不跟的话 就是上一次add 里面的全部撤销了
git reset HEAD XXX/XXX/XXX.java // 就是对某个文件进行撤销了
git rm和rm的使用区别
git rm与git rm --cached
git rm 和 git reset HEAD 区别
3. 提交管理
$ git log
$ git log --pretty=oneline // 一行显示commit信息
$ git log --pretty=oneline --graph // 展示每个提交所在的分支及其分化衍合情况
$ git log --pretty=oneline --graph -10 // 显示条数
// 此时 git log 的记录也会被移除
$ git reset --hard HEAD^ // 版本回退到上一个版本commit
$ git reset --hard HEAD^^ // 版本回退到上上一个版本commit
$ git reset --hard HEAD~n // 版本回退到上n个版本commit
// 如果记得 commit-id 可以再翻回之前的版本
$ git reset --hard // 版本到到上一个版本commit
$ git log // 查看提交历史
$ git reflog // 查看命令历史记录每一次命令
// 撤销修改
$ git reset HEAD readme.txt
4. 工作区和暂存区
工作区(Working Directory):就是你在电脑里能看到的目录
版本库(Repository):工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库。
第一步是用git add把文件添加进去,实际上就是把文件修改添加到暂存区;
第二步是用git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支。
$ git add // 把修改文件添加到暂存区(stage,或者叫index)
$ git status // 查看状态
$ git commit -m "message" // 一次性把暂存区的所有修改提交到分支。
5. checkout : HEAD是checkout的灵魂
// 新分支
git branch branch_name // 创建新分支
git checkout branch_name // 切换分支,取出branch_name版本的head
git checkout -b branch_name // 合并以上两个命令,即创建并切换到新分支
git branch // 查看所有分支,以及当前所在分支
cat .git/HEAD // 查看 HEAD 中的内容
cat .git/refs/heads/branch_name // 查看当前分支所在的 commit_id
// tag_name
git checkout tag_name // 在当前分支上取出 tag_name 的版本
// 从HEAD检出覆盖当前文件的修改
git checkout -- test1.txt // 指定文件, -- 不可少
git checkout . // 这条命令把 当前目录所有修改的文件 从HEAD中检出并且把它恢复成未修改时的样子
// 检出 commit_id 指向
// git提示我们已经不在任何分支上,HEAD指针也是指向具体的c1的commit值
// 进入了“分离头指针”状态
git checkout commit_id // "分离头指针"
git checkout -b branch_name // 创建并切换到新分支
git checkout --detach branch_name // 指定分支最后一次提交 commit_id 的“分离头指针”状态
// 检出 指定 commit_id 下的 指定文件,到暂存区
git checkout branch_name -- test1.txt
git rm --cache test1.txt // 从暂存区删除
git checkout HEAD test1.txt // 恢复,即丢弃该文件所有修改
// 强行重置分支
// 如果branch_name,则基于当前所在分支,重置分支 branch_name
// 以前的分支内容就没了
// (慎用!)
git checkout -B branch_name
git reset --hard commit_id // 可以通过 commit_id 恢复
// 基于当前所在分支新建一个赤裸裸的分支,没有任何的提交历史,但是当前分支的内容一一俱全
// 严格意义上说,还不是一个分支,因为HEAD指向的引用中没有commit值,只有在进行一次提交后,它才算得上真正的分支
git checkout --orphan
// 这个命令适用于在切换分支的时候,将当前分支修改的内容一起打包带走,同步到切换的分支下
// 第一,如果当前分支和切换分支间的内容不同的话,容易造成冲突
// 第二,切换到新分支后,当前分支修改过的内容就丢失了
// (慎用!)
git checkout --merge
// 这个命令可以用来打补丁
// 这个命令主要用来比较两个分支间的差异内容,并提供交互式的界面来选择进一步的操作
// 这个命令不仅可以比较两个分支间的差异,还可以比较单个文件的差异
git checkout -p
git checkout 命令详解
6. 生成私钥(只需要一个key,可以多处使用)
cd ~/.ssh
$ ssh-keygen -t rsa -C "自己的电脑名"
$ ssh -T [email protected]
注:
git config --global user.email "4***[email protected]"
git config --global user.name "V***r"
7. git remote
git remote // 查看关联的远程仓库
git remote -v // 显示可以抓取和推送的origin的地址。如果没有推送权限,就看不到push的地址
git remote add origin ****** // 添加远程仓库
git push -u origin master
// 由于远程库是空的,我们第一次推送master分支时,加上了-u参数,
// Git不但会把本地的master分支内容推送的远程新的master分支,
// 还会把本地的master分支和远程的master分支关联起来,
// 在以后的推送或者拉取时就可以简化命令
git push origin master
git clone git@******.git // 从远程仓库克隆
// 提交本地仓库其他分支到远程仓库
git checkout dev3
git push origin dev3
// 指定本地dev分支与远程origin/dev分支的链接
git branch --set-upstream-to=origin/dev dev
8. 分支管理
其他版本控制系统如SVN等都有分支管理,但是用过之后你会发现,这些版本控制系统创建和切换分支比蜗牛还慢,简直让人无法忍受,结果分支功能成了摆设,大家都不去用。
但Git的分支是与众不同的,无论创建、切换和删除分支,Git在1秒钟之内就能完成!无论你的版本库是1个文件还是1万个文件。
// 合并分支
git branch // 查看分支
git branch -a // 查看所有分支,包括远程仓库的分支
git branch -d dev1 // 删除分支
git branch -D dev1 // 强行删除分支
git merge dev1 // 合并dev1分支到当前分支(master)
// 冲突解决
// 如 master 和 feature1 修改了同一个地方,合并时发生冲突
git merge feature1
// 这种情况下,Git无法执行“快速合并”,
// 只能试图把各自的修改合并起来,但这种合并就可能会有冲突
// 文件存在冲突,必须手动解决冲突后再提交
git status // 查看冲突
// Git用<<<<<<<,=======,>>>>>>>标记出不同分支的内容
git log --graph --pretty=oneline --abbrev-commit
// 分支管理策略
// 通常合并分支时,Git会用Fast forward模式,看不到merge信息
// 如果强制禁用Fast forward模式,Git就会在merge时生成一个新的commit
// 这样,从分支历史上就可以看出分支信息
git merge --no-ff -m "message" feature1
// 合并分支时,加上--no-ff参数就可以用普通模式合并,
// 合并后的历史有分支,能看出来曾经做过合并,
// 而fast forward合并就看不出来曾经做过合并。
// git stash 保存和恢复 工作现场
git stash // 将当前工作现场保存到 stash list
git stash save "message" // 带信息的保存方式
git stash list // 查看保存的 stash list
git stash apply // 将缓存堆栈中的stash多次应用到工作目录中,但并不删除stash拷贝
git stash apply satsh@{num} // 恢复指定工作现场
git stash pop // 将缓存堆栈中的第一个stash删除,并将对应修改应用到当前的工作目录下
git stash drop stash@{num} // 删除指定工作现场
git stash clear // 清空stash list
git stash show stash@{num} // 查看指定stash的工作现场
git stash show -p/--patch stash@{num} // 查看指定stash的diff
// 暂存未跟踪或忽略的文件
/**
默认情况下,git stash会缓存下列文件:
.添加到暂存区的修改(staged changes)
.Git跟踪的但并未添加到暂存区的修改(unstaged changes)
但不会缓存一下文件:
.在工作目录中新的文件(untracked files)
.被忽略的文件(ignored files)
**/
// 使用-u或者--include-untracked可以stash untracked文件
git stash -u/--include-untracked
git stash -a/--all // 使用-a或者--all命令可以stash当前目录下的所有修改
git-stash用法小结
// 变基
// 只对尚未推送或分享给别人的本地修改执行变基操作清理历史
// 从不对已推送至别处的提交执行变基操作
// 不要对在你的仓库外有副本的分支执行变基
//(慎用)
git rebase //
变基
9. 标签管理
发布一个版本时,我们通常先在版本库中打一个标签(tag),这样,就唯一确定了打标签时刻的版本。将来无论什么时候,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来。所以,标签也是版本库的一个快照。
Git的标签虽然是版本库的快照,但其实它就是指向某个commit的指针(跟分支很像对不对?但是分支可以移动,标签不能移动),所以,创建和删除标签都是瞬间完成的。
tag就是一个让人容易记住的有意义的名字,它跟某个commit绑在一起
git tag // 查看所有标签
git tag v1.0 // 默认标签是打在最新提交的commit上的
git tag v1.0 commit_id // 指定 commit 打标签
git merge dev1 --no-ff -m "merge message" // 有 merge的commit信息
git log --pretty=oneline --graph --abbrev-commit -10 // commit 的 log 信息
git show v1.0 // 查看 指定 tag 的信息
git tag -a v1.0 -m "tag message" commit_id // 打标签时添加信息
// 注意:标签总是和某个commit挂钩。
// 如果这个commit既出现在master分支,又出现在dev分支,
// 那么在这两个分支上都可以看到这个标签。
git tag -d v1.0.0 // 删除标签
git push origin v0.9.0 // 推送某个标签到远程
git push origin --tags // 一次性推送全部尚未推送到远程的本地标签
// 删除远程仓库的标签
git tag -d v0.9.0 // 先删除本地的tag
git push origin :refs/tags/v0.9.0 // 再删除远程仓库的tag,github上检查一下
// 远程 tag 代码拉取
git checkout v1.4.0 // 此时head指针处于游离状态,需要新建分支
git checkout -b v1.4.0 // 承载 tag v1.4.0 的代码
10. 自定义 git
git config --global color.ui true // git ui
.gitignore
忽略文件的原则是:
- 忽略操作系统自动生成的文件,比如缩略图等;
- 忽略编译生成的中间文件、可执行文件等,也就是如果一个文件是通过另一个文件自动生成的,那自动生成的文件就没必要放进版本库,比如Java编译产生的.class文件;
- 忽略你自己的带有敏感信息的配置文件,比如存放口令的配置文件。
git add aaa.class // .gitignore : *.class 文件被屏蔽
git add -f aaa.class // -f 强行添加文件
git check-ignore -v aaa.class // 可以查看哪条规则屏蔽了文件