写这个东西一为了总结思路,二为了在公司内部的讲演。
耳熟能详
概念
操作
- git init
- git clone
- git pull
- git fetch
- git merge
- git branch
- git reset
- git revert
- git reflog
- git log
- git config
初次见面
设置账户
git config
git config --global user.name "Manjack" user.email "manjack@aobi.com"
就算不加上--global
参数,也会设置到全局变量里,没办法对某个repo设置name和email。
config文件有三个层次:
- repo层面的,保存在每个repo的.git文件夹里
[remote "origin"]
url = https://github.com/wangshub/wechat_jump_game.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
remote = origin
merge = refs/heads/master
- 用户层面的,保存在
C:/user/<user-name>/.gitconfig
[user]
email = exkulo@qq.com
name = ManjackGo
- 系统层面,做一些全局设定,比如<别名><默认行为(比如fetch使用merge还是rebase)>
C:/ProgramData/git/config
生成sshkey
和服务器采用非对称加密进行校验,需要把公钥上传至服务器自己的账号里。使用代码:
ssh-keygen -t rsa -C "manjack@aobi.com"
三次回车使用默认值。公钥会保存在:
- windows
C:\Users\<user-name>\.ssh/id_rsa.pub
- UNIX/MAC
~ /.gitconfig
把文件里的内容全选(必须包括最后一行的空行)粘贴到自己gitlab账户的ssh密钥里面,完成配置。
建立一个repository
一、自己建立一个空repo
随便在某个文件夹使用git init
。可以看到生成了一个.git文件夹。git自动帮我们建立了一条叫做master的分支。
二、从网上clone一个repo
- 从网上的repo拿到一个远端网址
- 执行
git clone <url>
可以得到一个新的repo,并帮我们把url设置为一个名字为remote
的远端。
相当于执行了以下操作:
git remote add remote <url>
git pull
.git文件夹
hooks # 钩子函数存放点,可使用自己喜欢的脚本写
|
pre-commit
pre-push
info
|
exclude # 一个本地版本的.ignore
objectsm #存放着历史文件,包括版本本身,以及版本对应的文件
|
21
c4
b5
...
refs
|
heads
|
master
nb
remotes
|
remote
tags
|
release1.0.0
config
description
HEAD #代表当前的版本指向
版本的实质
当我们完成一次commit操作,实质上发生了:
- 把当前版本变动的文件压缩,产生hash作为名称
- 把这些文件的hash集合起来,hash一次
- 把当前状态的head进行一次哈希,作为本次提交的tree
- 给当前的提交一个hash值,作为log的版本号
以上所有的文件均储存在object文件里,文件夹的两个字母作为一串hash码的头两个字母,文件夹里的文件名是hash另外一部分的字符串。
可以使用
git cat-file -p <file-name>
来解压查看文件。
(演示ING...)
提交代码
working, stage, head
解释...
add
-
git add .
把当前目录的变动提交到stage区 -
git add
<file-name>
commit
git commit
vim基础操作
安装的时候默认使用vim作为编辑器,在这里基本只要知道以下几个点就可以用了:
- i进入编辑模式
- esc退出编辑模式
- wq保存并退出
git commit -m "<message>"
-
git commit --amend <message>
添加本次提交到上一次的提交,并修改上一次提交的log(若没有得提交则只改log)
所谓版本,tag,branch
只是一个代表着某个版本的字符串。保存在refs里面,打开可以看到所对应的字符串。所谓的撤回操作,就是返回到某个版本。而HEAD代表着当前工作目录所对应的分支或者版本。
(展示HEAD,展示refs)
撤回操作
svn中的revert
-
对工作区
也就把工作区的变动回复到head的状态,采用以下代码:
git reset --hard HEAD~0
(解释--hard --soft的区别),把目标目录变成某个版本的样子, ~0表示版本 -
对某个文件
git reset --hard HEAD
git reset
把当前head以及HEAD指向某个版本,把后面的版本摒弃。(摒弃不意味着消失,git的一切提交都不会消失,只是变成了难以再获取到的孤魂野鬼)。HEAD~1代表上一个版本。
注意:
当HEAD是合并而来的版本的时候,HEAD~1代表当前分支的父节点,HEAD^1代表另一分支的父节点
黄金法则 GOLDEN RULE
不要在公共的分支上(已经在服务器上存在的分支)进行reset操作。
svn中的update to revision
svn中我们使用这种方法来检出过去的代码,在git中使用:
git checkout <commit>
就可以把工作区checkout到这个状态。
注意:此时处于一个dettached head状态。
非大陆版本翻译为“断头状态”。HEAD一般是指向refs/heads中的某个文件(这些文件又会指向某个版本),成为attched head状态,而当checkout为某个版本的时候,HEAD会显示为某个版本号。成为断头。
当你需要在checkout出来的版本工作
断头状态下所有的提交均不属于任何分支,属于无效提交。当需要在这个状态下工作时,最好建立一个新的分支来工作,最后再合并到目标分支。
git revert
同样用于撤销操作,需要和svn中作出区分。这是一个安全的操作,可以用于已经共享的分支。具体操作相当于找到某个版本的changeset,逆之,然后作为一次新的commit提交。相当于帮我们手工做了一次改错。
使用方法git revert <commit>
。
必学时光回溯大法
任何想好好实用git的人都必须学会这一节。
当我们执行reset之后,hard模式下三个tree都会退回到你的目标版本,此时执行git log
,是看不到被reset掉后面的版本的,就好像什么都没发生过一样。这样子当自己手贱不小心reset掉自己需要的代码了,岂不是要捶胸顿足?
不用怕,之前就讲过,git是一个永远都不会丢失提交的vcs,只要是提交过的,都能找回。这个时候需要一个神器了,那就是reflog。让我们输入reflog,可以看到如下的东西:
$git reflog
c75dc97 (HEAD -> nb) HEAD@{0}: reset: moving to HEAD~1
c1998f3 (master) HEAD@{1}: checkout: moving from master to nb
c1998f3 (master) HEAD@{2}: commit: add the first line
c75dc97 (HEAD -> nb) HEAD@{3}: commit (initial): commit first
可以看到最上面reset了一个版本。现在我们突然想要前面的某个版本了,直接执行
git checkout HEAD@{n}
就可回到任意版本,复制出你要的文件然后回到最新版本复制回去,或者新开分支工作都可以, whatever you like。
令人激动的分支操作
基于版本的分支。
查看
查看分支,带星号的为当前所处分支git branch
查看远端分支git branch -r
切换分支
git checkout <branch>
实质上是改变了HEAD的指向。
新建分支
git branch <branch>
git checkout -r <branch>
新建分支并切换过去
删除分支
git branch -d <branch>
安全删除分支,必须在被合并之后才允许删除
git branch -D <branch>
强行删除分支
merge
把一堆操作集合起来作为一个merge commit,会自动处理好历史。
操作步骤:
- 切换到当前分支
git checkout <master-branch>
- 合并
git merge <feature-branch>
rebase
换基。同样需要尊崇黄金法则,不能更改公共分支。
直接把整条分支的起点挪到源分支的head处。在公共分支使用容易引起冗余changeset。(选择性讲解,看时间)
rebase和merge的区别
...
远端操作
存放在refs/remotes文件夹下
新建立远端
git remote add <remote-name> <remote-url>
一般起名字为origin,跟着git的标准写。
删除远端
git remote remove <remote-name>
rename
就叫rename git remote rename <old> <new>
pull
相当于fetch + merge/rebase
git pull <remote-name>
当加上--rebase标志时表示使用rebase,一般由于是公共分支,不要这么搞比较好。
push
把所有的commit提交到服务器
git push <remote-name> [--force]
别名
允许我们自定义别名,比如使用decompress来代表解压操作,那么
git config --global alias.decompress "cat-file -p"
既可。
网友评论