宅男在线永久免费观看网直播,亚洲欧洲日产国码无码久久99,野花社区在线观看视频,亚洲人交乣女bbw,一本一本久久a久久精品综合不卡

全部
常見問題
產(chǎn)品動(dòng)態(tài)
精選推薦

Git從入門到精通,Git命令大全

管理 管理 編輯 刪除

Git說明:https://www.runoob.com/manual/git-guide/

騰訊Github:https://github.com/Tencent

阿里巴巴Github:https://github.com/alibaba

Git鏡像:https://www.gitclone.com/、https://ghproxy.com/

Git入門

資料來源:https://www.runoob.com/git/git-tutorial.html、http://git-scm.com/docs

查看Git命令的幫助信息,git <command> --help

1.Git 工作區(qū)、暫存區(qū)和版本庫(以本地舉例)、遠(yuǎn)程倉庫

  • 工作區(qū):就是你在電腦里能看到的目錄。
  • 暫存區(qū):英文叫 stageindex。一般存放在 .git 目錄下的 index 文件(.git/index)中,所以我們把暫存區(qū)有時(shí)也叫作索引(index)。
  • 版本庫:工作區(qū)有一個(gè)隱藏目錄 .git,這個(gè)不算工作區(qū),而是 Git 的版本庫。
  • Git從入門到精通,Git命令大全
  • Git 工作區(qū)、暫存區(qū)和版本庫
  • 圖中左側(cè)為工作區(qū),右側(cè)為版本庫。在版本庫中標(biāo)記為 "index" 的區(qū)域是暫存區(qū)(stage/index),標(biāo)記為 "master" 的是 master 分支所代表的目錄樹。
  • 圖中我們可以看出此時(shí) "HEAD" 實(shí)際是指向 master 分支的一個(gè)"游標(biāo)"。所以圖示的命令中出現(xiàn) HEAD 的地方可以用 master 來替換。
  • 圖中的 objects 標(biāo)識(shí)的區(qū)域?yàn)?Git 的對(duì)象庫,實(shí)際位于 ".git/objects" 目錄下,里面包含了創(chuàng)建的各種對(duì)象及內(nèi)容。
  • 當(dāng)對(duì)工作區(qū)修改(或新增)的文件執(zhí)行 git add 命令時(shí),暫存區(qū)的目錄樹被更新,同時(shí)工作區(qū)修改(或新增)的文件內(nèi)容被寫入到對(duì)象庫中的一個(gè)新的對(duì)象中,而該對(duì)象的ID被記錄在暫存區(qū)的文件索引中。
  • 當(dāng)執(zhí)行提交操作(git commit)時(shí),暫存區(qū)的目錄樹寫到版本庫(對(duì)象庫)中,master 分支會(huì)做相應(yīng)的更新。即 master 指向的目錄樹就是提交時(shí)暫存區(qū)的目錄樹。
  • 當(dāng)執(zhí)行 git reset HEAD 命令時(shí),暫存區(qū)的目錄樹會(huì)被重寫,被 master 分支指向的目錄樹所替換,但是工作區(qū)不受影響。
  • 當(dāng)執(zhí)行 git rm --cached 命令時(shí),會(huì)直接從暫存區(qū)刪除文件,工作區(qū)則不做出改變。
  • 當(dāng)執(zhí)行 git checkout . 或者 git checkout -- 命令時(shí),會(huì)用暫存區(qū)全部或指定的文件替換工作區(qū)的文件。這個(gè)操作很危險(xiǎn),會(huì)清除工作區(qū)中未添加到暫存區(qū)中的改動(dòng)。
  • 當(dāng)執(zhí)行 git checkout HEAD . 或者 git checkout HEAD 命令時(shí),會(huì)用 HEAD 指向的 master 分支中的全部或者部分文件替換暫存區(qū)和以及工作區(qū)中的文件。這個(gè)命令也是極具危險(xiǎn)性的,因?yàn)椴坏珪?huì)清除工作區(qū)中未提交的改動(dòng),也會(huì)清除暫存區(qū)中未提交的改動(dòng)。

2.Git文件狀態(tài)

在Git中文件大概分為四種狀態(tài):已修改(modified)、已暫存(staged)、已提交(committed)、未追蹤(Untrack)

  • .gitignore內(nèi)的文件,不會(huì)擁有任何一種狀態(tài),被git徹底無視。
  • 處于ignore列表的文件,無法被add添加;但是可以強(qiáng)制添加
  • 空目錄、以及子目錄全部是空目錄的目錄不會(huì)有Untrack狀態(tài),也無法通過add改變狀態(tài)(無效)
  • 工作目錄新增文件時(shí),只要不處于ignore目錄,都會(huì)變成Untrack狀態(tài);
  • 沒有add過的文件或者被restore(不帶--staged)的文件,處于Untrack狀態(tài);
  • 初次add和被add后產(chǎn)生修改的文件,會(huì)處于modifed狀態(tài)。
  • 處于modified狀態(tài)的文件,最開始可以進(jìn)行add和restore兩種操作,此時(shí)的add操作叫做 更新要提交的內(nèi)容,add后變?yōu)閟taged狀態(tài),restore(不加staged標(biāo)記)后變?yōu)閁ntrack;
  • add后變?yōu)閟taged狀態(tài)的文件,可用restore --staged 變回modified狀態(tài);這個(gè)staged狀態(tài)的內(nèi)容可以用來恢復(fù)內(nèi)容。沒有被add的modified狀態(tài)文件內(nèi)容沒有被記錄(雖然有撤回,但是本質(zhì)不一樣);
  • 處于staged狀態(tài)的文件,在沒有commit之前再次產(chǎn)生修改時(shí),會(huì)同時(shí)具有staged和modified兩個(gè)狀態(tài)(可以把statged狀態(tài)的內(nèi)容拉回來,覆蓋。);但是commit時(shí)會(huì)使用內(nèi)容最新的那個(gè)狀態(tài);
  • commit會(huì)提交所有staged狀態(tài)的文件,所以commit可以理解有一個(gè)modified到staged狀態(tài)的過程(實(shí)際可能不存在,因?yàn)闀捍鎱^(qū)本來就有變動(dòng)的記錄);所以暫存狀態(tài)不能理解為處于暫存區(qū),應(yīng)當(dāng)指的是被納入下一次提交的文件;任何被追蹤的產(chǎn)生修改的文件都會(huì)在暫存區(qū)被記錄;成為下一次提交的一部分;
  • 未被追蹤的文件被刪除時(shí),不會(huì)產(chǎn)生git狀態(tài)。處于modofy未add時(shí),會(huì)變成deleted狀態(tài);處于staged狀態(tài)會(huì)保持暫存狀態(tài);
  • 已經(jīng)被刪除的(deleted狀態(tài))被追蹤的文件,恢復(fù)后會(huì)變成modified狀態(tài);
  • 提示
  • add的作用是將文件添加到暫存區(qū),只有被add的文件才會(huì)被追蹤
  • 暫存區(qū)
  • (1)所謂的暫存區(qū)只是一個(gè)簡(jiǎn)單的索引文件而已。
    (2)暫存區(qū)這個(gè)索引文件里面包含的是文件的目錄樹,像一個(gè)虛擬的工作區(qū),在這個(gè)虛擬工作區(qū)的目錄樹中,記錄了文件名、文件的時(shí)間戳、文件長(zhǎng)度、文件類型以及最重要的SHA-1值,文件的內(nèi)容并沒有存儲(chǔ)在其中,所以說 它像一個(gè)虛擬的工作區(qū)。
    (3)索引指向的是.Git/objects下的文件。
    (4)暫存區(qū)的作用:除非是繞過暫存區(qū)直接提交,否則Git想把修改提交上去,就必須將修改存入暫存區(qū)最后才能commit。每次提交的是暫存區(qū)所對(duì)應(yīng)的文件快照。

