Git随身手册

本文是关于Git探索的一篇文章,阐述了Git的大部分命令和使用方式,并列举了几个典型的使用场景以供参考和体会。

对于Git这个分布式的VCS,从链表的角度来看待是最容易理解的:

一次commit相当于添加一个节点,节点由hash标识,内容就是所做修改的索引;每个分支都是一条链,有一个指向头结点的指针HEAD

Git配置

下载地址:点我跳转下载

添加环境变量:

以Windows为例:

%GIT_HOME%\bin;%GIT_HOME%\usr\bin;

生成SSH密钥:

ssh-keygen -t rsa -C "example@abc.com"

会提示输入路径,建议:

/c/User/用户名/.ssh/id_rsa_abc

添加多Host环境

添加多host环境,对于在公司使用自己的机器是很有必要的,公私分明嘛~

文件位置/C/User/用户名/.ssh/config,没有就新建一个:内容如下

# 配置git.oschina.net
Host git.oschina.net
HostName git.oschina.net
IdentityFile C:\\Users\\用户名\\.ssh\\id_rsa_oschina
PreferredAuthentications publickey
User oschinaUserName # 配置github.com
Host github.com
HostName github.com
IdentityFile C:\\Users\\用户名\\.ssh\\id_rsa_github
PreferredAuthentications publickey
User githubUserName

测试连接:

连通后会生成 /C/User/用户名/.ssh/known_hosts 文件:

ssh -T git@github.com
ssh -T git.oschina.net

这样就可以把公钥 id_rsa_xxx 添加到git服务器上的 SSH Keys 中去了。

最后可按需要,顺带配置用户信息:

全局配置:

git config --global user.name 姓名
git config --global user.email 邮箱

为当前仓库设置用户信息:

git config --local user.name 姓名
git config --local user.email 邮箱

一般仓库可以采用SSH方式关联,但必须以HTTP/HTTPS方式关联远程仓库时,可以考虑记住密码:在用户目录下生成文件.git-credential记录用户名密码的信息。

# 默认会话时长(据说是15min):
git config --local credential.helper cache # linux/mac
git config --local credential.helper wincred # windows # 自己定义会话时间:
git config credential.helper 'cache --timeout=3600' # linux/mac
git config credential.helper 'wincred --timeout=3600' # windows
# 不过期会话时间:
git config --local credential.helper store

至此,Git配置结束。

Git操作

Git相关的命令如果记不太清楚可以使用提示:

git --help
git 具体某条命令 --help

仓库(clone,remote,fetch,pull,push)

在当前目录初始化一个仓库:

git init

克隆一个远程仓库:

git clone <URL> [--branch <branch> --depth=1] [./dir]

# 准备后续免密push的操作(字符需要Escape方式编码,git remote -v可看到密码)
git clone http://账号:密码@git.ops.test.com.cn/root/puppet.git

添加子module,这样子文件夹会做文件处理:

git submodule add <URL> <./submodule>

远程仓库关联:

git remote [-v]
git remote add <name> <URL>
git remote set-url <name> <URL>
git remote remove <name>

拉取本地仓库没有的内容(新增分支,远程分支修改等):

git fetch [origin <branch>]

拉取本分支的更新并合并:pull = fetch + merge,默认拉去所有合并到对应分支,当指定远程分支时默认合并到当前分支:

git pull origin <remote_branch>[:<local_branch>]

准备推送本分支的修改到远程仓库前可以先查看本地分支和远程分支的关联情况:

git branch -vv

已经关联远程分支可以直接push:

git push

远程分支不存在:

git push [-u] origin <local_branch>:<remote_branch>
# -u 表示添加关联

只关联不push:

git branch --set-upstream-to <origin/remote_branch> <local_branch>

忽略追踪(.gitignore)

编辑仓库中的 .gitignore 文件,内容格式如下

vim .gitignore
# 忽略目录
build/
# 忽略yml后缀文件
*.yml
# 不忽略a.yml
!a.yml

