GIT教程
Git基础
Git官网(下载速度慢) https://git-scm.com/
阿里云加速(下载速度快):https://npm.taobao.org/mirrors/git-for-windows/
01——版本控制
集中式(svn)
svn因为每次存的都是差异 需要的硬盘空间会相对的小一点 可是回滚的速度会很慢
优点:
代码存放在单一的服务器上 便于项目的管理
缺点:
服务器宕机: 员工写的代码得不到保障
服务器炸了: 整个项目的历史记录都会丢失
分布式(git)
git每次存的都是项目的完整快照 需要的硬盘空间会相对大一点
(Git团队对代码做了极致的压缩 最终需要的实际空间比svn多不了太多 可是Git的回滚速度极快)
优点:
完全的分布式
缺点:
学习起来比SVN陡峭
02——版本管理
-
版本库👉
.git
-
- 当我们使用git管理文件时,比如
git init
时,会创建出一个.git
文件,我们把这个文件称为版本库。 .git文件
另外一个作用就是它在创建的时候,会自动创建master分支
,并且将HEAD指针指向master分支。
- 当我们使用git管理文件时,比如
-
工作区
-
- 本地项目存放文件的位置,即workspace
-
暂存区(Index/Stage)
-
- 暂时存放文件的地方,通过add命令将工作区的文件加到缓冲区
-
本地仓库(Repository)
-
- 通常情况下,我们使用commit命令可以将暂存区的文件添加到本地仓库
- 通常而言,HEAD指针指向的是master分支
-
远程仓库(Remote)
-
- GitHub托管项目时,它就是一个远程仓库
- 通常我们使用clone命令将远程仓库代码拷贝下来,本地代码更新后,通过push推送到远程仓库
工作流程:「工作区 -> 暂存区 -> 版本库」
「Git是什么」
Git是一个版本管理控制系统(缩写VCS),它可以在任何时间点,将文档的状态作为更新记录保存起来,也可以在任何时间点,将更新记录恢复回来。
「基本工作流程」
git仓库 | 暂存区 | 工作目录 |
---|---|---|
用于存放提交记录 | 临时存放被修改文件 | 被Git管理的项目目录 |
「Git底层命令」git对象、树对象、提交对象
git存储数据,一个文件对应一条内容,校验和(生成的哈希值)的前两个字符用于命名子目录,余下的38个字符则用作文件名
git对象: Git 的核心部分是一个简单的键值对数据库 。 你可以向该数据库插入任意类型的内容,它会返回一个键值,通过该键值可以在任意时刻再次检索该内容
git hash-object -w fileUrl : 生成一个key(hash值):val(压缩后的文件内容)键值对存到 .git/objects
在Git中,文件名并没有被保存——我们仅保存了文件的内容 解决方案:树对象 tree对象:fileUrl–文件路径 所有内容均以树对象和数据对象 (git 对象 的形式存储,其中树对象对应了 UNIX 中的目录项,数据对象 (git 对象 则大致上对应文件内容
git update-index --add --cacheinfo 100644 hash test.txt : 往暂存区添加一条记录(让git对象 对应上 文件名 )存到.git/index
git write-tree : 生成树对象存到.git/objects
现在有三个树对象 (执行了三次 write tree ),分别代表了我们想要跟踪的不同项目快照。然而问题依旧:若想重用这些快照,你 必须记住所有三个SHA 1 哈希值。 并且,你也完全不知道是谁保存了这些快照,在什么时刻保存的,以及为什么保存这些快照。 而以上这些,正是提交对象( commit object)能为你保存的基本信息
我们 可以通过调用 commit tree 命令创建一个提交对象,为此需要指定一个树对象的 SHA 1 值,以及该提交的父提交对象(如果有的话 第一次将暂存区做快照就没有父对象)
commit对象
echo 'first commit' | git commit-tree treehash : 生成一个提交对象存到.git/objects
对以上对象的查询 git commit tree 不但生成提交对象 而且会将对应的快照(树对象)提交到本地库中
echo 'second commit' | git commit-tree 0155eb -p hash值(第一次提交对象hash)
// cac0cab538b970a37ea1e769cbbde608743bc96d
echo 'third commit' | git commit-tree 3c4e9c -p cac0cab
// 1a410efbd13591db07496601ebc7a059dd55cfe9
git cat-file -p hash : 拿对应对象的内容
git cat-file -t hash : 拿对应对象的类型
查看暂存区
git ls-files -s
「Git高层命令」CRUD
C(新增) Create
命令: git init
解析: 要对现有的某个项目开始用 Git 管理,只需到此项目所在的目录,执行: git init
作用: 初始化后,在当前目录下会出现一个名为 .git 的目录,所有 Git 需要的数据和资源都存放在这个目录中。不过目前,仅仅是按照既有的结构框架 初始化好了里边所有的文件和目录,但我们还没有开始跟踪管理项目中的任何一个文件。
U(修改) Update
在工作目录中修改文件
git status // 确定文件当前处于什么状态
git add ./ // 跟踪一个新文件,放到暂存区,同时做成git对象放到版本库(工作目录到版本库,再到暂存区)
git commit -m "msg"
D(删除 & 重命名) Delete
git rm 要删除的文件 git mv 老文件 新文件
git status git status
git commit -m "msg" git commit -m "msg"
R(查询) Retrieve
git status : 查看工作目录中文件的状态(已跟踪(已提交 已暂存 已修改) 未跟踪)
git diff : 查看未暂存的修改
git diff --cache : 查看未提交的暂存
git log --oneline : 查看提交记录
分支
分支的本质其实就是一个提交对象!!!
HEAD:
是一个指针 它默认指向master分支 切换分支时其实就是让HEAD指向不同的分支
每次有新的提交时 HEAD都会带着当前指向的分支 一起往前移动
git log --oneline --decorate --graph --all : 查看整个项目的分支图
git branch : 查看分支列表
git branch -v: 查看分支指向的最新的提交
git branch name : 在当前提交对象上创建新的分支
git branch name commithash: 在指定的提交对象上创建新的分支
git checkout name : 切换分支
git branch -d name : 删除空的分支 删除已经被合并的分支
git branch -D name : 强制删除分支
「Git使用前配置」
在使用git前,需要告诉git你是谁,在向git仓库中提交时需要用到。
- 配置提交人姓名:
git config --global user.name 提交人姓名
// 全局配置 不加global就只针对项目 - 配置提交人邮箱:
git config --global user.email 提交人邮箱
- 查看git配置信息:
git config --list
- 取消配置信息 git config --global --unset user.name
- 取消配置信息 git config --global --unset user.email
「注意」
- 如果要对配置信息进行修改,重复上述命令即可。
- 配置只需要执行一次。
「配置别名」
Git并不会在你输入部分命令时自动推断出你想要的命令。 如果不想每次都输入完整的 Git 命令,可以通过 git config 文件来轻松地为每一个命令设置一个别名。
$ git config --global alias.co checkout
$ git config --global a lias.br branch
$ git config --global alias.ci commit
$ git config --global alias.st status
// 当要输入git commit 时,只需要输入 git ci
「Git提交步骤」
-
git init
初始化git仓库- hooks 目录包含客户端或服务端的钩子脚本;
info 包含一个全局性排除文件
logs 保存日志信息
objects 目录存储所有数据内容;
refs 目录存储指向数据的提交对象的指针(分支)
config 文件包含项目特有的配置选项
description 用来显示对仓库的描述信息
HEAD 文件指示目前被检出的分支
index 文件保存暂存区信息
- hooks 目录包含客户端或服务端的钩子脚本;
-
git status
查看文件状态 -
git add 文件列表
追踪文件 -
git commit -m 提交信息
向本地仓库中提交代码 -
git log
查看提交记录 -
git rm 文件名 删除工作目录中对应的文件,再将修改添加到暂存区
-
git mv 原文件名 新文件名 将工作目录中的文件进行重命名,再将修改添加到暂存区
-
git push https://github.com/ovfan/git-demo.git master
本地仓库推送到GitHub远程仓库 -
git remote add origin https://github.com/ovfan/git-demo.git
为远端仓库地址添加别名。 -
- 添加完别名后,下次推送使用
git push origin master
- 添加完别名后,下次推送使用
-
git push -u 远程仓库地址别名 分支名称
-u 记住推送地址及分支,下次推送只需要输入git push
即可
「撤销」
- 用暂存区中的文件覆盖工作目录中的文件:
git checkout 文件
- 将文件从暂存区中删除:
git rm --cached 文件
- 将git仓库中指定的更新记录恢复出来,并且覆盖暂存区和工作区目录:
git reset --hard commitID
当暂存区域已经准备妥当可以提交时,在此之前,请一定要确认还有什么修改过的或新建的文件还没有 git add 过,否则提交的时候不会记录这些还没暂存起来的变化。所以,每次准备提交前,先用 git status 看下,是不是都已暂存起来了,然后再运行提交命令 git commit
工作目录下面的所有文件都不外乎这两种状态: 已跟踪(已提交 已修改 或者 已暂存)或 未跟踪
克隆仓库 后的文件
如果在克隆仓库之后立即执行此命令,会看到类似这样的输出:
On branch master
nothing to commit, working directory clean
未跟踪文件
如果 创建一个新文件 README 保存退出后运行 git status 会看到该文件出现
在未跟踪文件列表中:
On branch master
U ntracked files:
(use "git add <file>..." to include in what will be
README
nothing added to commit but untracked files present (use "git add" to
track)
跟踪新文件(暂存)
命令: git add 文件名
作用: 跟踪一个新文件
再次运行 git status 命令,会看到 README 文件已被跟踪,并处于暂存状态:
Changes to be committed:
(use "git reset HEAD <file>..." to
new file: README
暂存已修改文件
Git 只不过暂存了你运行 git add 命令时的版本,如果现在提交,那么提交的是添加注释前的版本,而非当前工作目录中的版本。所以,运行gitadd 之后又作了修订的文件,需要重新运行 git add 把最新版本重新暂存起来:
$ git add README
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to
new file: README
查看已暂存和未暂存的更新
如果要查看具体修改了什么地方,可以用 git diff 命令 这个命令 它已经能 解决 我们两个问题了: 当前做的哪些更新还没有暂存?有哪些更新已经暂存起来准备好了下次提交?
1. 当前做的哪些更新还没有暂存?
命令: git diff 不加参数直接输入 git diff
2. 有哪些更新已经暂存起来准备好了下次提交?
命令: git diff cached 或者 git diff staged(1.6.1 以上
Git进阶
01----分支
为了便于理解,可以认为分支就是当前工作目录中代码的一份副本,使用分支,可以让我们从开发主线上分离出来,以免影响开发主线。分支本质是一个提交对象,所有的分支都会有机会被HEAD所引用(HEAD一个时刻只会指向一个分支),当我们有新的提交的时候 HEAD会携带当前持有的分支往前移动
Git 的分支,其实本质上仅仅是指向提交对象的可变指针 。 Git 的默认分支名字是 master 。 在多次提交操作之后,你其实已经有一个指 向最后那个提交对象的 master 分支。 它会在每次的提交操作中自动向前移动。
「分支细分」
- 主分支(master):第一次向 git 仓库中提交更新记录时自动产生的一个分支。
主分支,用于部署生产环境的分支,确保稳定性。
master分支一般由develop以及hotfix分支合并,任何情况下都不能直接修改代码。
-
开发分支(develop):作为开发的分支,基于 master 分支创建。
develop为开发分支,通常情况下,保存最新完成以及bug修复后的代码。
开发新功能时,feature分支都是基于develop分支下创建的。
-
功能分支(feature):作为开发具体功能的分支,基于开发分支创建。
开发新功能,基本上以develop为基础创建feature分支。
分支命名:feature/ 开头的为特性分支, 命名规则: feature/user_module、 feature/cart_module。
-
**release分支:**release 为预上线分支,发布提测阶段,会release分支代码为基准提测。
-
hotfix分支:分支命名:hotfix/ 开头的为修复分支,它的命名规则与 feature 分支类似。线上出现紧急问题时,需要及时修复,以master分支为基线,创建hotfix分支,修复完成后,需要合并到master分支和develop分支。
「功能分支 -> 开发分支 -> 主分支」
只在 master 主分支上保留完全稳定的代码——有可能仅仅是已经发布或即将发布的代码。 他们还有一些名为 develop 或者 feature 的平行分支,被用来做后续开发或者测试稳定性——这些分支不必保持绝对稳定,但是一旦达到稳定状态,它们就可以被合并入 master 分支了。等待下一次的发布。
「分支命令」
-
git branch
查看本地分支 -
git branch -r
查看远程分支 -
git branch 分支名称
创建分支 -
git checkout -b 分支名称
创建并切换到新建分支
-
git checkout 分支名称
切换分支 -
git merge 来源分支
合并分支 -
git branch -d 分支名称
删除分支 -
- 分支被合并后才允许删除
git branch -D
强制删除
-
git branch -m <oldbranch-name> <newbranch-name>
重命名分支 -
git log --oneline --decorate --graph --all 查看项目分叉历史
-
git branch name(旧版本名字) commitHash(旧版本的hash值) 新建一个分支并且使分支指向对应的提交对象
-
git add .
全部上传到缓存区 -
git add 指定文件
指定文件上传到缓存区
查看分支列表 : git branch
查看合并到当前分支的分支列表: git branch --merged
一旦出现在这个列表中 就应该删除
查看没有合并到当前分支的分支列表: git branch --no-merged
一旦出现在这个列表中 就应该观察一下是否需要合并
「暂时保存更改」—Git存储
在git 中,可以暂时提取分支上所有的改动并存储,让开发人员得到一个干净的工作副本,临时转向其他工作。
注:在切换分支时,如果当前分支上有未暂存的修改 或者 有未提交的暂存,分支可以切换成功,但是可能会污染其他分支
使用场景:分支临时切换
- 存储临时改动:
git stash
- 恢复改动:
git stash pop
「Git分支的注意点」
在切换的时候 一定要保证当前分支是干净的!!!
允许切换分支:
分支上所有的内容处于 已提交状态
(避免)分支上的内容是初始化创建 处于未跟踪状态
(避免)分支上的内容是初始化创建 第一次处于已暂存状态
不允许切分支:
分支上所有的内容处于 已修改状态 或 第二次以后的已暂存状态
在分支上的工作做到一半时 如果有切换分支的需求, 我们应该将现有的工作存储起来
git stash : 会将当前分支上的工作推到一个栈中
分支切换 ---> 进行其他工作 ---> 完成其他工作后 ---> 切回原分支
git stash apply : 将栈顶的工作内容还原 但不让任何内容出栈
git stash drop : 取出栈顶的工作内容后 就应该将其删除(出栈)
** git stash pop : git stash apply + git stash drop 加上将要移除的储藏的名字来移除它
git stash list : 查看存储
「实际案例分析」
工作流:
1 开发某个网站。
2 为实现某个新的需求,创建一个分支。
3 在这个分支上开展工作。
正在此时,你突然接到一个电话说有个很严重的问题需要紧急修补。你将按照如下方式来处理:
1 切换到你的线上分支( production branch )。
2 为这个紧急任务新建一个分支,并在其中修复它。
3 在测试通过之后,切换回线上分支,然后合并这 个修补分支,最后将改动推送到线上分支。
4 切换回你最初工作的分支上,继续工作。
Git 流:
首先,我们假设你正在你的项目上工作,并且已经有一些提交。
现在,你已经决定要解决你的公司使用的问题追踪系统中的#53 问题。 想要新建一个分支并同时切换到那个分支上,你可以运行一个带有 b 参数的 git checkout命令
git checkout b iss53
相当于
git branch iss53
git checkout iss53
你继续在#53 问题上工作,并且做了一些提交。 在此过程中, iss53 分支在不断的向前推进,因为你已经检出到该分支。
!!!现在你接到那个电话,有个紧急问题等待你来解决
有了 Git 的帮助,你不必把这个紧急问题和 iss53 的修改混在一起,你也不需要花大力气来还原关于 53# 问题的修改,然后再添加关于这个紧急问题的修改,最后将这个修改提交到线上分支。 你所要做的仅仅是切换回 master 分支。但是,在你这么做之前,要留意你的工作目录和暂存 区里那些还没有被提交的修改,它可能会和你即将检出的分支产生冲突从而阻止 Git 切换到该分支 。 最好的方法是,在你切换分支之前,保持好一个干净的状态。 (提交你的所有修改)
git checkout master // 切换回主的master
这个时候,你的工作目录和你在开始 #53 问题之前一模一样,现在你可以专心修复紧急问题了。 请牢记:当你切换分支的时候, Git 会重置你的工作目录,使其看起来像回到了你在那个分支上最后一次提交的样子。 Git 会
自动添加、删除、修改文件以确保此时你的工作目录和这个分支最后一次提交时的样子一模一样。
接下来,你要修复这个紧急问题。 让我们建立一个针对该紧急问题的分支( hotfix branch ),在该分支上工作直到问题解决。
git checkout -b hotfix
做出修改
git commit -a -m 'fixed the broken email address'
你可以运行你 的测试,确保你的修改是正确的,然后将其合并回你的 master 分支来部署到线上。 你可以使用 git merge 命令来达到上述目的
git checkout master
git merge hotfix
在合并的时候, 有时候会出现 快进( fast forward 这个词。 由于当前 master 分支所指向的提交是你当前提交的直接上游,所以 Git 只是简单的将指针向前移动。 换句话说,当你试图合并两个分支时,如果顺着一个分支走下去能够到达另一个分支,那么 Git 在合并两者的时候,只会简单的将指针 向前推进(指针右移),因为这种情况下的合并操作没有需要解决的分歧 这就叫做 快进( fast forward)
关于这个紧急问题的解决方案发布之后,你准备回到被打断之前时的工作中。 然而,你应该先删除 hotfix 分支,因为你已经不再需要它了master 分支已经指向了同一个位置。 你可以使 用带 d 选项的 git branch 命令来删除分支 。 现在你可以切换回你正在工作的分支继续你的工作,也就是针对 #53 问题的那个分支
git branch -d hotfix
git checkout iss53
你在 hotfix 分支上所做的工作并没有包含到 iss53 分支中。 如果你需要拉取 hotfix 所做的修改,你可以使用 git merge master 命令将 master 分支合并入 iss53 分支,或者你也可以等到 iss53 分支完成其使命,再将其合并回 master 分支。
git checkout master
git merge iss53
最终删除 iss 53 号分支
git branch -d iss53
冲突
有时候合并操作不会如此顺利。 如果你在两个不同的分支中,对同一个文件的同一个部分进行了不同的修改, Git 就没法干净的合并它们。 如果你对 #53 问题的修改和有关 hotfix 的修改都涉及到同一个文件的同一处,在合并它们的时候就会产生合并冲突此时 Git 做了合并,但是没有自动地创建一个新的合并提交。 Git 会暂停下来,等待你去解决合并产生的冲突。 你可以在合并冲突后的任意时刻使用 git status 命令来 查看那些因包含合并冲突而处于未合并( unmerged)状态的文件。在你解决了所有文件 里的冲突之后,对每个文件使用 git add 命令来将其标记为冲突已解决。 一旦暂存这些原本有冲突的文件, Git 就会将它们标记为冲突已解决
「后悔药」
撤销工作目录的修改 : git checkout -- filename // 作用:将在工作目录中对文件的修改撤销
撤销暂存区的修改 : git reset HEAD filename // 作用:将文件从暂存区中撤回到工作目录
撤销提交 : git commit --amend // 作用:注释写错了可以修改一次
这个命令会将暂存区中的文件提交。如果自上次提交以来你还未做任何修改(例如,在上次提交后马上执行了此命令),那么快照会保持不变,而你所修改的只是提交信息(注释内容)
如果 你提交后发现忘记了暂存某些需要的修改,可以像下面这样操作
git commit -m 'initial commit'
git add forgotten_file
git commit -amend
最终你只会有一个提交 第二次提交将代替第一次提交的结果
「reset三部曲」
// 移动 HEAD
git reset --soft commithash ---> 用commithash的内容重置HEAD内容
git reset [--mixed] commithash ---> 用commithash的内容重置HEAD内容 重置暂存区
git reset --hard commithash ---> 用commithash的内容重置HEAD内容 重置暂存区 重置工作目录
「路径reset」
所有的路径reset都要省略第一步!!!
第一步是重置HEAD内容 我们知道HEAD本质指向一个分支 分支的本质是一个提交对象
提交对象 指向一个树对象 树对象又很有可能指向多个git对象 一个git对象代表一个文件!!!
HEAD可以代表一系列文件的状态!!!!
git reset [--mixed] commithash filename
用commithash中filename的内容重置暂存区
「checkout深入理解」
git checkout brancname 跟 git reset --hard commithash特别像
共同点
都需要重置 HEAD 暂存区 工作目录
区别
checkout对工作目录是安全的 reset --hard是强制覆盖
checkout动HEAD时不会带着分支走而是切换分支
reset --hard时是带着分支走
checkout + 路径
git checkout commithash filename
重置暂存区
重置工作目录
git checkout -- filename
重置工作目录
「Git基本流程细化」
【初始化仓库】git init
当我们运行 git init ,这会创建一个 Git 仓库,其中的 HEAD 引用指向未创建的分支。此时,只有工作目录有内容
【获取工作目录内容】git add
现在我们想要提交这个文件,所以用 git add 来获取工作目录中的内容,并将其复制到索引中
【保存快照并创建提交对象】git commit
接着运行 git commit ,它会取得索引中的内容并将它保存为一个永久的快照,然后创建一个指向该快照的提交对象,最后更新 master 来指向本次提交。
commit -m 和 commit -am 的区别
git commit -m “” 只会提交添加到缓存区的文件(只提交添加的)
git commit -a -m “” 能提交修改过,但是没有添加到缓存区的文件(修改过的就能提交)
【状态查询】git status
此时如果我们运行 git status ,会发现没有任何改动,因为现在三棵树完全相同
【文件修改并提交】
现在我们想要对文件进行修改然后提交它。 我们将会经历同样的过程;首先在工作目录中修改文件。 我们称其为该文件的 v2 版本,并将它标记为红色
如果现在运行 git status ,我们会看到文件显示在 “Changes not staged for commit,” 下面并被标记为红色,因为该条目在索引与工作目录之间存在不同。接着我们运行 git add 来将它暂存到索引中。
此时,由于索引和 HEAD 不同,若运行 git status 的话就 会看到“Changes to be committed” 下的该文件变为绿色 也就是说,现在预期的下一次提交与上一次提交不同。 最后,我们运行 git commit 来完成提交。
现在运行 git status 会没有输出,因为三棵树又变得相同了
【切换分支或克隆】
切换分支或克隆的过程也类似。 当检出一个分支时,它会修改 HEAD 指向 新的分支引用,将 索引 填充为该次提交的快照,然后将 索引 的内容复制到工作目录中 。
【重置reset三部曲】
移动 HEAD:
reset 做的第一件事是移动 HEAD 的指向。假设我们再次修改了 file.txt 文件并第三次提交它。 现在的历史看起来是这样
git reset -soft HEAD~ :这与改变 HEAD 自身不同( checkout 所做的); reset 移动 HEAD 指向的分支。 HEAD~ 加个波浪号 代表回到上一次的 HEAD指向
看一眼上图,理解一下发生的事情:它本质上是撤销了上一次 git commit 命令。 当你在运行 git commit 时, Git 会创建一个新的提交,并移动 HEAD 所指向的分支来使其指向该提交 。
当你将它 reset 回 HEAD~ (HEAD 的父结点)时,其实就是把该分支移动回原来的位置,而不会改变索引和工作目录。 现在你可以更新索引并再次运行 git commit 来完成 git commit --amend 所要做的事情了。
注:如果还想回到v3版本,可以git reflog 找到v3版本的hash值,然后git reset --soft [hash值]
更新暂存区(索引)
!!!注意 git reset HEAD~ 等同于 git reset --mixed HEAD~
理解一下发生的事情:它依然会撤销一上次 提交 ,但还会 取消暂存 所有的东西。 于是,我们回滚到了所有 git add 和 git commit 的命令执行之前。
更新工作目录
你撤销了最后的提交、 git add 和 git commit 命令 以及 工作目录中的所有工作。
checkout [branch] 与reset --hard [branch]的区别
不带路径:
首先不同于 reset --hard,checkout 对工作目录是安全的,它会通过检查来确保不会将已更改的文件弄丢。而 reset --hard 则会不做检查就全面地替换所有东西。
第二个重要的区别是如何更新 HEAD。 reset 会移动 HEAD 分支的指向,而 checkout 只会移动 HEAD 自身来指向另一个分支。
带路径:
git checkout commithash <file>
运行 checkout 的另一种方式就是指定一个文件路径,这会像 reset 一样不会移动 HEAD 。 它就像是 git reset --hard [branch] file。 这样对工作目录并不安全,它也不会移动 HEAD 将会跳过第 1 步 更新暂存区 和 工
作目录
git checkout -- <file> // 相比于 git reset --hard commitHash 跟文件名的形式第一 第二步都没做
【数据恢复】git reflog
当你正在 工作时, Git 会默默地记录每一次你改变 HEAD 时它的值。 每一次你提交或改变分支,引用日志都会被更新
git reflog 并不能显示 足够多的信息。 为了使显示的信息更加有用,我们可以执行 git log -g ,这个命令会以标准日志的格式输出引用日志
例如下面的那个就是你丢失的提交,你可以通过创建一个新的分支指向这个提交来恢复它。 例如,你可以创建一个名为 recover branch 的分支指向这个提交( ab1afef)
git branch recover branch ab1afef
现在有一个名为 recover branch 的分支是你的 master 分支曾经指向的地方,再一次使得前两次提交可到达。
【打标签tag】
Git 可以给历史中的某一个提交打上标签,以示重要。
列出标签
git tag
git tag -l 'v1.8.5*'
v1.8.5 v1.8.5-rc0 v1.8.5 rc1 v1.8.5 rc2 v1.8.5 rc3 v1.8.5.1 v1.8.5.2 v1.8.5.3
创建标签
Git使用两种主要类型的标签:轻量标签 与 附注标签
轻量标签很像一个不会改变的分支—它只是一个特定提交的引用
git tag v1.4
git tag v1.4 commitHash
// 附注标签是存储在 G it 数据库中的一个完整对象。 它们是可以被校验的;其中包含打标签者的名字、电子邮件地址、日期时间;等等
git tag -a v1.4
git tag -a v1.4 commitHash
git tag -a v1.4 commitHash m 'my version 1.4'
查看特定标签:
git show tagname //git show可以显示任意类型的对象( git 对 象 树对象 提交对象 tag 对象)
远程标签
默认情况下,git push 命令并不会传送标签到远程仓库服务器上。 在创建完标签后你必须显式地推送标签到 共享服务器上。你可以运行
git push origin [tagname]
如果想要一次性推送很多标签,也可以使用带有--tags 选项的 git push 命令。这将会把所有不在远程仓库 服务器上的标签全部传送到那里。
git push origin --tags
删除标签
删除标签要删除掉你本地仓库上的 标签,可以使用命令 git tag -d < tagname>。
应该注意的是上述命令并不会从任何远程仓库中移除这个标签,你必须使用
git push <remote> :refs/tags/<tagname> 来更新你的远程仓库:
git push origin :refs/tags/v1.4
检出标签
如果你想查看某个标签所指向的文件版本,可以使用git checkout 命令
git checkout tagname
02-----GitHub
当和开发团队共享数据时,设置一个远程仓库,可以把它看成一个文件管理服务器
,利用这个服务器可以与开发团队的其他成员进行数据交换。
「三个必须懂得概念」
本地分支 创建本地分支,在需要打包的文件根目录下 git init --> git add * --> git commit -m “message"
远程跟踪分支(remote/分支名) 在GitHub上新建仓库,复制关联代码 git remote add origin xxx 到本地运行
远程分支 git push oringin master (先关联再推送)
「远程协作的基本流程」
第一步: 项目经理创建一个空的远程仓库
第二步: 项目经理创建一个待推送的本地仓库
第三步: 为远程仓库配别名 配完用户名 邮箱
git remote add <shortname> <url> //添加一个新的远程 Git仓库,同时指定一个你可以轻松引用的简写
git remote -v // 显示远程仓库使用的 Git 别名 与其对应的 URL
git remote show [remote-name] // 查看某一个远程仓库的更多信息
git remote rename pb paul // 重命名
git remote rm [remote-name]//如果因为一些原因想要移除一个远程仓库 你已经从服务器上搬走了或不再想 使用某一个特定的镜像了,又或者某一个贡献者不再贡献了
第四步: 在本地仓库中初始化代码 提交代码
第五步: 推送
git push [remote-name] [branch-name] // 将本地项目的master分支推送到 origin(别名) 服务器
第六步: 邀请成员 // 如果你想与他人合作,并想给他们提交的权限,你需要把他们添加为 Collaborators,别人接受
第七步: 成员克隆远程仓库
git clone url (克隆时不需要 git init 初始化) // 默认克隆时为远程仓库起的别名为 origin
第八步: 成员做出修改
第九步: 成员推送自己的修改
git push [remote-name] [branch-name]
第十步: 项目经理拉取成员的修改
git fetch [remote-name] //必须注意 git fetch 命令会将数据拉取到你的本地仓库 它并不会自动合并或修改你当前的工作。 当准备好时你必须手动将其合并入你的工作。
git merge [远程跟踪分支]
「远程跟踪分支」
远程跟踪分支
利用远程跟踪分支将本地分支与远程分支进行交互,远程跟踪分支 是远程分支状态的引用。它们是你不能移动的本地分支。当你做任何网络通信操作时,它们会自动移动。
当克隆 一个仓库时,它通常会自动地创建一个跟踪 origin/master 的 master 分支
本地没有分支
git checkout --track 远程跟踪分支(remote/分支名)
本地已经创建了分支
git branch -u 远程跟踪分支(remote/分支名)
假设你的网络里有一个在 git.ourcompany.com 的 Git 服务器。 如果你从这里克隆, Git 的 clone 命令会为你自动将其命名为 origin ,拉取它的所有数据,创建一个指向它的 master 分支的指针,并且在本地将其命名为 origin/master 。 Git 也会给你一个与 origin master 分支在指向同一个地方的本地 master 分支,这样你就有工作的基础
如果你在本地的 master 分支做了一些工作,然而在同一时间,其他人推送提交到 git.ourcompany.com 并更新了它的 master 分支,那么 你们 的提交历史将向不同的方向前进。 只要你不与 origin 服务器连接,你的origin /master 指针就不会移动
如果要同步你的工作,运行 git fetch origin 命令。 这个命令查找 “origin” 是哪一个服务器(在本例中,它是 git.ourcompany.com从中抓取本地没有的数据,并且更新本地数据库,移动 origin/master 指针指向新的、更新后的位置。
推送其他分支
当你想要公开分享一个分支时,需要将其推送到有写入权限的远程仓库上。 本地的分支并不会自动与远程仓库同步。 你必须显式地推送想要分享的分支。 这样,你就可以把不愿意分享的内容放到私人分支上,而将需要和别人协作的内容推送到公开分支
如果希望和别人一起在名为 serverfix 的分支上工作,你可以像推送第一个分支那样推送它。
git push origin serverfix
这里有些工作被简化了。 Git 自动将 serverfix 分支名字展开为 refs/heads/serverfix:refs/heads/serverfix 你也可以运行 git push origin serverfix:serverfix。它会做同样的事 相当于它说, 推送本地的 serverfix 分支,将其作为远程仓库的 serverfix 分支。
git push origin serverfix:awesomebranch
如果并不想让远程仓库上的分支叫做 serverfix ,可以运行 以上命令 将本地的 serverfix 分支推送到远程仓库上
的 awesomebranch 分支 。
git fetch origin
下一次其他协作者从服务器上抓取数据时,他们会在本地生成一个远程 跟 踪 分支 origin/serverfix ,指向服务器的 serverfix 分支的引用 。 要特别注意的一点是当抓取到新的远程跟踪分支时,本地不会自动生成一份可编辑的副本(拷贝)。 换一句话说,这种情况下,不会有一个新的serverfix分支只有一个不可以修改origin/ serverfix指针 。
git merge origin/serverfix ( 其他协作者)
可以运行 git merge origin/serverfix 将这些工作合并到当前所在的分支。 如果想要在自己的 serverfix 分支上工作,可以将其建立在远程跟踪分支之上:
git checkout b serverfix origin/serverfix (其他协作者)
跟踪分支
从一个远程跟踪分支( origin/master) 检出一个本地分支会自动创建一个叫做 “ 跟踪分支 ”(有时候也叫做 “上游分支 ”: master )。只有主分支 并且 克隆时才会自动建跟踪分支。跟踪分支是与远程分支有直接关系的本地分支。 如果在一个跟踪分支上输入 git pull。Git 能自动地识别去哪个服务器上抓取、合并到哪个分支 。
删除远程分支
git push origin --delete serverfix //删除远程分支
git remote prune origin --dry --run //列出仍在远程跟踪但是远程已被删除的无用分支
git remote prune origin // 清除上面命令列出来的远程跟踪
「拉取操作」
如果你想要参与某个项目,但是并没有推送权限,这时可以对这个项目进行“派生”( Fork )。 派 生的意思是指, GitHub 将在你的空间中创建一个完全属于你的项目副本,且你对其具有推送权限。通过这种方式,项目的管理者不再需要忙着把用户添加到贡献者列表并给予他们推送权限。 人们可以派生这个项目,将修改推送到派生出的项目副本中,并通过创建合并请求( Pull Request )来让他们的改动进入源版本库。
派生(Fork)基本流程:
1. 从 master 分支中创建一个新分支 (自己 fork 的项目)
2. 提交一些修改来改进项目 (自己 fork 的项目)
3. 将这个分支推送到 GitHub 上 (自己 fork 的项目)
4. 创建一个合并请求
5. 讨 论,根据实际情况继续修改
6. 项目的拥有者合并或关闭你的合并请求
派生注意点:
每次在发起新的Pull Request 时 要去拉取最新的源仓库的代码而不是自己 fork 的那个仓库。
git remote add <shortname 源仓库 > <url 源仓库
git fetch 远程仓库名字
git merge 对应的远程跟踪分支
- 克隆远端数据仓库到本地:
git clone 仓库地址
- 拉取远程仓库中最新的版本:
git pull 远程仓库地址 分支名称
「ssh免登录」
生成密钥:ssh-keygen
密钥存储目录:C:\Users\lenovo\.ssh
公钥名称:id_rsa.pub
私钥名称:id_rsa
「Git忽略清单」
将不需要被git管理的文件名字添加到此文件中,在执行git命令的时候,git就会忽略这些文件。
git忽略清单文件名称:「.gitignore」
将工作目录中的文件全部添加到暂存区:git add .
看看如何配置该文件信息。👇
# 此行为注释 会被Git忽略
# 忽略 node_modules/ 目录下所有的文件
node_modules
# 忽略所有.vscode结尾的文件
.vscode
# 忽略所有.md结尾的文件
*.md
# 但README.md 除外
!README.md
# 会忽略 doc/something.txt 但不会忽略doc/images/arch.txt
doc/*.txt
# 忽略 doc/ 目录下所有扩展名为txt文件
doc/**/*.txt
GIt命令汇总大全
Git 底层命令 --剖析Git对象
find .git/objects -type f
// 用find命令查看.git/objects目录(递归子目录)中的所有文件
git rev-list --objects --all
// 查看所有git对象的SHA-1哈希值与文件名的对应关系
git rev-list --objects --all | grep 83c4fbc43a6f187d4e8a247a1c9aced872b2315d
// 查看SHA-1哈希值为83c4fbc43a6f187d4e8a247a1c9aced872b2315d的文件名
echo "Hello World!" | git hash-object --stdin
// 计算内容为Hello World!文件的SHA-1哈希值
echo "Hello World!" | git hash-object -w --stdin
// 计算内容为Hello World!文件的SHA-1哈希值并写入到当前git本地版本库中
git hash-object README.txt // 查看README.txt的SHA-1哈希值
git hash-object -w README.txt // 查看README.txt的SHA-1哈希值并写入到当前git本地版本库中
git cat-file -p master^^{tree}
// 查看master分支HEAD指针git目录(tree对象)下的各子目录(tree对象)和文件(blob对象)的SHA-1哈希值
100644 blob 7abd3a56703ad4a7120571967f5d06607b5e5502 README.txt
040000 tree 9f448c40e684dc38109574007c661277c815fb7e ss
注:040000:表示目录 100644:表示一般文件 100755:表示可执行文件 120000:表示符号链接
git cat-file -p 7abd3a56703ad4a7120571967f5d06607b5e5502
// 查看SHA-1哈希值为7abd3a56703ad4a7120571967f5d06607b5e5502文件的内容
git show 7abd3a56703ad4a7120571967f5d06607b5e5502
// 查看SHA-1哈希值为7abd3a56703ad4a7120571967f5d06607b5e5502文件的内容
git cat-file -t f3961f5 // 查看f3961f5提交对象的类型:显示为commit
git cat-file -p f3961f5
/ 查看f3961f5提交对象的信息:包含git目录(tree对象)、上次提交对象的SHA-1哈希值及提交时Author、Date和注释信息
tree ead34240822030a3f71df4fc351057d80d7d83f8
parent 33d5bbc5d61b024aab5078e40548c4e3da808e0e
author kekec <kekec@qq.com> 1537258258 +0800
committer kekec <kekec@qq.com> 1537258258 +0800
123 desc txt
git cat-file -p tag1.0 // 查看轻量标签或附注标签tag1.0信息
git cat-file tag tag1.0 // 查看附注标签tag1.0信息
git ls-tree ead34240822030a3f71df4fc351057d80d7d83f8
// 查看tree目录对象ead34240822030a3f71df4fc351057d80d7d83f8中包含的blob文件对象和tree目录对象
git ls-tree HEAD // 查看HEAD所指向tree目录对象中包含的blob文件对象和tree目录对象
git verify-pack -v .git/objects/pack/pack-a9282552b62cbe3f255fbb20374695a17c1ba2a2.idx
// 查看pack-a9282552b62cbe3f255fbb20374695a17c1ba2a2.pack压缩包中的内容
git update-index n.txt // 将修改状态的n.txt文件添加到暂存区
git update-index --add n.txt // 将未追踪状态或修改状态的n.txt文件添加到暂存区
git update-index --add --cacheinfo 100644 5d11580eed65ffd34b6786274a60460b3582aa7d n.txt
// 使用类型为100644、SHA-1哈希值为5d11580eed65ffd34b6786274a60460b3582aa7d的信息将追踪状态或修改状态的n.txt添加到暂存区
git write-tree // 将整个暂存区内容生成一个tree对象,并输出其SHA-1哈希值
echo "add n.txt" | git commit-tree 31b7ca405196ca9e8fb4d5404b315bef9f2c841f -p HEAD
// 用git write-tree得到的31b7ca405196ca9e8fb4d5404b315bef9f2c841f树对象创建一个注释为add n.txt的提交对象,并将提交对象的父亲设置为当前HEAD
git update-ref refs/heads/master 372aa8e425b57ca30e2974b8e7737133caaa0b7f
// 若当前分支为master,更新HEAD指向上面git commit-tree命令得到的372aa8e425b57ca30e2974b8e7737133caaa0b7f提交对象,此时用git log就可以看到这条commit记录
git write-tree --prefix=ss // 将暂存区中ss目录下的内容 生成一个tree对象,并输出其SHA-1哈希值
git update-ref -d refs/remotes/origin/v1.0 // 删除v1.0远程分支cache
git update-index --chmod=+x engine_mac.sh
// 为engine_mac.sh增加可执行权限(linux、unix、mac os x系统上需要)
Git 标准命令大全
配置
git config --global user.name "kekec" // 配置提交用户名
git config --global user.email "kekec@qq.com" // 配置e-mail信息
git config --global core.editor vim // 配置默认文本编辑器,当Git 需要你输入信息时会调用它
git config --global alias.st status // 为status配置别名st,这样git status就可以写成git st
git config --list // 查看当前仓库的所有配置信息(包括分支相关的信息)
git config user.name // 查看当前仓库的用户名信息
git config -e --global // 编辑全局配置文件(用户名和e-mail信息就记录在其中) 所在目录:c:/users/<用户名>/.gitconfig
git config -e // 编辑当前仓库的配置文件 所在目录:.git\config
git config --global credential.helper wincred // windows下删除git凭据,后面执行git命令会弹框要求输入用户名和密码
创建版本库
git init // 在当前目录创建一个空的git代码库
git init MyGame // 在当前目录创建一个名为MyGame的文件夹,然后在其中创建一个空的git代码库
git目录解析
logs/refs/heads:各个本地分支的版本log记录
logs/refs/remotes:各个远程分支cache的log记录
logs/refs/stash:储藏区数据
logs/HEAD:git操作记录
objects:2级文件索引(把SHA-1哈希值拆成了:2位+38位),存储commit数据、blob文件数据和tree目录数据
objects/pack:pack文件为存储commit、tree目录及blob文件的压缩数据;idx文件为pack文件中各数据对象的索引
objects/info/packs:该文件记录所有git库的pack文件列表
refs/heads:各个本地分支HEAD
refs/remotes:各个远程分支cache的HEAD
refs/tags:各个附注标签的信息
COMMIT_EDITMSG:上一次提交的注释
config:版本库相关的配置信息
description:仓库描述信息,供gitweb程序使用
index:暂存区相关的信息
HEAD:指向当前分支的最近提交(如:ref: refs/heads/master)
注:可通过git rev-parse HEAD命令打印当前HEAD的commit id
ORIG_HEAD:执行git merge/git pull/git reset操作时
会把调整为新值之前的先前版本的HEAD记录到OERG_HEAD中,用于恢复或回滚之前的状态
FETCH_HEAD:git fech将所有抓取分支的HEAD记录到.git/FETCH_HEAD中
MERGEHEAD:正在合并进HEAD的commit id
packed-refs:远程版本库cache和远程标签cache
日志与文件状态
git reflog // 查看操作记录 注:每条操作记录使用HEAD@{n}来标识
git show HEAD@{5} // 查看索引为5的操作记录的详细信息
git status // 查看当前所处的分支暂存区和工作区的文件(会显示当前所处分支)
注1:处于暂存区的文件状态::staged(已暂存);处于工作区的文件状态::untrack(未跟踪)、modified(已修改)
注2:工作区中的空目录不会被git追踪
git status -s --ignored // 以简洁模式查看暂存区和工作区的文件(全部显示,不执行文件过滤)
git status -uno // 查看暂存区和工作区的非untrack(未跟踪)状态文件
git status -uall // 查看暂存区和工作区的状态文件(递归子目录显示出里面的文件)
git log // 查看本地版本库提交记录(会显示当前所处分支,HEAD指针指向哪个分支的哪条提交)
git log --stat // 查看本地版本库提交记录(会显示当前所处分支,HEAD指针指向哪个分支的哪条提交和每次提交的文件变更简略统计信息)
git log -- README.md // 查看README.md文件的本地版本库提交记录
git log --graph -- README.md // 以图形化方式查看README.md文件的本地版本库提交记录
git log -p README.md // 查看README.md文件的本地版本库提交记录(显示出每次的修改内容)
git log --grep "test" // 显示注释中含有test字符串的提交
git log --author=kekec // 查看本地版本库中作者为kekec的提交记录
git log -S "SplitPath(FString& str)" // 查看SplitPath(FString& str)内容是什么时候加到项目中那些文件中去的
git log --since=2.weeks // 查看最近2周的提交记录
git log --since="2 weeks 3 days 2 hours 30 minutes 59 seconds ago" // 查看2周3天2小时30分59秒以前的提交记录
git log --after="2018-10-7" --before="2018-10-12" // 查看2018.10.7~2018.10.12之间的提交记录
git log --since="2018-10-7" --until="2018-10-12"
// 功能同上:git log --after="2018-10-7" --before="2018-10-12"
注:--since、--until 标记和 --after、--before 标记分别是等价的
git whatchanged README.md // 查看README.md文件的本地版本库提交记录(包括文件改名)
git log --follow README.md // 功能同上:git whatchanged README.md
git log -3 // 查看最近3条本地版本库提交记录
git log -3 --pretty --oneline // 查看最近3条本地版本库提交记录(简洁模式,一行显示一个提交)
git log --graph --oneline // 以图形化简洁模式查看当前分支的本地版本库提交记录
git log release --graph --oneline // 以图形化简洁模式查看release分支的本地版本库提交记录
git log --graph --oneline --no-merges // 以图形化简洁模式查看当前分支的本地版本库提交记录(过滤merge过来的提交)
git log --graph --oneline --merges // 以图形化简洁模式查看当前分支的本地版本库提交记录(只显示有2个及以上父亲节点的提交)
git log --graph --oneline --name-only // 以图形化简洁模式查看当前分支的本地版本库提交记录(并显示每次提交的文件名称清单)
git log --graph --oneline --name-status // 以图形化简洁模式查看当前分支的本地版本库提交记录(并显示每次提交的文件状态、名称清单)
git log --graph --oneline --stat // 以图形化简洁模式查看当前分支的本地版本库提交记录(并显示每次提交的文件变化统计、各文件名及增删记录)
git log --graph --oneline --shortstat // 以图形化简洁模式查看当前分支的本地版本库提交记录(并显示每次提交的文件变化统计及增删记录)
git log --graph --oneline --decorate --all // 以图形化简洁模式查看所有分支的本地版本库提交记录树
git log --graph --pretty=format:"%H - %an, %ad : %s" // 自定义格式图形化查看所有分支的本地版本库提交记录树
git log master..v5.0 // 查看v5.0分支还未合并到master分支上的提交记录列表
git log v5.0..master // 查看master分支还未合并到v5.0分支上的提交记录列表
git log master...v5.0 // git log master..v5.0 + git log v5.0..master
git shortlog -sn // 统计各个提交者的次数
git blame README.md // 显示README.md最近一次的修改信息
git show 3a6c702376168aa15a2f3d7bc98000d07a70d023 README.md // 查看README.md文件的3a6c702376168aa15a2f3d7bc98000d07a70d023提交的修改内容
git show HEAD // 查看最近一次提交的修改内容
git show --name-only HEAD // 查看最近一次提交的文件列表(不显示具体的修改内容)
标签(查看/新建/切换/删除)
git tag // 列出所有的标签
git tag -l 'tag1*' // 列出所有tag1开头的标签
git tag tag1.0 // 创建名为tag1.0的轻量标签
git tag -a tag1.0 -m "tag1.0 desc" // 添加tag1.0 desc注释并创建名为tag1.0的附注标签
git tag tag2.0 abffefc5d82078cbaea7fcbb5106ab0c21cbeba9 // 在abffefc5d82078cbaea7fcbb5106ab0c21cbeba9提交处创建名为tag2.0的轻量标签
git tag -a tag2.0 -m "tag2.0 desc" abffefc // 在abffefc提交处创建名为tag2.0的附注标签
git tag -d tag2.0 // 删除名为tag2.0的标签
git show tag1.0 // 查看名为tag1.0相关的信息
git ls-remote --tags // 查看所有远端的标签
分支(查看/新建/切换/删除)
查看/新建
git branch // 列出所有本地分支
git branch -r // 列出所有远程分支cache
git branch -a // 列出所有本地分支和远程分支cache
git branch -av // 列出所有本地分支和远程分支cache(含简单说明)
git branch -vv // 查看所有本地分支和远程分支cache之间的追踪关系
git branch v1.0 // 在当前分支的HAED指针下创建名为v1.0的分支(创建完不会切到v1.0分支上)
git branch --track v1.0 origin/v1.0
// 若v1.0分支不存在则先新建,然后将其与远程分支origin/v1.0建立追踪关系 ① 远程分支origin/v1.0要存在,否则命令执行失败 ② 执行完不会切到v1.0分支上
git branch v2.0 372aa8e425b57ca30e2974b8e7737133caaa0b7f
// 在372aa8e425b57ca30e2974b8e7737133caaa0b7f提交处创建名为v2.0的分支(创建完不会切到v2.0分支上)
git branch -m v1.0 x1.0 // 将分支v1.0重命名为x1.0
切换/删除
git checkout v1.0 // 切换到v1.0分支上(v1.0分支不存在则命令执行失败)
git checkout -b v1.0 // 创建并切换到v1.0分支上(v1.0分支存在则命令执行失败)
git checkout -B v1.0 // 不存在则创建,并切换到v1.0分支上
git checkout -b v1.0 5a95f2d // 在5a95f2d提交处创建并切换到v1.0的分支上
git checkout -b v1.0 tag1.0 // 在标签tag1.0处创建并切换到v1.0的分支上
git checkout -t origin/v1.0 // 创建并切换到origin/v1.0远程分支cache的名为v1.0本地分支上,并建立两者追踪关系(本地分支v1.0存在则命令执行失败)
git checkout -b x1.0 -t origin/v1.0 、
// 创建并切换到origin/v1.0远程分支cache的名为x1.0本地分支上,并建立两者追踪关系(本地分支x1.0存在则命令执行失败)
注1:切换分支前,必须处理工作区(未追踪的文件不用处理)和暂存区的修改才能切换成功
注2:切换成功后,工作区会被设置成分支的内容
注3:不允许在远程分支cache上提交,需要创建对应关联的本地分支,然后在本地分支上进行提交
git checkout -f v1.0 // 强制切换到v1.0分支上,丢弃暂存区和工作区中的所有文件的修改(工作区中未追踪的文件不受影响)
git checkout -f -B v1.0 origin/v1.0
// 不存在则创建,强制切换到v1.0分支上,丢弃暂存区和工作区中的所有文件的修改,并将HEAD指向origin/v1.0处(工作区中未追踪的文件不受影响)
git checkout - // 切换到上一次分支
git branch -d v2.0 // 删除名为v2.0的分支(必须先切到其他分支上才能执行删除操作)
git branch -D v2.0 // 强制删除名为v2.0的分支(必须先切到其他分支上才能执行删除操作)
git branch -dr origin/v2.0 // 删除远程分支origin/v2.0 cache
文件(增加/删除/提交/撤销)
增加
git add README.md // 将当前目录下的README.md文件加入到暂存区
git add . // 将当前目录下(递归子目录)所有文件加入到暂存区
git add -u . // 将当前目录下(递归子目录)所有追踪状态的文件加入到暂存区
git add Doc/\*.txt // 将当前目录的Doc文件夹下(递归子目录)所有txt后缀的文件加入到暂存区
删除
git rm README.md // 删除工作区文件,并且将这次删除放入暂存区(若README.md在工作区或暂存区中有修改,命令会执行失败)
git rm -f README.md // 强制删除工作区文件,并且将这次删除放入暂存区(即使README.md在工作区或暂存区中有修改,也会执行删除操作)
git rm --cached README.md // 不删除工作区对应的文件,只将README.md删除放入暂存区以供提交
git mv README.md test.md // 将README.md改名为test.md,并且将这个改名放入暂存区
提交
git commit -m "desc" // 添加desc注释并将暂存区中的所有修改提交到本地仓库
git commit README.md -m "desc" // 添加desc注释并将暂存区中的README.md的修改提交到本地仓库
git commit --amend -m "desc" // 添加desc注释使用当前提交覆盖上一次的提交(若上一次提交包含1.txt和2.txt的修改,当前提交只包含1.txt的修改;执行命令后,本地版本库中为本次的1.txt和上一次2.txt)。若没有提交内容,则用来改写上一次提交的日志信息
git commit -m "desc" --amend README.txt // 添加desc注释使用README.txt的当前提交覆盖上一次的提交
git commit -a -m "desc" // 添加desc注释并将工作区和暂存区中的所有修改提交到本地仓库
git commit -am "desc" // 功能同上
git commit -c b5cad94d229e72bd7aff5fe2c6f022b29c30e7a8
// 拿372aa8e425b57ca30e2974b8e7737133caaa0b7f提交的信息(作者、提交者、注释、时间戳等)来提交当前修改
撤销
git reset -- README.md // 丢弃暂存区中的README.md文件的修改
git reset README.md // 功能如上 丢弃暂存区中的README.md文件的修改
git reset b5cad94 README.md // 使用本地版本库b5cad94提交处的README.md版本覆盖暂存区中的README.md
git reset // 丢弃暂存区中的所有文件的修改(工作区不受影响)
git reset --mixed // --mixed为缺省参数,命令与上面git reset一样
git reset --hard // 丢弃暂存区和工作区中的所有文件的修改(工作区中未追踪的文件不受影响)
git reset --hard 4.24.3-release
// 仅将当前分支的HEAD指向tag为4.24.3-release的位置(丢弃暂存区和工作区中的所有文件的修改,工作区中未追踪的文件不受影响)
git reset --soft b5cad94d229e72bd7aff5fe2c6f022b29c30e7a8
// 仅将当前分支的HEAD指向372aa8e425b57ca30e2974b8e7737133caaa0b7f提交(暂存区和工作区中的所有文件的修改都不丢弃)
git reset --soft HEAD~ // 仅将当前分支的HEAD指向上一次提交(暂存区和工作区中的所有文件的修改都不丢弃)
git reset --soft HEAD~2 // 仅将当前分支的HEAD指向上两次提交(暂存区和工作区中的所有文件的修改都不丢弃)
git reset --merge <commit> // 在被污染的工作区中回滚merge或者pull
(1) 即便你已经在本地更改了一些你的工作区,你也可安全的git pull,前提是你知道将要pull的内容不会覆盖你的工作区中的内容。
(2) git pull完后,你发现这次pull下来的修改不满意,想要回滚到pull之前的状态,我们可以执行git reset --hard ORIG_HEAD,但是这个命令有个副作用就是清空你的工作区,即丢弃你的本地未add的那些改变。
为了避免丢弃工作区中的内容,可以使用git reset --merge ORIG_HEAD,注意其中的--hard 换成了 --merge,这样就可以避免在回滚时清除工作区。
git reset --keep <commit> // 保留工作区并丢弃一些之前的提交
假设你正在编辑一些文件,并且已经提交,接着继续工作,但是现在你发现当前在工作区中的内容应该属于另一个分支,与之前的提交没有什么关系。此时,可以开启一个新的分支,并且保留着工作区中的内容。
(1) 这次是把在branch1中的改变提交了。
(2) 此时发现,之前的提交不属于这个分支,此时新建了branch2分支,并切换到了branch2上。
(3) 此时可以用reset --keep把在start之后的提交清除掉,但是保持工作区不变。
git checkout -- README.md // -- 符号非常重要,否则就变成了切换到README.md分支了
// 当README.md在暂存区中有修改时,使用暂存区中的修改覆盖工作区中的README.md
// 当README.md不在暂存区中时,使用本地版本库中的HEAD指针处的修改覆盖工作区中的README.md
git checkout -- . // 使用暂存区和本地版本库来恢复当前目录(递归子目录)下的所有文件 注:若暂存区中有修改,优先使用暂存区
git checkout HEAD README.md // 使用本地版本库中的HEAD处提交覆盖暂存区和工作区中的README.md
git checkout 9a387f22ff949fa16336508adc2284384bd6a890 README.md // 使用本地版本库中的9a387f22ff949fa16336508adc2284384bd6a890修改覆盖暂存区和工作区中的README.md
git checkout -b v2.0 tag2.0 // 在名为tag2.0的提交处创建并切换到v2.0分支上(v2.0分支存在则命令执行失败)
git revert --no-edit 3a6c702376168aa15a2f3d7bc98000d07a70d023 // 回滚3a6c702376168aa15a2f3d7bc98000d07a70d023提交,然后提交到本地仓库
git revert HEAD~ // 回滚HEAD的上一次提交,然后会弹出vim环境编辑注释(输入:q直接使用默认注释内容、输入:q!放弃修改使用默认注释内容、输入:x或:wq保存当前修改的注释内容),然后提交到本地仓库
git revert -n HEAD~3 // 回滚掉HEAD~3处的提交,不自动提交到本地仓库
git revert -n HEAD~2..HEAD // 回滚掉(HEAD~2, HEAD]之间的2次提交,不自动提交到本地仓库
注:git reset是把HEAD向后移动来删除提交,而git revert是用一次新的提交来回滚之前的提交(HEAD会继续前进)
查看差异
git diff README.md // 查看当前目录下的README.md在工作区和暂存区之间的差异
git diff --cached README.md // 查看当前目录下的README.md在暂存区和本地仓库最后一次提交之间的差异
git diff --cached 372aa8e425b57ca30e2974b8e7737133caaa0b7f README.md // 查看当前目录下的README.md在暂存区和本地仓库的372aa8e425b57ca30e2974b8e7737133caaa0b7f提交之间的差异
git diff HEAD README.md // 查看当前目录下的README.md在工作区和本地仓库HEAD指针处提交之间的差异
git diff 372aa8e425b57ca30e2974b8e7737133caaa0b7f README.md // 查看当前目录下的README.md在工作区和本地仓库的372aa8e425b57ca30e2974b8e7737133caaa0b7f提交之间的差异
git diff 372aa8e425b57ca30e2974b8e7737133caaa0b7f HEAD README.md // 查看当前目录下的README.md在本地仓库的372aa8e425b57ca30e2974b8e7737133caaa0b7f提交和最后一次提交之间的差异
git diff 372aa8e425b57ca30e2974b8e7737133caaa0b7f HEAD // 查看本地仓库的372aa8e425b57ca30e2974b8e7737133caaa0b7f提交和最后一次提交之间的差异
git diff 372aa8e b5cad94 README.md // 查看当前目录下的README.md在本地仓库的372aa8e提交和b5cad94提交之间的差异
注:可以将git diff换成git difftool来使用外部diff工具(可以在c:/users/<用户名>/.gitconfig文件配置beyond compare作为默认的difftool和mergetool)来查看差异
分支合并
git merge-base Master Feature // 查看Master和Feature分支的最优共同commit父节点
git merge Feature // 将Feature分支merge合并到当前分支Master(无冲突时会直接提交)
git merge -m "merge test" Feature // 将Feature分支merge合并到当前分支Master(无冲突时使用merge test注释直接提交)
git merge --no-commit Feature // 将Feature分支merge合并到当前分支Master(不自动提交)
git rebase Feature // 将Feature分支rebase合并到当前分支Master
注1:git rebase会先找出共同的祖先节点,从祖先节点把Feature分支的提交记录全都剪切下来,然后合到Master 分支(合并前后commitID会不一样)
注2:相对来说,git merge处理冲突更直接,但会增加一些冗余的提交记录;而git rebase能够保证清晰线性的提交记录,但这也将合并的操作没有被记录下来
注3:最好是用git rebase合并远程分支到本地,git merge合并Feature分支到Master分支
注4:在合并Feature分支到Master分支前,务必先执行git pull -r origin Feature来进行远程分支与本地分支的rebase合并
注5:处于冲突状态(conflict)的文件为UU(可通过git status -s --ignored来查找),手动处理完冲突后,然后使用git add该文件,最后继续执行git merge/rebase --continue来完成合并的提交工作
注6:README.md文件冲突内容如下
<<<<<<< HEAD
123 456 789 000 111 222 333 444 555 ss // 当前分支的内容
=======
123 456 789 000 ss tt // Feature分支的内容
>>>>>>> Feature
注7:可以使用git mergetool来使用外部merge工具(可以在c:/users/<用户名>/.gitconfig文件配置beyond compare作为默认的mergetool)来处理冲突。
修改完当前文件后,可再次调用git mergetool来处理下一个冲突,直至全部处理完毕,然后使用git add该文件,最后继续执行git merge/rebase --continue来完成合并的提交工作
git merge/rebase --abort // 撤销当前merge或rebase操作
git merge/rebase --skip // 强制使用Feature分支的内容
git merge/rebase --continue // 手动处理完冲突后使用git add该文件,最后继续执行git merge/rebase --continue来完成合并的提交工作
git merge origin/master // fetch完之后,可以将远程分支cache master分支merge合并到当前分支上
git rebase origin/master // fetch完之后,可以将远程分支cache master分支rebase合并到当前分支上
git rebase --onto master 76cada~ // 将当前分支从[76cada, HEAD]区间段的提交ebase合并到master上
git cherry-pick 9a341e // 将9a341e提交合入当前分支。若不冲突,则直接使用9a341e的提交信息进行commit,否则要先进行冲突处理,然后继续执行git cherry-pick --continue来完成合并的提交工作
git cherry-pick 371c2…971209 // 将(371c2, 971209]提交合入当前分支(每个提交都会在当前分支上创建一个commit)
git cherry-pick 371c2~…971209 // 将 [371c2, 971209] 提交合入当前分支(每个提交都会在当前分支上创建一个commit)
git cherry-pick -n 9a341e d2f99e // 将9a341e和d2f99e提交合入当前分支(不提交),后续需要手动commit
git cherry-pick --abort // 撤销当前cherry-pick操作
git cherry-pick --quit // 清理当前操作状态,不撤销修改强制退出cherry-pick操作过程
git cherry-pick --continue // 手动处理完冲突后,最后继续执行git cherry-pick --continue来完成合并的提交工作
查看远程版本库
git remote -v // 显示远程仓库的URL 注:由于git是分布式的,所有远程仓库可能有很多个
origin https://github.com/kekec/Test.git (fetch)
origin https://github.com/kekec/Test.git (push)
git remote-ls // 查看远程仓库URL和分支信息
From https://github.com/kekec/Test.git
fae0fc82d711425daa897a63137d7e1af09512ba HEAD
fae0fc82d711425daa897a63137d7e1af09512ba refs/heads/master
git remote // 查看远程仓库名称 一般为origin
git remote rename origin test // 将远程仓库名称从origin修改为test
git remote show origin // 显示远程仓库的信息
* remote origin
Fetch URL: https://github.com/kekec/Test.git
Push URL: https://github.com/kekec/Test.git
HEAD branch: master
Remote branches:
master tracked
v3.1 tracked
Local branch configured for 'git pull':
master merges with remote master
Local refs configured for 'git push':
master pushes to master (fast-forwardable)
v3.1 pushes to v3.1 (up to date)
git remote rm origin // 删除.git/config文件中添加remote origin相关的信息
git remote add origin https://github.com/kekec/Test.git // 在.git/config文件中添加remote origin指向的远程仓库URL(若已存在,则命令执行失败)
git remote set-url origin https://github.com/kekec/Test.git // 修改.git/config文件中添加remote origin指向的远程仓库URL
git remote prune origin // 对于远程仓库不存在的分支,清除对应的远程分支cache
远程操作
git clone https://github.com/kekec/Test.git // 将https://github.com/kekec/Test.git上的当前分支克隆到本地(会创建一个名为Test目录,远程仓库名称使用默认名origin)
git clone https://username:password@github.com/kekec/Test.git // 使用账号为username密码为password将https://github.com/kekec/Test.git上的当前分支克隆到本地(会创建一个名为Test目录,远程仓库名称使用默认名origin)
git clone https://github.com/kekec/Test.git MyProject // 将https://github.com/kekec/Test.git上的当前分支克隆到本地(会创建一个名为MyProject目录,远程仓库名称使用默认名origin)
git clone -b v1.0 https://github.com/kekec/Test.git // 将https://github.com/kekec/Test.git上的v1.0分支克隆到本地(会创建一个名为Test目录,远程仓库名称使用默认名origin)
git clone -b v1.0 https://github.com/kekec/Test.git d:\MyGame // 将https://github.com/kekec/Test.git上的v1.0分支克隆到d:\MyGame目录(会在d:\MyGame中创建一个名为Test目录,远程仓库名称使用默认名origin)
git clone -o TestPrj https://github.com/kekec/Test.git // 将https://github.com/kekec/Test.git上的当前分支克隆到本地(会创建一个名为Test目录,并将远程仓库名称设置为TestPrj)
git fetch origin master // 从远程仓库拉取master分支状态的变化信息(工作区文件不会更新)
git fetch // 从远程仓库拉取所有分支和tag状态的变化信息(工作区文件不会更新)
git fetch -p // 从远程仓库拉取所有分支和tag状态的变化信息,并清除已被删除的远程分支和tag在本地的缓存(工作区文件不会更新)
git fetch origin --tags // 从远程仓库拉取所有tag到本地(工作区文件不会更新)
git pull <远程仓库名> <远程分支名>:<本地分支名>
git pull origin master // 先执行fetch,然后将远程origin/master分支merge合并到当前分支(最后会更新origin/master, origin/HEAD指针到最新提交)
git pull https://github.com/kekec/Test.git master // 先执行fetch,将远程origin/master分支merge合并到当前分支(最后不会更新origin/master, origin/HEAD指针到最新提交)
git pull origin v1.0:master // 先执行fetch,然后将远程origin/v1.0分支merge合并到本地master分支
git pull origin // 先执行fetch,然后将对应的远程分支merge合并到当前分支(当前分支需要预存远程分支的追踪关系)
git pull // 先执行fetch,然后将对应的远程分支merge合并到当前分支(当前分支需要预存远程分支的追踪关系,而且当前分支只有一个远程仓库)
git pull -p // 先执行fetch,然后将对应的远程分支merge合并到当前分支,并清除已被删除的远程分支和tag在本地的缓存
git pull -r origin master // 先执行fetch,然后将远程origin/master分支rebase合并到master分支
git push <远程仓库名> <本地分支名>:<远程分支名>
git push -u origin master // 将本地仓库的修改push到origin所指向的远程仓库URL的master分支上,并在.git/config文件中记录当前分支与远程分支master的对应关系
git push origin // 将当前分支更新推送给对应的远端分支
git push // 将当前分支更新推送给对应的远端分支(当前分支只有一个远程仓库,可以省略仓库名origin)
git push origin -f // 使用当前分支更新强行覆盖对应的远端分支(合入远端分支有冲突时,也使用当前分支更新)
git push origin v1.0 // 将本地分支v1.0更新推送给对应的远端分支remotes/origin/v1.0
git push --set-upstream origin v1.0 // 将本地分支v1.0更新推送给对应的远端分支remotes/origin/v1.0,并将建立与远程分支origin/v1.0的追踪关系
git push origin --all // 将本地所有分支更新推送给各自对应的远端分支
git push origin tag1.0 // 将本地标签tag1.0更新到远端标签tag1.0
git push origin --tags // 将本地所有标签更新到对应的远端标签
git push origin :v1.0 // 删除远端分支v1.0
git push origin :refs/tags/tag1.0 // 删除远程标签tag1.0
git push origin -d v1.0 // 删除远端分支v1.0 功能同上
储藏区
git stash // 将工作区中所有文件的修改备份压栈到储藏区,然后丢弃工作区与暂存区的所有文件的修改
git stash pop // 使用储藏区的栈顶处备份(stash@{0})来恢复当前分支的工作区,并将栈顶备份移除
git stash apply stash@{1} // 使用储藏区的栈顶下面一个备份(stash@{1})来恢复当前分支的工作区,但不移除储藏区中任何备份
git stash list // 查看储藏区栈列表
git stash show -p stash@{0} // 查看储藏区的栈顶处备份中各个文件的内容
git stash drop // 直接移除储藏区的栈顶处备份(不用于恢复当前分支的工作区)
git stash clear // 清除储藏区栈列表
工作区
git clean -nd // 探测工作区中有哪些未追踪状态的文件和目录
git clean -fd // 删除工作区中未追踪状态的文件和目录
暂存区
git ls-files // 查询暂存区中的文件列表(递归子目录)
git ls-files -s // 查看暂存区中所有文件的blob数据块信息
git ls-files -s -- README.md // 查看暂存区中的README.md文件的blob数据块信息
其他命令
git fsck --full // 列出所有未引用的blob、tree、commit对象
git archive --format zip --output d:/file.zip master // 将当前master分支所有文件使用zip压缩方式打包到d:/file.zip
Git瘦身
git count-objects -v // 查看git对象的统计信息
find .git/objects -type f -print0 | xargs -0 du -hk | sort -nr | head -5 // 查找git库中最大的5个文件(du -hk中的k代表单位为KB)
find .git/objects -type f -size +1M -print0 | xargs -0 du -hm | sort -nr | head -5 // 查找git库中size超过1M的最大的5个文件(du -hm中的k代表单位为MB)
git verify-pack -v .git/objects/pack/pack-b340eea7566df839294b71ec91a327ca2ece0b94.idx | sort -k 3 -nr | head -5 // 对压缩存储的git库查找最大的5个文件
git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch FramePro.cpp' --prune-empty --tag-name-filter cat -- --all // 从git库的历史记录中彻底清理FramePro.cpp
git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin // 清理所有废弃的ref引用
git gc --prune=now // ①将所有的对象压缩存储到pack二进制文件中,以节省空间和提高效率 ②移除与任何提交都不相关的陈旧对象
git reflog expire --expire=now --all // 清除所有操作记录日志
除了使用git原生命令外,可以使用专门的工具BFG(java实现)来对Git库瘦身
经典GItflow
(1) master分支存储了正式发布的历史(master分支上的所有提交都会分配一个版本号)
(2) develop分支作为功能的集成分支
(3) 每个新功能位于一个自己的Feature分支,该分支使用develop分支作为父分支。当新功能完成时,合并回develop分支。新功能提交应该从不直接与master分支交互
(4) 一旦develop分支上有了做一次发布(或者说快到了既定的发布日)的足够功能,就从develop分支上fork一个release分支。
新建的分支用于开始发布循环,所以从这个时间点开始之后新的功能不能再加到这个分支上。 这个分支只应该做Bug修复、文档生成和其它面向发布任务。
对外发布的工作完成后,发布分支会合并到master分支并分配一个版本号打好Tag。另外,这些从新建发布分支以来的做的修改要合并回develop分支。
(5) hotfix分支用于生成快速给产品发布版本(production releases)打补丁,修复完成,修改应该马上合并回master分支(打好Tag)和develop分支(当前的发布分支)。
息
git ls-files -s – README.md // 查看暂存区中的README.md文件的blob数据块信息
### 其他命令
git fsck --full // 列出所有未引用的blob、tree、commit对象
git archive --format zip --output d:/file.zip master // 将当前master分支所有文件使用zip压缩方式打包到d:/file.zip
### Git瘦身
git count-objects -v // 查看git对象的统计信息
find .git/objects -type f -print0 | xargs -0 du -hk | sort -nr | head -5 // 查找git库中最大的5个文件(du -hk中的k代表单位为KB)
find .git/objects -type f -size +1M -print0 | xargs -0 du -hm | sort -nr | head -5 // 查找git库中size超过1M的最大的5个文件(du -hm中的k代表单位为MB)
git verify-pack -v .git/objects/pack/pack-b340eea7566df839294b71ec91a327ca2ece0b94.idx | sort -k 3 -nr | head -5 // 对压缩存储的git库查找最大的5个文件
git filter-branch --force --index-filter ‘git rm --cached --ignore-unmatch FramePro.cpp’ --prune-empty --tag-name-filter cat – --all // 从git库的历史记录中彻底清理FramePro.cpp
git for-each-ref --format=‘delete %(refname)’ refs/original | git update-ref --stdin // 清理所有废弃的ref引用
git gc --prune=now // ①将所有的对象压缩存储到pack二进制文件中,以节省空间和提高效率 ②移除与任何提交都不相关的陈旧对象
git reflog expire --expire=now --all // 清除所有操作记录日志
除了使用git原生命令外,可以使用专门的工具BFG(java实现)来对Git库瘦身
### 经典GItflow
[外链图片转存中...(img-d3yWshWh-1625702843730)]
(1) master分支存储了正式发布的历史(master分支上的所有提交都会分配一个版本号)
(2) develop分支作为功能的集成分支
(3) 每个新功能位于一个自己的Feature分支,该分支使用develop分支作为父分支。当新功能完成时,合并回develop分支。新功能提交应该从不直接与master分支交互
(4) 一旦develop分支上有了做一次发布(或者说快到了既定的发布日)的足够功能,就从develop分支上fork一个release分支。
新建的分支用于开始发布循环,所以从这个时间点开始之后新的功能不能再加到这个分支上。 这个分支只应该做Bug修复、文档生成和其它面向发布任务。
对外发布的工作完成后,发布分支会合并到master分支并分配一个版本号打好Tag。另外,这些从新建发布分支以来的做的修改要合并回develop分支。
(5) hotfix分支用于生成快速给产品发布版本(production releases)打补丁,修复完成,修改应该马上合并回master分支(打好Tag)和develop分支(当前的发布分支)。