拓展:status提示信息


Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

  • 既然是Changes not staged for commit,就說明出現(xiàn)這個(gè)提示下的所有文件改動(dòng),都是存在于工作區(qū)的。stage是暫存區(qū)的意思,not stage說明都不在暫存區(qū),那么說明在工作區(qū)。
  • (use “git add …” to update what will be committed)。執(zhí)行這條命令就可以工作區(qū)里面的改變加入到暫存區(qū)??梢詧?zhí)行g(shù)it add .把當(dāng)前目錄下所有改動(dòng)加入暫存區(qū)。
  • (use “git checkout – …” to discard changes in working directory)。執(zhí)行這條命令將丟棄在工作區(qū)的改動(dòng)??梢詧?zhí)行g(shù)it checkout *把當(dāng)前目錄下所有工作區(qū)的改動(dòng)丟棄掉
Untracked files: 
      (use "git add <file>..." to include in what will be committed)

  • Untracked files,就說明出現(xiàn)這個(gè)提示下的所有文件都是當(dāng)前HEAD沒有被加入過的文件。這種改動(dòng)也屬于工作區(qū)。
  • (use “git add …” to include in what will be committed)。把Untracked files加入暫存區(qū)。
On branch master
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)

  • 當(dāng)前分支比遠(yuǎn)程分支多了一次commit
Your branch and 'origin/master' have diverged, and have 1 and 1 different commits each, respectively

pull報(bào)錯(cuò)了,查看狀態(tài)顯示這個(gè),先留著待解決吧

3.HEAD是什么

HEAD是Git中非常重要的一個(gè)概念,你可以稱它為指針或者引用,它可以指向任意一個(gè)節(jié)點(diǎn),并且指向的節(jié)點(diǎn)始終為當(dāng)前工作目錄,換句話說就是當(dāng)前工作目錄(也就是你所看到的代碼)就是HEAD指向的節(jié)點(diǎn)。

4.git重命名檢測(cè)

Git 采用了不同的方法:它沒有選擇去存儲(chǔ)與文件移動(dòng)操作相關(guān)的信息,而是采用了重命名檢測(cè)算法。在該算法中,如果一個(gè)文件在某一次提交中消失了,它依然會(huì)存在于其前次提交,而如果某個(gè)擁有相同名字或相似內(nèi)容的文件出現(xiàn)在了另一個(gè)位置,Git 就會(huì)自動(dòng)檢測(cè)到。如果是這種情況,Git 就會(huì)假定該文件被移動(dòng)過了。

Git項(xiàng)目文件說明

Git init后主要有兩個(gè)重要的文件和目錄:.git目錄和.gitignore

1. .gitignore

.gitignore文件存在于根目錄(與.git同級(jí)的目錄)用于在將文件提交到git暫存區(qū)時(shí),指定將哪些文件排除;

有時(shí)候你想添加(git add)一個(gè)文件到Git,但發(fā)現(xiàn)添加不了,多半原因是這個(gè)文件被.gitignore忽略了

git add .不會(huì)添加被.gitignore忽視的文件,而git add -f . 強(qiáng)制添加所有文件,即使是.gitignore忽視的文件也添加。

當(dāng).gitignore文件不是你編寫的,但是它編寫的不符合實(shí)際需求,你可以使用git check-ignore命令進(jìn)行檢查,看是哪一個(gè)規(guī)則有問題了


#檢測(cè)
 git check-ignore -v App.class
#結(jié)果
.gitignore:3:*.class	App.class

.gitignore只能忽略那些原來沒有被track的文件,如果某些文件已經(jīng)被納入了版本管理中,則修改.gitignore是無效的。解決方法就是先把本地緩存刪除(改變成未track狀態(tài)),然后再提交。


git rm -r --cached .
git add .
git commit -m ‘update .gitignore’

也可以手動(dòng)指定一個(gè)文件作為git忽略文件


git config core.excludesfile ***

對(duì)于全局Git配置,可以使用如下命令對(duì)全部倉庫進(jìn)行配置。


git config --global core.excludesfile **/.gitignore(文件相對(duì)或絕對(duì)位置)