gitignore只能忽略untracked文件,对于stracked文件需要删除索引:

git rm --cached [-r] <file>

Git中的文件状态

Git仓库中文件大概有如下几种状态,并可通过相应的操作切换:

staging area(add)

  • 保存(new-untracked)和(modified),不包括(remove-untracked):
git add .
  • 保存(remove-untracked)和(modified),不包括(new-untracked):
git add -u
  • 保存所有变化:
git add -A
  • 部分提交,后续会有选择,舍弃的修改将留在working directory:
git add -p filename
# y - 存储这个hunk
# n - 不存储这个hunk
# q - 离开,不存储这个hunk和其他hunk
# a - 存储这个hunk和这个文件后面的hunk
# d - 不存储这个hunk和这个文件后面的hunk
# g - 选择一个hunk
# / - 通过正则查找hunk
# j - 不确定是否存储这个hunk,看下一个不确定的hunk
# J - 不确定是否存储这个hunk,看下一个hunk
# k - 不确定是否存储这个hunk,看上一个不确定的hunk
# K -不确定是否存储这个hunk,看上一个hunk
# s - 把当前的hunk分成更小的hunks
# e - 手动编辑当前的hunk
# ? - 输出帮助信息

暂存(stash)

这样可以保持分支的工作现场干净,操作对象是整个staging area

# push
git stash # pick
git stash apply # pop
git stash drop # pop & pick
git stash pop

repository(commit)

提交:

git commit [filename] -m "annotation"

提交working directory,相当于:git add -u + git commit -m "boom~"

git commit -am "boom~"

撤销HEAD并提交staging area补充到HEAD提交:

git commit -amend -m "make up"

查看(status,log,diff,blame,grep)

查看staging areaworking directory的状态:

git status

查看提交记录:

git log --online --graph --all
# all: 所有分支(默认当前)
# oneline: 简易hash, --pretty=oneline
# graph: 画出合并切出图

操作记录,含reset

git reflog --oneline

文件对比:

  • 对比 (staging area | repository) 和 working directory
git diff [branch1 branch2] <file>
# 加branch会对比两个分支中的文件
  • 对比 repositoryworking directory
git diff HEAD <file>
  • 对比 repositorystaging area
git diff --cached <file>

查看修改人:

git blame <file>

查找内容:

git grep '[123]\{1,\}'

分支(branch,checkout,merge)

分支可以理解为链表,链表中的元素是commit

查看分支:

# -a 包含远程分支
git branch [-a]

切出分支:

git checkout origin/release|$hash$|tags/v1.0

# 切出分支并切换当前分支
git checkout -b|-B <new_branch> origin/release|$hash$|tags/v1.0 # 仅切出新分支
git branch <new_branch> origin/release|$hash$|tags/v1.0

合并developmaster

  1. 合并前检查是否存在冲突:
git diff master develop --stat
  1. 开始合并,并解决冲突:
(master)$ git merge [--squash] develop
# --squash 融合提交记录,参见rebase # 对于无法自动合并的冲突需要手动处理
<<<<<< HEAD
# 当前更改
======
# 传入的更改
>>>>>> dev
  1. 提交前检查冲突是否处理完毕:
git diff --check
# 如果没问题就可以 commit -am 了
  1. 如果冲突太多太麻烦,想放弃解决了,可以终止:
git merge --abort

删除分支:

# -r表示一并删除origin里面分支,这只是删除了一个本地追踪,下次不会再fetch它:
git branch -d [-r] <branch_name>
# 删除远程的分支还需要push过去删除
git push origin -d <remote_branch>

标签(tag)

Fetch仓库TAG:

git fetch origin --tags

查看TAG:

git tag
git tag -l 'v1.0.*'
git show v1.0.0

在当前分支HEAD打TAG:

git tag v0.1
# 在某个commit上打tag,并加附注
git tag -a v0.2 -m "version 0.1 released" $hash$

push tag:

