git各命令的原理和初级使用,顺手玩下git钩子

栏目: 编程工具 · 发布时间: 5年前

内容简介:该文章是在阅读猴子也懂的git入门和公司中多数是这样开发的:每个commit就是每个版本,每个记录的意思。称呼不一样。

该文章是在阅读猴子也懂的git入门和 抛物线大神的git原理和使用小册子,额,需要一点点零花钱 之后总结的,估摸着不适合新手...

TL;DR

  • 核心概念:暂存区(索引),数据库(repository)是每个commit组成的,HEAD/branch/tag都指向某个commit
  • 远程仓库实际上和本地仓库没啥不同,纯粹为了7x24小时开机并交换大家的修改。
  • 没事常常 git statusgit lg ,没写错,配置 git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit" ,炒鸡炫酷
  • 需要在git执行某条命令的时候执行脚本,就用到钩子
  • 搭建远程仓库

git概念理解

  • 没有git的时候,想要保存文件的状态只能备份备份再备份,如果放到服务器上指不定还被谁不小心的覆盖了。用git管理文件的时候,更新的历史会保存在git里,也不会轻易被覆盖。
  • 文件更新的历史保存git的数据库(repository)。有本地的数据库还有远程数据库,可以自己新建,也可以复制远程的。
  • 若要把文件或目录的添加和变更保存到数据库,就需要进行提交,执行提交后,数据库中会生成上次提交的状态与当前状态的差异记录(也被称为revision),系统根据修改的内容计算出40位数字和英文生成版本号,俗称某个commit或者某个版本
  • 实际操作的目录称为工作树(working tree),在数据库和工作树之间有索引,索引是为了向数据库提交做准备的区域。没有索引的文件是不能提交到数据库的~。索引很多时候又被称为stage,暂存区。工作树的内容跟着HEAD走。一旦HEAD指向新的版本,工作树的内容也会变成那个版本,形同备份~
  • branch、tag、HEAD都是某个版本的引用,可以想象,数据库是一条横着的线,每次提交就是一个点,每个点有自己的id,点上面可能有branch、tag、HEAD这几个指向

git命令的本质

  • git clone url [projectName] 复制url的远程数据库到本地,git会将这个远程数据库命名为origin,projectName可选,省略的话文件夹名字同远程数据库的,写的话就重命名。这里HEAD指向master分支的最新的版本,自然工作区也跟着HEAD。
    git各命令的原理和初级使用,顺手玩下git钩子
  • git add file/. ,将工作树的某些文件创建索引的, . 表示所有文件,注意,add添加的不是文件名字,而是文件改动的内容。新文件必须通过这个才让git追踪这个文件。不然git不知道该文件的存在。
  • git commit -m"认真写改了啥" ,将索引添加到本地数据库,可以想象成横线多了一个点,又长了些。HEAD自动更新到新的commit,且HEAD会拖着当前的分支,让其也指向新的commit。
  • git pull [origin] [master] ,将远程数据库的某个分支的内容更新到本地数据库的相应分支,pull 的内部操作其实是把远程仓库取到本地后(使用的是 fetch),再用一次 merge 来把远端仓库的新 commits 合并到本地。后面两项是指哪个远程仓库的哪个分支,省略的话是origin,然后当前目录所在的分支。这里注意,执行这个操作的时候,可能远程数据库和本地数据库合并的时候,有冲突,解决掉就好,然后 git add .;git commit 本地的数据库从分叉的地方开始插入到远程数据库里更新的后面,有冲突的话将会生成多生成一个commit。可以 git log 看看
  • git push [origin] [master] ,将本地的数据库添加到远程数据库哪个分支,如果总是想省略(我是省略重度依赖者。。), git config --global push.default current ,这样是处在哪个分支就会更新origin的哪个分支。如果实在master分支,这个操作会让 origin/HEAD,origin/master 指向最新的commit,也就是远程仓库的HEAD和master指针。
  • git checkout [-b] branch ,将 HEAD 指向branch ,工作目录的文件内容跟着HEAD,变成这个版本的内容 ,俗称切换分支,当然后面的参数可以是任意的commitID,需要注意的是,当前目录所在分支尽量clean,如果有需要提交的可能会切换失败,如果切换成功,默认为在新的分支下做了这些变更。 -b 一般是创建新分支且切换到新分支的意思。
  • git stash -u ,暂存当前分支的改动,工作区恢复到最新的commit版本,一般常用于紧急切换分支,又不想盲目提交commit,想要恢复改动的内容 git stash pop-u 是将新建的文件一并暂存。
  • git merge branch ,从目标 commit 和当前 commit (即 HEAD 所指向的 commit)分叉的位置起,把目标 commit 的路径上的所有 commit 的内容一并应用到当前 commit,然后自动生成一个新的 commit。merge会自动合并,如果同一个文件上修改可能会合并失败,解决完冲突之后 git add 文件;git commit 就可以了。放弃merge的话 git merget --abort ,merge后面可以是branch,也可以是一般的commit。是不是感觉和pull很像,当然!!!pull就是fetch和merge的合体~~~
    git各命令的原理和初级使用,顺手玩下git钩子
  • git branch [newbranch] [-d] 省略后面的,会显示所有分支,加上后面的表示创建分支,删除分支的话 -d ,强制删除 -D
  • git tag tagName ,tag 是一个和 branch 非常相似的概念,它和 branch 最大的区别是:tag 不能移动。所以在很多团队中,tag 被用来在关键版本处打标记用。多用在master分支上。
  • git revert commitId ,将某commit取反,也就是放弃某次的修改,这个命令会生成新的commit。
  • git reset commitId --hard ,将HEAD以及当前的branch指向移动到目标commit,工作区的内容随着HEAD一起变化,有时候想丢弃某些commits用这个命令。经常用这个 git reset HEAD --hard 放弃本地所有的修改,恢复到上一次的commit状态。
  • git remote name url ,添加一个远程数据库,并且起一个名字,感觉用的不多

