1. 程式人生 > >使用 Git 進行版本控制

使用 Git 進行版本控制

fat 並運行 emp 再次 其他 發生 all extend 需要

使用 Git 進行版本控制

版本控制軟件讓你能夠拍攝處於可行狀態的項目的快照。修改項目(如實現新功能)後,如果項目不能正常運行,可恢復到前一個可行狀態。

通過使用版本控制軟件,你可以無憂無慮地改進項目,不用擔心項目因你犯了錯而遭到破壞。對大型項目來說,這顯得尤其重要,但對於較小的項目,哪怕是只包含

一個文件的程序,這也大有裨益。

在這個附錄中,你將學習如何安裝 Git ,以及如何使用它來對當前開發的程序進行版本控制。 Git 是當前最流行的版本控制軟件,它包含很多高級工具,可幫助團隊協作

開發大型項目,但其最基本的功能也非常適合獨立開發人員使用。 Git 通過跟蹤對項目中每個文件的修改來實現版本控制,如果你犯了錯,只需恢復到保存的前一個狀

態即可。

D.1 安裝 Git

Git 可在所有操作系統上運行,但其安裝方法因操作系統而異。接下來的幾節詳細說明了如何在各種操作系統中安裝它。

D.1.1 在 Linux 系統中安裝 Git

要在 Linux 系統中安裝 Git ,請執行如下命令:

$ sudo apt-get install git

這就成了。你現在可以在項目中使用 Git 了。

D.1.2 在 OS X 系統中安裝 Git

你的 OS X 系統可能已經安裝了 Git ,因此請嘗試執行命令 git --version 。如果你在輸出中看到了具體的版本號,說明你的系統安裝了 Git ;如果你看到一條消息,提示你安裝

或升級 Git ,只需按屏幕上的說明做即可。

你也可以訪問 https://git-scm.com/ ,單擊鏈接 Downloads ,再單擊適合你所用系統的安裝程序。

D.1.3 在 Windows 系統中安裝 Git

要在 Windows 系統中安裝 Git ,請訪問 http://msysgit.github.io/ ,並單擊 Download 。

D.1.4 配置 Git

Git 跟蹤誰修改了項目,哪怕參與項目開發的人只有一個。為此, Git 需要知道你的用戶名和電子郵件地址。你必須提供用戶名,但可以使用虛構的電子郵件地址:

$ git config --global user.name "username"

$ git config --global user.email "[email protected]"

如果你忘記了這一步,在你首次提交時, Git 將提示你提供這些信息。

D.2 創建項目

我們來創建一個要進行版本控制的項目。在你的系統中創建一個文件夾,並將其命名為 git_practice 。在這個文件夾中,創建一個簡單的 Python 程序:

hello_world.py

print("Hello Git world!")我們將使用這個程序來探索 Git 的基本功能。

D.3 忽略文件

擴展名為 .pyc 的文件是根據 .py 文件自動生成的,因此我們無需讓 Git 跟蹤它們。這些文件存儲在目錄 __pycache__ 中。為讓 Git 忽略這個目錄,創建一個名為 .gitignore 的特殊文件(這個

文件名以句點打頭,且沒有擴展名),並在其中添加下面一行內容:

.gitignore

__pycache__/

這讓 Git 忽略目錄 __pycache__ 中的所有文件。使用文件 .gitignore 可避免項目混亂,開發起來更容易。

註意 如果你使用的是 Python 2.7 ,請將這行內容改為 *.pyc 。 Python 2.7 不會創建目錄 __pycache__ ,它將每個 .pyc 文件都存儲在相應 .py 文件所在的目錄中。其中的星

號讓 Git 忽略所有擴展名為 .pyc 的文件。

你可能需要修改文本編輯器的設置,使其顯示隱藏的文件,這樣才能使用它來打開文件 .gitignore 。有些編輯器被設置成忽略名稱以句點打頭的文件。

D.4 初始化倉庫

你創建了一個目錄,其中包含一個 Python 文件和一個 .gitignore 文件,可以初始化一個 Git 倉庫了。為此,打開一個終端窗口,切換到文件夾 git_practice ,並執行如下命令:

git_practice$ git init

Initialized empty Git repository in git_practice/.git/

git_practice$