git push origin v1.0
# push 本地所有tag
git push origin --tags

删除tag

# 删除本地tag
git tag -d v1.0
# 删除远程tag
git push origin --delete tag v1.0

cherry-pick

使用cherry-pick可以把其他分支的一部分commit提交到当前分支:

git log --all --online
# cherry-pick
git cherry-pick [-n] $hash$ $hash$
#-n,表示先不commit,把commits保留到staging area

撤销(checkout,reset,revert,rm)

checkout:用staging area覆盖work directory

git checkout -- <file>

reset:用repository覆盖staging area,若working directory有修改,则丢弃staging area

git reset HEAD <file>
  • soft, 把repository的($hash$,HEAD]切出到staging area
git reset --soft HEAD~1|$hash$
  • mixed, 把repository的($hash$,HEAD]切出到working directory
git reset --mixed HEAD~1|$hash$
  • hard, 把repository的($hash$,HEAD]抛弃:
git reset --hard HEAD~1|$hash$

案例:找回reset掉的内容:

  1. 查看操作记录:
git reflog --oneline
  1. 找到某次reset操作(reset记录会以reset前的HEAD做hash标识),把HEAD指向它:
git reset --hard $reset_hash$
# 或者
git rebase --onto HEAD HEAD $reset_hash$

revert:提交逆修改,HEAD继续前进,而resetHEAD回退:

git revert HEAD~1|$hash$

rm --cached:删除追踪索引,不能操作work directory的文件;该操作会把文件从staging area|repository 移到work directory并置为untracked;此外如果该文件曾commit过,会在staging area生成一个deleted:<file>记录:

git rm --cached [-r] <file>

rm:删除repository中的文件,并在staging area添加一个deleted:<file>

git rm <file>

rm -f:删除untracked文件和文件夹:

git rm <file> -f [-r] [-q]
# -r 表示递归
# -q 无删除回显

clean -fd:清理工作区,递归删除所有untracked的文件和文件夹:

git clean -fd

好了,重头戏来了。

衍合(rebase)

这个翻译其实有些抽象,rebase的作用是对一段线性提交做一些操作,操作后分化出一个新的分支。

这里我对提交的理解是:若干个commit以hash标识成点,形成一个commit链;其中HEAD是指针变量,分支名是指针常量(链表头结点,或者理解成一维数组名)。

下面的语法中,endpoint是可选的,默认为HEAD。如果发现endpoint常量指针(即分支名),则分化出的分支自动应用到该分支并checkout过去。

语法:

git rebase [-i] [--onto] [base_branch] startpoint [endpoint]
# 其中线性提交段是 (startpoint, endpoint],前开后闭

rebase合入分支最新修改(merge按时间排序commit,rebase根据分支排序),reabase把冲突处理交给提MR的人处理,提交记录比merge更干净:

git rebase origin/master [HEAD]
# solve conflicts
git add <conflict_files>
git rebase --continue

编辑分支上的一段线性提交(reword,squash,reorder,drop):

git rebase -i startpoint [endpoint]
# p, pick = 使用提交
# r, reword = 使用提交,但修改提交说明
# e, edit = 使用提交,但停止以便进行提交修补
# s, squash = 使用提交,但和前一个版本融合
# f, fixup = 类似于 "squash",但丢弃提交说明日志
# x, exec = 使用 shell 运行命令(此行剩余部分)
# d, drop = 删除提交

下面分析4个rebase典型案例,假设当前分支状态如下图所示:

案例1-并集:next基于master;此时得知master有新修改,next需要同步master的最新修改。

git rebase master next

# 命令完成后自动切到next分支
# 此时next = [master + next#HEAD]

案例2-差集:topic基于next,next基于master;此时得知next有重大bug,要求topic中属于next部分的提交都得去掉。

# 差集计算:topic = master + (topic - next)
git rebase --onto master next topic # 多段差集:topic = master + (topic#HEAD~4, topic]
git rebase --onto master HEAD~4 topic