忽略規(guī)則如下:

  1. 空格不匹配任意文件,可作為分隔符,可用反斜杠轉(zhuǎn)義
  2. #開頭的文件標(biāo)識(shí)注釋,可以使用反斜杠進(jìn)行轉(zhuǎn)義
  3. ! 開頭的模式標(biāo)識(shí)否定,該文件將會(huì)再次被包含,如果排除了該文件的父級(jí)目錄,則使用 ! 也不會(huì)再次被包含??梢允褂梅葱备苓M(jìn)行轉(zhuǎn)義
  4. / 結(jié)束的模式只匹配文件夾以及在該文件夾路徑下的內(nèi)容,但是不匹配該文件
  5. / 開始的模式匹配項(xiàng)目跟目錄
  6. 如果一個(gè)模式不包含斜杠,則它匹配相對(duì)于當(dāng)前 .gitignore 文件路徑的內(nèi)容,如果該模式不在 .gitignore 文件中,則相對(duì)于項(xiàng)目根目錄
  7. ** 匹配多級(jí)目錄,可在開始,中間,結(jié)束
  8. ? 通用匹配單個(gè)字符
  9. [] 通用匹配單個(gè)字符列表
  10. 各種項(xiàng)目的gitignore
  11. 參考地址:https://github.com/github/gitignore

2. .git目錄

任意文件夾中,用 git init 命令初始化倉庫,即可在此文件夾下創(chuàng)建 .git 文件夾(.打頭為隱藏文件夾,所以平時(shí)可能看不到)。這個(gè)文件夾之外的部分叫做工作區(qū)(Working Directory),.git 文件夾我們稱做 Git倉庫 (Git Repository)。 通常會(huì)有7個(gè)文件5個(gè)目錄,常見目錄如下:


COMMIT_EDITMSG
HEAD
ORIG_HEAD
FETCH_HEAD
config
description
index
hooks/
info/
logs/
objects/
refs/

1. 文件 COMMIT_EDITMSG

此文件是一個(gè)臨時(shí)文件,存儲(chǔ)最后一次提交的信息內(nèi)容,git commit 命令之后打開的編輯器就是在編輯此文件,而你退出編輯器后,git 會(huì)把此文件內(nèi)容寫入 commit 記錄。

實(shí)際應(yīng)用: git pull 遠(yuǎn)程倉庫后,新增了很多提交,淹沒了本地提交記錄,直接 cat .git/COMMIT_EDITMSG 就可以弄清楚最后工作的位置了。

2. HEAD

此文件永遠(yuǎn)存儲(chǔ)當(dāng)前位置指針,就像 linux 中的 $PWD 變量和命令提示符的箭頭一樣,永遠(yuǎn)指向當(dāng)前位置,表明當(dāng)前的工作位置。在 git 中 HEAD 永遠(yuǎn)指向當(dāng)前正在工作的那個(gè) commit。(孤立HEAD?????)

HEAD 存儲(chǔ)一個(gè)分支的 ref,Linux中運(yùn)行:cat .git/HEAD 通常會(huì)顯示:


ref: refs/heads/master

這說明你目前正在 master 分支工作。此時(shí)你的任何 commit,默認(rèn)自動(dòng)附加到 master 分支之上

git cat-file -p HEAD, 顯示詳細(xì)的提交信息:


tree 4cbb261560348e1727b5137f3ab6eceae8e1f34d
parent 22c457fe24f737505356edfb8696c7e50fd9d971
author Evan You <[email protected]> 1654857613 +0800
committer Evan You <[email protected]> 1654857613 +0800

chore: test pass


image.png
孤立head,不指向任何commit

3. ORIG_HEAD

正因?yàn)?HEAD 比較重要,此文件會(huì)在你進(jìn)行危險(xiǎn)操作時(shí)備份 HEAD,如以下操作時(shí)會(huì)觸發(fā)備份


git reset
git merge
git rebase
git pull

此文件應(yīng)用示例


# 回滾到上一次的狀態(tài)(慎用!!!)
git reset --hard ORIG_HEAD

4. FETCH_HEAD

這個(gè)文件作用在于追蹤遠(yuǎn)程分支的拉取與合并,與其相關(guān)的命令有 git pull/fetch/merge,而git pull 命令相當(dāng)于執(zhí)行以下兩條命令:


$ git fetch
$ git merge FETCH_HEAD

# 顯示如下>>>
From https://github.com/xxx/xxxx
* branch            master     -> FETCH_HEAD
Updating f785638..59db1b2

此時(shí)會(huì)默默備份 HEAD 到 ORIG_HEAD

5. config

此文件存儲(chǔ)項(xiàng)目本地的 git 設(shè)置,典型內(nèi)容如下:


[core]
        repositoryformatversion = 0
        filemode = true
        bare = false
        logallrefupdates = true
        ignorecase = true
[remote "origin"]
        url = [email protected]/xxx.git
        fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
        remote = origin
        merge = refs/heads/master
[branch "v2.6.0"]
        remote = origin
        merge = refs/heads/v2.6.0
[branch "v2.8.0"]
        remote = origin
        merge = refs/heads/v2.8.0

[core] 段的內(nèi)容跟 git config 命令對(duì)應(yīng)

執(zhí)行以下命令:


git config user.name abc
git config user.email [email protected]

會(huì)在 config 文件中追加以下內(nèi)容:


... ...
[user]
name = abc
email = [email protected]

git config --global 影響的則是全局配置文件 ~/.gitconfig。

[remote] 段表示遠(yuǎn)程倉庫配置

[branch] 段表示分支同步設(shè)置

假設(shè)當(dāng)前在 master 分支,執(zhí)行 git pull 若出現(xiàn)以下提示:


There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details.

git pull 就說明 .git/config 文件缺少對(duì)應(yīng)的 [branch "master"] 字段。

解決方案為:


git branch -u origin/master master
# 或者執(zhí)行一次 push
git push -u origin master

會(huì)出現(xiàn)提示:


Branch 'master' set up to track remote branch 'master' from 'origin'.