輸出表明 Git 在 git_practice 中初始化了一個空倉庫。倉庫是程序中被 Git 主動跟蹤的一組文件。 Git 用來管理倉庫的文件都存儲在隱藏的 .git/ 中,你根本不需要與這個目錄打交道,但千

萬不要刪除這個目錄,否則將丟棄項目的所有歷史記錄。

D.5 檢查狀態

執行其他操作前,先來看一下項目的狀態:

git_practice$ git status

# On branch master

#

# Initial commit

#

? # Untracked files:

# (use "git add <file>..." to include in what will be committed)

#

# .gitignore

# hello_world.py

#

? nothing added to commit but untracked files present (use "git add" to track)

git_practice$

?

在 Git 中,分支 是項目的一個版本。從這裏的輸出可知,我們位於分支 master 上(見?)。你每次查看項目的狀態時,輸出都將指出你位於分支 master 上。接下來的輸出表明,我們

將進行初始提交。提交 是項目在特定時間點的快照。

Git 指出了項目中未被跟蹤的文件(見?),因為我們還沒有告訴它要跟蹤哪些文件。接下來,我們被告知沒有將任何東西添加到當前提交中,但我們可能需要將未跟蹤的文件加

入到倉庫中(見?)。

D.6 將文件加入到倉庫中

下面將這兩個文件加入到倉庫中,並再次檢查狀態:

?

?

git_practice$ git add .

git_practice$ git status

# On branch master

#

# Initial commit

#

# Changes to be committed:

# (use "git rm --cached <file>..." to unstage)

#

? #

new file: .gitignore

# new file: hello_world.py

#

git_practice$

命令 git add . 將項目中未被跟蹤的所有文件都加入到倉庫中(見?)。它不提交這些文件,而只是讓 Git 開始關註它們。現在我們檢查項目的狀態時,發現 Git 找出了需要提交

的一些修改(見?)。標簽 new file 意味著這些文件是新添加到倉庫中的(見?)。

D.7 執行提交

下面來執行第一次提交:

?

?

?

git_practice$ git commit -m "Started project."

[master (root-commit) c03d2a3] Started project.

2 files changed, 1 insertion(+)

create mode 100644 .gitignore

create mode 100644 hello_world.py

? git_practice$ git status

# On branch masternothing to commit, working directory clean

git_practice$

我們執行命令 git commit -m " message " (見?)以拍攝項目的快照。標誌 -m 讓 Git 將接下來的消息( "Started project." )記錄到項目的歷史記錄中。輸出表明我

們在分支 master 上(見?),且有兩個文件被修改了(見?)。

現在我們檢查狀態時,發現我們在分支 master 上,且工作目錄是幹凈的(見?)。這是你每次提交項目的可行狀態時都希望看到的消息。如果顯示的消息不是這樣的,請仔細閱

讀,很可能你在提交前忘記了添加文件。

D.8 查看提交歷史

Git 記錄所有的項目提交。下面來看一下提交歷史:

git_practice$ git log

commit a9d74d87f1aa3b8f5b2688cb586eac1a908cfc7f

Author: Eric Matthes <[email protected]>

Date: Mon Mar 16 07:23:32 2015 -0800

Started project.

git_practice$

你每次提交時, Git 都會生成一個包含 40 字符的獨一無二的引用 ID 。它記錄提交是誰執行的、提交的時間以及提交時指定的消息。並非在任何情況下你都需要所有這些信息,因此

Git 提供了一個選項,讓你能夠打印提交歷史條目的更簡單的版本:

git_practice$ git log --pretty=oneline

a9d74d87f1aa3b8f5b2688cb586eac1a908cfc7f Started project.

git_practice$

標誌 --pretty=oneline 指定顯示兩項最重要的信息:提交的引用 ID 以及為提交記錄的消息。

D.9 第二次提交

為展示版本控制的強大威力,我們需要對項目進行修改,並提交所做的修改。為此,我們在 hello_world.py 中再添加一行代碼:

hello_world.py

print("Hello Git world!")

print("Hello everyone.")

如果我們現在查看項目的狀態,將發現 Git 註意到了這個文件發生了變化:

git_practice$ git status

# On branch master

# 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)

#

? #

modified: hello_world.py

#

? no changes added to commit (use "git add" and/or "git commit -a")

git_practice$

?

