Git是用C語言開發的分佈版本號控制系統。版本號控制系統可以保留一個文件集合的歷史記錄,並能回滾文件集合到還有一個狀態(歷史記錄狀態)。還有一個狀態可以是不一樣的文件,也可以是不一樣的文件內容。舉個樣例,你可以將文件集合轉換到兩天以前的狀態,或者你可以在生產代碼和實驗性質的代碼之間進行切換。文件集合每每被稱做是「源碼」。在一個分佈版本號控制系統中,每個人都有一份完整的源碼(包含源碼所有的歷史記錄信息),而且可以對這個本地的數據進行操做。分佈版本號控制系統不需要一個集中式的代碼倉庫。html
當你對本地的源碼進行了改動,你可以標註他們跟下一個版本號相關(將他們加到index中),而後提交到倉庫中來(commit)。Git保存了所有的版本號信息,因此你可以轉換你的源碼到不論什麼的歷史版本號。你可以對本地的倉庫進行代碼的提交,而後與其它的倉庫進行同步。你可以使用Git來進行倉庫的克隆(clone)操做,完整的複製一個已有的倉庫。倉庫的所有者可以經過push操做(推送變動到別處的倉庫)或者Pull操做(從別處的倉庫拉取變動)來同步變動。git
Git支持分支功能(branch)。假設你想開發一個新的產品功能,你可以創建一個分支,對這個分支的進行改動,而不至於會影響到主支上的代碼。github
Git提供了命令行工具;這個教程會使用命令行。你也可以找到圖形工具,譬如與Eclipse配套的EGit工具,但是這些都不會在這個教程中進行描寫敘述。算法
Git 術語
ubuntu
術語 | 定義 |
---|---|
倉庫 | 一個倉庫包含了所有的版本號信息、所有的分支和標記信息. |
Repository | 在Git中倉庫的每份拷貝都是完整的。倉庫讓你可以從中 |
取得你的工做副本。 | |
一個分支意味着一個獨立的、擁有本身歷史信息的代碼線 | |
分支 | (code line)。你可以從已有的代碼中生成一個新的分支 |
Branches | ,這個分支與剩餘的分支全然獨立。默認的分支每每是叫 |
master。用戶可以選擇一個分支,選擇一個分支叫作 | |
checkout. | |
標記 | 一個標記指的是某個分支某個特定時間點的狀態。經過標 |
Tags | 記,可以很是方便的切換到標記時的狀態,好比2009年1月25 |
號在testing分支上的代碼狀態 | |
提交 | 提交代碼後,倉庫會建立一個新的版本號。這個版本號可以在 |
Commit | 興許被又一次得到。每次提交都包含做者和提交者,做者和 |
提交者可以是不一樣的人 | |
URL | URl用來標識一個倉庫的位置 |
用來表示代碼的一個版本號狀態。Git經過用SHA1 hash算法 | |
修訂 | 表示的id來標識不一樣的版本號。每一個 SHA1 id都是160位長 |
Revision | ,16進制標識的字符串.最新的版本號可以經過HEAD來獲取. |
以前的版本號可以經過"HEAD~1"來獲取,以此類推。 |
在Ubuntu上,你可以經過apt來安裝git命令行工具併發
sudo apt-get install git-core
對於其它的Linux版本號,請查看相關的軟件包安裝工具用法。msysgit項目提供了Windows版本號的Git,地址是http://code.google.com/p/msysgit/app
你可以在.gitconfig文件裏防止git的全局配置。文件位於用戶的home文件夾。上述已經提到每次提交都會保存做者和提交者的信息,這些信息都可以保存在全局配置中。興許將會介紹配置用戶信息、高亮顯示和忽略特定的文件。less
經過例如如下命令來配置username和Email
git config --global user.name "Example Surname" git config --global user.email "your.email@gmail.com" # Set default so that all changes are always pushed to the repository git config --global push.default "matching"
獲取Git配置信息,運行下面命令:
git config --list
興許將經過一個典型的Git工做流來學習。在這個過程當中,你會建立一些文件、建立一個本地的Git倉庫、提交你的文件到這個倉庫中。這以後,你會克隆一個倉庫、在倉庫之間經過pull和push操做來交換代碼的改動。凝視(以#開頭)解釋了命令的詳細含義,讓咱們打開命令行開始操做吧。
如下建立一些文件,它們會被放到版本號控制之中
#Switch to home cd ~/ # Create a directory mkdir ~/repo01 # Switch into it cd repo01 # Create a new directory mkdir datafiles # Create a few files touch test01 touch test02 touch test03 touch datafiles/data.txt # Put a little text into the first file ls >test01
每個Git倉庫都是放置在.git文件夾下.這個文件夾包括了倉庫的所有歷史記錄,.git/config文件包括了倉庫的本地配置。
下面將會建立一個Git倉庫,加入�文件倒倉庫的索引中,提交更改。
# Initialize the local Git repository git init # Add all (files and directories) to the Git repository git add . # Make a commit of your file to the local repository git commit -m "Initial commit" # Show the log file git log
經過git diff命令,用戶可以查看更改。經過改變一個文件的內容,看看gitdiff命令輸出什麼,而後提交這個更改到倉庫中
# Make some changes to the file echo "This is a change" > test01 echo "and this is another change" > test02 # Check the changes via the diff command git diff # Commit the changes, -a will commit changes for modified files # but will not add automatically new files git commit -a -m "These are new changes"
如下會向你展現倉庫現有的狀態以及過往的提交歷史
# Make some changes in the file echo "This is a new change" > test01 echo "and this is another new change" > test02 # See the current status of your repository # (which files are changed / new / deleted) git status # Show the differences between the uncommitted files # and the last commit in the current branch git diff # Add the changes to the index and commit git add . && git commit -m "More chaanges - typo in the commit message" # Show the history of commits in the current branch git log # This starts a nice graphical view of the changes gitk --all
經過git amend命令,咱們可以改動最後提交的的信息。上述的提交信息中存在錯誤,如下會改動這個錯誤。
git commit --amend -m "More changes - now correct"
假設你刪除了一個在版本號控制之下的文件,那麼使用git add .不會在索引中刪除這個文件。需要經過帶-a選項的git commit命令和-A選項的git add命令來完畢
# Create a file and put it under version control touch nonsense.txt git add . && git commit -m "a new file has been created" # Remove the file rm nonsense.txt # Try standard way of committing -> will not work git add . && git commit -m "a new file has been created" # Now commit with the -a flag git commit -a -m "File nonsense.txt is now removed" # Alternatively you could add deleted files to the staging index via git add -A . git commit -m "File nonsense.txt is now removed"
咱們將建立一個遠端的Git倉庫。這個倉庫可以存儲在本地或者是網絡上。
遠端Git倉庫和標準的Git倉庫有例如如下區別:一個標準的Git倉庫包含了源碼和歷史信息記錄。咱們可以直接在這個基礎上改動代碼,因爲它已經包含了一個工做副本。但是遠端倉庫沒有包含工做副本,僅僅包含了歷史信息。可以使用–bare選項來建立一個這種倉庫。
爲了方便起見,演示樣例中的倉庫建立在本地文件系統上
# Switch to the first repository cd ~/repo01 # git clone --bare . ../remote-repository.git # Check the content, it is identical to the .git directory in repo01 ls ~/remote-repository.git
作一些更改,而後將這些更改從你的第一個倉庫推送到一個遠端倉庫
cd ~/repo01
echo "Hello, hello. Turn your radio on" > test01echo "Bye, bye. Turn your radio off" > test02
git commit -a -m "Some changes"
git push ../remote-repository.git
除了經過完整的URL來訪問Git倉庫外,還可以經過git remote add命令爲倉庫加入�一個短名稱。當你克隆了一個倉庫之後,origin表示所克隆的原始倉庫。即便咱們從零開始,這個名稱也存在。
# Add ../remote-repository.git with the name origin git remote add origin ../remote-repository.git # Again some changes echo "I added a remote repo" > test02 # Commit git commit -a -m "This is a test for the new remote origin" # If you do not label a repository it will push to origin git push origin
經過下面命令在新的文件夾下建立一個新的倉庫
# Switch to home cd ~ # Make new directory mkdir repo02 # Switch to new directory cd ~/repo02 # Clone git clone ../remote-repository.git .
經過拉取,可以從其它的倉庫中獲取最新的更改。在第二個倉庫中,作一些更改,而後將更改推送到遠端的倉庫中。而後第一個倉庫拉取這些更改
# Switch to home cd ~ # Switch to second directory cd ~/repo02 # Make changes echo "A change" > test01 # Commit git commit -a -m "A change" # Push changes to remote repository # Origin is automatically maintained as we cloned from this repository git push origin # Switch to the first repository and pull in the changes cd ~/repo01 git pull ../remote-repository.git/ # Check the changes less test01
假設在你的工做副本中,你建立了不想被提交的文件,你可以丟棄它。
# Create a new file with content touch test04 echo "this is trash" > test04 # Make a dry-run to see what would happen # -n is the same as --dry-run git clean -n # Now delete git clean -f 你可以提取老版本號的代碼,經過提交的ID。git log命令可以查看提交ID # Switch to home cd ~/repo01 # Get the log git log # Copy one of the older commits and checkout the older revision via 譯者注:checkout 後加commit id就是把commit的內容拷貝到index和工做副本中 git checkout commit_name
假設你還未把更改添�到索引中,你也可以直接還原所有的更改
#Some nonsense change echo "nonsense change" > test01 # Not added to the staging index. Therefore we can # just checkout the old version #譯者注:checkout後假設沒有commit id號,就是從index中拷貝數據到工做副本,不涉及commit部分的改變 git checkout test01 # Check the result cat test01 # Another nonsense change echo "another nonsense change" > test01 # We add the file to the staging index git add test01 # Restore the file in the staging index #譯者注:複製HEAD所指commit的test01文件到index中 git reset HEAD test01 # Get the old version from the staging index #譯者注:複製index中test01到工做副本中 git checkout test01 #譯者注,以上兩條命令可以合併爲git checkout HEAD test01 也可以經過revert命令進行還原操做 # Revert a commit git revert commit_name
即便你刪除了一個未加入�到索引和提交的文件,你也可以還原出這個文件
# Delete a file rm test01 # Revert the deletion git checkout test01
假設你已經加入�一個文件到索引中,但是未提交。可以經過git resetfile 命令將這個文件從索引中刪除
// Create a file touch incorrect.txt // Accidently add it to the index git add . // Remove it from the index git reset incorrect.txt // Delete the file rm incorrect.txt
假設你刪除了目錄且還沒有提交,可以經過下面命令來恢復這個目錄 。譯者注:即便已經提交,也可以還原
git checkout HEAD -- your_dir_to_restore
譯者注:checkout和reset這兩個命令的含義是不一樣的,可以參閱這篇文章http://marklodato.github.com/visual-git-guide/index-en.html
經過分支,可以創造獨立的代碼副本。默認的分支叫master。Git消耗很是少的資源就能建立分支。Git鼓舞開發者多使用分支
如下的命令列出了所有的本地分支,當前所在的分支前帶有*號
git branch
假設你還想看到遠端倉庫的分支,可以使用如下的命令
git branch -a
可以經過如下的命令來建立一個新的分支
# Syntax: git branch <name> <hash> # <hash> in the above is optional # if not specified the last commit will be used # If specified the corresponding commit will be used git branch testing # Switch to your new branch git checkout testing # Some changes echo "Cool new feature in this branch" > test01 git commit -a -m "new feature" # Switch to the master branch git checkout master # Check that the content of test01 is the old one cat test01
經過Merge咱們可以合併兩個不一樣分支的結果。Merge經過所謂的三路合併來完畢。分別來自兩個分支的最新commit和兩個分支的最新公共commit.可以經過例如如下的命令進行合併
# Syntax: git merge <branch-name> git merge testing
一旦合併發生了衝突,Git會標誌出來,開發者需要手工的去解決這些衝突。解決衝突之後,就可以將文件加入�到索引中,而後提交更改
刪除分支的命令例如如下:
#Delete branch testing git branch -d testing # Check if branch has been deleted git branch
默認的,Git僅僅會推送匹配的分支的遠端倉庫。這意味在使用git push命令默認推送你的分支以前,需要手工的推送一次這個分支。
# Push testing branch to remote repository git push origin testing # Switch to the testing branch git checkout testing # Some changes echo "News for you" > test01 git commit -a -m "new feature in branch" # Push all including branch git push
經過這樣的方式,你可以肯定哪些分支對於其它倉庫是可見的,而哪些僅僅是本地的分支
假設兩個不一樣的開發者對同一個文件進行了改動,那麼合併衝突就會發生。而Git沒有智能到本身主動解決合併兩個改動。
在這一節中,咱們會首先製造一個合併衝突,而後解決它,並應用到Git倉庫中。
如下會產生一個合併衝突
# Switch to the first directory cd ~/repo01 # Make changes touch mergeconflict.txt echo "Change in the first repository" > mergeconflict.txt # Stage and commit git add . && git commit -a -m "Will create merge conflict 1" # Switch to the second directory cd ~/repo02 # Make changes touch mergeconflict.txt echo "Change in the second repository" > mergeconflict.txt # Stage and commit git add . && git commit -a -m "Will create merge conflict 2" # Push to the master repository git push # Now try to push from the first directory # Switch to the first directory cd ~/repo01 # Try to push --> you will get an error message git push # Get the changes git pull origin master
Git將衝突放在收到影響的文件裏,文件內容例如如下:
<<<<<<< HEAD Change in the first repository ======= Change in the second repository >>>>>>> b29196692f5ebfd10d8a9ca1911c8b08127c85f8
上面部分是你的本地倉庫,如下部分是遠端倉庫。現在編輯這個文件,而後commit更改。另外的,你可以使用git mergetool命令
# Either edit the file manually or use git mergetool # You will be prompted to select which merge tool you want to use # For example on Ubuntu you can use the tool "meld" # After merging the changes manually, commit them git commit -m "merged changes"
經過rebase命令可以合併多個commit爲一個。這樣用戶push更改到遠端倉庫的時候就可以先改動commit歷史
接下來咱們將建立多個commit,而後再將它們rebase成一個commit
# Create a new file touch rebase.txt # Add it to git git add . && git commit -m "rebase.txt added to index" # Do some silly changes and commit echo "content" >> rebase.txt git add . && git commit -m "added content" echo " more content" >> rebase.txt git add . && git commit -m "added more content" echo " more content" >> rebase.txt git add . && git commit -m "added more content" echo " more content" >> rebase.txt git add . && git commit -m "added more content" echo " more content" >> rebase.txt git add . && git commit -m "added more content" echo " more content" >> rebase.txt git add . && git commit -m "added more content" # Check the git log message git log
咱們合併最後的七個commit。你可以經過例如如下的命令交互的完畢
git rebase -i HEAD~7
這個命令會打開編輯器讓你改動commit的信息或者 squash/ fixup最後一個信息.Squash會合並commit信息而fixup會忽略commit信息(待理解)
你也可以對兩個分支進行rebase操做。例如如下所述,merge命令合併兩個分支的更改。rebase命令爲一個分支的更改生成一個補丁,而後應用這個補丁到還有一分支中
使用merge和rebase,最後的源碼是同樣的,但是使用rebase產生的commit歷史更加的少,而且歷史記錄看上去更加的線性
# Create new branch git branch testing # Checkout the branch git checkout testing # Make some changes echo "This will be rebased to master" > test01 # Commit into testing branch git commit -a -m "New feature in branch" # Rebase the master git rebase master
在push更改到其它的Git倉庫以前,咱們需要細緻檢查本地分支的commit歷史
在Git中,你可以使用本地的commit。開發者可以利用這個功能方便的回滾本地的開發歷史。但是在push以前,需要觀察你的本地分支歷史,是否當中有些commit歷史對其它用戶來講是無關的
假設所有的commit歷史都跟同一個功能有關,很是多狀況下,你需要rebase這些commit歷史爲一個commit歷史。
交互性的rebase主要就是作重寫commit歷史的任務。這樣作是安全的,因爲commit尚未被push到其餘的倉庫。這意味着commit歷史僅僅有在被push以前被改動。
假設你改動而後push了一個已經在目標倉庫中存在的commit歷史,這看起來就像是你實現了一些別人已經實現的功能
一個補丁指的是一個包括對源碼進行改動的文本文件。你可以將這個文件發送給某人,而後他就可以應用這個補丁到他的本地倉庫。
如下會建立一個分支,對這個分支所一些改動,而後建立一個補丁,並應用這個補丁到master分支
# Create a new branch git branch mybranch # Use this new branch git checkout mybranch # Make some changes touch test05 # Change some content in an existing file echo "New content for test01" >test01 # Commit this to the branch git add . git commit -a -m "First commit in the branch" # Create a patch --> git format-patch master git format-patch origin/master # This created patch 0001-First-commit-in-the-branch.patch # Switch to the master git checkout master # Apply the patch git apply 0001-First-commit-in-the-branch.patch # Do your normal commit in the master git add . git commit -a -m "Applied patch" # Delete the patch rm 0001-First-commit-in-the-branch.patch
Git贊成你設定你本身的Git命令。你可以給你本身常用的命令起一個縮寫命令,或者合併幾條命令道一個命令上來。
如下的樣例中,定義了git add-commit 命令,這個命令合併了git add . -A 和git commit -m 命令。定義這個命令後,就可以使用git add-commit -m"message" 了.
git config --global alias.add-commit '!git add . -A && git commit'
但是很不幸,截止寫這篇文章以前,定義同名命令在msysGit中尚未支持。同名命令不能以!開始。
有時候,你不但願某些文件或者目錄被包括在Git倉庫中。但是假設你把它們加到.gitignore文件裏之後,Git會中止跟蹤這個文件。但是它不會將這個文件從倉庫中刪除。這致使了文件或者目錄的最後一個版本號仍是存在於倉庫中。爲了取消跟蹤這些文件或者目錄,你可以使用例如如下的命令
# Remove directory .metadata from git repo git rm -r --cached .metadata # Remove file test.txt from repo git rm --cached test.txt
這樣作不會將這些文件從commit歷史中去掉。假設你想將這些文件從commit歷史中去掉,可以參考git filter-branch命令
如下列出了在平常工做中很實用的Git命令
實用的Git命令
命令 | 描寫敘述 |
---|---|
git blame filename | 誰建立了或者是改動了這個文件 |
git checkout -b mybranch | 以上上個commit信息爲起點,建立一條 |
master~1 | 新的分支 |
如上所述,咱們的操做不需要Git服務。我可以僅僅使用文件系統或者是Git倉庫的提供者,像Github或Bitbucket。但是,有時候,擁有一個本身的服務是比較方便的,在ubuntu下安裝一個服務相對來講是比較easy的
肯定你已經安裝了ssh
apt-get install ssh
假設你尚未安裝Git服務,安裝它
sudo apt-get install git-core
加入�一個名爲git的用戶
sudo adduser git
而後使用git用戶進行登錄,建立一個空的倉庫
# Login to server # to test use localhost ssh git@IP_ADDRESS_OF_SERVER # Create repository git init --bare example.git
現在你就可以向遠端的倉庫提交變動了
mkdir gitexample cd gitexample git init touch README git add README git commit -m 'first commit' git remote add origin git@IP_ADDRESS_OF_SERVER:example.git git push origin master
Git支持遠端的操做。Git支持多種的傳輸類型,Git自帶的協議就叫作git。如下的的命令經過git協議從克隆一個倉庫
git clone git@github.com:vogella/gitbook.git
相同的,你可以經過http協議來克隆倉庫
# The following will clone via HTTP git clone http://vogella@github.com/vogella/gitbook.git
假設你克隆了一個遠端倉庫,那麼原先的倉庫就叫作origin
你可以push改動到origin中,經過 git push origin 命令. 固然,push到一個遠端的倉庫需要對倉庫的寫權限
你可以經過git remote add name gitrepo 命令加入�多個倉庫。好比,你可以經過http協議再次加入�以前clone過來的倉庫:
// Add the https protocol git remote add githttp https://vogella@github.com/vogella/gitbook.git
假設你的防火牆屏蔽了出http之外的所有協議,那麼使用http協議來獲取倉庫是很好的方法。.
Git相同支持經過代理server使用http協議。如下的Git命令會展現這一點。你可以爲所有的程序設置代理server或者僅僅是爲Git服務提供。
如下的樣例用到了環境變量
# Linux export http_proxy=http://proxy:8080 # On Windows # Set http_proxy=http://proxy:8080 git clone http://dev.eclipse.org/git/org.eclipse.jface/org.eclipse.jface.snippets.git # Push back to the origin using http git push origin
如下的樣例僅僅是用到了Git的配置
// Set proxy for git globally git config --global http.proxy http://proxy:8080 // To check the proxy settings git config --get http.proxy // Just in case you need to you can also revoke the proxy settings git config --global --unset http.proxy
除了若是本身的服務,你也可以使用Git服務提供商提供的服務。最流行的Git服務提供站點是GitHub和Bitbucket。它們都提供了有限制的免費服務
可以經過 https://github.com/ 訪問GitHub. GitHub上所有的公開倉庫都是免費的。假設你想在上面使用私有的倉庫,那麼就需要付費給GitHub
GitHub需要你建立ssh的公鑰私鑰。生成一份Ubuntu的公鑰私鑰可以訪問 sshkey creation in Ubuntu ,Windows環境可以訪問msysgit ssh key generation.
在GitHub上建立一個帳戶和一個倉庫之後。你會收到怎樣將你的項目上傳到GitHUb的指南,當中的命令大體例如如下:
Global setup: Set up git git config --global user.name "Your Name" git config --global user.email your.email@gmail.com Next steps: mkdir gitbook cd gitbook git init touch README git add README git commit -m 'first commit' git remote add origin git@github.com:vogella/gitbook.git git push -u origin master Existing Git Repo? cd existing_git_repo git remote add origin git@github.com:vogella/gitbook.git git push -u origin master
可以經過 https://bitbucket.org/ 訪問Bitbucket. Bitbucket 提供了無限制了公共倉庫和僅僅能有五我的訪問的私有倉庫。假設你需要超過五我的訪問私有倉庫,就需要付費給Bitbucket
這個教程主要說明Git命令行的使用。完畢了這個教程之後,你可能想要找到一個Git的圖形工具
Git提供了兩個圖形工具。 gitk能夠展現倉庫的歷史信息、git gui 讓你能夠經過編輯器來完畢Git操做
Eclipse EGit 項目提供了Git與Eclipse的集成,在最新的Eclipse版本號中可以找到
在提出問題以前,請先查看 vogella FAQ. 假設你有不論什麼的問題或者是從文章中找到錯誤,那麼可以使用www.vogella.com Google Group. 我本身寫了一個簡短的列表 how to create good questions 可能會對你實用.
Git homepage
EGit - Teamprovider for Eclipse
Video with Linus Torwalds on Git
Progit book - Free Git book
Video casts about Git
http://code.google.com/p/msysgit/ Git on Windows
http://github.com/guides/git-cheat-sheet Git Cheat Sheets
Date: 2012-08-26 日
HTML generated by org-mode 6.33x in emacs 23