Git-由淺入深-小白教程

Git簡介

Git是目前世界上最先進的分佈式版本控制系統(沒有之一)。

基本操作

  1. 創建空目錄
$ mkdir learngit	//創建空目錄,儘量選擇無中文路徑創建
$ cd learngit		//選擇目錄
$ pwd				//顯示目錄路徑
/Users/michael/learngit	
  1. 將目錄變爲Git倉庫
$ git init			//初始化目錄爲Git管理倉庫
Initialized empty Git repository in /Users/michael/learngit/.git/

初始化後會多了一個.git的目錄,這個目錄是Git來跟蹤管理版本庫的,沒事千萬不要手動修改這個目錄裏面的文件,不然改亂了,就把Git倉庫給破壞了。

  1. 添加
$ git add readme.txt	//把文件添加到倉庫,可添加多個文件,或同時添加多個文件,空格隔開
  1. 提交
$ git commit -m "wrote a readme file"	//把之前add的文件都提交到倉庫,-m 後面是說明
[master (root-commit) eaadf4e] wrote a readme file
 1 file changed, 2 insertions(+)  //1 file changed:1個文件被改動;2 insertions:插入了兩行內容
 create mode 100644 readme.txt
  1. 提交日誌
$ git log			//添加 --pretty=oneline 參數查看簡潔版
commit 1094adb7b9b3807259d8cb349e7df1d4d6477073 (HEAD -> master)	//commit id(版本號),HEAD :當前版本,
Author: Michael Liao <[email protected]>
Date:   Fri May 18 21:06:15 2018 +0800

    append GPL				//說明

commit e475afc93c209a690c39c13a46716e8fa000c366
Author: Michael Liao <[email protected]>
Date:   Fri May 18 21:03:36 2018 +0800

    add distributed

commit eaadf4e385e865d25c48e7ca9c8395c3f7dfaef0
Author: Michael Liao <[email protected]>
Date:   Fri May 18 20:59:18 2018 +0800

    wrote a readme file	
  1. 版本回退
$ git reset --hard HEAD^	//HEAD^:上一個版本,HEAD^^:上上一個版本,HEAD~100:往上一百個版本
HEAD is now at e475afc add distributed
  1. 版本還原回退
$ git reset --hard 1094a	//還原版本版本號部分
HEAD is now at 83b0afe append GPL
  1. 操作日誌
$ git reflog		//記錄所有操作及輸出
e475afc HEAD@{1}: reset: moving to HEAD^
1094adb (HEAD -> master) HEAD@{2}: commit: append GPL
e475afc HEAD@{3}: commit: add distributed
eaadf4e HEAD@{4}: commit (initial): wrote a readme file
  1. 查看當前狀態
$ 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:   readme.txt

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

	LICENSE

no changes added to commit (use "git add" and/or "git commit -a")
  1. 修改撤銷
1.
$ git checkout -- readme.txt	//就是讓這個文件回到最近一次git commit或git add前的狀態。
2.
$ git reset HEAD readme.txt		//git reset命令既可以回退版本,也可以把暫存區的修改回退到工作區。當我們用HEAD時,表示最新的版本。
Unstaged changes after reset:
M	readme.txt
  1. 刪除和還原
$ rm test.txt	//刪除文件

$ git rm test.txt	//從版本庫中刪除該文件,那就用命令git rm刪掉,並且git commit
rm 'test.txt'
$ git commit -m "remove test.txt"
[master d46f35e] remove test.txt
 1 file changed, 1 deletion(-)
 delete mode 100644 test.txt

$ git checkout -- test.txt	//git checkout其實是用版本庫裏的版本替換工作區的版本,無論工作區是修改還是刪除,都可以“一鍵還原”。

遠程倉庫

  1. 創建SSH Key
$ ssh-keygen -t rsa -C "[email protected]"		//打開Shell(Windows下打開Git Bash),創建SSH Key,你需要把郵件地址換成你自己的郵件地址,然後一路回車

如果一切順利的話,可以在用戶主目錄裏找到.ssh目錄,裏面有id_rsa和id_rsa.pub兩個文件,這兩個就是SSH
Key的祕鑰對,id_rsa是私鑰,不能泄露出去,id_rsa.pub是公鑰,可以放心地告訴任何人。

  1. 在GitHub上添加自己電腦上的公鑰

登錄GitHub,打開設置,找到 SSH and GPG Keys,點擊 New SSH Key
Title隨意填寫,在key中粘貼公鑰,最後點擊Add Key,就ok了

  1. 遠程庫
  • 關聯遠程庫