輸出指出了我們當前所在的分支(見?)、被修改了的文件的名稱(見?),還指出了所做的修改未提交(見?)。下面來提交所做的修改,並再次查看狀態:

?

git_practice$ git commit -am "Extended greeting."

[master 08d4d5e] Extended greeting.

1 file changed, 1 insertion(+)

? git_practice$ git status

# On branch master

nothing to commit, working directory clean

? git_practice$ git log --pretty=oneline

08d4d5e39cb906f6cff197bd48e9ab32203d7ed6 Extended greeting.

be017b7f06d390261dbc64ff593be6803fd2e3a1 Started project.

git_practice$

我們再次執行了提交,並在執行命令 git commit 時指定了標誌 -am (見?)。標誌 -a 讓 Git 將倉庫中所有修改了的文件都加入到當前提交中(如果你在兩次提交之間創建了新

文件,可再次執行命令 git add . 將這些新文件加入到倉庫中)。標誌 -m 讓 Git 在提交歷史中記錄一條消息。

我們查看項目的狀態時,發現工作目錄也是幹凈的(見?)。最後,我們發現提交歷史中包含兩個提交(見?)。

D.10 撤銷修改

下面來看看如何放棄所做的修改,恢復到前一個可行狀態。為此,首先在 hello_world.py 中再添加一行代碼:

hello_world.py

print("Hello Git world!")

print("Hello everyone.")

print("Oh no, I broke the project!")保存並運行這個文件。

我們查看狀態,發現 Git 註意到了所做的修改:

git_practice$ git status

# On branch master

# 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)

#

? #

modified: hello_world.py

#

no changes added to commit (use "git add" and/or "git commit -a")

git_practice$

Git 註意到我們修改了 hello_world.py (見?)。我們可以提交所做的修改,但這次我們不提交所做的修改,而要恢復到最後一個提交(我們知道,那次提交時項目能夠正常地運

行)。為此,我們不對 hello_world.py 執行任何操作 —— 不刪除剛添加的代碼行,也不使用文本編輯器的撤銷功能,而在終端會話中執行如下命令:

git_practice$ git checkout .

git_practice$ git status

# On branch master

nothing to commit, working directory clean

git_practice$

命令 git checkout 讓你能夠恢復到以前的任何提交。命令 git checkout . 放棄自最後一次提交後所做的所有修改,將項目恢復到最後一次提交的狀態。

如果我們返回到文本編輯器,將發現 hello_world.py 被修改成了下面這樣:

print("Hello Git world!")

print("Hello everyone.")

就這個項目而言,恢復到前一個狀態微不足道,但如果我們開發的是大型項目,其中數十個文件都被修改了,那麽恢復到前一個狀態,將撤銷自最後一次提交後對這些文件所做

的所有修改。這個功能很有用:實現新功能時,你可以根據需要做任意數量的修改,如果這些修改不可行,可撤銷它們,而不會對項目有任何傷害。你無需記住做了哪些修改,

因而不必手工撤銷所做的修改, Git 會替你完成所有這些工作。

註意 想要看到以前的版本,你可能需要在編輯器窗口中單擊,以刷新文件。

D.11 檢出以前的提交

你可以檢出提交歷史中的任何提交,而不僅僅是最後一次提交,為此可在命令 git check 末尾指定該提交的引用 ID 的前 6 個字符(而不是句點)。通過檢出以前的提交,你可以

對其進行審核,然後返回到最後一次提交,或者放棄最近所做的工作,並選擇以前的提交:

git_practice$ git log --pretty=oneline

08d4d5e39cb906f6cff197bd48e9ab32203d7ed6 Extended greeting.

be017b7f06d390261dbc64ff593be6803fd2e3a1 Started project.

git_practice$ git checkout be017b

Note: checking out ‘be017b‘.

?

You are in ‘detached HEAD‘ state. You can look around, make experimental

changes and commit them, and you can discard any commits you make in this

state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may

do so (now or later) by using -b with the checkout command again. Example:

git checkout -b new_branch_name

HEAD is now at be017b7... Started project.

git_practice$

檢出以前的提交後,你將離開分支 master ,並進入 Git 所說的分離頭指針( detached HEAD )狀態(見?)。 HEAD 表示項目的當前狀態,之所以說我們處於分離狀態,是因為我們離