git的查找和配置

  • git log ,查看日志, git log --patch 查看详细的日志, git log --stat 查看简要的日志,想要切回到某个版本的时候会用到
  • git show [commitID] [某文件] ,看某一个版本的日志。省略commit表示当前的commit,省略某文件表示所有文件。
  • git diff commitID ,将工作区的内容和目标commit做一个对比。
  • git status ,查看当前的状态,随时会用
  • git config ,对git的一系列配置。属于「一次付出,终身受用」的高性价比内容。global参数针对全局git,不加那只针对当前的仓库起作用。全局配置在用户主目录下的一个隐藏文件 ~/.gitconfig 中,本地配置在仓库根目录的 .git/config 。查看配置 git config --global --list 。以下是常用的配置: 比如配置别名, git config --global alias.co checkout;git config --global alias.ci commit;git config --global alias.br branch 也就是可以 git co xxbranch;git ci -m"xx";git br
    比如配置不容易的命令, git config --global alias.unstage 'reset HEAD' 下次 git unstage file 就表示将暂存区的修改撤销掉,回到工作树那边。 git config --global alias.back 'reset HEAD --hard'git back 表示放弃所有修改,工作区返回到上一次的commit。 git config --global alias.last 'log -1' 显示最后一次提交的信息。 git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit" 嘿嘿,这样可以 git lg 显示日志,特别好用!!!强烈推荐!!!
    比如上面配置push。

分支的应用

公司中多数是这样开发的:

feature-xxx,hotfix-xxx
pull requests

HEAD、master与branch

每个commit就是每个版本,每个记录的意思。称呼不一样。

  • git log 执行后,一般第一行的 commit 后面括号里的 HEAD -> master, origin/master, origin/HEAD ,是几个指向这个 commit 的引用。
  • 在 Git 的使用中,经常会需要对指定的 commit 进行操作。每一个 commit 都有一个它唯一的指定方式也就是上图中每个黄色的 commit 右边的那一长串字符。两个 SHA-1 值的重复概率极低,所以你可以使用这个 SHA-1 值来指代 commit,也可以只使用它的前几位来指代它(例如第一个 78bb0ab7d541…16b77,你使用 78bb0ab 甚至 78bb 来指代它通常也可以),
  • 但毕竟这种没有任何含义的字符串是很难记忆的,所以 Git 提供了「引用」的机制:使用固定的字符串作为引用,指向某个 commit,作为操作 commit 时的快捷方式。

HEAD

  • HEAD 是 Git 中一个独特的引用,它是唯一的。
  • HEAD是当前工作目录所对应的commit。
  • 当有新的commit的时候(commit或者pull的时候),工作目录会与最新的commit对应,HEAD也就指向最新的commit。
  • 当使用checkout、reset等指令手动改变工作目录的commit时,HEAD也会跟过去
  • 当前目录的commit在哪,HEAD就在哪,永远指向当前目录的commit,也就是可以用HEAD操作当前目录的commit