案例3-修改commit:编辑(reword,reorder,edit,drop)一段Commit:

git rebase -i HEAD~4 HEAD

案例4-融合commit:融合(squash)操作也属于修改,但这里单独拿出来示例,因为它可以多人合作完成,也可以个人独立完成:

  1. 方式一:由A同学解冲突。 A同学利用squash合并commit,B同学直接合并。
# A同学
git rebase -i next topic # B同学
(next)$ git merge topic
  1. 方式二:由B同学解冲突。 B同学自己融合A同学提交的MR。
(next)$ git merge --squash topic
git commit -m "merged topic to next"

其他命令(mv,repack,bisect)

# 重命名/移动staged的文件后自动处于staged
git mv oldfile newfile
git mv file folder # repack 把松散对象打包以提高git运行效率
git repack -d # 二分查找有问题的提交
git bisect start master f608824
git bisect run make test
# test脚本为判断是否有问题的依据
line = gets
exit 1 if line != "15\n"

一些技巧

  1. 浅克隆:对于比较大的仓库,本地不想要那么多无关的分支,无关的历史记录,可以考虑浅克隆。
# 以浅克隆的方式获取库
git clone <URL> --branch <master> --depth=1 # 添加origin中的分支
git remote set-branches origin <branch_new1> <branch_new2> # 以浅克隆的方式fetch origin中的分支
git fetch --depth 1 origin [<branch_new1>] # 深化origin 中的克隆深度为 N
git fetch origin --deepen N # 删除分支
git branch -rd <branch_name>
git push origin -d <branch_name>
  1. 拓扑序:对于提交日志,默认是按commit时间排序,拓扑序可以把相关联的多个提交放在一起显示。
# 默认按时间排序
git log --date-order --oneline # 指定拓扑排序
git log --topo-order --oneline
  1. 二分查找:有时候无法从final版本代码定位问题,可能需要回滚代码定位。可以考虑log(N)复杂度的二分查找。
# 开始二分查找(reset的时候会回到这个HEAD)
git bisect start
# 告诉git,当前的HEAD提交是有问题的
git bisect bad
# 告诉git,某个提交是OK的
git bisect good $hash$
# 这时git会reset到中间的commit,此时编译验证,并告知结果
git bisect <bad/good>
# 这样git会不断划分区间查找,最终会告诉你哪个commit有问题。找到后退出查找模式
git bisect reset

以上。

此外,如题,笔者也在不停探索,如果有错误欢迎指出斧正~

最后感谢这个游戏:Githug

以及这个通关攻略:「Githug」Git 游戏通关流程

还有这个在线练习平台:Git在线练习

Git随身手册的更多相关文章

  1. git学习手册

    #git学习手册 git: Git是一个开源的分布式版本控制系统,可以有效.高速的处理从很小到非常大的项目版本管理.[2] Git 是 Linus Torvalds 为了帮助管理 Linux内核开发而 ...

  2. Ubuntu下安装Git以及Git帮助手册【转】

    转自:http://milkythinking.com/blog/2011/04/17/install_git_and_manual/ Git简介 Git是一个分布式版本控制系统,对应的是SVN.CV ...

  3. svn 迁移至git操作手册

    svn 迁移至git操作手册 项目交付.版本管理工具变更等情况下,迁移svn旧历史记录有很大必要,方便后续追踪文件的提交历史,文件修改记录比对等.git自带了从svn迁移至git的工具命令,可很好的对 ...

  4. Git使用手册【转】

    转自:https://www.jianshu.com/p/e32a8e7ca93b 目录: Git是什么 基本概念 Git的诞生 Git的安装与配置 创建版本库 Git操作略览 远程仓库:git的杀招 ...

  5. Git Manual / Git使用手册 / Git, GitLab, Git Bash, TortoiseGit (建议全文复制到Word文档中通过导航窗格查看)

    Git使用手册 目录 1     引言 2     Git.GitLab简介 2.1      Git 2.2      GitLab 2.3      Git基本概念 3     运行环境 4    ...

  6. 《mac的git安装手册-1》

    <mac的git安装手册-1> 下载地址 https://git-scm.com/downloads 如果遇到上面这个问题打开系统偏好设置: OK,这样就能安装了

  7. 《mac的git安装手册-2》

    <mac的git安装手册-2> 下载地址 https://git-scm.com/downloads 如果遇到打不开的情况,请在系统偏好设置内——>安全性与隐私下 ——>选择仍 ...

  8. 常用Git命令手册

    常用Git命令手册 此文只是对Git有一定基础的人当记忆使用,比较简略,初级学员强烈推荐廖雪峰老师的Git系列教程,通俗易懂,戳此处即可开始学习 1.安装Git Linux sudo apt-get ...

  9. Git使用手册/Git教程:git fetch 将远程仓库的分支及分支最新版本代码拉取到本地

    相关文章: 关于验证是否存在ssh配置以及生成SSH Key的方法可以参照文章:Git使用手册:生成SSH Key 关于SSH Key的使用和公钥在gitHub.gitLab的配置等,请参考文章:Gi ...

