0%

Git 学习

@[toc]

2018-12-09,博客园

教程

整理 Git 命令如下,按第一个教程顺序整理

常用命令

初始化命令

  • git init

    在当前文件夹初始化一个本地仓库

提交命令

  • git add

    将改动(文件变化)添加到到暂存区(缓冲区),以待正式提交(commit)

  • git commit(不建议单独使用)

    将暂存区的改动提交到Git,对其中文件进行一次快照,保存为一个节点

  • git commit -m <对提交的描述信息>

    在提交变化的同时添加描述信息

  • git commit --amend

    好像是将暂存区的修改直接提交到当前所在节点,而不是新建一个节点(提交)
    有待检验

分支命令

  • git branch <新建分支名> [目标节点]

    在目标节点新建一个分支
    若不指定目标节点,则默认在当前节点(HEAD)新建分支

  • git branch -f <指定分支名> <目标节点位置>

    此命令可以将指定分支强制指向目标节点
    git branch -f master HEAD~4命令的作用是使master强制指向HEAD所在节点的前4级节点
    其中,<目标节点位置>可以是具体的节点哈希值,也可以是相对引用的节点

  • git branch -u <指定远程分支名> [指定本地分支名]

    将指定远程分支与指定本地分支关联
    如果省略[本地分支名],则默认将当前分支与远程分支关联。[疑问]1

切换命令

  • git checkout <分支名/标签名/节点哈希值等>

    切换到对应的分支、标签或节点。(实际上是改变HEAD的指向,“HEAD的指向”代表当前所在位置)

  • git checkout -b <新建分支名>

    在当前节点新建一个分支,并立即切换到这一新建分支

  • git checkout -b <新建分支名> <目标远程分支名>[疑问]3

    在当前节点新建并切换到一个新分支,同时将其与指定的远程分支关联,用来跟踪这一远程分支

相对引用

  • git checkout <分支名/HEAD>^

    将HEAD指向指定分支名指向节点的上一节点,即父节点。
    或将HEAD指向HEAD的父节点
    其中,^符号可以一次使用多个。每使用一个代表将HEAD往上一级节点移动一次
    比如git checkout master^^命令表示将HEAD指针指向master指向节点的上两级节点(即上一级的上一级节点)

  • git checkout <分支名/HEAD>~[数字]

    作用类比于上一条命令。但通过[数字]可以直接指定将HEAD往前指向的节点级数
    若不加[数字]则默认上移一级,即git checkout master~git checkout master^作用相同

  • git checkout <节点>^[数字]

    数字指定回溯到哪一条分支
    若没有数字,则默认回溯到直接分支(即合并操作执行时HEAD所在的分支)

  • git checkout <节点>~^2~2

    支持链式操作,将多个切换命令合并为一条命令

合并命令

  • git merge <分支名>(合并方法1)

    将<分支名>指定的分支合并到当前所在分支
    即以当前分支为主,最终合并的结果(最终节点)也是由当前分支来指向【疑问】10
    merge的优势在于可以保持提交历史的顺序、结构

  • git rebase <目标分支> [移动分支](合并方法2)

    直译为“以目标分支(分支1)为基础,结合移动分支(分支2)进行梳理整合”
    [移动分支]的提交记录整理,复制一个副本合并到[目标分支],得到一个线性提交记录。原提交记录依然存在。
    同时将[移动分支]指向rebase得到的分支顶端节点(有待验证)
    直译过来就是“将[移动分支]整合到[目标分支]
    若不指定[移动分支],则默认移动当前分支
    优势在于可以保留干净、线性的提交树

标签命令

  • git tag <标签名> [指定节点]

    将标签名标注于指定节点
    若不指定节点,则加标签于当前节点(HEAD)

查看命令

  • git log

    列出提交记录(具体列出全部还是当前分支有待确定)

撤销变更命令[疑问]4

  • git reset <目标节点>(仅适用于本地分支)

    将当前分支指向目标节点
    即忽略目标节点之后的所有提交
    但被忽略的节点所作的变更依旧存在,只是处于未加入暂存区状态

  • git revert <节点>(适用于远程分支)

    撤销指定节点的修改,即回到指定节点父节点的状态
    实现方式不同于git reset <目标节点>命令
    git reset [目标节点]仅仅通过修改指向实现,
    git revert <节点>是对当前节点与其父节点的差异重做而产生一个新的提交节点,得到指定节点的子节点,但是该子节点的状态与指定节点的父节点状态相同
    此命令没有实际使用过,有待检验

远程命令

克隆到本地

  • git clone <ssh/https地址>

    从远程仓端克隆远程仓库到本地

从远程仓库拉取内容

  • git fetch

    下载远程仓库所有分支及提交记录到本地各个远程分支

  • git fetch <remote> <place>

    类比push命令的参数
    可以理解为仅仅是将远程仓库内容下载下来,但是并没有对本地文件作出改动。但是会更新本地仓库的远程分支指向。
    区别于git pull命令
    不需要当前处于远程分支

  • git fetch <远程仓库名称> <指定的远程分支名>【疑问】9

    同时会更新本地仓库的对应的远程分支(单独的fetch会更新吗?)

  • git fetch <远程仓库名称> <源节点>:<本地目标分支>(实际很少用)

    <源节点>是指远程仓库中的索引位置,<目标分支>才是本地分支了。类比push命令,刚好相反。
    如果本地仓库不存在指定的目标分支,则Git自动在本地仓库(当前节点)创建一个同名分支,并执行操作
    不更新本地的远程分支(?)

  • git fetch <远程仓库名称> :<本地目标分支>

    命令自动在本地(当前节点)创建一个本地分支

  • git pull <>

    相当于git fetchgit merge相继作用的效果
    即不光下载远程内容并把本地仓库远程分支指向最新节点,同时将当前所在分支指向这一节点[疑问]5【疑问】8