其實(shí)就是生成以下內(nèi)容在 .git/config中:


[branch "master"]
remote = origin
merge = refs/heads/master

手動(dòng)編輯 .git/config,效果一樣。這就是 upstream 的真正含義,即生成 config 中的這段配置。

6. description

說明這個(gè)文件主要用于 GitWeb 的描述,如果要啟動(dòng) GitWeb 可用如下命令:


# 確保lighttpd已安裝: brew install lighttpd
$ git instaweb --start

默認(rèn)會(huì)啟動(dòng) lighttpd 服務(wù)并打開瀏覽器 http://127.0.0.1:1234 (試著改成對(duì)外IP并分享給別人?)

以下顯示當(dāng)前的 git 倉庫名稱以及描述,默認(rèn)的描述如下:

description

默認(rèn)描述

上面這段話就是默認(rèn)的 description 文件的內(nèi)容,編輯這個(gè)文件來讓你 GitWeb 描述更友好。

7. hooks/目錄

存放 git hooks,用于在 git 命令前后做檢查或做些自定義動(dòng)作。運(yùn)行 ls -F1 .git/hooks


prepare-commit-msg.sample  # git commit 之前,編輯器啟動(dòng)之前觸發(fā),傳入 COMMIT_FILE,COMMIT_SOURCE,SHA1
commit-msg.sample          # git commit 之前,編輯器退出后觸發(fā),傳入 COMMIT_EDITMSG 文件名
pre-commit.sample          # git commit 之前,commit-msg 通過后觸發(fā),譬如校驗(yàn)文件名是否含中文
pre-push.sample            # git push 之前觸發(fā)

pre-receive.sample         # git push 之后,服務(wù)端更新 ref 前觸發(fā)
update.sample              # git push 之后,服務(wù)端更新每一個(gè) ref 時(shí)觸發(fā),用于針對(duì)每個(gè) ref 作校驗(yàn)等
post-update.sample         # git push 之后,服務(wù)端更新 ref 后觸發(fā)

pre-rebase.sample          # git rebase 之前觸發(fā),傳入 rebase 分支作參數(shù)
applypatch-msg.sample      # 用于 git am 命令提交信息校驗(yàn)
pre-applypatch.sample      # 用于 git am 命令執(zhí)行前動(dòng)作
fsmonitor-watchman.sample  # 配合 core.fsmonitor 設(shè)置來更好監(jiān)測(cè)文件變化



參考
https://git-scm.com/docs/githooks

如果要啟用某個(gè) hook,只需把 .sample 刪除即可,然后編輯其內(nèi)容來實(shí)現(xiàn)相應(yīng)的邏輯。

比如要校驗(yàn)每個(gè) commit message 至少要包含兩個(gè)單詞,否則就提示并拒絕提交,將 commit-msg.sample 改為 commit-msg 后,編輯如下:


#!/bin/sh
grep -q 'Ss+S' $1 || { echo '提交信息至少為兩個(gè)單詞' && exit 1; }

這樣當(dāng)提交一個(gè) commit 時(shí),會(huì)執(zhí)行 bash 命令: .git/hooks/commit-msg .git/COMMIT_EDITMSG,退出值不為 0,就拒絕提交。

8. info/目錄

此文件夾基本就有兩個(gè)文件:

  1. 文件 info/exclude 用于排除規(guī)則,與 .gitignore 功能類似。
  2. 可能會(huì)包含文件 info/refs ,用于跟蹤各分支的信息。此文件一般通過命令 git update-server-info 生成,內(nèi)容通常如下:

9. logs/目錄

記錄了操作信息,git reflog 命令以及像 HEAD@{1} 形式的路徑會(huì)用到。如果刪除此文件夾(危險(xiǎn)!),那么依賴于 reflog 的命令就會(huì)報(bào)錯(cuò)。

文件夾 objects/

此文件夾簡(jiǎn)單說,就是 git的數(shù)據(jù)庫,運(yùn)行 tree .git/objects,可以看到目錄結(jié)構(gòu):


.git/objects/
|-- 0c
|   `-- d370696b581c38ee01e62b148a759f80facc2d
|-- 59
|   `-- 3d5b490556791212acd5a516a37bbfa05d44dd
|-- 61
|   `-- be44eedde61d723e5761577a2b420ba0fc2794
|-- 64
|   `-- c0aed8ddcbb546bdcec2848938fc82348db227
|-- d4
|   `-- 9904676ce8ddde276bdbfa9bbec313e90e0f50
|-- info
`-- pack
    |-- pack-75e3f2aa378752ec93a8e9f375f01204d498605b.idx
    `-- pack-75e3f2aa378752ec93a8e9f375f01204d498605b.pack

這些文件分兩種形式:pack壓縮包 形式放在 pack/ 目錄下,除此之外都是 hash文件 形式,被叫做 loost objects。

這個(gè)文件夾以及相應(yīng)的算法,我沒找到獨(dú)立的名稱,就叫它 hash-object 體系吧。因?yàn)榇_實(shí)有個(gè) git hash-object 命令存在,是一個(gè)底層的負(fù)責(zé)生成這些 loost objects 文件,如果要看到這些文件各自的含義,執(zhí)行以下命令:


git cat-file --batch-check --batch-all-objects

可以看到


04c87c65f142f33945f2f5951cf7801a32dfa240 commit 194
098217953a6ca169bed33d2be8a07d584fcdaf30 tree 31
0cd370696b581c38ee01e62b148a759f80facc2d commit 245
2a810017bfc85d7db2627f4aabdaa1583212bda3 blob 19
3920a07c1d5694df6b8658592b0939241d70e9e5 tree 93
593d5b490556791212acd5a516a37bbfa05d44dd tag 148
61be44eedde61d723e5761577a2b420ba0fc2794 tree 154
... ...

但你會(huì)發(fā)現(xiàn)這個(gè)列表里有些值在文件夾中并不存在,因?yàn)槌?loost objects 它還匯總了 pack 文件中的內(nèi)容。hash文件

又稱為 loose object,文件名稱共由40字符的 SHA-1 hash 值組成,其中前兩個(gè)字符為文件夾分桶,后38個(gè)字符為文件名稱。

按文件內(nèi)容可分為四種類型:commit, tree, blob, tag,若執(zhí)行以下命令會(huì)生成所有四種類型:


echo -en 'xxn' > xx # 共 3 個(gè)字符
git add .
git commit -m 'update xx'
git tag -a 'v1.0' -m 'release: 1.0.0'

經(jīng)過以上操作后,對(duì)比一下文件樹,發(fā)現(xiàn)多了四個(gè) hash文件:


|-- 0c
| `-- d370696b581c38ee01e62b148a759f80facc2d
|-- 18
| `-- 143661f96845f11e0b4ab7312bdc0f356834ce
|-- 30
| `-- 20feea86d222d83218eb3eb5aa9f58f73df04d
|-- 59
| `-- 3d5b490556791212acd5a516a37bbfa05d44dd
|-- 61
| `-- be44eedde61d723e5761577a2b420ba0fc2794
|-- 64
| `-- c0aed8ddcbb546bdcec2848938fc82348db227
|-- ad
| `-- f4c9afac7afae3ff3e95e6c4eefe009d547f00
|-- cc
| `-- c9bd67dc5c467859102d53d54c5ce851273bdd
|-- d4
| `-- 9904676ce8ddde276bdbfa9bbec313e90e0f50
|-- info
`-- pack
|-- pack-75e3f2aa378752ec93a8e9f375f01204d498605b.idx
`-- pack-75e3f2aa378752ec93a8e9f375f01204d498605b.pack

