GitLab是一款使用MIT許可證的基于網絡的Git倉庫管理工具,我們可以使用它來搭建自己的Git倉庫,本文將介紹如何使用Gitlab在Linux下快速搭建Git倉庫。
在Linux(CenterOS7.6)下我們會以Docker的方式來安裝Gitlab,對Docker不了解的朋友可以參考:開發者必備Docker命令。
docker pull gitlab/gitlab-ce
需要注意的是我們的Gitlab的http服務運行在宿主機的1080端口上,這里我們將Gitlab的配置,日志以及數據目錄映射到了宿主機的指定文件夾下,防止我們在重新創建容器后丟失數據。
docker run --detach \
--publish 10443:443 --publish 1080:80 --publish 1022:22 \
--name gitlab \
--restart always \
--volume /mydata/gitlab/config:/etc/gitlab \
--volume /mydata/gitlab/logs:/var/log/gitlab \
--volume /mydata/gitlab/data:/var/opt/gitlab \
gitlab/gitlab-ce:latest
由于Gitlab運行在1080端口上,所以我們需要開放該端口,注意千萬不要直接關閉防火墻,否則Gitlab會無法啟動。
# 開啟1080端口
firewall-cmd --zone=public --add-port=1080/tcp --permanent
# 重啟防火墻才能生效
systemctl restart firewalld
# 查看已經開放的端口
firewall-cmd --list-ports
docker logs gitlab -f
Gitlab的使用Gitlab啟動完成后第一次訪問,會讓你重置root帳號的密碼
重置完成后輸入帳號密碼登錄
選擇創建項目、創建組織、創建帳號
創建組織
首先我們需要創建一個組織,然后在這個組織下分別創建用戶和項目,這樣同組織的用戶就可以使用該組織下的項目了。
創建用戶并修改密碼找到添加用戶的按鈕
輸入用戶名密碼添加用戶
在編輯界面中修改用戶密碼
創建項目并添加README文件
將用戶分配到組織
git clone http://192.168.3.101:1080/macrozheng/hello.git
進入項目目錄,修改一下README.md并提交:
# 進入項目工程目錄
cd hello/
# 將當前修改的文件添加到暫存區
git add .
# 提交代碼
git commit -m "first commit"
git push
git pull
# 切換并從當前分支創建一個dev分支
git checkout -b dev
# 將新創建的dev分支推送到遠程倉庫
git push origin dev
其他常用命令# 切換到dev分支
Git是當前最先進、最主流的分布式版本控制系統,免費、開源!核心能力就是版本控制。再具體一點,就是面向代碼文件的版本控制,代碼的任何修改歷史都會被記錄管理起來,意味著可以恢復到到以前的任意時刻狀態。支持跨區域多人協作編輯,是團隊項目開發的必備基礎,所以Git也就成了程序員的必備技能。
主要特點:
Git是Linux之父被迫開發的,為了解決Linux混亂的代碼管理而開發的。Linux和Git之父 李納斯·托沃茲(Linus Benedic Torvalds),來自1969年的芬蘭。
先了解下Git的基本概念,及基本框架、工作流程。
概念名稱 | 描述 |
工作區(Workspace) | 就是在電腦里能看到的代碼庫目錄,是我們搬磚的地方,新增、修改的文件會提交到暫存區 |
暫存區(stage 或 index) | 用于臨時存放文件的修改,實際上上它只是一個文件(.git/index),保存待提交的文件列表信息。 |
版本庫/倉庫(Repository) | Git的管理倉庫,管理版本的數據庫,記錄文件/目錄狀態的地方,所有內容的修改記錄(版本)都在這里。 |
服務端/遠程倉庫(origin 或 remote) | 服務端的版本庫,專用的Git服務器,為多人共享提供服務,承擔中心服務器的角色。本地版本庫通過push指令把代碼推送到服務端版本庫。 |
本地倉庫 | 用戶機器上直接使用的的的版本庫 |
分支(Branch) | 分支是從主線分離出去的“副本”,可以獨立操作而互不干擾,倉庫初始化就有一個默認主分支master。 |
頭(HEAD) | HEAD類似一個“指針”,指向當前活動 分支 的 最新版本。 |
提交(Commit) | 把暫存區的所有變更的內容提交到當前倉庫的活動分支。 |
推送(Push) | 將本地倉庫的版本推送到服務端(遠程)倉庫,與他人共享。 |
拉取(Pull) | 從服務端(遠程)倉庫獲取更新到本地倉庫,獲取他人共享的更新。 |
獲取(Fetch) | 從服務端(遠程)倉庫更新,作用同拉取(Pull),區別是不會自動合并。 |
沖突(Conflict) | 多人對同一文件的工作副本進行更改,并將這些更改合并到倉庫時就會面臨沖突,需要人工合并處理。 |
合并(Merge) | 對有沖突的文件進行合并操作,Git會自動合并變更內容,無法自動處理的沖突內容會提示人工處理。 |
標簽(Tags) | 標簽指的是某個分支某個特定時間點的狀態,可以理解為提交記錄的別名,常用來標記版本。 |
master(或main) | 倉庫的“master”分支,默認的主分支,初始化倉庫就有了。Github上創建的倉庫默認名字為“main” |
origin/master | 表示遠程倉庫(origin)的“master”分支 |
origin/HEAD | 表示遠程倉庫(origin)的最新提交的位置,一般情況等于“origin/master” |
工作區、暫存區、版本庫是Git最基本的概念,關系如下圖:
工作區(Workspace)就是在電腦里能看到的代碼庫目錄,是我們搬磚的地方,新增、修改的文件會提交到暫存區。
暫存區(stage或index) 用于臨時存放文件的修改,實際上上它只是一個文件(.git/index),保存待提交的文件列表信息。
版本庫/倉庫(Repository /r??pɑ?z?t??ri/ 倉庫)Git的管理倉庫,管理版本的數據庫,記錄文件/目錄狀態的地方,所有內容的修改記錄(版本)都在這里。就是工作區目錄下的隱藏文件夾.git,包含暫存區、分支、歷史記錄等信息。
如上圖,為對應本地倉庫目錄的結構關系。
Git的工作流程核心就下面幾個步驟,掌握了就可以開始寫Bug了。
Git在執行提交的時候,不是直接將工作區的修改保存到倉庫,而是將暫存區域的修改保存到倉庫。要提交文件,首先需要把文件加入到暫存區域中。因此,Git管理的文件有三(+2)種狀態:
Git官網:www.git-scm.com/ 下載安裝包進行安裝。Git的使用有兩種方式:
指令git --version查看安裝版本號
$ git --version
git version 2.33.0.windows.2
復制代碼
本文是在Windows 平臺上完成的,不過這個對學習Git沒什么影響。
Git有三個主要的配置文件:三個配置文件的優先級是① < ② < ③
#查看git配置
git config --list
git config -l
#查看系統配置
git config --system --list
#查看當前用戶(global)全局配置
git config --list --global
#查看當前倉庫配置信息
git config --local --list
復制代碼
倉庫的配置是上面多個配置的集合:
$ git config --list
$ git config -l
diff.astextplain.textconv=astextplain
http.sslbackend=openssl
http.sslcainfo=C:/Program Files/Git/mingw64/ssl/certs/ca-bundle.crt
core.autocrlf=true
core.fscache=true
core.symlinks=false
pull.rebase=false
credential.helper=manager-core
credential.https://dev.azure.com.usehttppath=true
init.defaultbranch=master
user.name=Kanding
user.email=123anding@163.com
復制代碼
當安裝Git后首先要做的事情是配置你的用戶信息—— 告訴Git你是誰?配置 用戶名、郵箱地址,每次提交文件時都會帶上這個用戶信息,查看歷史記錄時就知道是誰干的了。
配置用戶信息:
$ git config --global user.name "Your Name"
$ git config --global user.email "email@example.com"
# 配置完后,看看用戶配置文件:
$ cat 'C:\Users\Kwongad\.gitconfig'
[user]
name=Kanding
email=123anding@163.com
復制代碼
工作目錄中的文件并不是全都需要納入版本管理,如日志、臨時文件、私有配置文件等不需要也不能納入版本管理,那該怎么辦呢?
在工作區根目錄下創建“.gitignore”文件,文件中配置不需要進行版本管理的文件、文件夾。“.gitignore”文件本身是被納入版本管理的,可以共享。有如下規則:
#為注釋
*.txt #忽略所有“.txt”結尾的文件
!lib.txt #lib.txt除外
/temp #僅忽略項目根目錄下的temp文件,不包括其它目錄下的temp,如不包括“src/temp”
build/ #忽略build/目錄下的所有文件
doc/*.txt #會忽略 doc/notes.txt 但不包括 doc/server/arch.txt
復制代碼
各種語言項目的常用.gitignore文件配置:github.com/github/giti…
如果不想用命令行工具,完全可以安裝一個Git的GUI工具,用的更簡單、更舒服。不用記那么多命令了,極易上手,不過Git基礎還是需要學習了解一下的。
?對于Git,建議用命令行,這樣你才能真的理解Git的思想? ??其實都只是工具而已,適合自己的就是最好的,沒必要糾結,多寫點Bug更重要!
SourceTree的官網 下載安裝包,支持Window、Mac系統,按照提示完成安裝。
TortoiseGit 官網下載安裝包,及中文語言包,按照提示完成安裝。小烏龜的Git是集成到操作系統里的,直接右鍵文件夾就可以進行Git操作了。
VSCode自帶的Git工具基本已經可以滿足日常使用了,既有可視化功能,也能敲命令,習慣了不就不用安裝其他GUI工具了。不過還是可以再安裝一些VSCode插件,來增強Git功能。
創建本地倉庫的方法有兩種:
# 準備一個文件夾“KwebNote”作為倉庫目錄,命令行進入該文件夾
Kwongad@Kwongad-T14 MINGW64 ~
$ cd d:
Kwongad@Kwongad-T14 MINGW64 /d
$ cd Project_Files
Kwongad@Kwongad-T14 MINGW64 /d/Project_Files
# 多次cd指令進入到倉庫目錄KwebNote:“cd <目錄名稱>”指令進入目錄,“cd ..”返回上級目錄(有空格)
Kwongad@Kwongad-T14 MINGW64 /d/Project_Files/github.kwong/KwebNote
# 開始初始化項目,也可指定目錄:git init [文件目錄]
$ git init
Initialized empty Git repository in D:/Project_Files/github.Kwong/KwebNote/.git/
復制代碼
注意:Git指令的執行,都需在倉庫目錄下。
創建完多出了一個被隱藏的.git目錄,這就是本地倉庫Git的工作場所。
克隆遠程倉庫,如在github上創建的倉庫“https://github.com/kwonganding/KWebNote.git”
$ git clone 'https://github.com/kwonganding/KWebNote.git'
Cloning into 'KWebNote'...
remote: Enumerating objects: 108, done.
remote: Counting objects: 100% (108/108), done.
remote: Compressing objects: 100% (60/60), done.
remote: Total 108 (delta 48), reused 88 (delta 34), pack-reused 0
Receiving objects: 100% (108/108), 9.36 KiB | 736.00 KiB/s, done.
Resolving deltas: 100% (48/48), done.
復制代碼
會在當前目錄下創建“KWebNote”項目目錄。
可以簡單理解為,git add命令就是把要提交的所有修改放到暫存區(Stage),然后,執行git commit就可以一次性把暫存區的所有修改提交到倉庫。
指令 | 描述 |
git add [file1] [file2] | 添加文件到暫存區,包括修改的文件、新增的文件 |
git add [dir] | 同上,添加目錄到暫存區,包括子目錄 |
git add . | 同上,添加所有修改、新增文件(未跟蹤)到暫存區 |
git rm [file] | 刪除工作區文件,并且將這次刪除放入暫存區 |
# 添加指定文件到暫存區,包括被修改的文件
$ git add [file1] [file2] ...
# 添加當前目錄的所有文件到暫存區
$ git add .
# 刪除工作區文件,并且將這次刪除放入暫存區
$ git rm [file1] [file2] ...
# 改名文件,并且將這個改名放入暫存區
$ git mv [file-original] [file-renamed]
復制代碼
修改文件“R.md”,未暫存:
執行git add .暫存:
git commit提交是以時間順序排列被保存到數據庫中的,就如游戲關卡一樣,每一次提交(commit)就會產生一條記錄:id + 描述 + 快照內容。
SHA1 是一種哈希算法,可以用來生成數據摘要 Git不適合大的非文本文件,會影響計算摘要、快照的性能。
多個提交就形成了一條時間線,每次提交完,會移動當前分支master、HEAD的“指針”位置。
Sourcetree上的歷史記錄:
一般情況,每完成一個小功能、一個Bu就可以提交一次,這樣會形成比較清晰的歷史記錄。
指令:
指令 | 描述 |
git commit -m '說明' | 提交變更,參數-m設置提交的描述信息,應該正確提交,不帶該參數會進入說明編輯模式 |
git commit -a | 參數-a,表示直接從工作區提交到版本庫,略過了git add步驟,不包括新增的文件 |
git commit [file] | 提交暫存區的指定文件到倉庫區 |
git commit --amend -m | 使用一次新的commit,替代上一次提交,會修改commit的hash值(id) |
git log -n20 | 查看日志(最近20條),不帶參數-n則顯示所有日志 |
git log -n20 --oneline | 參數“--oneline”可以讓日志輸出更簡潔(一行) |
git log -n20 --graph | 參數“--graph”可視化顯示分支關系 |
git log --follow [file] | 顯示某個文件的版本歷史 |
git blame [file] | 以列表形式顯示指定文件的修改記錄 |
git reflog | 查看所有可用的歷史版本記錄(實際是HEAD變更記錄),包含被回退的記錄(重要) |
git status | 查看本地倉庫狀態,比較常用的指令,加參數-s簡潔模式 |
通過git log指令可以查看提交記錄日志,可以很方便的查看每次提交修改了哪些文件,改了哪些內容,從而進行恢復等操作。
# 提交暫存區到倉庫區
$ git commit -m [message]
# 提交所有修改到倉庫
$ git commit -a -m'修改README的版權信息'
# 提交暫存區的指定文件到倉庫區
$ git commit [file1] [file2] ... -m [message]
# 使用一次新的commit,替代上一次提交
# 如果代碼沒有任何新變化,則用來改寫上一次commit的提交信息
$ git commit --amend -m [message]
$ git log -n2
commit 412b56448568ff362ef312507e78797befcf2846 (HEAD -> main)
Author: Kanding <123anding@163.com>
Date: Thu Dec 1 19:02:22 2022 +0800
commit c0ef58e3738f7d54545d8c13d603cddeee328fcb
Author: Kanding <123anding@163.com>
Date: Thu Dec 1 16:52:56 2022 +0800
# 用參數“--oneline”可以讓日志輸出更簡潔(一行)
$ git log -n2 --oneline
5444126 (HEAD -> main, origin/main, origin/HEAD) Update README.md
228362e Merge branch 'main' of github.com:kwonganding/KWebNote
復制代碼
Git中最重要的就是提交記錄了,其他如標簽、分支、HEAD 都對提交記錄的“指針”引用,指向這些提交記錄,理解這一點很重要。
上圖中:
打開這些文件內容看看,就更容易理解這些“指針”的真面目了。
# tag
$ git tag -a 'v1' -m'v1版本'
$ cat .git/refs/tags/v1
a2e2c9caea35e176cf61e96ad9d5a929cfb82461
# main分支指向最新的提交
$ cat .git/refs/heads/main
8f4244550c2b6c23a543b741c362b13768442090
# HEAD指向當前活動分支
$ cat .git/HEAD
ref: refs/heads/main
# 切換到dev分支,HEAD指向了dev
$ git switch dev
Switched to branch 'dev'
$ cat .git/HEAD
ref: refs/heads/dev
復制代碼
這里的主分支名字為“main”,是因為該倉庫是從Github上克隆的,Github上創建的倉庫默認主分支名字就是“main”,本地創建的倉庫默認主分支名字為“master”。
“指針”引用:之所以用引號的“指針”,是為了便于統一和理解。和指針原理類似,都是一個指向,只是實際上可能更復雜一點,且不同的“指針”引用會有區別。
每一個提交都有一個唯一標識,主要就是提交的hash值commit id,在很多指令中會用到,如版本回退、揀選提交等,需要指定一個提交。那標識唯一提交有兩種方式:
通過git log、git reflog可以查看歷史日志,可以看每次提交的唯一編號(hash)。區別是git reflog可以查看所有操作的記錄(實際是HEAD變更記錄),包括被撤銷回退的提交記錄。
$ git reflog -n10
5acc914 (HEAD -> main) HEAD@{0}: reset: moving to HEAD~
738748b (dev) HEAD@{1}: reset: moving to HEAD~
9312c3e HEAD@{2}: reset: moving to HEAD~
db03fcb HEAD@{3}: reset: moving to HEAD~
1b81fb3 HEAD@{4}: reset: moving to HEAD~
41ea423 HEAD@{5}: reset: moving to HEAD~
d3e15f9 HEAD@{6}: reset: moving to d3e15f9
1b81fb3 HEAD@{7}: reset: moving to HEAD~1
41ea423 HEAD@{8}: reset: moving to HEAD~
d3e15f9 HEAD@{9}: reset: moving to HEAD~
復制代碼
git diff用來比較不同文件版本之間的差異。
指令 | 描述 |
git diff | 查看暫存區和工作區的差異 |
git diff [file] | 同上,指定文件 |
git diff --cached | 查看已暫存的改動,就是暫存區與新版本HEAD進行比較 |
git diff --staged | 同上 |
git diff --cached [file] | 同上,指定文件 |
git diff HEAD | 查看已暫存的+未暫存的所有改動,就是與最新版本HEAD進行比較 |
git diff HEAD~ | 同上,與上一個版本比較。HEAD~表示上一個版本,HEAD~10為最近第10個版本 |
git diff [id] [id] | 查看兩次提交之間的差異 |
git diff [branch] | 查看工作區和分支直接的差異 |
??畫個圖更清晰些:
# 查看文件的修改
$ git diff README.md
# 查看兩次提交的差異
$ git diff 8f4244 1da22
# 顯示今天你寫了多少行代碼:工作區+暫存區
$ git diff --shortstat "@{0 day ago}"
復制代碼
Git作為分布式的版本管理系統,每個終端都有自己的Git倉庫。但團隊協作還需一個中間倉庫,作為中心,同步各個倉庫。于是服務端(遠程)倉庫就來承擔這個職責,服務端不僅有倉庫,還配套相關管理功能。
可以用公共的Git服務器,也可以自己搭建一套Git服務器。
Git服務器一般提供兩種登錄驗證方式:
#查看當前遠程倉庫使用的那種協議連接:
$ git remote -v
origin git@github.com:kwonganding/KWebNote.git (fetch)
origin https://github.com/kwonganding/KWebNote.git (push)
# 更改為https地址,即可切換連接模式。還需要禁用掉SSL, 才能正常使用https管理git
git config --global http.sslVerify false
復制代碼
基于HTTPS的地址連接遠程倉庫,Github的共有倉庫克隆、拉取(pull)是不需要驗證的。
$ git clone 'https://github.com/kwonganding/KWebNote.git'
Cloning into 'KWebNote'...
# 倉庫配置文件“.git/config”
[remote "origin"]
url=https://github.com/kwonganding/KWebNote.git
fetch=+refs/heads/*:refs/remotes/origin/*
pushurl=https://github.com/kwonganding/KWebNote.git
復制代碼
推送(push)代碼的時候就會提示輸入用戶名、密碼了,否則無法提交。記住用戶密碼的方式有兩種:
# 直接修改倉庫的配置文件“.git/config”
[remote "origin"]
url=https://用戶名:密碼@github.com/kwonganding/KWebNote.git
fetch=+refs/heads/*:refs/remotes/origin/*
pushurl=https://github.com/kwonganding/KWebNote.git
復制代碼
# 參數“--global”全局有效,也可以針對倉庫設置“--local”
# store 表示永久存儲,也可以設置臨時存儲
git config --global credential.helper store
# 存儲內容如下,打開文件“倉庫\.git\.git-credentials”
https://kwonganding:[加密內容付費可見]@github.com
復制代碼
SSH(Secure Shell,安全外殼)是一種網絡安全協議,通過加密和認證機制實現安全的訪問和文件傳輸等業務,多用來進行遠程登錄、數據傳輸。SSH通過公鑰、私鑰非對稱加密數據,所以SSH需要生成一個公私鑰對,公鑰放服務器上,私有自己留著進行認證。
① 生成公私鑰:通過Git指令ssh-keygen -t rsa生成公私鑰,一路回車即可完成。生成在“C:\Users\用戶名\.ssh”目錄下,文件id_rsa.pub的內容就是公鑰。
② 配置公鑰:打開id_rsa.pub文件,復制內容。Github上,打開Setting? SSH and GPG keys ? SSH keys ? 按鈕New SSH key,標題(Title)隨意,秘鑰內容粘貼進去即可。
SSH配置完后,可用ssh -T git@github.com來檢測是否連接成功。
$ ssh -T git@github.com
Hi kwonganding! You've successfully authenticated, but GitHub does not provide shell access.
復制代碼
指令 | 描述 |
git clone [git地址] | 從遠程倉庫克隆到本地(當前目錄) |
git remote -v | 查看所有遠程倉庫,不帶參數-v只顯示名稱 |
git remote show [remote] | 顯示某個遠程倉庫的信息 |
git remote add [name] [url] | 增加一個新的遠程倉庫,并命名 |
git remote rename [old] [new] | 修改遠程倉庫名稱 |
git pull [remote] [branch] | 取回遠程倉庫的變化,并與本地版本合并 |
git pull | 同上,針對當前分支 |
git fetch [remote] | 獲取遠程倉庫的所有變動到本地倉庫,不會自動合并!需要手動合并 |
git push | 推送當前分支到遠程倉庫 |
git push [remote] [branch] | 推送本地當前分支到遠程倉庫的指定分支 |
git push [remote] --force/-f | 強行推送當前分支到遠程倉庫,即使有沖突,??很危險! |
git push [remote] --all | 推送所有分支到遠程倉庫 |
git push –u | 參數–u表示與遠程分支建立關聯,第一次執行的時候用,后面就不需要了 |
git remote rm [remote-name] | 刪除遠程倉庫 |
git pull --rebase | 使用rebase的模式進行合并 |
git push、git pull是團隊協作中最常用的指令,用于同步本地、服務端的更新,與他人協作。
推送(push):推送本地倉庫到遠程倉庫。
拉取(pull):從服務端(遠程)倉庫更新到本地倉庫。
兩者都是從服務端獲取更新,主要區別是fetch不會自動合并,不會影響當前工作區內容。
git pull=git fetch + git merge
# fetch只更新版本庫
$ git fetch
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 2), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), 663 bytes | 44.00 KiB/s, done.
From github.com:kwonganding/KWebNote
2ba12ca..c64f5b5 main -> origin/main
# 執行合并,合并自己
$ git merge
Updating 2ba12ca..c64f5b5
Fast-forward
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
復制代碼
分支是從主線分離出去的“副本”,分支就像是平行宇宙,可獨立發展,獨立編輯、提交,也可以和其他分支合并。分支是Git的核心必殺利器之一,分支創建、切換、刪除都非常快,他非常的輕量。所以,早建分支!多用分支!
比如有一個項目團隊,準備10月份發布新版本,要新開發一堆黑科技功能,占領市場。你和小伙伴“小美”一起負責開發一個新功能A,開發周期2周,在這兩周你們的代碼不能影響其他人,不影響主分支。這個時候就可以為這個新功能創建一個分支,你們兩在這個分支上干活,2周后代碼開發完了、測試通過,就可以合并進要發版的開發分支了。安全、高效,不影響其他人工作,完美!
在實際項目中,一般會建幾個主線分支。
分支就是指向某一個提交記錄的“指針”引用,因此創建分支是非常快的,不管倉庫多大。當我們運行git branch dev創建了一個名字為dev的分支,Git實際上是在.git\refs\heads下創建一個dev的引用文件(沒有擴展名)。
$ git branch dev
$ cat .git/refs/heads/dev
ca88989e7c286fb4ba56785c2cd8727ea1a07b97
復制代碼
指令 | 描述 |
git branch | 列出所有本地分支,加參數-v顯示詳細列表,下同 |
git branch -r | 列出所有遠程分支 |
git branch -a | 列出所有本地分支和遠程分支,用不同顏色區分 |
git branch [branch-name] | 新建一個分支,但依然停留在當前分支 |
git branch -d dev | 刪除dev分支,-D(大寫)強制刪除 |
git checkout -b dev | 從當前分支創建并切換到dev分支 |
git checkout -b feature1 dev | 從本地dev分支代碼創建一個 feature1分支,并切換到新分支 |
git branch [branch] [commit] | 新建一個分支,指向指定commit id |
git branch --track [branch] [remote-branch] | 新建一個分支,與指定的遠程分支建立關聯 |
git checkout -b hotfix remote hotfix | 從遠端remote的hotfix分支創建本地hotfix分支 |
git branch --set-upstream [branch] [remote-branch] | 在現有分支與指定的遠程分支之間建立跟蹤關聯: |
git checkout [branch-name] | 切換到指定分支,并更新工作區 |
git checkout . | 撤銷工作區的(未暫存)修改,把暫存區恢復到工作區。 |
git checkout HEAD . | 撤銷工作區、暫存區的修改,用HEAD指向的當前分支最新版本替換 |
git merge [branch] | 合并指定分支到當前分支 |
git merge --no-ff dev | 合并dev分支到當前分支,參數--no-ff禁用快速合并模式 |
git push origin --delete [branch-name] | 刪除遠程分支 |
git rebase master | 將當前分支變基合并到master分支 |
?switch:新的分支切換指令 | 切換功能和checkout一樣,switch只單純的用于切換 |
git switch master | 切換到已有的master分支 |
git switch -c dev | 創建并切換到新的dev分支 |
關于 checkout 指令:checkout是Git的底層指令,比較常用,也比較危險,他會重寫工作區。支持的功能比較多,能撤銷修改,能切換分支,這也導致了這個指令比較復雜。在Git 2.23版本以后,增加了git switch、git reset指令。
git switch:專門用來實現分支切換。 git reset:專門用來實現本地修改的撤銷,更多可參考后續“reset”內容。
$ git branch
dev
* main
# 列出了當前的所有分支,星號“*”開頭的“main”為當前活動分支。
復制代碼
代碼倉庫可以有多個分支,master為默認的主分支,但只有一個分支在工作狀態。所以要操作不同分支,需要切換到該分支,HEAD就是指向當前正在活動的分支。
# 切換到dev分支,HEAD指向了dev
# 此處 switch 作用同 checkout,switch只用于切換,不像checkout功能很多
$ git switch dev
Switched to branch 'dev'
$ cat .git/HEAD
ref: refs/heads/dev
復制代碼
使用 git checkout dev切換分支時,干了兩件事:
此時的活動分支就是dev了,后續的提交就會更新到dev分支了。
?切換時還沒提交的代碼怎么辦?
把兩個分支的修改內容合并到一起,常用的合并指令git merge [branch],將分支[branch]合并到當前分支。根據要合并的內容的不同,具體合并過程就會有多種情況。
如下圖,master分支么有任何提交,“git merge dev”合并分支dev到master,此時合并速度就非常快,直接移動master的“指針”引用到dev即可。這就是快速合并(Fast forward),不會產生新的提交。
強制不用快速合并:git merge --no-ff -m "merge with no-ff" dev,參數--no-ff不啟用快速合并,會產生一個新的合并提交記錄。
如果master有變更,存在分支交叉,則會把兩邊的變更合并成一個提交。
上圖中,創建dev分支后,兩個分支都有修改提交,因此兩個分支就不在一條順序線上了,此時合并dev到master就得把他們的修改進行合并操作了。
在有沖突的文件中,<<<<<<< HEAD開頭的內容就表示是有沖突的部分,需要人工處理,可以借助一些第三方的對比工具。人工處理完畢后,完成合并提交,才最終完成此次合并。=======分割線上方是當前分支的內容,下方是被合并分支的變更內容。
把兩個分支的修改內容合并到一起的辦法有兩種:merge 和 rebase,作用都是一樣的,區別是rebase的提交歷史更簡潔,干掉了分叉,merge的提交歷史更完整。
$ git rebase master
$ git checkout master
$ git merge dev
復制代碼
標簽(Tags)指的是某個分支某個特定時間點的狀態,是對某一個提交記錄的的固定“指針”引用。一經創建,不可移動,存儲在工作區根目錄下.git\refs\tags。可以理解為某一次提交(編號)的別名,常用來標記版本。所以發布時,一般都會打一個版本標簽,作為該版本的快照,指向對應提交commit。
當項目達到一個關鍵節點,希望永遠記住那個特別的提交快照,你可以使用 git tag 給它打上標簽。比如我們今天終于完成了V1.1版本的開發、測試,并成功上線了,那就可給今天最后這個提交打一個標簽“V1.1”,便于版本管理。
默認標簽是打在最新提交的commit上的,如果希望在指定的提交上打標簽則帶上提交編號(commit id):git tag v0.9 f52c633
指令 | 描述 |
git tag | 查看標簽列表 |
git tag -l 'a*' | 查看名稱是“a”開頭的標簽列表,帶查詢參數 |
git show [tagname] | 查看標簽信息 |
git tag [tagname] | 創建一個標簽,默認標簽是打在最新提交的commit上的 |
git tag [tagname] [commit id] | 新建一個tag在指定commit上 |
git tag -a v5.1 -m'v5.1版本' | 創建標簽v5.1.1039,-a指定標簽名,-m指定說明文字 |
git tag -d [tagname] | 刪除本地標簽 |
git checkout v5.1.1039 | 切換標簽,同切換分支 |
git push [remote] v5.1 | 推送標簽,標簽不會默認隨代碼推送推送到服務端 |
git push [remote] --tags | 提交所有tag |
如果要推送某個標簽到遠程,使用命令git push origin [tagname],或者,一次性推送全部到遠程:git push origin --tags
注意:標簽總是和某個commit掛鉤。如果這個commit既出現在master分支,又出現在dev分支,那么在這兩個分支上都可以看到這個標簽。
# tag
$ git tag -a 'v1' -m'v1版本'
$ cat .git/refs/tags/v1
a2e2c9caea35e176cf61e96ad9d5a929cfb82461
# 查看標簽列表
$ git tag
v1
復制代碼
發現寫錯了要回退怎么辦?看看下面幾種后悔指令吧!
指令 | 描述 |
git checkout . | 撤銷工作區的(未暫存)修改,把暫存區恢復到工作區。不影響暫存區,如果沒暫存,則撤銷所有工作區修改 |
git checkout [file] | 同上,file指定文件 |
git checkout HEAD . | 撤銷工作區、暫存區的修改,用HEAD指向的當前分支最新版本替換工作區、暫存區 |
git checkout HEAD [file] | 同上,file指定文件 |
git reset | 撤銷暫存區狀態,同git reset HEAD,不影響工作區 |
git reset HEAD [file] | 同上,指定文件file,HEAD可省略 |
git reset [commit] | 回退到指定版本,清空暫存區,不影響工作區。工作區需要手動git checkout簽出 |
git reset --soft [commit] | 移動分支master、HEAD到指定的版本,不影響暫存區、工作區,需手動git checkout簽出更新 |
git reset --hard HEAD | 撤銷工作區、暫存區的修改,用當前最新版 |
git reset --hard HEAD~ | 回退到上一個版本,并重置工作區、暫存區內容。 |
git reset --hard [commit] | 回退到指定版本,并重置工作區、暫存區內容。 |
git revert[commit] | 撤銷一個提交,會用一個新的提交(原提交的逆向操作)來完成撤銷操作,如果已push則重新push即可 |
# 只撤銷工作區的修改(未暫存)
$ git checkout .
Updated 1 path from the index
# 撤銷工作區、暫存區的修改
$ git checkout HEAD .
Updated 1 path from f951a96
復制代碼
reset是專門用來撤銷修改、回退版本的指令,支持的場景比較多,多種撤銷姿勢,所以參數組合也比較多。簡單理解就是移動master分支、HEAD的“指針”地址,理解這一點就基本掌握reset了。
如下圖:
reset有三種模式,對應三種參數:mixed(默認模式)、soft、hard。三種參數的主要區別就是對工作區、暫存區的操作不同。
模式名稱\ | 描述 | HEAD的位置 | 暫存區 | 工作區 |
soft | 回退到某一個版本,工作區不變,需手動git checkout | 修改 | 不修改 | 不修改 |
mixed(默認) | 撤銷暫存區狀態,不影響工作區,需手動git checkout | 修改 | 修改 | 不修改 |
hard | 重置未提交修改(工作區、暫存區) | 修改 | 修改 | 修改 |
穿梭前,用git log可以查看提交歷史,以便確定要回退到哪個版本。要重返未來,用git reflog查看命令歷史,以便確定要回到未來的哪個版本。
git reset [--soft | --mixed | --hard] [HEAD]
# 撤銷暫存區
$ git reset
Unstaged changes after reset:
M R.md
# 撤銷工作區、暫存區修改
$ git reset --hard HEAD
# 回退版本庫到上一個版本,并重置工作區、暫存
$ git reset --hard HEAD~
# 回到原來的版本(恢復上一步的撤銷操作),并重置工作區、暫存
$ git reset --hard 5f8b961
# 查看所有歷史提交記錄
$ git reflog
ccb9937 (HEAD -> main, origin/main, origin/HEAD) HEAD@{0}: commit: 報表新增導入功能
8f61a60 HEAD@{1}: commit: bug:修復報表導出bug
4869ff7 HEAD@{2}: commit: 用戶報表模塊開發
4b1028c HEAD@{3}: commit: 財務報表模塊開發完成
復制代碼
安全的撤銷某一個提交記錄,基本原理就是生產一個新的提交,用原提交的逆向操作來完成撤銷操作。注意,這不同于reset,reset是回退版本,revert只是用于撤銷某一次歷史提交,操作是比較安全的。
如上圖:
# revert撤銷指定的提交,“-m”附加說明
$ git revert 41ea42 -m'撤銷對***的修改'
[main 967560f] Revert "123"
1 file changed, 1 deletion(-)
復制代碼
標題 \ 指令 | checkout | reset | revert |
主要作用(撤銷) | 撤銷工作區、暫存區未提交修改 | 回退版本,重置工作區、暫存區 | 撤銷某一次提交 |
撤銷工作區 | git checkout [file] | git reset HEAD [file] | |
撤銷工作區、暫存區 | git checkout HEAD [file] | git reset --hard HEAD [file] | |
回退版本 | git reset --hard [commit] | ||
安全性 | 只針對未提交修改,安全 | 如回退了已push提交,不安全 | 安全 |
可看出reset完全可以替代checkout來執行撤銷、回退操作,reset本來也是專門用來干這個事情的,可以拋棄checkout了(撤銷的時候)。
Git flow(Git工作流程)是指軟件項目中的一種Git分支管理模型,經過了大量的實踐和優化,被認為是現代敏捷軟件開發和DevOps(開發、技術運營和質量保障三者的交集)的最佳實踐。Git flow主要流程及關鍵分支:原圖地址-processon
?主分支:master,穩定版本代碼分支,對外可以隨時編譯發布的分支,不允許直接Push代碼,只能請求合并(pull request),且只接受hotfix、release分支的代碼合并。
?熱修復分支:hotfix,針對線上緊急問題、bug修復的代碼分支,修復完后合并到主分支、開發分支。
?發版分支:release,版本發布分支,用于迭代版本發布。迭代開發完成后,合并dev代碼到release,在release分支上編譯發布版本,以及修改bug(定時同步bug修改到dev分支)。測試完成后此版本可以作為發版使用,然后把穩定的代碼push到master分支,并打上版本標簽。
?開發分支:dev,開發版本分支,針對迭代任務開發的分支,日常開發原則上都在此分支上面,迭代完成后合并到release分支,開發、發版兩不誤。
?其他開發分支:dev-xxx,開發人員可以針對模塊自己創建本地分支,開發完成后合并到dev開發分支,然后刪除本地分支。
當你正在dev分支開發一個功能時,代碼寫了一半,突然有一個線上的bug急需要馬上修改。dev分支Bug沒寫完,不方便提交,就不能切換到主分支去修復線上bug。Git提供一個stash功能,可以把當前工作區、暫存區 未提交的內容“隱藏”起來,就像什么都沒發生一樣。
# 有未提交修改,切換分支時報錯
$ git checkout dev
error: Your local changes to the following files would be overwritten by checkout:
README.md
Please commit your changes or stash them before you switch branches.
Aborting
# 隱藏
$ git stash
Saved working directory and index state WIP on main: 2bc012c s
# 查看被隱藏的內容
$ git stash list
stash@{0}: WIP on main: 2bc012c s
# 比較一下,什么都沒有,一切都沒有發生過!
$ git diff
# 去其他分支修改bug,修復完成回到當前分支,恢復工作區
$ git stash pop
復制代碼
在上面示例中,有未提交修改,切換分支時報錯。錯誤提示信息很明確了,commit提交或stash隱藏:Please commit your changes or stash them before you switch branches.
如果切換分支時,未提交修改的內容沒有沖突,是可以成功切換的,未提交修改會被帶過去。
指令 | 描述 |
git stash | 把未提交內容隱藏起來,包括未暫存、已暫存。 等以后恢復現場后繼續工作 |
git stash list | 查看所有被隱藏的內容列表 |
git stash pop | 恢復被隱藏的內容,同時刪除隱藏記錄 |
git stash save "message" | 同git stash,可以備注說明message |
git stash apply | 恢復被隱藏的文件,但是隱藏記錄不刪除 |
git stash drop | 刪除隱藏記錄 |
當然這里先提交到本地也是可以的,只是提交不是一個完整的功能代碼,而是殘缺的一部分,影響也不大。
當有一個緊急bug,在dev上修復完,我們需要把dev上的這個bug修復所做的修改“復制”到master分支,但不想把整個dev合并過去。為了方便操作,Git專門提供了一個cherry-pick命令,讓我們能復制一個特定的提交到當前分支,而不管這個提交在哪個分支。
如上圖,操作過程相當于將該提交導出為補丁文件,然后在當前HEAD上重放,形成無論內容還是提交說明都一致的提交。
# 選擇一個commit,合并進當前分支
$ git cherry-pick [commit]
復制代碼
轉載鏈接:https://juejin.cn/post/7195030726096453690