使用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的特殊文件(這個文件名以句點打頭,且沒有擴展名),並在其中添加下面一行內容:
__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 master
nothing 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 上,且沒有任何未提交的修改(見❼)。
需要經過一定的練習才能學會使用版本控制,但一旦開始使用,你就再也離不開它。

發佈了51 篇原創文章 · 獲贊 21 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章