HEAD

简介

        git 是通过HEAD来确定你当前在哪个分支上工作。HEAD是指向分支(例如master),分支指向提交(可以直接理解为HEAD指向的是当前分支当前提交版本)。

        我们的主线往往是一根直线,多一个分支相当于多一个分叉,无数分支纵横交错就像一颗树状的结构,所以我们称之为目录树。commit rebase reset merge这些都是改变目录树的操作。

git--详解_d3

符号

^x:  尖头符号,形似箭头,表示要朝那个方向,始终是走一步,x 表示第几个岔路口,代表方向盘

~y:  波浪符号,表示要在该方向上走 y 步,始终沿着该方向,代表油门 

示例 

自己: HEAD, HEAD^0 或 HEAD~0

父亲: HEAD^, HEAD~

母亲: HEAD^2

爷爷: HEAD^~, HEAD~2, HEAD^^

奶奶: HEAD^^2, HEAD~^2

姥爷: HEAD^2~, HEAD^2^

姥姥: HEAD^2^2

origin

        origin 是远程仓库的名字,可以在 .git/config 之中进行修改。代码库(repository)可以存放在本地,也可以存放到远程。默认origin指向的是远程仓库。

        若通过git clone https://github.com/user1/repository命令克隆下来代码,则git remote -v的结果为:

origin https://github.com/user1/repository.git (fetch)
origin https://github.com/user1/repository.git (push)

        一般会使用git remote add origin xxx(远程仓库地址),也可以用其他名字,例如:git remote add upstream https://github.com/user2/repository.git,用git remote -v查看:

origin https://github.com/user1/repository.git (fetch)
origin https://github.com/user1/repository.git (push)
upstream https://github.com/user2/repository.git (push)
upstream https://github.com/user2/repository.git (push)

master、origin master 与 origin/master

其他网址

​master、origin master 与 origin/master - 简书​

简介

  • master
  • 它代表本地的某个分支名。
  • origin master
  • 代表着两个概念:前面的​origin​代表远程名,后面的​master​代表远程分支名。
  • origin/master
  • 只代表一个概念,即远程分支名,是从远程拉取代码后在本地建立的一份拷贝(因此也有人把它叫作本地分支)。