$ git remote add origin [email protected]:michaelliao/learngit.git	//關聯遠程庫,遠程庫的名字就是origin,這是Git默認的叫法

把本地庫的內容推送到遠程,用git push命令,實際上是把當前分支master推送到遠程。
由於遠程庫是空的,我們第一次推送master分支時,加上了-u參數,Git不但會把本地的master分支內容推送的遠程新的master分支,還會把本地的master分支和遠程的master分支關聯起來,在以後的推送或者拉取時就可以簡化命令。

  • 推送同步遠程庫
$ git push -u origin master		//把本地庫的所有內容推送到遠程庫上
Counting objects: 20, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (15/15), done.
Writing objects: 100% (20/20), 1.64 KiB | 560.00 KiB/s, done.
Total 20 (delta 5), reused 0 (delta 0)
remote: Resolving deltas: 100% (5/5), done.
To github.com:michaelliao/learngit.git
 * [new branch]      master -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.

由於遠程庫是空的,我們第一次推送master分支時,加上了-u參數,Git不但會把本地的master分支內容推送的遠程新的master分支,還會把本地的master分支和遠程的master分支關聯起來,在以後的推送或者拉取時就可以簡化命令。

  • 提交遠程庫
$ git push origin master	//把本地master分支的最新修改推送至GitHub
  • 克隆遠程庫
$ git clone [email protected]:michaelliao/gitskills.git	//克隆遠程庫至本地
Cloning into 'gitskills'...
remote: Counting objects: 3, done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 3
Receiving objects: 100% (3/3), done.

創建遠程庫時勾選Initialize this repository with a README,這樣GitHub會自動爲我們創建一個README.md文件。創建完畢後,可以看到README.md文件

分支管理

分支相當於不同的時間線,互不影響

創建與合併分支

  • 查看分支:git branch

  • 創建分支:git branch <name>

  • 切換分支:git checkout <name>或者git switch <name>

  • 創建+切換分支:git checkout -b <name>或者git switch -c <name>

  • 合併某分支到當前分支:git merge <name>

  • 刪除分支:git branch -d <name>

解決衝突

當兩個分支編輯同一處內容併合並時產生衝突

$ git merge feature1		//合併產生衝突
Auto-merging readme.txt
CONFLICT (content): Merge conflict in readme.txt
Automatic merge failed; fix conflicts and then commit the result.
$ git cat					//查看內容可看到衝突部分
Git is a distributed version control system.
Git is free software distributed under the GPL.
Git has a mutable index called stage.
Git tracks changes of files.
<<<<<<< HEAD
Creating a new branch is quick & simple.
=======
Creating a new branch is quick AND simple.

>>>>>>> feature1
  • 查看分支合併情況:$ git log --graph --pretty=oneline --abbrev-commit

用git log --graph命令可以看到分支合併圖。

分支管理策略

  • 合併分支(Fast forward ):$ git merge --no-ff -m "merge with no-ff" dev

強制禁用Fast forward模式,Git就會在merge時生成一個新的commit,保留原分支信息這樣,從分支歷史上就可以看出分支信息

  • 分支策略

在實際開發中,我們應該按照幾個基本原則進行分支管理:
首先,master分支應該是非常穩定的,也就是僅用來發布新版本,平時不能在上面幹活;
那在哪幹活呢?幹活都在dev分支上,也就是說,dev分支是不穩定的,到某個時候,比如1.0版本發佈時,再把dev分支合併到master上,在master分支發佈1.0版本;
你和你的小夥伴們每個人都在dev分支上幹活,每個人都有自己的分支,時不時地往dev分支上合併就可以了。
所以,團隊合作的分支看起來就像這樣:
分支策略圖

Bug分支

軟件開發中,bug就像家常便飯一樣。有了bug就需要修復,在Git中,由於分支是如此的強大,所以,每個bug都可以通過一個新的臨時分支來修復,修復後,合併分支,然後將臨時分支刪除。
當你接到一個修復一個代號101的bug的任務時,很自然地,你想創建一個分支issue-101來修復它,但是,等等,當前正在dev上進行的工作還沒有提交,如果此時切換分支,最後提交的時候再暫存區的修改將一併被提交。

  • 保存分支狀態:$ git stash
  • 查看保存分支狀態列表:$ git stash list
  • 恢復分支狀態:$ git stash apply
  • 刪除分支狀態:$ git stash drop
  • 恢復並刪除分支狀態:$ git stash pop
  • 恢復指定狀態:$ git stash apply stash@{0}
  • 複製其他分支提交:$ git cherry-pick 4c805e2

先複製提交 再 恢復