branch

  • Git 还有一种引用,叫做 branch(分支)
  • HEAD 除了可以指向 commit,还可以指向一个 branch,当它指向某个 branch 的时候,会通过这个 branch 来间接地指向某个 commit;另外,当 HEAD 在提交时自动向前移动的时候,它会像一个拖钩一样带着它所指向的 branch 一起移动。
    git各命令的原理和初级使用,顺手玩下git钩子
  • branch可以理解为是指向commit的一个引用,也可以理解为从第一个commit到branch指向的commit之间所有的commits的一个串

master

  • 默认的branch,创建新仓库的时候,第一条commit创建,master会指向它,HEAD指向master
  • git clone 的时候,除了从远程仓库把 .git 这个仓库目录下载到工作目录中,还会 checkout (签出) master(checkout 的意思就是把某个 commit 作为当前 commit,把 HEAD 移动过去,并把工作目录的文件内容替换成这个 commit 所对应的内容)。
    git各命令的原理和初级使用,顺手玩下git钩子
  • origin/HEAD,origin/master是远程仓库的镜像引用

「引用」的本质

所谓「引用」(reference),其实就是一个个的字符串。这个字符串可以是一个 commit 的 SHA-1 码(例:c08de9a4d8771144cd23986f9f76c4ed729e69b0),也可以是一个 branch(例:ref: refs/heads/feature3)。

Git 中的 HEAD 和每一个 branch 以及其他的引用,都是以文本文件的形式存储在本地仓库 .git 目录中,而 Git 在工作的时候,就是通过这些文本文件的内容来判断这些所谓的「引用」是指向谁的。

git的高级(难一点)的命令

这部分不具体写命令了,如果有需求,再进行查阅吧。

把当前所在分支的分叉的所有commits,都复制一份放在参数branch后面
git add 笑声.txt;git commit --amend

示例

# 查看状态
git status
# 添加索引
git add file
# 添加数据库,将HEAD自动更新到新的commit,且HEAD会拖着当前的分支,让其也指向新的commit
git commit -m"msg"
# 将远程数据库的内容更新到本地数据库,默认的远程数据库和分支名字是 origin master
git pull origin master
# 将本地数据库添加到远程数据库。你用不加参数的 git push 只能上传那些之前从远端 clone 下来或者 pull 下来的分支,而如果需要 push 你本地的自己创建的分支,则需要手动指定目标仓库和目标分支(并且目标分支的名称必须和本地分支完全相同),就像上面这样。所有分支都可以用 git push 来直接 push,目标自动指向 origin 仓库的同名分支,通过 git config 指令来设置 push.default 的值为:current
git push origin master
# 添加远程数据库并且将远程数据库起个名字,一般起origin
git remote origin http://xxxxx
# 复制远程数据库,默认的新目录的名字同项目名,git会将这个地址命名为origin
git clone http://xxxx projectName
# 查看数据库
git log
# 切换到某一版本,或者分支
git checkout xxxx
# 需要暂存修改,stash是临时保存文件修改内容的区域
git stash
# 释放
git stash pop
# 查看分支
git branch
# 创建分支 hotfix- feature- release- develop master,其实只是将当前commit创建了一个引用,HEAD指针并没有指向新分支,如果需要,git checkout xxx
git branch xxx
# 创建并切换到新分支,创建新引用,且将HEAD指向这个新引用
git checkout -b xxx
# 删除分支,所谓的删除,只是删除这个commit的引用,可以从git log那找到这个commit,未合并到master的分支会删除失败,但可以强制删除,-d改成-D
git branch -d xxx


# issue1分支需要合并到master上,rebase的历史记录更少

# merge
git checkout master;git pull;git merge issue1;

# rebase
git checkout issue1;git pull;git rebase master;git checkout master;git merge issue1


# 查看标签,想要看注解加上 -n
git tag
# 打标签
git tag tagnamexxxx
# 打注解标签
git tag -am "注释信息" tagnamexxx
# 看包含标签的历史记录
git log --decorate
# 删除标签
git tag -d tagnamexxxx
复制代码

git钩子的简单使用

一个新需求下来了,通常自己建个分支开始完成功能,等到完成的时候,自己测得也差不多了,就会合并到develop分支,然后部署到服务器,让测试来测。每次这样嫌费劲,就想着push到develop的时候,部署自动操作,这样省了很多麻烦吖。。。

这就用到钩子了,这边我没怎么研究,大约知道,就是在执行 add commit push pull merge 等操作的时候,可以在相应的时机执行相应的脚本。

