用生命谱写代码的赞歌

0%

Git 版本控制工具

Git 命令

本文主要介绍 Git 版本控制的部分命令,顺带谈了谈 Github 多人协作以及 hexo

Git的几个专有名词:

  • Workspace:工作区
  • Index / Stage:暂存区
  • Repository:仓库区(或本地仓库)
  • Remote:远程仓库

git 配置 & vi 命令 & cmd

  • Git 是一个分布式版本控制软件,保存历史记录,多人协作
  • 相对于 SVN 更强大,用户非常多
  • nice 查看模式 (:)
    • 通过上下箭头键查看过长日志
    • 想要退出模式按下字母Q
  • vi编辑模式(Visual Interface可视化接口)
    • **vi 文件名(或者vim 文件名)**:进入文件编辑区域
    • vi默认是命令模式,输入 u 可以撤销, ctr+r 表示恢复撤销
    • 输入 i 表示 insert ,可以进入编辑模式
    • Esc:退出编辑模式
    • :w 回车:保存
    • :q:退出
    • :q!:修改后不保存,强制退出
    • 输入 :wq 表示编辑完毕保存并退出
  • cmd 命令:dir 查看当前目录所有文件

git 操作

  • ls:查看当前目录所有文件
  • ls -a:查看所有文件,包括隐藏文件
  • cd ~:返回到当前用户目录
  • cd ..:必须空格..才能返回上级目录
  • cd -:代表进入最近的切换目录(类似于 git checkout -)
  • mkdir 『文件夹名』:创建一个文件夹
  • mkdir 『文件夹名』 && cd 『文件夹名』:新建并进入该文件夹
  • mv 『目录1』 『目录2』:移动一个目录到另一个目录下,如果目录2不存在则重命名目录1为目录2
  • rmdir 『空文件夹名』:删除一个空文件夹
  • rm 『文件名』:删除指定文件
  • rm -r 『文件夹名』:递归删除指定文件夹文件
  • rm -rf 『文件夹名』rm 表示删除, -rf 表示递归强制删除指定文件夹
  • pwd(Print Working Directory):显示当前工作目录

git 初始化代码库

  • git init:在当前目录下初始化一个 git 仓库,创建版本管理仓库
  • git init 『project-name』:创建一个目录同时初始化为Git代码库
  • git init --bare:初始化裸仓库
  • git clone 『url』:下载一个项目和它的整个代码历史
  • git clone -o 『anothername』 『url』:克隆版本库同时修改默认 origin 别名
  • git clone -b 『branchname』 『url』:克隆远程仓库某个分支
  • git clone -b 『branchname』 『url』 『本地目录名』:在本地目录克隆远程仓库某个分支,如果没有该目录则新建

git 配置

  • git config --list (查看 git 配置信息 -l)
  • git config --global --list (查看 git 全局配置信息 -global -l)
  • git config [--global] -e 编辑配置文件(全局)
  • git config --get core.editor 获取相应的配置
  • git config color.ui true 输出彩色信息
  • git config core.ignoreCase false 设置文件名大小写敏感
  • git config push.default simple 设置推送策略为 simple
  • git config --global core.editor vim 设置 git 编辑器是 vim
  • git config --global alias.co checkout 设置命令别名
  • 设置提交代码时的用户信息
    • git config [--global] user.name 『name』 配置用户名
    • git config [--global] user.email 『email address』 配置用户邮箱

git 忽略

  • vim .gitignore 添加本项目的忽略文件
  • vim .git/info/exclude 添加本项目的忽略文件并不把此文件纳入版本管理
  • git config --global core.excludesfile ~/.gitignore 设置全局忽略文件
  • git update-index --assume-unchanged <file> 对已加入版本管理的文件不做更改检查
  • git update-index --no-assume-unchanged <file> 对已加入版本管理的文件做更改检查

git 查看状态/提交暂存区/提交本地仓库并创建提交日志

  • git status:查看仓库状态,是否有改动后未提交的文件(工作区),不跟着空目录,除非在目录下新建 .gitkeep 文件
  • git add 『file1』 『file2』 ...:添加指定文件到暂存区
  • git add 『file路径』:将文件提交到暂存区
    • git add file1 file2
    • git add .
    • git add --all
    • git add -A
  • git rm 『file1』 『file2』 ...:删除工作区文件,并且将这次删除放入暂存区
  • git rm --cached 『file』:从暂存区中取消要提交的文件(停止追踪指定文件),但文件会保留在工作区
  • git rm --cached -r js/:移除目录必须添加 -r 参数,表示递归移除
  • git mv 『file-original』 『file-renamed』:改名文件,并且将这个改名放入暂存区