git pull origin foo相当于git pull origin foo; git merge o/foo
git pull origin bar~1:bugFix相当于git fetch origin bar~1:bugFix; git merge bugFix
只关心提交最终合并到哪里

  • git pull --rebase

    相当于git fetch + git rebase <远程分支>

向远程仓库推送内容

  • git push <remote> <place>

    以上为push命令的标准表述

  • git push <远程仓库名称> <要推送的本地分支名>

    可以直译为“将本地分支A推送到远程仓库1”
    向指定远程仓库推送指定的本地分支的提交记录,并更新本地仓库中与指定本地分支相关联的远程分支[疑问已解决]7
    [疑问]2

  • git push <远程仓库名称> <源节点>:<远程目标分支>

    如果在远程仓库不存在指定的目标分支,则Git会在远程仓库自行创建一个新的分支

  • git push <远程仓库名称> :<远程目标分支>

    删除指定的远程分支

进阶命令

整理提交记录

  • git cherry-pick <指定节点> [指定节点] ...(cherry-pick意为“精挑细选”)

    可以在一条命令中指定多个节点为执行对象(好像需要是节点的哈希值)可以是提交树上任意位置的节点[疑问]6,但不能是当前节点上游的节点
    命令的作用顾名思义,是选中指定节点,并按顺序将节点副本顺次附加到当前所在节点(HEAD)之后
    或许这个命令可以直译为“精选”命令

交互式rebase

  • git rebase -i <分支名/节点/HEAD>~[数字]

    使用参数--interactive(简写为-i
    尝试了一下,好像只能用HEAD作为索引?(经验证,不是)
    数字n代表包括HEAD所在节点向上的n个节点
    打开一个rebase UI界面

    • 调整提交记录的顺序(通过鼠标拖放)
    • 删除不想要的提交
    • 合并提交

描述节点

  • git describe <索引>

    作用是输出关于离[索引]最近的标签的信息
    “最近”的意思仅限于同一条分支(有待验证)
    <索引>指所有可以指向具体节点的值,官方表述为“任何能被 Git 识别成提交记录的引用”
    若不指定具体节点,则作用于当前节点(HEAD)

注意事项

  • 节点哈希值基于 SHA-1,共 40 位

  • 分支名/HEAD等本质上类似一个指针,指向某个节点

    具体讲,分支名指向当前分支的最新节点;而HEAD指向当前状态实际所在的节点
    同时,git checkout [分支名/标签名/节点哈希值]命令的本质是移动HEAD指针的指向

  • 本地仓库里的远程分支,或者说远程仓库分支对应的本地分支名(如果存在)不能手动移动。只有在与远程仓库同步时才能够自动修改。

疑问

  • 既然可以用rebase UI直接对节点重排,那各个提交记录到底是记录的“变化”还是文件本身的快照啊?

    如果只是变化的话,重拍之后怎么可能还可以正确应用呢?

  • 尝试了一下,git rebase -i [索引]好像只能用HEAD作为索引?

    不必。索引均可。

  • 对提交进行重排之后,所有后续节点都会产生相应改变?还是说因为记录的都是“变化”,所以改变内容不影响后续?

  • 实际工作环境是否存在“本地仓库的远程分支”这一说法?

    “远程跟踪”一节提到了,确实存在。
    原话如下:

    1
    2
    3
    当你克隆时, Git 会为远程仓库中的每个分支在本地仓库中创建一个远程分支(比如 o/master)。然后再创建一个跟踪远程仓库中活动分支的本地分支,默认情况下这个本地分支会被命名为 master。

    克隆完成后,你会得到一个本地分支(如果没有这个本地分支的话,你的目录就是“空白”的),但是可以查看远程仓库中所有的分支(如果你好奇心很强的话)。这样做对于本地仓库和远程仓库来说,都是最佳选择。
  • 本地仓库有,而远程仓库没有的分支能否推送到远程端并自动创建一个新分支?

1. 如果当前没有指向具体分支,而是分离HEAD状态呢?
2. 本地仓库有,而远程仓库没有的分支能否推送到远程端并自动创建一个新分支?
3. 是否能够不指定“远程分支名”,从而默认关联某一远程分支
4. 没懂,看完再看一下。
5. 但是不更新在本地的远程分支?比如o/master,不会改变?
6. git cherry-pick命令的作用对象是否可以是任意节点(除当前分支的上游节点外)?
7. 若关联的本地分支与远程分支名称不一致,则在push命令中是以远程分支名为准吗?试一试。(顺便试一试脚注的冒号用中文冒号行不行)

显然,中文冒号不行
经试验,push命令中指定的分支名以本地分支为准
故可以直译为“将本地分支A推送到远程仓库1”

8. 是否仅限于当前分支?试一试
9. 应该也是对应于push命令,fetch则以远程分支名为准,将指定的远程分支的记录全部拉取到本地与之相关联的分支上。试一试

单独的fetch会更新本地仓库的远程分支吗?试一试

10. 若当前指向一个具体节点而不是某一个分支名呢?即处在分离HEAD状态,且可以更进一步,HEAD指向的节点没有其他任何分支同时指向,会发生什么?

单纯移动HEAD?