举几个例子可能会更加清晰地说明问题

  • git fetch origin master
  • 它的意思是从名为 origin 的远程上拉取名为 master的分支到本地分支origin/master` 中
  • 既然是拉取代码,当然需要同时指定远程名与分支名,所以分开写。
  • git merge origin/master
  • 它的意思是合并名为 origin/master 的分支到当前所在分支。
  • 既然是分支的合并,当然就与远程名没有直接的关系,所以没有出现远程名,需要指定的是被合并的分支。
  • git push origin master
  • 它的意思是推送本地的 master 分支到远程 origin
  • 涉及到远程以及分支,当然也得分开写了。
  • git fetch origin master stable oldstable;
  • 一次性拉取多个分支的代码
  • git merge origin/master hotfix-2275 hotfix-2276 hotfix-2290;
  • 一次性合并多个分支的代码

fetch和pull区别

其他网址


准备工作

每一个本地库下都有一个.git的隐藏文件夹,文件夹中的文件保存着跟这个本地库相关的信息

git--详解_git_02

首先来看下其中的config文件

[core]
repositoryformatversion = 0
filemode = false
bare = false
logallrefupdates = true
symlinks = false
ignorecase = true
hideDotFiles = dotGitOnly
[remote "origin"]
url = git@github.com:seanzou88/fetch.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
remote = origin
merge = refs/heads/master

从这个文件中我们可以了解到:

1,本地库的当前分支为master,其关联的远程库名称为origin(不同的名称可以指向同一个远程库,参见git remote命令)

2,远程库origin所在的位置为(URL):git@github.com:seanzou88/fetch.git

然后可以查看.git文件夹下的HEAD文件:ref: refs/heads/master

其指向.git\refs\heads\master文件:ce71505b3626a3648b2c32ea2081d65049cad300

这个文件中保存的是本地库中最新的commit id

.git\refs文件夹很有意思,里面分为3个文件夹

git--详解_详解_03

  • heads文件夹:前面说过了
  • remotes文件夹:中的每一个文件夹代表一个远程库名称(git remote),其中的每个文件关联远程库的一个分支,其中保存该分支的最新commit id
  • .git\logs文件夹:保存的是.git\refs文件夹下相应文件的变更记录

准备工作到此结束,下面可以具体看看git fetch和git pull之间的区别了。

git fetch和git pull的区别

git fetch origin

本地的latest commit id为:ce71505b3626a3648b2c32ea2081d65049cad300

githup上的latest commit id为:ab8cd391f978fe5384a78c92001ef8ae861046f0

before​:

.git\refs\heads\master:ce71505b3626a3648b2c32ea2081d65049cad300

.git\refs\remotes\origin\master:ce71505b3626a3648b2c32ea2081d65049cad300

.git\logs\refs\heads\master:

0000000000000000000000000000000000000000 

        ce71505b3626a3648b2c32ea2081d65049cad300 

        ......    

        commit (initial): first commit 

.git\logs\refs\remotes\origin\master:

0000000000000000000000000000000000000000 

        ce71505b3626a3648b2c32ea2081d65049cad300 

        ......    

        update by push

after​:

.git\refs\heads\master(不变)

.git\refs\remotes\origin\master:ab8cd391f978fe5384a78c92001ef8ae861046f0

.git\logs\refs\heads\master(不变)

.git\logs\refs\remotes\origin\master

0000000000000000000000000000000000000000 

        ce71505b3626a3648b2c32ea2081d65049cad300 

        ......        

        update by push

ce71505b3626a3648b2c32ea2081d65049cad300 

        ab8cd391f978fe5384a78c92001ef8ae861046f0 

        ......    

        fetch origin: fast-forward

本地库并没有变化,也就是说,git fetch只会将本地库所关联的远程库的commit id更新至最新

HEAD没有变化很容易理解,因为本地库并没有变化

git pull origin master:master

本地的latest commit id为:3643a1a65fc88ae0e9f28f12168629758d027415

githup上的latest commit id为:64df093f73294d82a3adce9694871b9fac2aecfb

before:

.git\refs\heads\master:3643a1a65fc88ae0e9f28f12168629758d027415

.git\refs\remotes\origin\master:3643a1a65fc88ae0e9f28f12168629758d027415

.git\logs\refs\heads\master

0000000000000000000000000000000000000000 

        3643a1a65fc88ae0e9f28f12168629758d027415 

        ......    

        commit (initial): first commit

.git\logs\refs\remotes\origin\master

0000000000000000000000000000000000000000 

        3643a1a65fc88ae0e9f28f12168629758d027415 

        ......    

        update by push

after:

.git\refs\heads\master:64df093f73294d82a3adce9694871b9fac2aecfb

.git\refs\remotes\origin\master(不变)

.git\logs\refs\heads\master:

0000000000000000000000000000000000000000 

        3643a1a65fc88ae0e9f28f12168629758d027415 

        ......    

        commit (initial): first commit

3643a1a65fc88ae0e9f28f12168629758d027415 

        64df093f73294d82a3adce9694871b9fac2aecfb 

        ......    

        pull origin master:master: fast-forward

.git\logs\refs\remotes\origin\master(不变)

  • 本地库更新至最新,git pull会将本地库更新至远程库的最新状态。
  • 由于本地库进行了更新,HEAD也会相应的指向最新的commit id。
  • 所以虽然从结果上来看,git pull = git fetch + git merge,但是从文件中保存的commit id来看,实现上不是这样实现的

为了更好的理解,画了个图:

git--详解_github_04

git reset --hard恢复

​实习生的代码被弄丢了!救命的时候绝对用的上——每天三分钟玩转Git (8)​