這四個(gè) hash文件 分別是:


cc/c9bd67dc5c467859102d53d54c5ce851273bdd # blob
30/20feea86d222d83218eb3eb5aa9f58f73df04d # commit
ad/f4c9afac7afae3ff3e95e6c4eefe009d547f00 # tree
18/143661f96845f11e0b4ab7312bdc0f356834ce # tag 

其實(shí)這些文件都經(jīng)過了壓縮,壓縮形式為 zlib。先安裝一下解壓工具 macOS 版 brew install pigz 或 windows 版 pigz,后執(zhí)行:


$ pigz -d < .git/objects/cc/c9bd67dc5c467859102d53d54c5ce851273bdd

# BLOB類型,顯示結(jié)果為>>>>(注意xx后有個(gè)n)
blob 3xx


$pigz -d < .git/objects/30/20feea86d222d83218eb3eb5aa9f58f73df04d

# COMMIT類型,顯示結(jié)果為>>>>
commit 248tree adf4c9afac7afae3ff3e95e6c4eefe009d547f00
parent 0cd370696b581c38ee01e62b148a759f80facc2d
author jamesyang.yjm <[email protected]> 1562044880 +0800
committer jamesyang.yjm <[email protected]> 1562044880 +0800

update xx

$ pigz -d < .git/objects/ad/f4c9afac7afae3ff3e95e6c4eefe009d547f00

# TREE類型,顯示結(jié)果為>>>>
tree 154100644 abc*???]}?bJ??X2??100644 asdf???CK?)?wZ???S?100644 iou???CK?)?wZ???S?100644 xx??g?FxY-S?L?Q';?100644 yy???CK?)?wZ???S?


$ pigz -d < .git/objects/18/143661f96845f11e0b4ab7312bdc0f356834ce

# TAG類型,顯示結(jié)果為>>>>
tag 155object 3020feea86d222d83218eb3eb5aa9f58f73df04d
type commit
tag v1.0
tagger jamesyang.yjm <[email protected]> 1562045942 +0800

release: 1.0.0

會(huì)發(fā)現(xiàn),顯示結(jié)果都是 type size+內(nèi)容 形式,這就是 object 文件的存儲(chǔ)格式:


[type] [size][NULL][content]

type 可選值:commit, tree, blob, tag,NULL 就是C語言里的字符結(jié)束符:?,size 就是 NULL后內(nèi)容的字節(jié)長(zhǎng)度。

type 的幾種類型可以使用 git cat-file -t hash 看到,內(nèi)容可以用 git cat-file -p hash 看到。


git cat-file -t ccc9bd67dc5c467859102d53d54c5ce851273bdd
# 顯示結(jié)果為>>>>
blob

git cat-file -p ccc9bd67dc5c467859102d53d54c5ce851273bdd
# 顯示結(jié)果為>>>>
xx

所以 blob 文件就是對(duì)原文件內(nèi)容的全量拷貝,同時(shí)前面加了 blob size?,而文件名稱的 hash 值計(jì)算是計(jì)算整體字符的 SHA-1 值:


echo -en 'blob 3?xxn' | shasum
# 顯示結(jié)果為>>>>
ccc9bd67dc5c467859102d53d54c5ce851273bdd  -

知道原理后,其它類型格式請(qǐng)自行參考 斯坦福 Ben Lynn 所著的 GitMagic。

所以,當(dāng)我們 git show 3020feea86d222d83218eb3eb5aa9f58f73df04d 時(shí),會(huì)發(fā)生些什么?

找到 3020feea86d222d83218eb3eb5aa9f58f73df04d 這個(gè) commit,顯示出來
找到此 commit 關(guān)聯(lián)的 tree object: adf4c9afac7afae3ff3e95e6c4eefe009d547f00,拉取相應(yīng)的 blob 文件,并與當(dāng)前工作區(qū)內(nèi)的文件做 diff,然后顯示出來

這就是 objects/ 文件夾作為 git數(shù)據(jù)庫 被使用的真實(shí)例子。pack文件

為什么會(huì)有 .pack 文件?

由于每次 commit 都會(huì)生成許多 hash文件,并且由于 blob 文件都是全量存儲(chǔ)的,導(dǎo)致 git 效率下降,于是有了 pack-format,優(yōu)勢(shì):

對(duì)于大倉庫存儲(chǔ)效率高
利于網(wǎng)絡(luò)傳輸,便于備份
增量存儲(chǔ),優(yōu)化磁盤空間
將 .git/objects 下的部分文件打包成 pack格式