项目根目录下 .git/hooks 下,有很多文件,去掉后缀 .sample 就可以在相应的时机执行这个脚本。脚本的语言,自己开心就好~~

本地仓库的钩子:

  • pre-commit: 执行git commit命令时触发,常用于检查代码风格

  • post-commit: 整个git commit完成后触发,常用于邮件通知、提醒

  • post-merge: 成功完成一次 merge行为后触发

  • pre-push: 执行git push命令时触发,可用于执行测试用例

  • pre-auto-gc: 执行垃圾回收前触发

  • prepare-commit-msg: commit message编辑器呼起前default commit message创建后触发,常用于生成默认的标准化的提交说明

  • commit-msg: 开发者编写完并确认commit message后触发,常用于校验提交说明是否标准

  • applypatch-msg: 执行git am命令时触发,常用于检查命令提取出来的提交信息是否符合特定格式

  • pre-applypatch: git am提取出补丁并应用于当前分支后,准备提交前触发,常用于执行测试用例或检查缓冲区代码

  • post-applypatch: git am提交后触发,常用于通知、或补丁邮件回复(此钩子不能停止git am过程)

  • pre-rebase: 执行git rebase命令时触发

  • post-rewrite: 执行会替换commit的命令时触发,比如git rebase或git commit --amend

  • post-checkout: 执行git checkout命令成功后触发,可用于生成特定文档,处理大二进制文件等

远程仓库用的钩子,一般我们就是要在服务端更新代码之后运行脚步,所以我们要修改的就是post-update或者post-receive。

  • pre-receive: 当服务端收到一个push操作请求时触发,可用于检测push的内容
  • update: 与pre-receive相似,但当一次push想更新多个分支时,pre-receive只执行一次,而此钩子会为每一分支都执行一次
  • post-receive: 当整个push操作完成时触发,常用于服务侧同步、通知

拿我为例,我用的,这里说下,最好是在服务器端执行 git pull ,但因为此项目是另外一个团队开发,我临时负责一个功能,也不知道服务器那边为啥不用git,我得到的信息是只能用复制替换

# .git/.hooks 新建pre-push

##!/bin/sh
# 拿到分支名
NAME=$(git branch | grep '*' | sed 's/* //')

echo "正在上传到服务器 $NAME"
# 在develop上push的时候主动将代码复制到服务器上面
if [ "$NAME" = "develop" ]
then
  scp  -r /Users/creen  root@10.2.2.156:/newoackend
fi

复制代码

搭建git服务器

我觉得买服务器的时候,估计就用到,所以怕忘了,索性记一笔,大段引用廖雪峰大神的git教程。 远程仓库实际上和本地仓库没啥不同,纯粹为了7x24小时开机并交换大家的修改。GitHub就是一个免费托管开源代码的远程仓库。但一般公司需要自己搭建。

Ubuntu或Debian系统完成安装需要以下几步:

# 安装git
sudo apt-get install git
# 创建一个git用户,用来运行git服务
sudo adduser git
# 创建证书登录,其实就是将所有需要登录的用户的id_rsa.pub文件,导入到服务器的/home/git/.ssh/authorized_keys文件里,一行一个。mac用户的公钥位置`~/.ssh/id_rsa.pub`
# 初始化Git仓库,先选定一个目录作为Git仓库,假定是/srv/sample.git,在/srv目录下输入命令,Git就会创建一个裸仓库,裸仓库没有工作区,因为服务器上的Git仓库纯粹是为了共享,所以不让用户直接登录到服务器上去改工作区,并且服务器上的Git仓库通常都以.git结尾
cd /srv
sudo git init --bare sample.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的用户可以在本地clone了

git clone git@server:/srv/sample.git
复制代码

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

JavaScript设计模式

JavaScript设计模式

Ross Harmes、Dustin Diaz / 谢廷晟 / 人民邮电出版社 / 2008 / 45.00元

本书共有两部分。第一部分给出了实现具体设计模式所需要的面向对象特性的基础知识,主要包括接口、封装和信息隐藏、继承、单体模式等内容。第二部分则专注于各种具体的设计模式及其在JavaScript语言中的应用,主要介绍了工厂模式、桥接模式、组合模式、门面模式等几种常见的模式。为了让每一章中的示例都尽可能地贴近实际应用,书中同时列举了一些JavaScript 程序员最常见的任务,然后运用设计模式使其解决方......一起来看看 《JavaScript设计模式》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

URL 编码/解码
URL 编码/解码

URL 编码/解码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具