0、前言:
0.1、為什么學習shell腳本
- 學習Shell(Shell腳本編程)是提升系統管理和開發效率的重要技能,尤其在Linux/Unix環境中作用顯著。Shell是用戶與操作系統內核的接口,學習Shell有助于掌握系統工作原理。
shell的核心作用
1、自動化重復任務【用for循環批量處理文件】
2、系統管理和維護【通過chmod管理權限、通過腳本監控CPU/內存使用率】
3、快速原型開發【shell腳本無需編譯是解釋型語言、可以快速數據清洗、格式轉換】
4、大多數Linux系統自帶解釋器【Bash】,腳本可以直接運行,無需額外配環境
5、★可以與其它工具集成【調用系統命令grep、awk、sed;與Python配合實現復雜功能】
- ★Shell是系統管理員和開發者的“瑞士軍刀”,學習它能讓你從“手動操作”升級為“自動化工程師”,顯著提升工作效率并加深對系統的理解。即使未來轉向其他語言,Shell思維仍會長期受益。
0.2、gitee用來干什么
- Gitee 就像一個專門管代碼的多功能平臺,不管是個人寫代碼、團隊一起做項目,還是企業搞開發,都能用它解決很多實際問題,從專業角度來說 git 是一個分布式的版本控制工具。
1.個人開發者:存代碼、備份、看歷史修改,還能跟別人分享自己寫的開源項目(比如讓大家一起改進你的小工具);Gitee 能設置 “自動流程”:你一提交代碼,它就自動幫你編譯、跑測試,有問題馬上告訴你,不用你自己點鼠標等半天。
2.小團隊 / 學生組:一起寫代碼不沖突,管任務進度,不用額外裝復雜軟件;如果兩人改了同一段代碼(比如都改了登錄功能),它會提醒 “這里有沖突”,幫你們理清誰改的是對的,避免改亂。
3.企業:除了上述功能,還能保障代碼安全、統計項目效率(比如多久能完成一個需求)、用 AI 輔助查代碼 bug,一套平臺搞定開發全流程。
4.gitee中還可以進行版本回退
- 常見版本控制工具:git、svn、cvs、vss、tfs
- 版本控制的分類:
- 本地版本控制,就是自己每次更行文件夾
- 集中版本控制(svn):所有數據都在單一服務器上,本地只有一個版本
- 分布式版本控制:所有版本信息倉庫全部都同步到每一個用戶電腦上,用戶可以在本地查看所有版本歷史,也可以離線提交到本地倉庫,只要在聯網的時候push到服務器上即可,只要有一個用戶版本沒問題,就可以恢復所有數據
1、shell指令:
1.1、Shell和linux的Bash指令之間的區別
- Shell是用戶和操作系統內核交互的命令行接口包含【Bash、Zsh、Fish、Sh等】,它是一種解釋型編程語言,shell逐行解釋執行;
Zsh:需要更強大的命令補全和主題定制(如 Oh My Zsh)。
Fish:追求用戶友好性(自動建議、語法高亮)。
Dash:需要極簡、快速的 Shell(如嵌入式系統)。
- Bash是Shell的具體實現,是目前最流行的默認Shell;
- Shell 像“汽車類別”(如轎車、SUV),Bash 像“特斯拉 Model 3”(具體車型);
- 差異性舉例:
- Bash 獨有命令:[[ ]] 條件判斷(比 [ ] 更強大)、{1…10} 數字序列生成、array=(“a” “b”) 數組支持
- 通用 Shell 命令:cd、ls、echo 等基礎命令在所有 Shell 中通用、if [ -f file ]; then … 這種 [ ] 語法在 Sh/Bash 中均可用
- 編寫腳本時,通過第一行(也叫shebang行)判斷用哪個Shell解釋:【如果不加 Shebang,系統會默認用當前 Shell】
#!/bin/bash # 強制用 Bash 解釋(支持 Bash 特性)
#!/bin/sh # 用系統默認 Shell(可能是 Dash,更嚴格遵循 POSIX 標準)
1.2、shell基礎入門:
1.2.1、變量和引號和$符:
- 1、變量定義與賦值:Shell 變量是存儲數據的容器 【語法:變量名=值(等號兩側不能有空格)】
# 變量示例:
name="Alice" # 定義字符串變量
age=25 # 定義數字變量(Shell 中所有變量本質是字符串)
path=/home/user # 定義路徑變量
- 2、變量的引用:【語法:$變量名 或 ${變量名}(推薦用 ${},避免歧義)】
echo $name # 輸出: Alice
echo "Hello, ${name}!" # 輸出: Hello, Alice!(更清晰)
- 注意:shell中變量名命名規則和C語言一致;
- 3、部分特殊變量:
# 腳本 test.sh 內容:
echo "腳本名: $0"
echo "第一個參數: $1"
echo "參數個數: $#$"
echo "所有參數: $@"# 運行腳本:
./test.sh Apple Banana
# 輸出:
# 腳本名: ./test.sh
# 第一個參數: Apple
# 參數個數: 2
# 所有參數: Apple Banana
-
4、環境變量:Shell 中的環境變量是全局可見的變量,用于存儲系統或用戶的配置信息(如路徑、用戶名、默認編輯器等),讓腳本和程序能在不同環境中正常運行。【環境變量是 Shell 中具有 “跨進程傳遞能力” 的全局變量】
- 環境變量分為兩種,一種是系統環境變量,一種是用戶環境變量,臨時設置的用戶環境變量(終端中直接 export 變量=值)只在當前 Shell 會話中有效,重啟或新開終端后會消失。如果想要設置永久保存具有跨進程傳遞能力的環境變量,就要往 ~/.bashrc 中加變量,例如: export JAVA_HOME=/usr/lib/jvm/java-11-openjdk 。
- 配置系統環境變量的意義:很多程序(如 Java、Python、Docker 等)需要依賴特定的環境變量才能正常工作(比如 JAVA_HOME 告訴程序 Java 安裝在哪里)。如果不配置永久環境變量,每次打開新終端或重啟系統后,都需要手動執行 export JAVA_HOME=… 才能讓程序正常運行,非常繁瑣。
永久配置后,系統會自動加載這些變量,一勞永逸。 - 普通環境變量在當前shell或者由此shell創建的子shell中都能訪問,其他變量可以理解為局部變量。案例如下
# 以下是在交互式shell中的執行結果 brush@ubuntu:~/Desktop$ local_tes=12 brush@ubuntu:~/Desktop$ export export_tes=13 brush@ubuntu:~/Desktop$ echo ${local_tes} 12 brush@ubuntu:~/Desktop$ echo ${export_tes} 13 brush@ubuntu:~/Desktop$ cat -n test.sh1 #!/bin/bash2 echo ${local_tes}3 echo ${export_tes} brush@ubuntu:~/Desktop$ bash ./test.sh13 brush@ubuntu:~/Desktop$
- 常用系統環境變量:查看所有環境變量用 env 或 printenv 命令,例如 printenv PATH 可單獨查看 PATH 的值。【Shell 中的系統環境變量是操作系統預定義的一組全局變量,它們就像 “系統的配置說明書”,控制著 Shell 及各種程序的運行方式、路徑查找、用戶信息等核心行為。例如:當你在終端輸入 ls 時,系統會依次在 PATH 包含的目錄中查找 ls 程序(實際在 /bin/ls),找到后執行。如果沒有 PATH,你必須輸入完整路徑(如 /bin/ls)才能執行命令,非常繁瑣。】
brush@ubuntu:~/Desktop$ printenv SHELL=/bin/bash LANGUAGE=zh_CN:en LC_ADDRESS=en_US.UTF-8 LC_NAME=en_US.UTF-8 LC_MONETARY=en_US.UTF-8 PWD=/home/brush/Desktop LOGNAME=brush export_tes=13 XDG_SESSION_TYPE=tty brush@ubuntu:~/Desktop$ printenv PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
-
5、Shell 引號:控制字符串解析規則,說白了就是一些特殊符號的權限問題
- 雙引號:允許變量擴展($var 會被替換為變量值)、允許命令替換(
command
或 $(command) 會被替換為命令輸出)、禁止通配符擴展(如 * 不會被解析為文件名)。 - 單引號:禁止所有擴展:變量、命令、通配符均按字面值處理。【就記住一點,單引號中禁止所有特殊符號起作用】
name="Alice" echo 'Hello, $name!' # 輸出: Hello, $name!(變量不擴展) echo 'Today is $(date)' # 輸出: Today is $(date)(命令不替換)name="Alice" echo 'Hello, $name!' # 輸出: Hello, $name!(變量不擴展) echo 'Today is $(date)' # 輸出: Today is $(date)(命令不替換)
- 雙引號:允許變量擴展($var 會被替換為變量值)、允許命令替換(
-
6、【$(命令)】 就是 “先執行命令,再拿結果用” 的語法
-
7、shell中$符號的用法
- 注意:$(( )) 內部會自動解析變量名,所以在 $(( )) 當中寫變量不用${變量名},直接寫變量名即可;
- 補充:${!變量名} 用于 “通過變量的值找到另一個變量”(間接獲取變量值),如果name=2、${name}的結果就是2、a=“name”、${!a}的結果也是2,對于shell中的參數而言,假設第一個參數是5,那么參數5的變量名就是1,${1}的結果就是5、a=1、${!a}的結果也是5。
- 關于測試雙引號作用時踩的坑:【交互shell和腳本shell傻傻分不清楚】
- 上面這個shell代碼很簡單吧,我第一次寫這個代碼的時候,我沒加最后一句echo,每次執行,就只是打印當前路徑,然后我并沒有觀察到我的liunx終端的路徑發生改變,我就用國內ai大量查找,死活沒給我講明白,最后通過sider(edge中的一款ai)才搞清楚,在程序中cd執行的就是將程序切換到某個路徑下,并非將外面的環境(交互shell)切換到某個路徑。【當你運行一個腳本(例如 bash test.sh 或 ./test.sh)時,系統會為腳本創建一個新的子進程。子進程能自由修改自己的工作目錄,但這些修改不會影響父進程(啟動它的 shell),因為每個進程的屬性是獨立的。】
- 上面的案例主要還是想測試下在執行cd命令時候,加雙引號和不加雙引號的區別,當程序中沒給 ${pth} 加雙引號,就會報錯說cd 參數太多。原因如下:賦值處的雙引號只影響賦值過程,不會“記住”在后續展開時自動為你加上保護。當 shell 遇到 cd ${pth} 時,先把 ${pth} 展開為 /home/brush/Desktop/a 1,然后進行單詞拆分(word splitting):默認以 IFS(通常是空格、制表符、換行)為界,把展開結果拆成多個獨立的字段,結果 cd 實際接收到兩個參數:/home/brush/Desktop/a 和 1。cd “${pth}” 告訴 shell:把變量整個作為一個單詞處理,不要進行單詞拆分或文件名展開。
- 這個例子就是想說明雙引號支持變量拓展,結果踩了個坑發現了Shell中賦值雙引號在變量傳遞過程中是不會整體傳遞的,有點像c中的宏定義,就是替換而已;還有發現了shell腳本中cd路徑和交互shell中cd路徑是兩碼事。
- 拓展:如果上面的shell腳本中用了單引號將 ${pth} 括起來,結果就是 ${pth} 本身就會被當做路徑,不會解析把pth當做變量解析了。
-
總結:一般情況下調用Bash中的變量的時候,在外面加個雙引號比較可靠。
1.2.2、條件判斷
- 基本語法格式
if [ 條件 ]; then命令...
elif [ 其他條件 ] && [ 其他條件 ]; then命令...
else命令...
fi
- 文件測試:
1.-e 判斷文件是否存在
2.-d 判斷文件是不是目錄
3.-f 判斷文件是不是常規文件
4.-r、-w、-x 判斷文件是否可讀、可寫、可執行
#!/bin/bash
file="/home/brush/Desktop/test.sh
if [ -e "$file" ]; then # 文件或目錄存在echo "存在"
fi
- 判斷字符串是否相等:
#!/bin/bash
s1="hello"
s2="world"if [ "$s1" = "$s2" ]; thenecho "相等"
elseecho "no equil"
fi
- 整數比較:
eq【是否等于】, -ne【是否不等于】, -lt【是否小于】, -le【是否小于等于】, -gt【是否大于】, -ge【是否大于等于】
#!/bin/bash
a=10
b=8
if [ "${a}" -gt "${b}" ]; thenecho '10 > 8'
elseecho '10 < 8'
fi
執行結果是:10 > 8
1.2.3、循環
-
for循環:
- 格式:
# 寫法1:遍歷列表(直觀,推薦) for 變量名 in 列表內容 do要執行的命令(變量用 $變量名 調用) done# 寫法2:C語言風格(適合數字范圍,需指定起始/結束/步長) for ((變量=起始值; 變量<=結束值; 變量=變量+步長)) do要執行的命令 done
- 實踐1【遍歷當前文件列表,計算有多少文件,用for的列表遍歷寫法】
#!/bin/bash count=0 for i in $(ls) doif [ -f ${i} ]; thencount=$((count+1))echo ${i} is a filefi done echo file number is : ${count}
- 實踐2【給兩個文件,分別通過for的c語言風格,輸入指定長度的序列,比如第1個參數是3,就會在第一個文件中輸入1-3,第2個參數是4,就會在第2個文件中輸入1-4】【提示1:通過內置變量 $# 來獲取傳遞給腳本的參數個數;提示2:$@ 是所有參數的集合】
#!/bin/bash for((i=1; i<=$#; i=i+1)) do#這里用了參數簡介引用echo 1-${!i} > file_${i}.txt done
-
while循環:未知循環次數,按條件停止
- 格式
while 條件判斷(滿足則繼續循環,不滿足則退出) do要執行的命令 done # 陷入“死循環”(按 Ctrl+C 強制停止)。
- 案例:輸入不是quit就一直循環
# 先定義一個初始變量,讓循環先啟動 input="" while [ "$input" != "quit" ] # 條件:只要 input 不是 quit,就繼續 doecho "請輸入內容(輸入 quit 退出):"read input # 讀取用戶輸入,存到 input 變量echo "你輸入的是:$input" done echo "循環結束!"
- 注意:不是所有條件都寫在while后面的 [ 條件 ] 當中,有的條件是直接寫的;
-
until(直到):條件為假時執行循環體,直到條件為真時停止。
- 基本格式
until 條件判斷 do要執行的命令 done
- 案例:
attempts=0 # until 寫法:條件(嘗試次數≥3)為真時停止 until ((attempts >= 3)); doecho "第 $((attempts+1)) 次嘗試..."attempts=$((attempts + 1)) done# 等價的 while 寫法:條件(嘗試次數<3)為真時執行 attempts=0 while ((attempts < 3)); doecho "第 $((attempts+1)) 次嘗試..."attempts=$((attempts + 1)) done
1.2.4、參數傳遞
- 執行腳本時,直接在腳本名后面跟參數,用空格分隔,就能向腳本中傳遞參數,有點像C++的構造函數中初始化參數列表的方式。
- 格式:【./腳本名 參數1 參數2 參數3 …】
- 例如:
# 執行腳本并傳遞 3 個參數:apple、"hello world"、123
./test.sh apple "hello world" 123
- 常用指令
- 案例:
#!/bin/bash
for i in $@
doecho $i
done
將代碼進一步修改,給 $@ 加上雙引號
#!/bin/bash
for i in "$@"
doecho $i
done
為什么會出現上面的情況,核心原因是 雙引號會 “保護”$@ 的特殊行為,讓它嚴格按照 “參數列表” 的原始形態展開,而不是被拆分成字符串碎片。 當你寫 $@(無引號)時,Shell 會觸發 “單詞拆分”(Word Splitting)機制:它會把 $@ 中的所有參數拼接成一個字符串(用空格分隔),比如變成 “15 hellow pi kjk”;然后按空格、制表符、換行符拆分這個字符串。
- $1 到 $9 可以直接用,第 10 個及以上參數必須用 ${10}、${11}…(加花括號),其實從嚴格書寫的角度來說,1到9也應該寫成 ${1} 到 ${9} 。
- 選項參數用 getopts 【了解即可】
1.3、實用技巧:
1.3.1、字符串操作:
- Shell 字符串支持拼接、截取、替換、長度計算等操作,是文本處理的基礎。
- 字符串拼接:
name="張三"
age=20
# 方法:雙引號內直接拼接
echo "姓名:${name},年齡:${age}" # 輸出:姓名:張三,年齡:20
- 字符串長度:
str="hello world"
echo "長度:${#str}" # 輸出:11
- 字符串截取:
str="abcdefg"
echo "${str:2:3}" # 從索引2開始,取3個字符 → "cde"
- 字符串替換:
str="hello world, world is beautiful"
echo "${str/world/China}" # 單次替換 → "hello China, world is beautiful"
echo "${str//world/China}" # 全局替換 → "hello China, China is beautiful"
- 字符串刪除:
- 從開頭刪除:1、${var#匹配模式}:從開頭最短匹配并刪除、2. ${var##匹配模式}:從開頭最長匹配并刪除,案例如下:
brush@ubuntu:~/Desktop$ cat -n test.sh1 #!/bin/bash2 str="/1/2345/7"3 echo ${str#/*/}4 echo ${str##/*/} brush@ubuntu:~/Desktop$ bash ./test.sh 2345/7 7
- 從結尾刪除:1. ${var%匹配模式}:從結尾最短匹配并刪除、2. ${var%%匹配模式}:從結尾最長匹配并刪除,參考上面案例,不做解釋了;
1.3.2、數組:
- Shell 支持索引數組(默認)和關聯數組(需聲明),用于存儲一組數據。
- 索引數組
# ====================索引數組的定義與賦值# 方法1:直接定義,用圓括號
array=(apple banana "cherry pie" 123)# 方法2:逐個賦值
array[0]=apple
array[1]=banana
array[2]="cherry pie"
array[3]=123# ====================訪問元素echo "${array[0]}" # 訪問第一個元素 → "apple"
echo "${array[2]}" # 訪問第三個元素 → "cherry pie"
echo "${array[@]}" # 訪問所有元素 → "apple banana cherry pie 123"
echo "${array[*]}" # 同 @,但合并為一個字符串 → "apple banana cherry pie 123"# ====================數組長度
echo "元素個數:${#array[@]}" # 輸出:4
echo "第一個元素長度:${#array[0]}" # 輸出:5("apple"的長度)# ====================遍歷數組
for item in "${array[@]}"; doecho "元素:$item"
done
- 關聯數組
# 聲明關聯數組
declare -A map# 賦值(鍵可以是字符串)
map["name"]="張三"
map["age"]=20
map["city"]="北京"# 訪問
echo "姓名:${map["name"]}" # 輸出:張三
echo "所有鍵:${!map[@]}" # 輸出:name age city
echo "所有值:${map[@]}" # 輸出:張三 20 北京# 遍歷
for key in "${!map[@]}"; doecho "鍵:$key,值:${map[$key]}"
done
1.3.3、重定向:
- 概念:Shell 中的重定向是控制命令輸入輸出流向的核心機制,簡單說就是 “改變數據的默認來源或去向”。默認情況下,命令的輸入來自鍵盤(標準輸入),輸出顯示在屏幕(標準輸出),錯誤信息也顯示在屏幕(標準錯誤)。重定向讓我們可以把輸入輸出 “轉移” 到文件或其他地方,非常實用。
- 前提知識:
- 0(stdin):標準輸入,默認是鍵盤
- 1(stdout):標準輸出,默認是屏幕(正常運行結果)
- 2(stderr):標準錯誤,默認是屏幕(錯誤提示信息)
- 重定向的本質就是改變這三個流的 “源頭” 或 “目的地”。
- 命令格式:
注意:腳本寫入多行中用了cat指令,cat最常用的場景就是預覽文件,但是cat的本質是讀取輸入(文件或標準輸入)并輸出內容 - 案例:
brush@ubuntu:~/Desktop$ clear
brush@ubuntu:~/Desktop$ ls -l
總用量 12
drwxrwxr-x 2 brush brush 4096 Sep 3 19:54 'a 1'
drwxrwxr-x 2 brush brush 4096 Sep 2 08:22 make_project
-rwxrwxrwx 1 brush brush 49 Sep 5 01:51 test.sh
# 測試重定向輸出(覆蓋)
brush@ubuntu:~/Desktop$ ls > file.txt
brush@ubuntu:~/Desktop$ cat -n file.txt1 a 12 file.txt3 make_project4 test.sh
# 測試重定向輸出(添加)
brush@ubuntu:~/Desktop$ echo this is append >> file.txt
brush@ubuntu:~/Desktop$ cat -n file.txt1 a 12 file.txt3 make_project4 test.sh5 this is append
# 測試錯誤信息重定向輸出(覆蓋)
brush@ubuntu:~/Desktop$ cd /home/666 2> file.txt
brush@ubuntu:~/Desktop$ cat -n file.txt1 -bash: cd: /home/666: 沒有那個文件或目錄
# 測試輸出所有信息
brush@ubuntu:~/Desktop$ cd /home | cd ./666 &> file.txt
brush@ubuntu:~/Desktop$ cat -n file.txt1 -bash: cd: ./666: 沒有那個文件或目錄
# 測試從文件讀內容
brush@ubuntu:~/Desktop$ cat -n file.txt1 -bash: cd: ./666: 沒有那個文件或目錄
brush@ubuntu:~/Desktop$ echo afdaf >> file.txt
brush@ubuntu:~/Desktop$ echo fadfaf666 >> file.txt
brush@ubuntu:~/Desktop$ grep 666 < file.txt
-bash: cd: ./666: 沒有那個文件或目錄
fadfaf666
brush@ubuntu:~/Desktop$
# 測試讓腳本‘安靜地’運行,不產生任何可見輸出的“黑洞命令”
brush@ubuntu:~/Desktop$ test.sh &> /dev/null
# 測試向腳本中寫入多行【】
brush@ubuntu:~/Desktop$ cat -n file.txt
brush@ubuntu:~/Desktop$ cat << o > file.txt
> fafaafafg
> fajjijja
> o
brush@ubuntu:~/Desktop$ cat -n file.txt1 fafaafafg2 fajjijja
1.3.4、函數:
- 函數用于封裝可復用的邏輯,避免代碼重復,提升腳本可讀性。
# 格式1:帶 function 關鍵字
function hello {echo "Hello, $1" # $1 是第一個參數
}# 格式2:無 function 關鍵字(更簡潔,推薦)
hello() {echo "Hello, $1"
}
- 函數返回值:用 return 數值(僅支持整數,0 表示成功,非 0 表示失敗)
- 局部變量:用 local 變量名(僅在函數內生效,避免污染全局變量)
add() {local a=$1 # 局部變量 alocal b=$2 # 局部變量 blocal sum=$((a + b))echo "兩數之和:$sum" # 打印信息(不是返回值)return $sum # 返回值(僅整數,這里返回 sum 的值)
}add 5 3 # 調用函數
echo "函數返回值:$?" # $? 是上一條命令的返回值 → 輸出:8
- 函數練習
rename_files() {local prefix=$1 # 新文件名前綴local ext=$2 # 文件擴展名local i=1# 遍歷所有 .txt 文件for file in *.txt; domv "$file" "${prefix}_${i}.${ext}"i=$((i + 1))doneecho "重命名完成,共處理 $((i-1)) 個文件"
}rename_files "new_file" "txt" # 調用函數,前綴為 new_file,擴展名 txt
1.4、高級玩法:【只做介紹,后續需要繼續深入】
- 正則表達式
- 信號處理
- 子Shell
- 調試技巧
2、gitee:
2.1、gitee上傳和下載文件的原理概覽:
- gitee與本地電腦進行溝通的四個存儲區域的通俗解釋:
1.工作區:正在改的草稿;
2.暫存區:準備提交的 “候選草稿”;
3.本地倉庫:自己電腦里的 “歷史版本庫”;
4.遠程倉庫:云端的 “共享版本庫”。
- 圖示說明:
- 如果已經有了和遠程倉庫關聯的本地倉庫,就用pull來獲取遠程倉庫的內容,高效便捷;不能再用clone來獲取遠程倉庫內容了,因為這樣做會浪費磁盤空間,可能導致多個本地倉庫副本之間狀態不一樣,給版本管理帶來混亂。
- 注意:只有通過add放到暫存區的文件才會被gitee跟蹤,被跟蹤的文件上傳都會審核,未被跟蹤的文件,gitee操作過程中不會對其進行審核操作。【盡量不要在gitee網頁端上傳文件,這種上傳不會觸發審核機制!】---------==f-a-f=-fafsafafasf
- 注意:Git Bash 本質上是一個模擬 Unix 終端環境的工具(在 Windows 上尤為明顯),它內置了一套類 Linux 的命令集,所以你熟悉的很多 Shell 指令(比如 Linux/macOS 終端里的命令)都能直接用。
- 注意:建立本地倉庫最好建立在磁盤下路徑下,文件路徑中沒有中文。
2.2、遠程倉庫沒有要上傳的項目的倉庫:
- ①、創建本地項目文件夾,在該文件夾下,在 git Bash 中通過 git init 創建本地倉庫
- ②、在本地倉庫中,通過 Git Bash 輸入指令 git add . 【將所有文件夾里修改的文件都加入暫存區】
- ③、在本地倉庫中,通過 Git Bash 輸入 git commit -m “提交說明” 【這一步是把文件存到本地倉庫】
- ④、在Gitee上新建遠程倉庫,填寫倉庫名稱最好和本地文件一樣,記住倉庫地址
- ⑤、在本地倉庫中,通過 Git Bash 輸入 git remote add origin 你的遠程倉庫地址 【將本地倉庫和遠程倉庫綁定】
- ⑥、在本地倉庫中,通過 Git Bash 輸入git push -u origin 遠程分支名稱 【把本地倉庫內容上傳,通過 git branch 查看遠程分支名】
- 注意:版本更新信息會記錄在本地倉庫的 .git 中
2.3、遠程倉庫已有倉庫存放項目,需要從本地拉取遠程倉庫內容并修改:
- ①、在你本地文件夾中,使用 git clone 遠程倉庫地址 【拉取遠程倉庫項目的所有信息,自動創建 .git 存放遠程倉庫項目的所有版本信息】
- ②、在本地倉庫修改代碼
- ③、在本地倉庫中,通過 Git Bash 輸入指令 git add . 【將所有文件夾里修改的文件都加入暫存區】
- ④、在本地倉庫中,通過 Git Bash 輸入 git commit -m “提交說明” 【這一步是把文件存到本地倉庫】
- ⑤、在本地倉庫中,通過 Git Bash 輸入git push【把本地倉庫內容上傳】
- ⑥、如果換了電腦,第一次推送會要求輸入Gitee賬號和密碼,這個賬號就是你的遠程倉庫地址當中的用戶名【例如:git@gitee.com:Bat/test.git 中 Bat 就是用戶名,有時候為了在gitee上為了路徑可用,有可能會有路徑中用戶名和gitee用戶名不一致的情況】,密碼就是你的Gitee密碼
- 注意:如果在本地通過ssh -keygen -t rsa -C “你的郵箱地址” 生成了公鑰,將公鑰(id_rsa.pub)粘貼到Gitee平臺中你的賬號設置當中,以后每次通過ssh的方式輸入遠程倉庫地址,就可以直接上傳,無需再輸入密碼了。
2.4、版本回退的方法:
- git checkout 就像一個 “狀態切換器”—— 可以在不同分支、不同版本、不同文件狀態之間靈活切換,是 Git 管理多版本和多分支的核心工具之一。
- 指令:git log 【可以查看歷史版本】
- 通過:git reset --hard 版本id 【退回某一個版本,注意此時只是本地倉庫退回了某個版本,gitee中的遠程倉庫并沒有回退,如果要回退,就要把本地回退版本重新push】,在本地倉庫版本回退后,如果再往遠程倉庫普通push,可能會出現下面提示:
【出現上面報錯的原因:Git 要求推送前,你的本地分支必須包含遠程分支的所有最新內容(確保 “基于最新版本修改”),否則就會拒絕推送,避免覆蓋遠程的新修改。這是一種保護機制,防止多人協作時出現代碼丟失。解決方案就是通過 git push -f 強制推送,這樣就能確保遠程倉庫也回退到之前版本,當然如果涉及多人開發,就要謹慎使用 -f 命令了,最好先查看最新提交,然后通過 git revert 反向提交,然后通過普通push就可以回退版本了,這樣既回退了內容,又保留了完整歷史,適合多人開發場景。】
git revert 的工作原理:
1、假設提交歷史是這樣的:
A → B → C → D(D 是最新提交)
如果 D 提交有問題,執行 git revert D 后:
Git 會分析 D 提交做了哪些修改(比如新增了某行代碼、刪除了某個文件);
自動創建一個新提交 E,這個提交會 “反向執行 D 的修改”(比如刪除 D 新增的代碼、恢復 D 刪除的文件);
最終歷史變成:A → B → C → D → E,E 的內容和 C 完全一致,但保留了 D 的歷史記錄。
2、git revert HEAD 【撤銷最近一次提交】
3、git revert abc123 # 撤銷 版本id為:abc123 這次提交的修改
4、使用revert后,可能會出現讓你確認 “撤銷操作的說明文字”,按默認內容保存退出即可完成整個 revert 流程;
-
如下總結了強制版本退回的流程:
-
如下總結了revert的操作流程:
先提交一個log.txt文件到遠程倉庫作為一次提交
再執行核心操作 git revert
這里只是本地版本回撤了,最后還要記得,通過git push 提交遠程倉庫,實現遠程倉庫版本回撤,這個時候,就不用加 -f 強制提交了
-
★總結:
- git reset 后面跟要回退到哪個版本
- git revert 后面跟要撤銷哪個版本的提交
2.5、創建分支:
- 創建分支的目的:你正在寫一本小說(主分支,比如叫main),已經寫完了第 5 章。這時候你想嘗試兩種結局:一個是 “圓滿結局”,一個是 “開放式結局”。如果直接在原稿上改,寫了一半想換另一種結局,之前的修改可能就亂了。分支就相當于 “復印一份當前的小說稿”,你可以在復印件上寫 “圓滿結局”(比如叫happy-ending分支),同時在另一份復印件上寫 “開放式結局”(比如叫open-ending分支)。原稿(主分支)保持不變,兩份復印件(新分支)各自修改,互不影響。最后哪個結局好,就把哪個 “合并” 到原稿里 —— 這就是分支的作用:同時嘗試多種修改,互不干擾。
- 創建分支的方法:
- 1、可以在gitee中創建
- 2、可以在本地創建,輸入【git branch 分支名】
- 查看分支:git branch -r 命令可以查看遠程所有分支
- 切換分支的方法:
- 1、可以在gitee中切換
- 2、可以在本地切換,輸入【 git checkout 分支名】
- 總結:建議使用本地創建的方式,這樣本地就能實時掌握遠程倉庫分支的情況,如果是網頁創建的,還需要在本地pull一下才能得知。
2.6、沖突解決的方法:
- gitee中出現沖突的場景:多個人(或你自己在不同分支)改了 “同一份文件的同一個地方”,最后要合并 / 提交時,Git 不知道該留哪版修改,就會出現沖突。具體分為下面兩種情況:
- 1、多人改同一文件:比如你和同事都在 main 分支編輯 “項目說明.md”:同事先改了第 5 行,寫 “項目截止日期是 10 月”,并提交到 Gitee;你沒先拉取同事的修改,自己也改了第 5 行,寫 “項目截止日期是 11 月”,然后想提交到 Gitee;這時候 Git 發現 “同一行有兩個不同的內容”,就會提示 “沖突”,不讓你直接提交。
- 2、自己在不同分支改同一文件:比如你在 dev 分支改了 “登錄頁面.html” 的按鈕顏色為紅色,又在 main 分支改了同一個按鈕顏色為藍色,之后想把 dev 分支合并到 main 分支時,Git 分不清該留紅色還是藍色,也會出現沖突。
- 解決沖突的方法:核心邏輯就是手動告訴 Git “該留哪部分修改”,確定后再重新提交 / 合并。
- 1、先拉取最新內容(確保本地有別人的修改)
- 2、找到沖突文件,手動修改,打開提示沖突的文件,gitee會有標記,刪干凈 <<<<<<<、=======、>>>>>>> 這些標記,只留最終要的內容
- 3、確認修改,重新提交:git add 沖突文件名、git commit -m “解決項目說明.md 的截止日期沖突”(寫個備注,說明改了啥)、git push(把解決完沖突的版本推到 Gitee)。
- 總結:沖突不可怕,本質是 “Git 拿不準該留哪版”,你只要手動確定最終內容,再告訴 Git 就行~