008 Linux 開發工具(下) —— make、Makefile、git和gdb

🦄 個人主頁: 小米里的大麥-CSDN博客
🎏 所屬專欄: Linux_小米里的大麥的博客-CSDN博客
🎁 GitHub主頁: 小米里的大麥的 GitHub
?? 操作環境: Visual Studio 2022

在這里插入圖片描述

文章目錄

  • Linux 開發工具(下)
    • Linux 項目自動化構建工具 —— `make` / `Makefile`
      • 1. 什么是 `make` 和 `Makefile`?
        • 為什么需要 `make`?
      • 2. `make` 的基本工作原理
        • 基本邏輯
        • 規則格式
      • 3. `make` 的工作流程
      • 4. 偽目標 `.PHONY` 與放置位置的討論
        • 關于 `.PHONY: clean` 的放置位置
      • 5. 常見符號與自動變量的使用
        • `@` —— 命令隱藏符
        • 自動變量 `$^` 與 `$@`
      • 6. 進階技巧(了解)
        • 變量定義與使用
        • 模式規則
      • 傳道解惑
        • ==文件 = 文件內容 + 文件屬性==
    • Linux 下第一個小程序——進度條
      • 1. 換行 vs 回車:鍵盤上的時光機
      • 2. 行緩沖區:快遞員的打包習慣
        • 實驗驗證與現象分析
        • Shell 提示符的輸出行為
        • 為什么覆蓋?
      • 3. 倒計時實現
      • 4. 由于進度條相關文章內容過長,詳見下一篇文章!
    • `git ` 的使用
      • 一、Git 的本質:時間管理大師的 "時光機"
      • 二、Linus Torvalds:被逼出來的創新
      • 三、Git 的革命性突破
      • 四、Git 的現代發展
      • 五、Git 改變了軟件開發的方式
      • 六、`git` 的使用([Git 教程](https://liaoxuefeng.com/books/git/introduction/index.html))
        • Git 的核心概念
        • Git 的工作流程
        • 1. 安裝 Git
        • 2. 配置 Git
        • 3. 創建/初始化倉庫
        • 4. 克隆遠程倉庫
        • 5. 查看倉庫狀態
        • 6. 添加文件到暫存區
        • 7. 提交更改
        • 8. 查看提交歷史
        • 9. 查看遠程倉庫
        • 10. 添加/連接遠程倉庫
        • 11. 推送本地分支到遠程倉庫
        • 12. 拉取遠程倉庫的更新
        • 13. 撤銷工作區的修改
        • 14. 撤銷暫存區的修改
        • 15. 撤銷提交
        • 16. 創建標簽
        • 17. 查看標簽
        • 18. 推送標簽到遠程倉庫
        • 19. 查看差異
        • 20. 查看遠程分支
        • 21. 刪除遠程分支
      • 1. Git 只會記錄已添加到暫存區(staging area)的修改
      • 2. Git 忽略某些文件:`.gitignore`
      • 3. Git 配置文件的管理
    • Linux 調試器 —— `gdb` 的使用
      • 一、背景知識
      • 二、Windows IDE 對應功能
      • 三、`gdb` 常用命令
        • 1. 查看源代碼
        • 2. 運行程序
        • 3. 單步執行
        • 4. 設置斷點
        • 5. 刪除斷點
        • 6. 繼續執行
        • 7. 查看和修改變量
        • 8. 跟蹤變量
        • 9. 查看函數調用棧
        • 10. 查看局部變量
        • 11. 跳轉到指定行
        • 12. 退出函數
    • 共勉

Linux 開發工具(下)

Linux 項目自動化構建工具 —— make / Makefile

1. 什么是 makeMakefile

在大型軟件項目中,源代碼通常散布在多個文件和目錄中。為了高效地管理這些文件之間的依賴關系并實現自動化編譯,Linux 提供了非常強大的工具 —— makemake 是一個自動化構建工具,它通過讀取 Makefile 文件中的規則來決定如何編譯和鏈接程序。Makefile 是一個文本文件,其中定義了項目的依賴關系和構建規則。

為什么需要 make
  • 自動化構建:手動編譯多個源文件并管理它們之間的依賴關系非常繁瑣,make 可以自動化這一過程。
  • 增量編譯make 只會重新編譯那些被修改的文件及其依賴項,從而節省編譯時間。
  • 跨平臺兼容Makefile 可以在不同的平臺上使用,只需稍作修改。

2. make 的基本工作原理

make 的核心功能是根據文件的修改時間自動判斷哪些文件需要重新編譯。具體來說,它會根據文件間的依賴關系,確保只有修改過的部分被重新編譯,避免無謂的重復編譯。

基本邏輯
  • 目標文件與依賴關系
    make 通過比較目標文件與依賴文件的修改時間來決定是否需要重新編譯。如果目標文件不存在,或者依賴文件較新,make 就會重新執行對應的編譯命令。

  • 舉例說明:假設我們有如下的依賴關系:

    • hello 依賴于 hello.o
    • hello.o 依賴于 hello.s
    • hello.s 依賴于 hello.i
    • hello.i 依賴于 hello.c

    hello.c 被修改后,make 會檢查文件的修改時間,并按照依賴關系從 hello.c 開始,逐層更新直到最終目標 hello

規則格式
目標文件:依賴文件命令

例如:

hello: hello.ogcc hello.o -o hello

如果 hello.o 發生了變化,make 會執行 gcc hello.o -o hello 來生成目標文件 hello


3. make 的工作流程

Makefile 中的依賴關系往往構成一個“棧式”結構,即從最終目標開始,逐層向下尋找依賴,直到最初的源文件。

  1. 查找文件make 會在當前目錄下查找名為 Makefilemakefile 的文件。
  2. 確定目標文件:找到文件后,它會查找文件中的第一個目標文件(如示例中的 hello)并將其作為最終的目標文件。
  3. 檢查依賴關系:如果目標文件不存在,或者其依賴文件的修改時間比目標文件更新,則執行相應的命令生成目標文件。
  4. 遞歸處理依賴:如果目標文件的依賴文件(如 hello.o)不存在,則會進一步在當前文件中查找該依賴文件的規則,并依此進行生成。
  5. 完成編譯:按照依賴關系一層一層地處理,直到最終生成第一個目標文件。
  6. 錯誤處理:如果在依賴關系的查找過程中出現錯誤(如最后被依賴的文件找不到),make 會直接退出并報錯;對于命令執行的錯誤或編譯不成功的情況,make 不會進行處理。

例如下面這個 Makefile 片段展示的完整依賴鏈:

# 目標文件 hello 依賴于 hello.o
hello: hello.o# gcc 用于編譯鏈接生成可執行文件 (Executable)gcc hello.o -o hello# 目標文件 hello.o 依賴于 hello.s
hello.o: hello.s# -c 表示只編譯生成目標文件,不進行鏈接gcc -c hello.s -o hello.o# 目標文件 hello.s 依賴于 hello.i
hello.s: hello.i# -S 表示生成匯編代碼 (Assembly code)gcc -S hello.i -o hello.s# 目標文件 hello.i 依賴于 hello.c
hello.i: hello.c# -E 表示只預處理生成中間文件gcc -E hello.c -o hello.i
  • 依賴判斷:當修改了 hello.c 后,hello.i 的時間戳就會落后于 hello.c,從而觸發后續所有目標的重新編譯。
  • 自動化依賴推導make 會根據目標與依賴之間的時間比較,自動“回溯”整個依賴鏈,直到確定哪些文件需要重新生成。

4. 偽目標 .PHONY 與放置位置的討論

定義:偽目標(如 clean)一般用于清理工程中的目標文件,它們沒有被第一個目標文件直接或間接關聯。可以通過命令(如 make clean)顯式執行其后的命令。偽目標的特性是 總是被執行,不會因為文件的存在而被忽略。

例如在 Makefile 中,我們經常會定義一些不對應實際文件的輔助目標,clean 目標通常用于刪除編譯產生的中間文件。為避免與同名文件產生沖突,我們使用 .PHONY 聲明該目標總是需要執行:

.PHONY: clean
clean:@rm -f hello.i hello.s hello.o hello
# 使用 `.PHONY` 聲明后,`make clean` 會始終執行清理命令,即使當前目錄下存在名為 `clean` 的文件。
關于 .PHONY: clean 的放置位置

放在開頭或結尾: 無論將 .PHONY: clean 放在 Makefile 的開頭還是結尾,其功能是相同的,都會告訴 make “clean” 不是一個真實存在的文件。然而,從 代碼可讀性維護性 的角度來看,通常建議將輔助目標(如 clean)放在文件的末尾。這樣做可以:

  • 保持主構建規則的集中:主要的目標和依賴關系放在上面,便于開發者快速了解構建流程。
  • 邏輯分明:清理等輔助目標作為附加功能放在末尾,形成明顯的區分。

5. 常見符號與自動變量的使用

在編寫 Makefile 時,合理使用一些特殊符號和自動變量能使文件更加簡潔與靈活。

@ —— 命令隱藏符

在規則的命令前加上 @ 符號,可以在執行時不將該命令打印到終端。例如:

clean:@rm -f hello.i hello.s hello.o hello
  • 作用:使得執行 make clean 時不會在終端中顯示 rm -f ... 這一行命令,從而使命令輸出更干凈,只顯示必要的信息。
自動變量 $^$@
  • $@:代表規則中的目標文件(Target)。
  • $^:代表規則中所有的依賴文件(Prerequisites),通常用來減少重復輸入依賴文件列表。

示例: 假設有多個依賴文件構成目標文件,我們可以這樣寫:

hello: hello.o util.o# $^ 表示所有依賴,即 "hello.o util.o"(:右邊部分,若有多個,用空格隔開)# $@ 表示目標,即 "hello"(:左邊部分)gcc $^ -o $@

好處:使用自動變量能讓規則更靈活且易于維護,尤其當依賴項較多時,避免重復書寫目標和依賴文件名稱。

6. 進階技巧(了解)

變量定義與使用

Makefile 中,我們可以定義變量來簡化重復的代碼。例如:

CC = gcc
CFLAGS = -Wall -O2myprogram: main.o utils.o$(CC) $^ -o $@main.o: main.c utils.h$(CC) $(CFLAGS) -c main.c -o main.outils.o: utils.c utils.h$(CC) $(CFLAGS) -c utils.c -o utils.o
  • CC:定義編譯器為 gcc
  • CFLAGS:定義編譯選項為 -Wall -O2
模式規則

當項目中有多個相似的文件需要編譯時,可以使用模式規則來簡化 Makefile。例如:

%.o: %.c$(CC) $(CFLAGS) -c $< -o $@
  • %.o:表示所有以 .o 結尾的目標文件。
  • %.c:表示所有以 .c 結尾的源文件。
  • $<:表示第一個依賴文件。

傳道解惑

文件 = 文件內容 + 文件屬性

在計算機系統中,文件不僅僅是包含數據內容的容器,它還具有一些屬性,描述了文件的元數據(metadata)。這些屬性包括文件的權限、修改時間、訪問時間、所有者、大小等。

我們可以將文件的概念表示為:文件 = 文件內容 + 文件屬性

1. 文件內容(File Content)

文件內容是文件實際存儲的數據。對于文本文件,它通常是可讀的字符串;對于二進制文件,它可以是任意的數據,如圖像、音頻、視頻或程序代碼等。文件內容是文件的核心部分,用戶創建、編輯和刪除文件時,主要涉及文件內容的操作。

例如,一個文本文件 hello.txt 的內容可能如下:

Hello, World!

2. 文件屬性(File Attributes)

文件屬性是描述文件元信息的數據,通常是系統自動管理的。這些屬性并不直接涉及文件的內容,但它們在文件的管理、訪問和權限控制中起著至關重要的作用。常見的文件屬性包括:

  • 文件權限(Permissions):指定哪些用戶或用戶組可以讀取、寫入或執行文件。
  • 所有者(Owner):文件的創建者或擁有者。
  • 創建時間(Creation Time):文件首次創建的時間。
  • 修改時間(Modification Time, mtime):文件內容最后一次修改的時間。
  • 訪問時間(Access Time, atime):文件最后一次被訪問的時間(無論是讀取、執行還是其他)。
  • 改變時間(Change Time, ctime):文件的元數據(如權限、所有者、位置)最后一次修改的時間。

3. 文件屬性詳解

  • 修改時間(mtime:修改時間表示文件內容上次修改的時間。每次文件內容改變時,mtime 就會更新。例如,如果你編輯并保存一個文本文件,那么該文件的 mtime 就會更新為當前時間。

  • 訪問時間(atime:訪問時間表示文件上次被訪問的時間。訪問可以是讀取文件內容、執行程序文件等操作。每當文件被讀取時,atime 就會更新。需要注意的是,有些操作系統會進行優化,使得訪問文件時不更新 atime,從而減少磁盤 I/O。例如,使用 cat 命令讀取文件內容會更新 atime

  • 改變時間(ctime:改變時間表示文件的元數據(如文件權限、文件名、所有者等)最后一次改變的時間。ctime 僅在文件的屬性發生變化時更新,而不是文件內容。例如,如果改變了文件的權限或文件的所有者,ctime 會發生變化。

4. 文件操作與屬性變化

  • 修改文件內容: 當我們修改文件內容時,文件的 mtime 會更新,而 atimectime 通常不變,除非文件本身被移動、重命名或修改其他元數據。例如,使用 echo "new content" > file.txt 命令修改 file.txt 文件內容時,文件內容發生了變化,因此 mtime 會更新。

  • 訪問文件: 當我們訪問文件(例如讀取文件內容)時,文件的 atime 會更新,但 mtimectime 不會發生變化。例如,使用 cat file.txt 讀取文件內容時,文件的 atime 會更新,表示文件被訪問了。

  • 修改文件屬性: 當我們修改文件的權限、所有者等屬性時,文件的 ctime 會更新。這個時間是文件元數據的變化標志,而不是文件內容本身的變化。例如,使用 chmod 修改文件權限時,ctime 會更新,但 mtimeatime 不會發生變化。

5. 文件屬性的查看與修改

在 Linux 系統中,可以使用 ls 命令查看文件的基本屬性(如權限、所有者、時間等):

ls -l file.txt

輸出例子:

-rw-r--r-- 1 user user 128 Feb 7 10:15 file.txt

其中:

  • -rw-r--r-- 是文件的權限。
  • 1 是硬鏈接數量。
  • user 是文件的所有者。
  • user 是文件的所屬用戶組。
  • 128 是文件的大小。
  • Feb 7 10:15 是文件的 mtime(修改時間)。

要查看文件的 atimectime,可以使用 stat 命令:

stat file.txt

輸出例子:

File: file.txt
Size: 128       Blocks: 8          IO Block: 4096   regular file
Device: 803h/2051d   Inode: 12345678  Links: 1
Access: 2025-01-01 10:00:00.000000000
Modify: 2025-01-01 10:00:00.000000000
Change: 2025-01-01 10:00:00.000000000
  • Accessatime(訪問時間)
  • Modifymtime(修改時間)
  • Changectime(更改時間)

Linux 下第一個小程序——進度條

1. 換行 vs 回車:鍵盤上的時光機

  • 換行(Line Feed, \n:光標移動到 下一行,但水平位置不變 。在一些系統中,換行符是 \n,也有的系統中(如 Windows)回車和換行會一起使用。
  • 回車(Carriage Return, \r:光標回到 當前行的行首,不換行 。在很多操作系統中,回車是用來將光標重置到行首的位置。換行符通常是 \r

生活場景比喻:想象你用打字機寫文章,打完一行字后需要做兩個動作:

  • 換行(Line Feed):把紙向上推一行(對應 \n
  • 回車(Carriage Return):把打印頭移回最左側(對應 \r

2. 行緩沖區:快遞員的打包習慣

行緩沖區(Line Buffering)是指輸出流的數據并不是直接輸出到屏幕或終端,而是先存儲在緩沖區中。當緩沖區滿時,數據才會被輸出。這種方式提升了效率,減少了對系統資源的頻繁訪問。在 C 語言中,printf() 是行緩沖的典型例子。它的工作原理是:當你調用 printf() 打印一行文本時,數據并不是立刻顯示,而是先被放到緩沖區中,直到遇到換行符 \n 時,系統才會將緩沖區的內容真正輸出到屏幕上。

生活場景比喻:快遞員不會每收到一個小物件就立刻送貨,而是攢滿一車再出發。 行緩沖區 就像這個 “攢滿一車” 的規則:

  • 遇到 \n 換行符時立刻 “送貨”(刷新緩沖區)
  • 緩沖區滿時自動刷新
  • 程序正常結束時也會自動刷新

標準輸出(stdout)在終端中是 行緩沖 的,如果沒有換行符 \n,緩沖區不會自動刷新,導致內容被覆蓋或丟失。

實驗驗證與現象分析
  • 代碼 1

    printf("123456\rAB");
    
    • 現象:只顯示 AB。實測 windowvs 2022 顯示 AB 456 應該是屬于 vs 的“個人行為”。
    • 原因\r 將光標移回行首,但緩沖區未刷新,內容被覆蓋或未輸出。
  • 代碼 2

    printf("123456\rAB\n");
    
    • 現象:終端顯示 AB3456
    • 原因\n 觸發了緩沖區的刷新,AB 覆蓋了 12,然后換行。

  • 代碼 3

    printf("123456\rAB");
    fflush(stdout); // 手動刷新緩沖區
    
    • 現象:終端顯示 AB3456。細節流程:
      • 123456 被輸出到終端,光標停留在 6 后面。
      • \r 將光標移動到行首(即 1 的位置)。
      • AB 被輸出,覆蓋了前兩個字符 12,此時終端內容為 AB3456,光標停留在 3 的位置。
    • 原因fflush(stdout) 強制刷新緩沖區,AB 覆蓋了 12

    為什么我看到的只有 AB

    我們不妨修改代碼,運行后,3 秒內會看到 AB3456,隨后提示符會進行覆蓋,這也就是為什么我們看到的只有 AB 了:

    int main()
    {printf("123456\rAB");fflush(stdout);sleep(3); // 暫停3秒,觀察輸出return 0;
    }
    
Shell 提示符的輸出行為
  • 當程序運行結束后,Shell 會立即在 當前光標位置 輸出提示符(如 [damai@VM-16-11-centos coding]$)。
  • 由于程序結束時,光標停留在 3 的位置,Shell 提示符會從 3 的位置開始輸出,覆蓋 掉后面的內容 3456
為什么覆蓋?
  • 終端的工作機制:終端是一個字符設備,它會嚴格按照光標位置輸出內容。如果光標不在行尾,新輸出的內容會從光標位置開始覆蓋已有的內容。
  • Shell 提示符的輸出:Shell 提示符不會主動換行,而是從當前光標位置開始輸出。因此,如果程序沒有將光標移動到行尾或換行,提示符就會覆蓋程序輸出的內容。

知道了這些內容,我們就可以嘗試看看下面代碼運行的結果了:

#include <stdio.h>
#include <unistd.h>int main()
{// 實驗1:無換行符,無刷新printf("123456\rAB");sleep(2); 			// 等待2秒觀察現象printf("\n"); 		// 換行以刷新緩沖區// 實驗2:有換行符printf("123456\rAB\n");sleep(2); 			// 等待2秒觀察現象// 實驗3:手動刷新printf("123456\rAB");fflush(stdout); 	// 手動刷新sleep(2); 			// 等待2秒觀察現象printf("\n"); 		// 換行return 0;
}

在來一遍,深刻理解

  1. 現象 1:沒有換行符 \n 的情況下調用 printf()

    #include <stdio.h>int main()
    {printf("hello Makefile!");sleep(3);return 0;
    }
    

    現象:這時 “hello Makefile!” 會先存入緩沖區,不會立刻顯示在屏幕上。直到程序結束,緩沖區中的內容才會被顯示出來。所以程序在運行完 sleep(3) 后,才會看到輸出結果。

  2. 現象 2:加上換行符 \n

    #include <stdio.h>int main()
    {printf("hello Makefile!\n");sleep(3);return 0;
    }
    

    現象:這時,換行符 \n 會強制刷新緩沖區,所以 “hello Makefile!” 會立即輸出,等待 3 秒后程序結束。

  3. 現象 3:調用 fflush(stdout) 強制刷新緩沖區:

    #include <stdio.h>
    #include <unistd.h>
    int main()
    {printf("hello Makefile!");fflush(stdout);  // 強制刷新緩沖區sleep(3);return 0;
    }
    

    現象:調用 fflush(stdout) 后,printf() 輸出的內容會立即顯示,無論是否遇到換行符,緩沖區中的內容都會被強制刷新到屏幕上,等待 3 秒后程序結束。


3. 倒計時實現

理解了回車換行和行緩沖區的概念后,我們再來做一個倒計時的實現,相信下面的代碼很容易理解:

int main()
{int cnt = 10;while (cnt >= 0){printf("%d\r", cnt);fflush(stdout);cnt--;sleep(1);}return 0;
}

運行一下,會發現倒計時的顯示效果是:10908070……,而不是預期的 1098 → ……。數字寬度不一致, 當 cnt 為兩位數 10 時,輸出 10;而當 cnt 變為一位數(如 9)時,輸出的是 9。因此,當從兩位數輸出變為一位數輸出時,上一輪輸出中的多余字符(例如 10 中的 1)依然殘留在屏幕上。我們做以下修改即可:

printf("%2d\r", cnt);	// 調整輸出格式:如果 cnt 只有一位數,則會在數字前補空格

再次運行會發現,倒計時站兩個字符,前一個字符空出,只有后一個字符在變化,顯得不太正常,我們接著做修改:

printf("%-2d\r", cnt);	// 修改對其規則:左對齊

于是,我們的倒計時就實現了:

#include <stdio.h>
#include <unistd.h> // 包含 sleep 函數int main()
{int cnt = 10; // 初始化倒計時值while (cnt >= 0) // 循環直到倒計時結束{printf("%-2d\r", cnt); // 格式化輸出,左對齊,固定寬度為2,并覆蓋之前輸出中多余的字符fflush(stdout);        // 強制刷新緩沖區,確保立即輸出cnt--;                 // 倒計時減1sleep(1);              // 暫停1秒}printf("倒計時結束!\n"); // 倒計時完成后輸出提示信息return 0;
}

4. 由于進度條相關文章內容過長,詳見下一篇文章!


git 的使用

這里會簡單敘述 Git 的誕生與核心價值,然而關于 git 遠遠不止于此,需要大量內容才能將 git 講清楚,所以,未來我會專門出一個專題來對 git 進行詳細的講解!

一、Git 的本質:時間管理大師的 “時光機”

要理解 Git,我們可以想象一個科幻場景:假設你正在寫一本小說,每天創作的新章節都會生成一個獨立的時間膠囊。某天你發現主角設定出了問題,只需打開對應日期的膠囊就能恢復原貌。Git 本質上就是這樣一個分布式時光機。它通過記錄文件的 “快照” 而非差異(如 SVN),讓每個開發者電腦都保存完整的版本庫。例如:

  • 張三改實驗報告:李四作為 “版本管家”,每次收到修改都存檔并標注(git commit
  • 多人協作寫代碼:就像樂隊分聲部排練,Git 確保所有樂譜修改能精準合并(git merge

二、Linus Torvalds:被逼出來的創新

Linux 之父林納斯·托瓦茲(Linus Torvalds)與 Git 的淵源,堪稱技術界的 “復仇爽文”:

在 2002 年以前,lucubrate Linux 的龐大社區還處于一種極度原始的代碼管理狀態,依靠著手工合并代碼來維系項目 Progress。這無疑給參與其中的開發者們帶來了巨大的不便與低效,令人不禁聯想起原始部落艱難求生的畫面。

隨后,商業工具 BitKeeper 的引入仿佛曙光初現,為 Linux 內核的代碼管理帶來了短暫的清朗時期。卻不曾想,因社區成員嘗試逆向工程這一敏感行為,(BitKeeper 開發團隊)憤然剝奪了 Linux 社區的使用授權。正如同好不容易借到的寶藏工具突然被奪走,開發者們再度陷入了深深的困境,這無疑是壓垮駱駝的最后一根稻草。

在這一刻,Linus Torvalds,Linux 之父,心中憤怒與不甘的火焰熊熊燃燒。他深知,若不能尋得有效的解決之道,Linux 項目的未來將滿是荊棘。于是,兩周,僅僅兩周的時間,他憑借著過人的智慧與毅力,完成了 Git 原型的編寫。而一個月內,Linux 內核便成功遷移到這個自主開發的全新系統上,整個過程仿若一場奇跡。

" 就像被房東趕走的窘迫之人,在絕望之中親手蓋出了一棟更豪華的別墅。" —— 網友評價

三、Git 的革命性突破

對比傳統版本控制工具,Git 實現了三大飛躍:

特性集中式(如 SVN)Git 分布式
網絡依賴必須聯網提交本地即可完成所有操作
數據安全中央服務器故障即丟失歷史每個副本都是完整備份
分支管理創建/合并分支耗時輕量級分支秒級切換

四、Git 的現代發展

Git 自誕生以來,逐漸在全球范圍內普及并成為開發人員的標準工具之一。以下是 Git 現代發展的幾個關鍵點:

1. GitHub 的崛起

2008 年,GitHub 上線,它為 Git 提供了一個強大的托管平臺,使得開發者可以方便地在線托管代碼,并且與其他開發者協作。GitHub 通過引入 Pull Request(PR)功能,讓 Git 的協作模式更加高效,推動了開源社區的快速發展。很多知名的開源項目(如 jQuery、Node.js 等)都遷移到了 GitHub。

2. 中國化適配:Gitee 等本土平臺

由于 GitHub 在中國大陸訪問受到一定限制,本土平臺如 Gitee 等逐漸興起。Gitee 不僅解決了訪問速度的問題,還提供了針對中國開發者的多種本地化功能,使得 Git 在國內的普及更加順利。

3. 可視化工具的普及

隨著 Git 的普及,越來越多的可視化工具如 GitKraken、SourceTree 等應運而生。這些工具通過圖形界面簡化了 Git 的操作,使得即使是沒有命令行經驗的開發者也能輕松上手。Git 的復雜操作變得更加直觀和易用,降低了學習成本。

4. 版本控制的精確性和回溯功能

Git 的最大優勢之一就是其強大的回溯能力。當開發者說“我回滾一下”,實際上就是“導演喊‘Cut!’重拍第 3 幕”。每個 commit 就像電影中的一個鏡頭,都可以精確回溯、查看和恢復,確保每一步的修改都能被追溯和復原。

五、Git 改變了軟件開發的方式

從 Linus Torvalds 的靈感到 Git 成為全球開發者的標準工具,Git 無疑已經成為軟件開發的核心技術之一。Git 的核心價值不僅僅在于它如何管理版本,更在于它如何改變了開發者的工作方式、提高了協作效率,并且推動了開源軟件的發展。

正如 Linus 所說:“Talk is cheap. Show me the code.” Git 用代碼改變了世界,它的出現不僅僅是一個工具的革命,更是一種工作方式、協作方式和思想方式的革命。Git 的設計思想和實踐,使得開發者能夠更加專注于代碼的創作,而不必過度擔心版本管理的問題。

Git 不僅是一個技術工具,更是一種創新精神的體現——快速響應變化、追求效率、關注團隊協作、并持續優化。它的成功,也象征著開源社區強大的生命力和創新能力。

六、git 的使用(Git 教程)

Git 的核心概念
  1. 倉庫(Repository):Git 倉庫是項目的核心,包含了項目的所有文件和歷史記錄。每個開發者都有一個完整的倉庫副本。
  2. 提交(Commit):每次提交都是項目的一個快照,記錄了文件的更改和提交信息。
  3. 分支(Branch):分支是開發中的獨立線路,允許開發者在不同的分支上并行工作。
  4. 合并(Merge):將不同分支的更改合并到一起,確保代碼的一致性。
  5. 克隆(Clone):從遠程倉庫復制一個完整的倉庫到本地。
  6. 拉取(Pull):從遠程倉庫獲取最新的更改并合并到本地分支。
  7. 推送(Push):將本地的更改上傳到遠程倉庫。
Git 的工作流程
  1. 初始化倉庫:使用 git init 命令創建一個新的 Git 倉庫。
  2. 添加文件:使用 git add 命令將文件添加到暫存區。
  3. 提交更改:使用 git commit 命令將暫存區的更改提交到倉庫。
  4. 創建分支:使用 git branch 命令創建一個新的分支。
  5. 切換分支:使用 git checkout 命令切換到不同的分支。
  6. 合并分支:使用 git merge 命令將不同分支的更改合并到一起。
  7. 查看歷史:使用 git log 命令查看提交歷史。

我們在 Linux CentOS 7 云服務器上使用 Xshell 連接并操作 Git 時的一些常用的 Git 命令:

1. 安裝 Git

首先,確保你的 CentOS 7 系統上已經安裝了 Git。如果沒有安裝,可以使用以下命令進行安裝:

# 更新 yum 軟件包
sudo yum update -y# 安裝 Git
sudo yum install -y git

安裝完成后,可以通過以下命令檢查 Git 版本,確認安裝成功:

git --version
2. 配置 Git

第一次使用 Git 之前,需要配置用戶名和郵箱,這些信息會出現在每次提交的記錄中。

git config --global user.name "your_name"   # 設置用戶名
git config --global user.email "your_email@example.com"  # 設置郵箱

通過以下命令查看當前的 Git 配置:

git config --list
3. 創建/初始化倉庫

在當前目錄下創建一個新的 Git 倉庫,使用以下命令(這會在當前目錄下生成一個 .git 目錄,用于存儲 Git 的版本控制信息):

git init
4. 克隆遠程倉庫

如果想從遠程倉庫克隆一個項目到本地,可以使用 git clone 命令,這會將遠程倉庫的內容克隆到當前目錄下的一個新文件夾中:

git clone https://github.com/username/repository.git
5. 查看倉庫狀態

使用以下命令可以查看當前倉庫的狀態,包括哪些文件被修改、哪些文件被暫存等:

git status
6. 添加文件到暫存區

在對文件進行修改后,需要將文件添加到暫存區(Stage),以便后續提交:

git add file_name	# 例如:git add temp.txt ,添加文件到暫存區

如果想添加所有修改過的文件,可以使用:

git add .
7. 提交更改

將暫存區的文件提交到本地倉庫,-m 選項后面跟的是本次提交的描述信息。描述信息就是提交日志,盡量提交有意義的信息!:

git commit -m "Your commit message"		# 例如:git commit -m "第一次提交" ,提交到本地倉庫
8. 查看提交歷史

使用以下命令可以查看當前倉庫的提交歷史:

git log

還可以通過 --oneline 選項簡化輸出:

git log --oneline
9. 查看遠程倉庫

查看當前配置的遠程倉庫:

git remote -v
10. 添加/連接遠程倉庫

添加/連接一個新的遠程倉庫:

git remote add origin 遠程版本庫的URL
# 例如:git remote add origin https://github.com/your_username/your_repo.git
11. 推送本地分支到遠程倉庫

將本地分支的提交推送到遠程倉庫:

git push origin 分支名稱
git push -u origin master		# 將 master 分支推送,并設置默認上游分支(常用)
12. 拉取遠程倉庫的更新

從遠程倉庫拉取最新的更改并合并到當前分支:

git pull origin 分支名稱
git pull origin master		# 拉取遠程倉庫的最新代碼并合并
13. 撤銷工作區的修改

撤銷工作區中某個文件的修改,恢復到最近一次提交的狀態:

git checkout -- 文件名稱
# 例如:git checkout -- file.txt	丟棄工作區修改,恢復到最后一次提交狀態
14. 撤銷暫存區的修改

將某個文件從暫存區撤回到工作區:

git reset HEAD 文件名稱
15. 撤銷提交

撤銷上一次提交,只回退 commit,保留代碼修改:

git reset --soft HEAD~1

撤銷最近一次提交,并將更改放回工作區:

git reset --soft HEAD^

如果你想撤銷提交并丟棄更改,可以使用:

git reset --hard HEAD^
16. 創建標簽

創建一個新的標簽:

git tag 標簽名稱
17. 查看標簽

查看所有標簽:

git tag
18. 推送標簽到遠程倉庫

將本地標簽推送到遠程倉庫:

git push origin 標簽名稱
19. 查看差異

查看工作區與暫存區的差異:

git diff

查看暫存區與最新提交的差異:

git diff --cached
20. 查看遠程分支

查看遠程倉庫的所有分支:

git branch -r
21. 刪除遠程分支

刪除遠程倉庫的指定分支:

git push origin --delete 分支名稱

至于分支管理、多人協作和沖突管理等操作暫時用不到,放到以后再說,有興趣可自行百度。


除了前面提到的基本操作,Git 在使用時還存在一些常見的注意事項(這里提到部分內容,如有其他問題需勤于百度):

1. Git 只會記錄已添加到暫存區(staging area)的修改

Git 不會自動跟蹤所有修改。它只會跟蹤你手動添加到暫存區的修改,即 默認記錄修改部分(工作區和暫存區)。也就是通過 git add 添加的文件或更改。

  • 工作區(Working Directory):對文件的任何修改都首先體現在工作區。
  • 暫存區(Staging Area):通過 git add 命令將修改暫存到 Git 中的暫存區。
  • 本地倉庫(Repository):通過 git commit 命令,將暫存區的修改提交到本地倉庫。

關鍵點(工作流程): 只有 git add 命令添加到暫存區的文件才會被 git commit 提交(修改文件 → git add 添加到暫存區 → git commit 提交到倉庫)。

示例:

echo "This is a test" > file.txt      # 修改文件
git status                            # 查看狀態,file.txt 會顯示為修改狀態
git add file.txt                      # 添加到暫存區
git commit -m "Updated file.txt"      # 提交修改

忘記 git add 的后果

如果修改了文件但沒有執行 git add,然后直接 git commit,Git 是不會將這些修改提交的。因此,Git 只會記錄已經添加到暫存區的修改。

2. Git 忽略某些文件:.gitignore

如果不希望某些文件被 Git 跟蹤(如編譯出來的二進制文件、IDE 配置文件等),可以使用 .gitignore 文件來指定不需要跟蹤的文件或文件夾。

創建 .gitignore

# 例如,忽略所有 *.log 文件
echo "*.log" >> .gitignore

然后 git add .gitignore 提交 .gitignore 文件!!!

關鍵點: .gitignore 文件是 Git 跟蹤文件的方式之一。

3. Git 配置文件的管理

Git 配置文件分為三種層級:

  • 系統級:影響系統上所有用戶的配置,通常位于 /etc/gitconfig
  • 全局級:影響當前用戶的配置,通常位于 ~/.gitconfig
  • 倉庫級:只對當前倉庫生效,位于倉庫的 .git/config

可以通過以下命令查看和修改 Git 配置:

git config --global user.name "Your Name"     # 設置全局用戶名
git config --global user.email "you@example.com"  # 設置全局郵箱

查看當前配置:

git config --list

Linux 調試器 —— gdb 的使用

一、背景知識

在程序開發過程中,為了有效定位和修復代碼中的錯誤,調試工具起著至關重要的作用。程序的發布方式主要有兩種:debug 模式和 release 模式。

  • debug 模式:此模式下編譯生成的程序包含了豐富的調試信息,例如變量名、函數名、源代碼行號等,方便開發者借助調試工具進行錯誤排查。不過,debug 模式通常會增加程序的體積,并且在一定程度上降低運行效率。
  • release 模式:旨在提供高性能的可執行程序,編譯時會進行各種優化,剔除不必要的調試信息,以確保程序運行速度和資源利用率最大化。在 Linux 系統中,使用 gcc 或 g++ 編譯器編譯出來的二進制程序,默認是 release 模式。

若要使用 gdb(GNU Debugger)對程序進行調試,必須在源代碼生成二進制程序時,加上 -g 選項。這樣,編譯器會在生成的可執行文件中嵌入調試所需的信息,使得 gdb 能夠準確地關聯程序運行狀態與源代碼。

編譯生成調試信息

假設有一個源文件 temp.c-g 告訴編譯器生成調試信息,-o temp 指定輸出文件名。可以通過以下命令編譯程序并生成調試信息:

gcc -g temp.c -o temp

啟動 gdb

gdb 啟動時需要提供一個已經編譯好的二進制文件。假設我們有一個名為 temp 的程序文件,通過以下命令啟動 gdb 準備進行調試:

gdb temp

退出 GDB

退出 GDB 的方式有兩種:

  • 輸入 quitq 命令(常用)。
  • 按下 Ctrl + D

二、Windows IDE 對應功能

對于 Windows 用戶習慣的 IDE 調試工具(如 Visual Studio),gdb 也提供了類似的功能。例如:

  • 設置斷點:在源代碼中設置斷點,并在程序執行時停止。
  • 單步調試:支持單步執行,可以選擇逐行執行代碼,或者進入函數內調試。
  • 變量觀察:支持查看和修改變量的值,并可以在調試過程中動態修改它們。
  • 堆棧跟蹤:查看當前調用棧以及每個函數的參數。

與 Windows 中的 IDE 相比,gdb 是命令行工具,因此需要通過命令行輸入調試命令,但功能是非常強大的。


三、gdb 常用命令

GDB 提示符的作用

  • 當你啟動 GDB 并加載程序后,GDB 會進入交互模式,顯示 (gdb) 提示符。
  • 這個提示符表示 GDB 正在等待你輸入命令。
  • 你只需要在 (gdb) 后面輸入命令,按回車執行。

例如:

(gdb) break main	# (gdb) 是 GDB 的提示符,只需要輸入 break main 并按回車即可
1. 查看源代碼

listl:查看源代碼。

  • list <行號>:從指定行號開始顯示源代碼。
  • list <函數名>:顯示指定函數的源代碼。
  • 默認每次顯示 10 行,按回車鍵繼續顯示后續內容。
(gdb) list 10      # 顯示從第 10 行開始的源代碼
(gdb) list         # 顯示當前行及接下來的 10 行
(gdb) l main       # 顯示 main 函數的源代碼
2. 運行程序

runr:從頭開始運行程序。

  • 如果程序需要參數,可以在 run 后面加上參數:
(gdb) run           	# 啟動程序的執行,不帶任何命令行參數
(gdb) run arg1 arg2   	# 啟動程序的執行,并傳遞兩個命令行參數:arg1 和 arg2
3. 單步執行
  • nextn:單步執行(不進入函數內部)。
  • steps:單步執行(進入函數內部)。
(gdb) next		# 單步執行
(gdb) step		# 進入函數內部
4. 設置斷點

breakb:設置斷點。

  • break <行號>:在指定行設置斷點。
  • break <函數名>:在函數入口處設置斷點。
  • info breakpoints:查看當前設置的所有斷點及其狀態。
(gdb) break 20				# 在第 20 行設置斷點
(gdb) break main			# 在 main 函數的開頭設置斷點
(gdb) info breakpoints    	# 查看所有斷點信息
5. 刪除斷點
  • delete breakpoints:刪除所有斷點。
  • delete breakpoints n:刪除序號為 n 的斷點。
  • disable breakpoints:禁用所有斷點,使其在下次調試時不起作用。
  • enable breakpoints:啟用所有已禁用的斷點。
(gdb) delete breakpoints     # 刪除所有斷點
(gdb) delete breakpoints 1   # 刪除序號為 1 的斷點
(gdb) disable breakpoints    # 禁用所有斷點
(gdb) enable breakpoints     # 啟用所有斷點
6. 繼續執行

continuec:從當前位置繼續執行,直到遇到下一個斷點或程序結束。

(gdb) continue    # 繼續執行程序
7. 查看和修改變量

printp:打印變量的值。

  • print <變量名>:打印變量的值。
  • print <表達式>:計算并打印表達式的值。
(gdb) print x			# 打印變量 x 的值
(gdb) print x + y

set var 變量名=值:修改變量的值。

(gdb) set var x=10    # 將變量 x 的值修改為 10
8. 跟蹤變量
  • display <變量名>:每次程序暫停時,自動打印變量的值。
  • undisplay <編號>:取消對變量的跟蹤。
(gdb) display x     # 每次停止時顯示變量 x 的值
(gdb) undisplay     # 取消所有跟蹤變量
9. 查看函數調用棧

backtracebt:查看當前函數的調用棧(包括參數和調用位置)。

(gdb) backtrace      # 查看函數調用棧
10. 查看局部變量

info locals:查看當前函數的局部變量。

(gdb) info locals	# 查看當前棧幀的局部變量
11. 跳轉到指定行

until <行號>:跳轉到指定行。

(gdb) until 30		# 跳轉到第30行
12. 退出函數

finish:執行完當前函數并暫停。

(gdb) finish	# 執行完當前函數并暫停

共勉

在這里插入圖片描述
在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/88164.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/88164.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/88164.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

前綴和題目:連續的子數組和

文章目錄 題目標題和出處難度題目描述要求示例數據范圍 解法思路和算法代碼復雜度分析 題目 標題和出處 標題&#xff1a;連續的子數組和 出處&#xff1a;523. 連續的子數組和 難度 5 級 題目描述 要求 給定一個整數數組 nums \texttt{nums} nums 和一個整數 k \tex…

隊的簡單介紹

隊列&#xff1a;只允許在一端進行插入數據操作&#xff0c;在另一端進行刪除數據操作的特殊線性表&#xff0c;隊列具有先進先出 FIFO(First In First Out)的特點。 入隊列&#xff1a;進行插入操作的一端稱為隊尾。 出隊列&#xff1a;進行刪除操作的一端稱為隊頭。 入隊列…

AI-Sphere-Butler之如何將豆包桌面版對接到AI全能管家~新玩法(一)

環境&#xff1a; AI-Sphere-Butler VBCABLE2.1.58 Win10專業版 豆包桌面版1.47.4 ubuntu22.04 英偉達4070ti 12G python3.10 問題描述&#xff1a; AI-Sphere-Butler之如何將豆包桌面版對接到AI全能管家~新玩法&#xff08;一&#xff09; 聊天視頻&#xff1a; AI真…

【STM32】啟動流程

1、.s啟動文件解析 STM32的啟動文件&#xff08;一般是.s匯編文件&#xff0c;如startup_stm32f407xx.s&#xff09;是STM32上電后執行的第一段代碼&#xff0c;承擔著“系統初始化化引導員”的角色。 它的主要作用是設置初始化棧指針&#xff08;SP&#xff09;、程序計數器&…

【vim】通過vim編輯器打開、修改、退出配置文件

通過vim編輯器打開任一配置文件 vim /etc/profile 英文輸入下&#xff0c;按i鍵進入INSERT模式&#xff0c;修改配置文件 完成修改后&#xff0c;按esc鍵退出INSERT模式 英文輸入下&#xff0c;輸入":wq!"&#xff0c;即可保存并退出 :q #不保存并退出 :q! …

Effective Modern C++ 條款6:當 auto 推導類型不符合預期時,使用顯式類型初始化慣用法

在C開發中&#xff0c;auto關鍵字以其簡潔性和高效性被廣泛使用。然而&#xff0c;“自動推導”并非萬能&#xff0c;尤其在某些特殊場景下&#xff0c;auto的推導結果可能與開發者預期不符&#xff0c;甚至導致未定義行為。今天&#xff0c;我們以《Effective Modern C》條款6…

學習Linux進程凍結技術

原文&#xff1a;蝸窩科技Linux進程凍結技術 功耗中經常需要用到&#xff0c;但是linux這塊了解甚少&#xff0c;看到這個文章還蠻適合我閱讀的 1 什么是進程凍結 進程凍結技術&#xff08;freezing of tasks&#xff09;是指在系統hibernate或者suspend的時候&#xff0c;將…

GitHub 趨勢日報 (2025年06月22日)

&#x1f4ca; 由 TrendForge 系統生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日報中的項目描述已自動翻譯為中文 &#x1f4c8; 今日獲星趨勢圖 今日獲星趨勢圖 624 LLMs-from-scratch 523 ai-engineering-hub 501 n8n 320 data-engineer-handb…

kotlin中為什么新增擴展函數功能?

在 Kotlin 中&#xff0c;擴展函數的本質是「不修改原有類代碼&#xff0c;為其新增功能」&#xff0c;這源自編程中「開閉原則」&#xff08;對擴展開放&#xff0c;對修改關閉&#xff09;的第一性原理。 核心需求&#xff1a;當需要給第三方庫的類&#xff08;如 Android 的…

excel 數據透視表介紹

Excel 數據透視表(PivotTable)就是你的數據分析神器!它能幫你快速匯總、分類、比較和分析 大量數據&#xff0c;從看似雜亂無章的表格中一鍵提取關鍵信息 &#xff0c;生成交互式的匯總報告。無需復雜公式&#xff0c;只需拖拽幾下&#xff0c;就能讓數據“開口說話”&#xff…

半導體行業中的專用標準產品ASSP是什么?

半導體行業中的專用標準產品ASSP是什么&#xff1f; “專用標準產品”&#xff08;ASSP - Application Specific Standard Product&#xff09;是半導體集成電路中的一個重要分類。 你可以把它理解為介于通用標準產品和全定制ASIC之間的一種芯片。以下是它的核心定義和特點&a…

秋招Day14 - MySQL - 鎖

MySQL中有幾種類型的鎖&#xff1f; 鎖粒度來分&#xff0c;有表鎖、頁鎖和行鎖。 加鎖機制劃分&#xff0c;有樂觀鎖和悲觀鎖。 按兼容性劃分&#xff0c;有共享鎖和排他鎖。 按鎖模式劃分&#xff0c;有記錄鎖&#xff0c;間隙鎖&#xff0c;next-key鎖&#xff0c;意向鎖…

/var/lib/docker/overlay2目錄過大怎么辦

/var/lib/docker/overlay2 是 Docker 默認用于存儲 容器鏡像和容器運行時數據 的核心目錄&#xff0c;基于 overlay2 存儲驅動實現。以下是其具體作用和內容的詳細解析&#xff1a; 1. overlay2 目錄的作用 存儲鏡像分層結構&#xff1a; Docker 鏡像采用分層設計&#xff0c;o…

JimuReport:一款免費的數據可視化報表工具

JimuReport&#xff08;積木報表&#xff09;是一款免費的企業級數據可視化報表軟件&#xff0c;提供拖拽的方式像搭建積木一樣完成在線設計&#xff0c;功能涵蓋數據報表、打印設計、圖表報表、門戶設計、大屏設計等。 數據源 JimuReport 支持 30 多種數據源&#xff0c;包括…

Neo4j.5.X社區版創建數據庫和切換數據庫

在使用Neo4j數據庫&#xff08;版本&#xff1a;neo4j-community-5.22.0&#xff09;時&#xff0c;系統自帶的“neo4j”和“system”數據庫適用于日常的簡單學習和練習&#xff0c;但對于新的項目&#xff0c;將項目數據與練習數據混用會帶來諸多不便&#xff0c;例如查詢效率…

DAY33神經網絡

浙大疏錦行 定義了一個簡單的神經網絡&#xff0c;主要是掌握pytorch框架

拼團系統多層限流架構詳解

拼團系統多層限流架構詳解 一、整體架構設計理念 多層限流采用"層層設防"思想&#xff0c;通過網關層全局流量控制→服務層接口粒度限流→本地資源隔離→熱點參數精準防護的四級防御體系&#xff0c;實現從粗到細的流量治理&#xff0c;確保大促期間系統穩定性。 …

[ctfshow web入門] web92 `==`特性與intval特性

信息收集 和之前的題差不多&#xff0c;這次是使用了不嚴格相等的&#xff0c;詳情看這篇博客&#xff1a; 和 在 PHP 中有何區別&#xff1f;一共包含哪些部分&#xff1f; 首先&#xff0c;不能使$num 4476&#xff0c;然后需要使intval($num,0)4476 include("flag…

在Springboot項目部署時遇到,centos服務器上,curl請求目標地址不通 ,curl -x 可以請求通的解決辦法

在甲方服務器部署項目時&#xff0c;通常遇到需要開通外網權限的問題&#xff0c;有的是直接給開通服務器的白名單&#xff0c;就可以直接訪問白名單外網地址了。也有的是通過網絡轉發&#xff0c;將url前面的部分替換&#xff0c;可以進行網絡請求。有一次遇到一個罕見的&…

Python異步爬蟲編程技巧:從入門到高級實戰指南

Python異步爬蟲編程技巧&#xff1a;從入門到高級實戰指南 &#x1f680; &#x1f4da; 目錄 前言&#xff1a;為什么要學異步爬蟲異步編程基礎概念異步爬蟲核心技術棧入門實戰&#xff1a;第一個異步爬蟲進階技巧&#xff1a;并發控制與資源管理高級實戰&#xff1a;分布式…