$ tree .git/objects/ | wc -l
311

$ git gc
Enumerating objects: 288, done.
Counting objects: 100% (288/288), done.
Delta compression using up to 4 threads
Compressing objects: 100% (287/287), done.
Writing objects: 100% (288/288), done.
Total 288 (delta 131), reused 90 (delta 0)

$ tree .git/objects/ | wc -l
12

可以看到文件數(shù)量減小了不少,其中大部分文件被打到一個(gè) .pack 包中,并且是增量存儲(chǔ),有部分變更的文件只存儲(chǔ) 基礎(chǔ)hash + 變更內(nèi)容,磁盤空間優(yōu)化很明顯。

git gc 其實(shí)運(yùn)行了兩條命令:git repack 用來打包 和 git prune-packed 用來移除已打包的 hash文件;

11.文件夾refs

refs 可以理解成文件系統(tǒng)中的 symbol link,看下結(jié)構(gòu):


$ tree .git/refs/

.git/refs
|-- heads
| `-- master
`-- tags
`-- v1.0

$ cat .git/refs/heads/master
5978c2c79cd3a4711fb8edd3166c9f9f5c8c97f5

$ cat .git/refs/tags/v1.0
5978c2c79cd3a4711fb8edd3166c9f9f5c8c97f5

$ git cat-file -t 5978c2c79cd3a4711fb8edd3166c9f9f5c8c97f5
commit

可以看到 master 和 v1.0 都指向 5978c2c79cd3a4711fb8edd3166c9f9f5c8c97f5 這個(gè) commit。

refs/heads/ 文件夾內(nèi)的 ref 一般通過 git branch 生成。git show-ref --heads 可以查看。

refs/tags/ 文件夾內(nèi)的 ref 一般通過 git tag 生成。git show-ref --tags 可以查看。

如下:


$ git branch abc

$ tree .git/refs/

.git/refs/
|-- heads
| |-- abc
| `-- master
`-- tags
`-- v1.0

$ cat .git/refs/heads/abc
5978c2c79cd3a4711fb8edd3166c9f9f5c8c97f5

說明新建分支其實(shí)就是生成了一個(gè)指向某個(gè) commit 的 symbol link,當(dāng)然在這里叫做 ref。

git tag 命令本質(zhì)與 git branch 相同,只生成一個(gè) ref 放在 tags 目錄下,所以被稱為 lightweight tag。

git tag -a xx 命令會(huì)首先生成一個(gè)類型為 tag 的 hash文件 放到 objects/ 目錄,然后生成 ref 放到 tags 目錄下指向那個(gè)文件。這就叫做 annotated tag,好處是可包含一些元信息如 tagger 和 message,被 git 的 hash-object 算法管理,可被 GPG 簽名等,所以更穩(wěn)定,更安全。

使用以下命令來拿到 refs 文件夾存儲(chǔ)的信息:


$ git show-ref --head --dereference
5978c2c79cd3a4711fb8edd3166c9f9f5c8c97f5 HEAD
5978c2c79cd3a4711fb8edd3166c9f9f5c8c97f5 refs/heads/abc
5978c2c79cd3a4711fb8edd3166c9f9f5c8c97f5 refs/heads/master
5978c2c79cd3a4711fb8edd3166c9f9f5c8c97f5 refs/tags/v1.0
5e84371048faa20412f5492e6af264a7e1edfec1 refs/tags/xx
5978c2c79cd3a4711fb8edd3166c9f9f5c8c97f5 refs/tags/xx^{}

我們來看這些信息如何變化的:


$ touch new_file && git add . && git commit -m 'add new_file'
[master 44b0d05] add new_file
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 new_file

$ git show-ref --head --dereference
44b0d05ddadaaa8d2cc40d6647cc474b26f5d8d3 HEAD
5978c2c79cd3a4711fb8edd3166c9f9f5c8c97f5 refs/heads/abc
44b0d05ddadaaa8d2cc40d6647cc474b26f5d8d3 refs/heads/master
5978c2c79cd3a4711fb8edd3166c9f9f5c8c97f5 refs/tags/v1.0
5e84371048faa20412f5492e6af264a7e1edfec1 refs/tags/xx
5978c2c79cd3a4711fb8edd3166c9f9f5c8c97f5 refs/tags/xx^{}

diff 一下可以看到:


5978c2c79cd3a4711fb8edd3166c9f9f5c8c97f5 HEAD
5978c2c79cd3a4711fb8edd3166c9f9f5c8c97f5 refs/heads/master

這兩行發(fā)生了變化。也就是每次 commit 時(shí),HEAD 與 heads 都會(huì)自動(dòng)更新。

12. index文件

文件保存成二進(jìn)制對(duì)象以后,還需要通知 Git 哪些文件發(fā)生了變動(dòng)。所有變動(dòng)的文件,Git 都記錄在一個(gè)區(qū)域,叫做"暫存區(qū)"(英文叫做 index 或者 stage)。等到變動(dòng)告一段落,再統(tǒng)一把暫存區(qū)里面的文件寫入正式的版本歷史。

git update-index命令用于在暫存區(qū)記錄一個(gè)發(fā)生變動(dòng)的文件。


$ git update-index --add --cacheinfo 100644 
3b18e512dba79e4c8300dd08aeb37f8e728b8dad test.txt

上面命令向暫存區(qū)寫入文件名test.txt、二進(jìn)制對(duì)象名(哈希值)和文件權(quán)限。

git ls-files命令可以顯示暫存區(qū)當(dāng)前的內(nèi)容。


$ git ls-files --stage
100644 3b18e512dba79e4c8300dd08aeb37f8e728b8dad 0 test.txt

上面代碼表示,暫存區(qū)現(xiàn)在只有一個(gè)文件test.txt,以及它的二進(jìn)制對(duì)象名和權(quán)限。知道了二進(jìn)制對(duì)象名,就可以在.git/objects子目錄里面讀出這個(gè)文件的內(nèi)容。