Feature分支

  • 強制刪除未合併分支:$ git branch -D feature-vulcan

多人協作

當你從遠程倉庫克隆時,實際上Git自動把本地的master分支和遠程的master分支對應起來了,並且,遠程倉庫的默認名稱是origin

  • 查看遠程庫信息:$ git remote
  • 查看詳細遠程庫信息:$ git remote -v

上面顯示了可以抓取和推送的origin的地址。如果沒有推送權限,就看不到push的地址。

  • 推送對應分支到遠程庫:$ git push origin master

但是,並不是一定要把本地分支往遠程推送,那麼,哪些分支需要推送,哪些不需要呢?

  • master分支是主分支,因此要時刻與遠程同步;
  • dev分支是開發分支,團隊所有成員都需要在上面工作,所以也需要與遠程同步;
  • bug分支只用於在本地修復bug,就沒必要推到遠程了,除非老闆要看看你每週到底修復了幾個bug;
  • feature分支是否推到遠程,取決於你是否和你的小夥伴合作在上面開發。

總之,就是在Git中,分支完全可以在本地自己藏着玩,是否推送,視你的心情而定!

  • 創建遠程分支到本地:$ git checkout -b dev origin/dev

當你的小夥伴從遠程庫clone時,默認情況下,你的小夥伴只能看到本地的master分支,需要別的分支還要遠程創建。

  • 連接分支:$ git branch --set-upstream-to=origin/dev dev
  • 抓取分支:$ git pull

相當於遠程分支與當前分支合併,抓取後能通過 $ git cat 查看修改修改內容
抓取分支前必須先連接遠程分支,才能識別要抓取的分支。

Rebase

分支太多容易出現混亂現象

$ git log --graph --pretty=oneline --abbrev-commit
* d1be385 (HEAD -> master, origin/master) init hello
*   e5e69f1 Merge branch 'dev'
|\  
| *   57c53ab (origin/dev, dev) fix env conflict
| |\  
| | * 7a5e5dd add env
| * | 7bd91f1 add new env
| |/  
* |   12a631b merged bug fix 101
|\ \  
| * | 4c805e2 fix bug 101
|/ /  
* |   e1e9c68 merge with no-ff
|\ \  
| |/  
| * f52c633 add merge
|/  
*   cf810e4 conflict fixed

Git有一種稱爲rebase的操作,有人把它翻譯成“變基”。

看不懂不寫了!

標籤管理

在Git中打標籤非常簡單,標籤可以是版本例如 V1.0,類似每次提交的 -m"sdsfdsf" 提交說明,因爲標籤也是基於提交的。

創建標籤

如果是分支上打標籤,默認標籤是打在最新提交的commit上的,也可以單獨給某個版本打標籤,找到commit id 就行

  • 分支上打標籤:$ git tag v1.0
  • 版本上打標籤:$ git tag v0.9 f52c633
  • 查看標籤:$ git tag
  • 查看標籤信息:$ git show v0.9
  • 創建標籤並附上說明:$ git tag -a v0.1 -m "version 0.1 released" 1094adb

注意:標籤總是和某個commit掛鉤。如果這個commit既出現在master分支,又出現在dev分支,那麼在這兩個分支上都可以看到這個標籤。

操作標籤

  • 刪除標籤:$ git tag -d v0.1

因爲創建的標籤都只存儲在本地,不會自動推送到遠程。所以,打錯的標籤可以在本地安全刪除。

  • 推送標籤到遠程:$ git push origin v1.0
  • 一次性推送全部:$ git push origin --tags
  • 遠程刪除標籤:$ git push origin :refs/tags/v0.9

使用GitHub

我們一直用GitHub作爲免費的遠程倉庫,如果是個人的開源項目,放到GitHub上是完全沒有問題的。其實GitHub還是一個開源協作社區,通過GitHub,既可以讓別人參與你的開源項目,也可以參與別人的開源項目。

如何參與一個開源項目呢?比如人氣極高的bootstrap項目,這是一個非常強大的CSS框架,你可以訪問它的項目主頁https://github.com/twbs/bootstrap,點“Fork”就在自己的賬號下克隆了一個bootstrap倉庫,然後,從自己的賬號下clone:git clone [email protected]:michaelliao/bootstrap.git

一定要從自己的賬號下clone倉庫,這樣你才能推送修改。如果從bootstrap的作者的倉庫地址[email protected]:twbs/bootstrap.git克隆,因爲沒有權限,你將不能推送修改。
Bootstrap的官方倉庫twbs/bootstrap、你在GitHub上克隆的倉庫my/bootstrap,以及你自己克隆到本地電腦的倉庫,他們的關係就像下圖顯示的那樣:

┌─ GitHub ────────────────────────────────────┐
│                                             │
│ ┌─────────────────┐     ┌─────────────────┐ │
│ │ twbs/bootstrap  │────>│  my/bootstrap   │ │
│ └─────────────────┘     └─────────────────┘ │
│                                  ▲          │
└──────────────────────────────────┼──────────┘
                                   ▼
                          ┌─────────────────┐
                          │ local/bootstrap │
                          └─────────────────┘

如果你想修復bootstrap的一個bug,或者新增一個功能,立刻就可以開始幹活,幹完後,往自己的倉庫推送。
如果你希望bootstrap的官方庫能接受你的修改,你就可以在GitHub上發起一個pull request。當然,對方是否接受你的pull request就不一定了。

使用碼雲

  • 碼雲

使用GitHub時,國內的用戶經常遇到的問題是訪問速度太慢,有時候還會出現無法連接的情況(原因你懂的)。
如果我們希望體驗Git飛一般的速度,可以使用國內的Git託管服務——碼雲(gitee.com)。
和GitHub相比,碼雲也提供免費的Git倉庫。此外,還集成了代碼質量檢測、項目演示等功能。對於團隊協作開發,碼雲還提供了項目管理、代碼託管、文檔管理的服務,5人以下小團隊免費

  • 使用碼雲

使用碼雲和使用GitHub類似,我們在碼雲上註冊賬號並登錄後,需要先上傳自己的SSH公鑰。選擇右上角用戶頭像 -> 菜單“修改資料”,然後選擇“SSH公鑰”,填寫一個便於識別的標題,然後把用戶主目錄下的.ssh/id_rsa.pub文件的內容粘貼進去

  • 關聯碼雲遠程庫:git remote add origin [email protected]:liaoxuefeng/learngit.git

如果在使用命令git remote add時報錯,這說明本地庫已經關聯了一個名叫origin的遠程庫,此時,可以先用git remote -v查看遠程庫信息

  • 刪除已有關聯:git remote rm origin
我們的本地庫就可以同時與多個遠程庫互相同步:

┌─────────┐ ┌─────────┐
│ GitHub  │ │  Gitee  │
└─────────┘ └─────────┘
     ▲           ▲
     └─────┬─────┘
           │
    ┌─────────────┐
    │ Local Repo  │
    └─────────────┘

自定義Git

在安裝Git一節中,我們已經配置了user.name和user.email,實際上,Git還有很多可配置項。
比如,讓Git顯示顏色,會讓命令輸出看起來更醒目:$ git config --global color.ui true

忽略特殊文件

有些時候,你必須把某些文件放到Git工作目錄中,但又不能提交它們,比如保存了數據庫密碼的配置文件啦,等等,每次git status都會顯示Untracked files(未跟蹤文件:未add的文件) …,有強迫症的童鞋心裏肯定不爽

  • 忽略特殊文件方法

在Git工作區的根目錄下創建一個特殊的.gitignore文件,然後把要忽略的文件名填進去,Git就會自動忽略這些文件。
不需要從頭寫.gitignore文件,GitHub已經爲我們準備了各種配置文件,只需要組合一下就可以使用了。所有配置文件可以直接在線瀏覽:配置文件大全

  • 忽略文件的原則是
  • 忽略操作系統自動生成的文件,比如縮略圖等;
  • 忽略編譯生成的中間文件、可執行文件等,也就是如果一個文件是通過另一個文件自動生成的,那自動生成的文件就沒必要放進版本庫,比如Java編譯產生的.class文件;
  • 忽略你自己的帶有敏感信息的配置文件,比如存放口令的配置文件。
  • 配置格式
Thumbs.db		//普通文件
*.py[cod]     	//*.pyc、*.pyo、*.pyd
*.so
*.egg
*.egg-info
dist			//文件或目錄
build
  • 提交配置文件

最後一步就是把.gitignore也提交到Git,就完成了!當然檢驗.gitignore的標準是git status命令是不是說working directory clean。

  • 強制提交

有些時候,你想添加一個文件到Git,但發現添加不了,原因是這個文件被.gitignore忽略了,
如果你確實想添加該文件,可以用-f強制添加到Git:$ git add -f App.class

  • 配置檢查

或者你發現,可能是.gitignore寫得有問題,需要找出來到底哪個規則寫錯了,可以用 $ git check-ignore命令檢查:$ git check-ignore -v App.class
Git會告訴我們,.gitignore的第3行規則忽略了該文件,於是我們就可以知道應該修訂哪個規則。