開了一個命名分支(這裏是 master )。

要回到分支 master ,可檢出它:

git_practice$ git checkout master

Previous HEAD position was be017b7... Started project.

Switched to branch ‘master‘

git_practice$

這讓你回到分支 master 。除非你要使用 Git 的高級功能,否則在檢出以前的提交後,最好不要對項目做任何修改。然而,如果參與項目開發的人只有你自己,而你又想放棄較近

的所有提交,並恢復到以前的狀態,也可以將項目重置到以前的提交。為此,可在處於分支 master 上的情況下,執行如下命令:

?

git_practice$ git status

# On branch master

nothing to commit, working directory clean

? git_practice$ git log --pretty=oneline

08d4d5e39cb906f6cff197bd48e9ab32203d7ed6 Extended greeting.

be017b7f06d390261dbc64ff593be6803fd2e3a1 Started project.

? git_practice$ git reset --hard be017b

HEAD is now at be017b7 Started project.

? git_practice$ git status

# On branch master

nothing to commit, working directory clean

? git_practice$ git log --pretty=oneline

be017b7f06d390261dbc64ff593be6803fd2e3a1 Started project.

git_practice$我們首先查看了狀態,確認我們在分支 master 上(見?)。查看提交歷史時,我們看到了兩個提交(見?)。接下來,我們執行命令 git reset --hard ,並在其中指定了要

永久地恢復到的提交的引用 ID 的前 6 個字符(見?)。再次查看狀態,發現我們在分支 master 上,且沒有需要提交的修改(見?)。再次查看提交歷史時,發現我們處於要從它

重新開始的提交中(見?)。

D.12 刪除倉庫

有時候,倉庫的歷史記錄被你搞亂了,而你又不知道如何恢復。在這種情況下,你首先應考慮使用附錄 C 介紹的方法尋求幫助。如果無法恢復且參與項目開發的只有你一個人,

可繼續使用這些文件,但要將項目的歷史記錄刪除 —— 刪除目錄 .git 。這不會影響任何文件的當前狀態,而只會刪除所有的提交,因此你將無法檢出項目的其他任何狀態。

為此,可打開一個文件瀏覽器,並將目錄 .git 刪除,也可通過命令行完成這個任務。這樣做後,你需要重新創建一個倉庫,以重新對修改進行跟蹤。下面演示了如何在終端會話中

完成這個過程:

?

git_practice$ git status

# On branch master

nothing to commit, working directory clean

? git_practice$ rm -rf .git

? git_practice$ git status

fatal: Not a git repository (or any of the parent directories): .git

? git_practice$ git init

Initialized empty Git repository in git_practice/.git/

? git_practice$ git status

# On branch master

#

# Initial commit

#

# Untracked files:

# (use "git add <file>..." to include in what will be committed)

#

# .gitignore

# hello_world.py

#

nothing added to commit but untracked files present (use "git add" to track)

? git_practice$ git add .

git_practice$ git commit -m "Starting over."

[master (root-commit) 05f5e01] Starting over.

2 files changed, 2 insertions(+)

create mode 100644 .gitignore

create mode 100644 hello_world.py

? git_practice$ git status

# On branch master

nothing to commit, working directory clean

git_practice$

我們首先查看了狀態,發現工作目錄是幹凈的(見?)。接下來,我們使用命令 rm -rf .git (在 Windows 系統中,應使用命令 rmdir /s .git )刪除了目錄 .git (見?)。

刪除文件夾 .git 後,當我們再次查看狀態時,被告知這不是一個 Git 倉庫(見?)。 Git 用來跟蹤倉庫的信息都存儲在文件夾 .git 中,因此刪除該文件夾也將刪除整個倉庫。

接下來,我們使用命令 git init 新建一個全新的倉庫(見?)。然後,我們查看狀態,發現又回到了初始狀態,等待著第一次提交(見?)。我們將所有文件都加入倉庫,並

執行第一次提交(見?)。然後,我們再次查看狀態,發現我們在分支 master 上,且沒有任何未提交的修改(見?)。

需要經過一定的練習才能學會使用版本控制,但一旦開始使用,你就再也離不開它。

中文字體: Noto Sans CJK SC Regular

英文字體: Liberation Serif

使用 Git 進行版本控制