git status命令會(huì)產(chǎn)生更可讀的結(jié)果。


$ git status
要提交的變更:
    新文件: test.txt

上面代碼表示,暫存區(qū)里面只有一個(gè)新文件test.txt,等待寫入歷史。

資料來源

參考:https://developer.aliyun.com/article/716483

Git遠(yuǎn)程倉庫

Git 并不像 SVN 那樣有個(gè)中心服務(wù)器。目前我們使用到的 Git 命令都是在本地執(zhí)行,如果你想通過 Git 分享你的代碼或者與其他開發(fā)人員合作。 你就需要將數(shù)據(jù)放到一臺(tái)其他開發(fā)人員能夠連接的服務(wù)器上。

1.添加遠(yuǎn)程倉庫


git remote add [shortname] [url] #添加遠(yuǎn)程倉庫
git remote rm name  # 刪除遠(yuǎn)程倉庫
git remote rename old_name new_name  # 修改倉庫名

2.查看遠(yuǎn)端倉庫


$ git remote
origin
$ git remote -v
origin    [email protected]:tianqixin/runoob-git-test.git (fetch)
origin    [email protected]:tianqixin/runoob-git-test.git (push)

3.獲取遠(yuǎn)端倉庫代碼 git fetch


# 只能fetch到一個(gè)空白的分支,然后可以手動(dòng)merge
$ git fetch <遠(yuǎn)程主機(jī)名> <遠(yuǎn)程分支名>:<本地分支名>

不填的話都是默認(rèn)

4.拉取 git pull


git pull <遠(yuǎn)程主機(jī)名> <遠(yuǎn)程分支名>:<本地分支名>
# 允許合并不相關(guān)的分支 
$ git pull --allow-unrelated-histories

git pull操作其實(shí)是git fetch 與 git merge 兩個(gè)命令的集合。 git fetch 和 git merge FETCH_HEAD 的簡(jiǎn)寫。

相關(guān)文檔:https://www.runoob.com/git/git-remote-repo.html

5.推送 git push


# 基本
$ git push <遠(yuǎn)程主機(jī)名> <本地分支名>:<遠(yuǎn)程分支名>
# 強(qiáng)制推送
$ git push --force origin master
# 刪除遠(yuǎn)程分支
$ git push origin --delete master
# 允許合并不相關(guān)的分支
$ git push --allow-unrelated-histories


提示
如果另一個(gè)開發(fā)者在我們之前已經(jīng)做過一次 push 操作,此次 push 命令就會(huì)被拒絕傳送提交。這時(shí)候,我們必須要先做一次 pull 操作,將其他人新上載的更新取回,并本地合并。

如果本地分支名與遠(yuǎn)程分支名相同,則可以省略冒號(hào),帶上-u 參數(shù)相當(dāng)于記錄了push到遠(yuǎn)端分支的默認(rèn)值,這樣當(dāng)下次我們還想要繼續(xù)push的這個(gè)遠(yuǎn)端分支的時(shí)候推送命令就可以簡(jiǎn)寫成git push即可。

Git 分支

1.創(chuàng)建分支命令 git branch


# 創(chuàng)建分支
$ git branch <branch>
# 創(chuàng)建分支并跟蹤遠(yuǎn)程分支
$ git branch -u o/master foo

2.切換分支命令 git checkout

第一作用是切換分支,第二個(gè)是撤銷修改。


# 切換指定分支
$ git checkout <branch>|<hash>|<tag>
# 創(chuàng)建一個(gè)的分支,它跟蹤遠(yuǎn)程分支
$ git checkout -b 本地分支名x origin/遠(yuǎn)程分支名x
# 從暫存區(qū)恢復(fù)到工作區(qū)
$ git checkout .


提示
當(dāng)你切換分支的時(shí)候,Git 會(huì)用該分支的最后提交的快照替換你的工作目錄的內(nèi)容, 所以多個(gè)分支不需要多個(gè)目錄。

實(shí)際測(cè)試:

假設(shè)分支1 a文件未提交,分支2 a文件已提交。切換到到分支2時(shí)會(huì)替換 分支1的a文件。1切換到2時(shí)也會(huì)替換a文件;

兩個(gè)分支都已經(jīng)提交的 切換時(shí)會(huì)互相替換。一個(gè)提交一個(gè)沒提交時(shí),從a到b,b會(huì)保持a的暫存區(qū)和工作區(qū)

3.合并分支命令 git merge


# 合并指定分支到當(dāng)前分支
$ git merge <branch>

4.刪除分支 git branch -d


# 刪除指定分支
$ git branch -d <branch>

5.分支列表 git branch


# 列出所有分支
$ git branch
# 查看遠(yuǎn)程所有分支
$ git branch -r
# 查看本地和遠(yuǎn)程所有分支
$ git branch -a

列出分支時(shí),帶*號(hào)的分支為當(dāng)前活動(dòng)分支

5.重命名分支 git branch -M


# 重命名指定分支
# 不填old默認(rèn)重命名當(dāng)前分支
$ git branch -m old new

# 強(qiáng)制重命名指定分支
$ git branch -M old new

git rebase 變基

1.介紹

Git rebase,通常被稱作變基或衍合, 可以理解為另外一種合并的方式,與merge 會(huì)保留分支結(jié)構(gòu)和原始提交記錄不同,rebase 是在公共祖先的基礎(chǔ)上,把新的提交鏈截取下來,在目標(biāo)分支上進(jìn)行重放,逐個(gè)應(yīng)用選中的提交來完成合并。

不同公司,不同情況有不同使用場(chǎng)景,不過大部分情況推薦如下:

自己?jiǎn)螜C(jī)的時(shí)候,拉公共分支最新代碼的時(shí)候使用rebase,也就是git pull -r或git pull --rebase。這樣的好處很明顯,提交記錄會(huì)比較簡(jiǎn)潔。但有個(gè)缺點(diǎn)就是rebase以后我就不知道我的當(dāng)前分支最早是從哪個(gè)分支拉出來的了,因?yàn)榛鬃兞寺?,所以看個(gè)人需求了。