配置別名

  • 常用別名
//常用操作
$ git config --global alias.co checkout
$ git config --global alias.ci commit
$ git config --global alias.br branch

//神奇操作
	//撤銷
	$ git config --global alias.unstage 'reset HEAD'
	$ git reset HEAD test.py		//原版
	$ git unstage test.py			//簡化
	//顯示最近一次提交
	$ git config --global alias.last 'log -1'
	$ git last						//簡化

//喪心病狂操作
	//顯示日誌(美化版)
	$ git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
	$ git lg							//簡化
  • 當前倉庫配置文件

配置Git的時候,加上–global是針對當前用戶起作用的,如果不加,那隻針對當前的倉庫起作用。
配置文件放哪了?每個倉庫的Git配置文件都放在.git/config文件中:

$ cat .git/config 
[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
    ignorecase = true
    precomposeunicode = true
[remote "origin"]
    url = [email protected]:michaelliao/learngit.git
    fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
    remote = origin
    merge = refs/heads/master
[alias]
    last = log -1

別名就在[alias]後面,要刪除別名,直接把對應的行刪掉即可。

  • 當前用戶配置文件

而當前用戶的Git配置文件放在用戶主目錄下的一個隱藏文件.gitconfig中:

$ cat .gitconfig
[alias]
    co = checkout
    ci = commit
    br = branch
    st = status
[user]
    name = Your Name
    email = [email protected]

搭建Git服務器

遠程倉庫實際上和本地倉庫沒啥不同,純粹爲了7x24小時開機並交換大家的修改。
GitHub就是一個免費託管開源代碼的遠程倉庫
搭建Git服務器需要準備一臺運行Linux的機器,強烈推薦用UbuntuDebian,這樣,通過幾條簡單的apt命令就可以完成安裝。

  1. 安裝git:$ sudo apt-get install git
  2. 創建git用戶,用來運行git服務:$ sudo adduser git
  3. 創建證書登錄

收集所有需要登錄的用戶的公鑰,就是他們自己的id_rsa.pub文件,把所有公鑰導入到/home/git/.ssh/authorized_keys文件裏,一行一個。

  1. 初始化Git倉庫

先選定一個目錄作爲Git倉庫,假定是/srv/sample.git,在/srv目錄下輸入命令:
$ sudo git init --bare sample.git
Git就會創建一個裸倉庫,裸倉庫沒有工作區,因爲服務器上的Git倉庫純粹是爲了共享,所以不讓用戶直接登錄到服務器上去改工作區,並且服務器上的Git倉庫通常都以.git結尾。然後,把owner改爲git:
$ sudo chown -R git:git sample.git

  1. 禁用shell登錄

出於安全考慮,第二步創建的git用戶不允許登錄shell,這可以通過編輯/etc/passwd文件完成。找到類似下面的一行:
git:x:1001:1001:,,,:/home/git:/bin/bash
改爲:
git:x:1001:1001:,,,:/home/git:/usr/bin/git-shell
這樣,git用戶可以正常通過ssh使用git,但無法登錄shell,因爲我們爲git用戶指定的git-shell每次一登錄就自動退出。

  1. 克隆遠程倉庫

現在,可以通過git clone命令克隆遠程倉庫了,在各自的電腦上運行:

$ git clone git@server:/srv/sample.git
Cloning into 'sample'...
warning: You appear to have cloned an empty repository.

管理公鑰

如果團隊很小,把每個人的公鑰收集起來放到服務器的/home/git/.ssh/authorized_keys文件裏就是可行的。如果團隊有幾百號人,就沒法這麼玩了,這時,可以用Gitosis來管理公鑰。

這裏我們不介紹怎麼玩Gitosis了,幾百號人的團隊基本都在500強了,相信找個高水平的Linux管理員問題不大。

管理權限

有很多不但視源代碼如生命,而且視員工爲竊賊的公司,會在版本控制系統裏設置一套完善的權限控制,每個人是否有讀寫權限會精確到每個分支甚至每個目錄下。因爲Git是爲Linux源代碼託管而開發的,所以Git也繼承了開源社區的精神,不支持權限控制。不過,因爲Git支持鉤子(hook),所以,可以在服務器端編寫一系列腳本來控制提交等操作,達到權限控制的目的。Gitosis就是這個工具。

這裏我們也不介紹Gitosis了,不要把有限的生命浪費到權限鬥爭中。

小結

  • 搭建Git服務器非常簡單,通常10分鐘即可完成;

  • 要方便管理公鑰,用Gitosis

  • 要像SVN那樣變態地控制權限,用Gitosis

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章