删除文件

在 git 中删除文件后有两个选择:

  1. 确实要从版本库中删除该文件,那就用命令 git rm 删掉,并且 git commit
  2. 删错了,因为版本库里还有呢,所以可以很轻松地把误删的文件恢复到最新版本 (git checkout -- 『file』)
  3. git checkout 其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。
  4. 命令 git rm 用于删除一个文件。如果一个文件已经被提交到版本库,那么你永远不用担心误删,但是要小心,你只能恢复文件到最新版本,你会丢失最近一次提交后你修改的内容。

git 代码提交本地仓库并创建提交日志

  • git commit -m 'xxx':提交到本地仓库并创建提交日志(必须初始化 git 配置)
  • git commit 『file』 -m 'xxx':指定文件提交到本地仓库并创建提交日志
  • git commit -a:会先把所有已经track的文件的改动git add进来,然后提交(有点像svn的一次提交,不用先暂存)。对于没有track的文件,还是需要执行git add <file> 命令
  • git commit --amend -m 『message』:使用一次新的 commit ,替代上一次提交(修改上一次提交日志)
  • git commit --amend 『file1』 『file2』...:重置上一次 commit ,并包括指定文件的新变化,如果你上一次提交忘了某个文件,可以通过该方式把指定文件和上一次提交合并之后作为一次提交

将文件添加到 git 版本库

git 版本控制系统分为工作区 (working directory) 和版本库 (repository)

Git 的版本库里存了很多东西,其中最重要的就是称为 stage (或者叫index) 的暂存区,还有 Git 为我们自动创建的第一个分支 master,以及指向 master 的一个指针叫 HEAD

  1. git add把文件添加进去,实际上就是把文件修改添加到暂存区
  2. git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支

我们创建 Git 版本库时, Git 自动为我们创建了唯一一个 master 分支,所以,现在, commit 就是往 master 分支上提交更改。

简单理解为,需要提交的文件修改统统放到暂存区,然后,一次性提交暂存区的所有修改

git 查看提交信息

  • git log:查看提交日志(显示永不重复的版本号)
  • git log --pretty=oneline:在一行显示提交日志
  • gitk:查看提交日志的图形化界面
  • git diff:显示暂存区和工作区的差异
  • git diff 『file』:查看文件修改
  • git diff -w 『file』:查看代码自动合并状况
  • git diff --cached 『file』:显示暂存区和上一个 commit 的差异
  • git diff HEAD:显示工作区与当前分支最新 commit 之间的差异
  • git diff HEAD -- 『file』:查看工作区和版本库里面最新版本文件的区别

git 查看各个分支之间的关系图

  1. 使用 git log 命令
1
2
3
4
5
6
7
8
9
10
11
12
git log --graph --decorate --oneline --simplify-by-decoration --all
说明:

--decorate 标记会让git log显示每个commit的引用(如:分支、tag等)

--oneline 一行显示

--simplify-by-decoration 只显示被branch或tag引用的commit

--all 表示显示所有的branch,这里也可以选择,比如我指向显示分支ABC的关系,则将--all替换为branchA branchB branchC

git log --graph --pretty=oneline --abbrev-commit --> 查看分支合并情况
  1. 使用 gitk 工具

gitk --simplify-by-decoration --all

git 分支操作

  • git branch:列出所有本地分支
  • git branch -u:修改已存在分支的上游关联
  • git branch -r:列出所有远程分支
  • git branch -a:列出所有本地和远程分支
  • git branch -vv:检查分支关联状态,查看所有本地分支并列出该分支最新的一次 commit
  • git branch 『branch-name』:基于当前分支创建一个新分支,仍然停留在当前分支(主分支最起码要有一次提交,才能基于主分支创建新分支)
  • git branch -m[-M] 『old-branch-name』 『new-branch-name』: 修改本地分支的名字(-M 表示强制更改)
  • git branch 『branch-name』 『commit』:新建一个分支,指向指定 commit
  • git branch --track 『branch-name』 『remote-branch-name』:新建一个分支,并与指定的远程分支建立追踪关系
  • git checkout -b 『branch-name』 (remote)/(branch):在本地创建一个分支跟踪远程分支
  • git checkout -b 『branch-name』:基于当前分支新建一个分支并切换到该分支
  • git checkout 『branch-name』:切换到指定分支,并更新工作区
  • git checkout -:在最近的两个分支之间切换
  • git merge 『branch-name』将指定分支合并到当前分支
  • git cherry-pick 『commit』:选择一个commit,合并到当前分支
  • git branch -d 『branch-name』:删除分支(注意:必须在删除的分支之外才行)
  • git show [branch-name]:可以看出分支上的递交状况