往公共分支上合代碼的時(shí)候,使用merge。如果使用rebase,那么其他開發(fā)人員想看主分支的歷史,就不是原來的歷史了,歷史已經(jīng)被你篡改了。舉個(gè)例子解釋下,比如張三和李四從共同的節(jié)點(diǎn)拉出來開發(fā),張三先開發(fā)完提交了兩次然后merge上去了,李四后來開發(fā)完如果rebase上去(注意李四需要切換到自己本地的主分支,假設(shè)先pull了張三的最新改動(dòng)下來,然后執(zhí)行,然后再git push到遠(yuǎn)端),則李四的新提交變成了張三的新提交的新基底,本來李四的提交是最新的,結(jié)果最新的提交顯示反而是張三的,就亂套了。

正因如此,大部分公司其實(shí)會(huì)禁用rebase,不管是拉代碼還是push代碼統(tǒng)一都使用merge,雖然會(huì)多出無意義的一條提交記錄“Merge … to …”,但至少能清楚地知道主線上誰合了的代碼以及他們合代碼的時(shí)間先后順序

2.原理

變基操作的工作原理很簡(jiǎn)單:Git 會(huì)讓我們想要移動(dòng)的提交序列在目標(biāo)分支上按照相同的順序重新再現(xiàn)一遍。這就相當(dāng)于我們?yōu)楦鱾€(gè)原提交做了個(gè)副本,它們擁有相同的修改集、同一作者、日期以及注釋信息。

3.命令


# 可以是commit 版本號(hào)、分支名稱,合并多個(gè)提交到一個(gè)版本
$ git rebase -i  [startpoint]  [endpoint]  
# 變基發(fā)生沖突時(shí),解決后繼續(xù)變基
$ git rebase --continue
# 無視沖突,繼續(xù)變基操作
$ git rebase --skip 
# 發(fā)生沖突時(shí)中斷變基
$ git rebase --abort"

-i的意思是--interactive,即彈出交互式的界面讓用戶編輯完成合并操作,[startpoint] [endpoint]則指定了一個(gè)編輯區(qū)間,如果不指定[endpoint],則該區(qū)間的終點(diǎn)默認(rèn)是當(dāng)前分支HEAD所指向的commit(注:該區(qū)間指定的是一個(gè)前開后閉的區(qū)間)。

Git 標(biāo)簽

Git 中的tag指向一次commit的id,通常用來給開發(fā)分支做一個(gè)標(biāo)記,如標(biāo)記一個(gè)版本號(hào)。

1.添加標(biāo)簽


git tag -a version -m "note"

注解:git tag 是打標(biāo)簽的命令,-a 是添加標(biāo)簽,其后要跟新標(biāo)簽號(hào),-m 及后面的字符串是對(duì)該標(biāo)簽的注釋。

2.提交標(biāo)簽到遠(yuǎn)程倉庫


git push origin -tags




請(qǐng)登錄后查看

小碼二開 最后編輯于2024-05-21 16:08:24

快捷回復(fù)
回復(fù)
回復(fù)
回復(fù)({{post_count}}) {{!is_user ? '我的回復(fù)' :'全部回復(fù)'}}
排序 默認(rèn)正序 回復(fù)倒序 點(diǎn)贊倒序

{{item.user_info.nickname ? item.user_info.nickname : item.user_name}} LV.{{ item.user_info.bbs_level || item.bbs_level }}

作者 管理員 企業(yè)

{{item.floor}}# 同步到gitee 已同步到gitee {{item.is_suggest == 1? '取消推薦': '推薦'}}
{{item.is_suggest == 1? '取消推薦': '推薦'}}
沙發(fā) 板凳 地板 {{item.floor}}#
{{item.user_info.title || '暫無簡(jiǎn)介'}}
附件

{{itemf.name}}

{{item.created_at}}  {{item.ip_address}}
打賞
已打賞¥{{item.reward_price}}
{{item.like_count}}
{{item.showReply ? '取消回復(fù)' : '回復(fù)'}}
刪除
回復(fù)
回復(fù)

{{itemc.user_info.nickname}}

{{itemc.user_name}}

回復(fù) {{itemc.comment_user_info.nickname}}

附件

{{itemf.name}}

{{itemc.created_at}}
打賞
已打賞¥{{itemc.reward_price}}
{{itemc.like_count}}
{{itemc.showReply ? '取消回復(fù)' : '回復(fù)'}}
刪除
回復(fù)
回復(fù)
查看更多
打賞
已打賞¥{{reward_price}}
2215
{{like_count}}
{{collect_count}}
添加回復(fù) ({{post_count}})

相關(guān)推薦

快速安全登錄

使用微信掃碼登錄
{{item.label}} 加精
{{item.label}} {{item.label}} 板塊推薦 常見問題 產(chǎn)品動(dòng)態(tài) 精選推薦 首頁頭條 首頁動(dòng)態(tài) 首頁推薦
取 消 確 定
回復(fù)
回復(fù)
問題:
問題自動(dòng)獲取的帖子內(nèi)容,不準(zhǔn)確時(shí)需要手動(dòng)修改. [獲取答案]
答案:
提交
bug 需求 取 消 確 定
打賞金額
當(dāng)前余額:¥{{rewardUserInfo.reward_price}}
{{item.price}}元
請(qǐng)輸入 0.1-{{reward_max_price}} 范圍內(nèi)的數(shù)值
打賞成功
¥{{price}}
完成 確認(rèn)打賞

微信登錄/注冊(cè)

切換手機(jī)號(hào)登錄

{{ bind_phone ? '綁定手機(jī)' : '手機(jī)登錄'}}

{{codeText}}
切換微信登錄/注冊(cè)
暫不綁定
CRMEB客服

CRMEB咨詢熱線 咨詢熱線

400-8888-794

微信掃碼咨詢

CRMEB開源商城下載 源碼下載 CRMEB幫助文檔 幫助文檔
返回頂部 返回頂部
CRMEB客服