随机推荐

  1. [leetcode] 464. Can I Win (Medium)

    原题链接 两个人依次从1~maxNum中选取数字(不可重复选取同一个),累和.当一方选取数字累和后结果大于等于给定的目标数字,则此人胜利. 题目给一个maxNum和targetNum,要求判断先手能否 ...

  2. 【MySQL】(二)InnoDB存储引擎

    InnoDB是事务安全的MySQL存储引擎,设计上采用了类似于Oracel数据库的架构.通常来说,InnoDB存储引擎是OLTP应用中核心表的首选存储引擎.同时,也正是因为InnoDB的存在,才使My ...

  3. 单调栈&单调队列

    最近打了三场比赛疯狂碰到单调栈和单调队列的题目,第一,二两场每场各一个单调栈,第三场就碰到单调队列了.于是乎就查各种博客,找单调栈,单调队列的模板题去做,搞着搞着发现其实这两个其实是一回事,只不过利用 ...

  4. [填坑] ubuntu检测不到外接显示器

    笔记本是win10+ubuntu18双系统,今天ubuntu(开启nivida独显状态)突然无法连外接屏幕,但切换win10就可以显示. 贴吧找到的简单解决方法,不需要重装驱动,记录分享在这里: su ...

  5. 深入学习 Intellij IDEA 调试技巧

    程序员的日常工作除了写代码之外,很大一部分时间将会在查找 BUG,解决问题.查找 BUG,离不开在 IDE 中调试代码.熟练的掌握调试技巧,可以帮助我们减少查找时间,快速定位问题. 在 IDEA 中调 ...

  6. centos6.5-7编译安装Ansible详细部署

    一.基础介绍==========================================================================================ansi ...

  7. win10去除快捷方式小箭头

    切忌删除注册表项: HKEY_CLASSES_ROOT -> lnkfile -> IsShortcut 这个方法以前是可以的,但是在2018年之后更新的系统就会出现任务栏图标打不开的情况 ...

  8. Golang Context 包详解

    Golang Context 包详解 0. 引言 在 Go 语言编写的服务器程序中,服务器通常要为每个 HTTP 请求创建一个 goroutine 以并发地处理业务.同时,这个 goroutine 也 ...

  9. abp(net core)+easyui+efcore实现仓储管理系统目录

    abp(net core)+easyui+efcore实现仓储管理系统目录 abp(net core)+easyui+efcore实现仓储管理系统——ABP总体介绍(一) abp(net core)+ ...

  10. 一份新的lilypond谱子,能设置页边距和设置换页符了

    给学生做的一份乐谱,这回能设置页边距了,以及设置换页符了. 顺带能设置一些代码片段(snippet),可以用热键代替使用 设置页边距的snippet: \paper { %双引号里面填页面大小 #(s ...