git 删除不存在对应远程分支的本地分支

  • git remote show origin:查看远程仓库详细信息,看到远程分支后面stale标记的,说明已经不需要了
  • git remote prune origin:删除没有与远程分支对应的本地分支

分支的 upstream

  • git branch --set-upstream master origin/next:手动建立追踪关系,指定 master 分支追踪 origin/next 分支(已过时)
  • git branch --set-upstream-to=origin/dev 『本地分支名』:为指定分支设置 upstream 追踪远程 origin/dev 分支,如果省略本地分支名,则默认设置当前分支
  • git branch --unset-upstream:取消当前分支的 upstream
  • git branch --unset-upstream [分支名]:取消其他分支的 upstream
查看 upstream 信息,主要是查看仓库目录下 .git/config 文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ cat .git/config
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
precomposeunicode = true
[branch "optimize_tab"]
[remote "meiqia"]
url = git@git.meiqia.com:crm_platform/crm_web_workbench.git
fetch = +refs/heads/*:refs/remotes/meiqia/*
[remote "myself"]
url = git@git.meiqia.com:hushijin/crm_web_workbench.git
fetch = +refs/heads/*:refs/remotes/myself/*
[branch "master"]
remote = meiqia
merge = refs/heads/master
[branch "hotfix"]
remote = meiqia
merge = refs/heads/hotfix
[branch "develop"]
remote = meiqia
merge = refs/heads/develop

其中[branch “分支名”]下的信息就是 upstream 信息,remote 项表示 upstream 的远程仓库名,merge 项表示远程跟踪分支名。

也可以通过 git remote show origin 查看:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ git remote show origin
* remote origin
Fetch URL: git@git.meiqia.com:crm_platform/crm_web_workbench.git
Push URL: git@git.meiqia.com:crm_platform/crm_web_workbench.git
HEAD branch: develop
Remote branches:
develop tracked
hotfix tracked
master tracked
Local branches configured for 'git pull':
develop merges with remote develop
hotfix merges with remote hotfix
master merges with remote master
Local refs configured for 'git push':
develop pushes to develop (up to date)
hotfix pushes to hotfix (up to date)
master pushes to master (local out of date)

Remote branches表示远程仓库的分支,git pull表示upstream跟踪分支。

git 基于远程分支创建新的本地分支

  • 基于远程分支无污染创建本地分支:git fetch origin hotfix & git checkout -b chief_fix FETCH_HEAD,将线上分支的 HEAD 指向本地分支
  • 或者 git fetch origin hotfix & git checkout -b chief_fix origin/hotfix,效果与上面一致

git 衍合

  • Your branch and ‘origin/xxx’ have diverged
  • git rebase: 解决 git 分支出现分叉的状况,在 rebase 的过程中如果遇到冲突就解决冲突,然后 git add 冲突的文件,标识冲突解决,然后再执行 git rebase --continue (注意 git add 之后不要执行 git commit)
  • git pull衍合会合并保留双方分叉提交并形成一个新的提交,git rebase衍合会合并保留双方提交,使之看起来像没有经过任何合并一样。

git 远程同步(拉取)

  • git remote add 『shortname』 『url』:指定你要 push 提交到的远端仓库别名和地址(增加一个新的远端仓库)
  • git remote rm 『shortname』:根据别名删除指定的远程仓库
  • git remote rename 『old name』 『new name』:修改远程仓库别名
  • 第一次使用Git的clone或者push命令连接GitHub时,会得到一个警告:SSH警告
  • git pull 『remote』 『remote-branch-name』:『branch-name』:取回远程仓库某个分支的更新,与本地分支合并,如果远程分支与当前分支合并则可以省略冒号后面的部分
  • git pull 『origin』 『next』:取回 origin/next 分支,再与当前分支合并.实质上,这等同于先做 git fetch ,再做 git merge
    • git fetch origin next
    • git merge origin/next 或者 git rebase origin/next:在本地分支 next 上合并远程 next 分支
  • git pull origin:本地的当前分支自动与对应的 origin 主机“追踪分支” (remote-tracking branch) 进行合并,如果当前分支只有一个追踪分支,连远程主机名都可以省略
  • git pull:如果当前分支只有一个追踪分支,连远程主机名都可以省略.当前分支自动与唯一一个追踪分支进行合并
  • git pull --rebase <远程主机名> <远程分支名>:<本地分支名>:如果合并需要采用 rebase 模式,可以使用 –-rebase 选项
  • git pull --rebase:表示把你的本地当前分支里的每个提交(commit)取消掉,并且把它们临时保存为补丁(patch)(这些补丁放到 “.git/rebase” 目录中),然后把本地当前分支更新为最新的 “origin” 分支,最后把保存的这些补丁应用到本地当前分支上

推荐使用 fetch + merge 代替 pull

  • git fetch 『远程主机名』:将某个远程主机所有分支的更新全部取回本地,但是不会自动 merge
  • git fetch 『远程主机名』 『分支名』:取回特定分支的更新
  • git fetch origin master:所取回的更新,在本地主机上要用”远程主机名/分支名”的形式读取。比如origin主机的master,就要用origin/master读取。即合并远程分支更新到本地分支 git merge origin/master
1
2
3
4
5
6
7
8
9
10
11
12
13
git fetch origin master
git log -p master..origin/master
git merge origin/master
以上命令的含义:
首先从远程的origin的master主分支下载最新的版本到origin/master分支上
然后比较本地的master分支和origin/master分支的差别
最后进行合并
上述过程其实可以用以下更清晰的方式来进行:
git fetch origin master:tmp
git diff tmp
git merge tmp
从远程获取最新的版本到本地的tmp分支上
之后再进行比较合并

git 远程操作(推送)

  • git push <远程主机名> <本地分支名>:<远程分支名>:推送本地分支到远程仓库
  • git push:仅限于 git clone 下来的项目,它会默认创建一个 remote ,名字叫 origin ,所以可以直接 git push ,不需要指定后面的 origin 别名
  • git remote add 『name』 『url』:添加远端仓库地址并起一个别名
  • git remote:查看所有远端地址,默认只能看到别名
  • git remote -v:查看所有远端地址详情
  • git remote show 『远端地址别名』:查看某个具体的远端地址
  • git remote show origin:查看 origin 远程仓库的所有信息,其中 Remote branches 表示远程仓库的分支, git pull 表示 upstream 跟踪分支
  • git remote rm 『远端主机别名』:删除远程主机(仓库)
  • git remote rename 『原主机名』 『新主机名』:重命名远程主机名
  • git push 『远端地址别名』 『要提交到的分支名称』:推送代码到对应仓库,如果远端没有对应的分支,则新建该分支,但不会设置上游
  • git push -u 『remote』 『branch』:把本地仓库推送到远端仓库, 加上了 -u 参数, Git 不但会把本地的分支内容推送到远程新的分支,还会把本地分支和远程分支关联起来,在以后的推送或者拉取时就可以简化命令
  • git push -u origin master:该命令和下一条命令功能一致, -u 是下一条命令 --set-upstream 的缩写,表示设置上游分支,建立本地分支与远程分支的跟踪关系
  • git push --set-upstream origin master:记住当前的远端地址别名并提交,下次提交可以直接 git push
  • git push -u --all:推送所有分支并设置上游
  • git push -u --all --tags:推送所有分支及标签

git 删除远程分支

  • git branch -dr 『remote/branch』:删除远程分支与本地分支的跟踪关系
  • git push --delete origin 『branch』:删除远程分支
  • git push origin :<branchName>:推送一个空分支到远程分支,相当于删除远程分支

git 撤销/版本回退

  • git checkout 『file』:恢复暂存区的指定文件到工作区
  • git checkout master(master~1/master~2) 『file』:将当前分支工作区恢复到master分支当前/前一个/前两个commit版本并暂存,可以提交并推送到远程仓库
  • git checkout -- 『file』:丢弃工作区修改,恢复到最近一次 git commitgit add 状态. 这里有两种情况:
    1. 一种是 file 自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态
    2. 一种是 file 已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态
    3. git checkout -- file 命令中的 -- 很重要,没有 -- ,就变成了“切换到另一个分支”的命令
  • git checkout 『commit』 『file』:恢复某个 commit 的指定文件到暂存区和工作区 git checkout (7位commit字母) 『file』
  • git checkout .:放弃暂存区的文件修改,恢复到工作区初始状态
  • git reset 『file』:重置暂存区的指定文件,与上一次 commit 保持一致,但工作区不变
  • git reset HEAD file:可以把暂存区的修改撤销掉 (unstage) ,重新放回工作区,工作区内容不变
  • git reset --soft HEAD^:回滚到HEAD之前最近的一次提交,工作区不作任何改变
  • git reset --hard HEAD^:HEAD 表示当前版本, HEAD^HEAD^^ , 版本回退太多采用 HEAD~100
  • git reset --hard:重置暂存区与工作区,与上一次 commit 保持一致
  • git reset 『commit』:重置当前分支的指针为指定 commit ,同时重置暂存区,但工作区不变
  • git reset --hard 『commit』:重置当前分支的 HEAD 为指定 commit ,同时重置暂存区和工作区,与指定commit一致
  • git reset --keep 『commit』:重置当前 HEAD 为指定 commit ,但保持暂存区和工作区不变
  • git revert 『commit』:生成一次新的 commit,需要填写提交注释,会撤销指定 commit,后者的所有变化都将被前者抵消,并且应用到当前分支
  • git reflog:用来记录你的每一次命令
  • git stash:暂时将为提交的变化移除,稍后再移入
  • git stash pop

git 撤销修改总结

  1. 场景1:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令 git checkout -- file
  2. 场景2:当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令 git reset HEAD file ,就回到了场景1,第二步按场景1操作。
  3. 场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,参考下面的版本回退总结,不过前提是没有推送到远程库。

git 版本回退总结

  • HEAD指向的版本就是当前版本,因此,Git允许我们在版本的历史之间穿梭,使用命令 git reset --hard commit_id
  • 穿梭前,用 git log 可以查看提交历史,以便确定要回退到哪个版本。
  • 要重返未来,用 git reflog 查看命令历史,以便确定要回到未来的哪个版本。

git 代码冲突常见解决方法

error: Your local changes to the following files would be overwritten by merge: protected/config/main.php
Please, commit your changes or stash them before you can merge.

  • 如果希望保留生产服务器上所做的改动,仅仅并入新配置项, 处理方法如下:
1
2
3
git stash
git pull
git stash pop

然后可以使用 git diff -w +文件名 来确认代码自动合并的情况.

反过来,如果希望用代码库中的文件完全覆盖本地工作版本. 方法如下:

1
2
git reset --hard
git pull

分支策略 Git flow

  • 在项目中长期存在两个分支: master 和 develop
  • 日常开发基于 develop 分支创建三个临时分支
    1. 功能分支:feature-功能名称,完成开发合并到 develop 分支后删除该分支
    2. 预发布分支:release-版本号,测试完成后合并到 develop 和 master 分支后删除该分支
    3. 修补bug分支:fixbug-名称,该分支是从 master 分支上面分出来的,修补结束后再合并到 master 和 develop 分支,最后删除该分支

git 每次 clone/pull/push 都要输入密码解决方案

  1. 进入项目路径下
  2. 输入 git config --global credential.helper store
  3. 然后,打开.gitconfig文件,发现下面代码,以后提交克隆输入一次用户名密码就ok了
1
2
[credential]
helper = store

如果没解决则可能是 git 开启了双因子控制,通过以下命令解决:

1
2
3
git remote -v
git remote origin
git remote add origin 你的项目仓库地址

github

  • git push origin 【空格】【冒号】【你的分支名字】: 删除github上的远程分支
  • Github 可以让你使用社交化的方式进行编程协作,免费在线托管你的仓库,实现多人合作
  • 多人协作
    • Pull Request
    • Collaborators
      • 项目页面->Settings->Collaborators->添加协作者
      • 协作者会收到一封email,然后点进去收到的邮件同意成为协作者

github pages 配合 hexo

  • github 免费提供一个静态资源托管服务
  • 新建一个仓库
    • 仓库名必须是: 你的 github用户名.github.io

hexo

  • 安装: npm install hexo-cli -g
    • hexo-cli是hexo的命令行模式, CLI = Command Line Interface, 官网推荐用户只安装一个 hexo-cli 即可. 在执行hexo init blognpm install的时候, hexo-cli 会自动安装 hexo 到博客的 node_modules 目录下. 另外, hexo-cli 安装后, 命令行的命令叫做 hexo, 这其实只是一个别名而已……
  • 初始化: hexo init blog
  • hexo server: 用于启动服务器, 主要用于本地预览
  • hexo new 文章名称(不用加后缀名.md, 它会自动加)
  • hexo generate: 生产静态文件, 该命令会把所有 md 文件以及其他资源生成到 public 目录中, 生产结束之后可以把 public 丢到一个 web 容器中, 就可以直接访问了, 不需要依赖于 hexo 了
  • 假如以后新增了一篇文章,使用 hexo generate 命令重新生成该目录

hexo常用命令(# 后面是注释)

  • hexo g # 完整命令为 hexo generate ,用于生成静态文件
  • hexo s # 完整命令为 hexo server ,用于启动服务器, 主要用来本地预览
  • hexo d # 完整命令为 hexo deploy ,用于将本地文件发布到github上
  • hexo n # 完整命令为 hexo new ,用于新建一篇文章