1. 說明
- 從原理到實際
- 從場景出發
- 先本地
- 在遠端
1.1 概念/原理
- git 關心的是“檔案快照”,而非“差異比較”。SVN等關心的是“差異”。簡單了解就是,git每次送出都是完整檔案的儲存。不會比較同一檔案在這次送出有什麼變化。
- git 大多數的操作都在“本地”
- git 每次commit都是在移動
。HEAD
相當于指針,指向某次送出HEAD
- 每個檔案都會有三種狀态:
、未追蹤
、暫存
已入庫
- git 所有指令都是圍繞檔案的狀态,與倉庫的狀态來工作
- git 三個地方,對應檔案三種狀态。
- Workspace:
,代碼目錄。包含了所有狀态的檔案工作區
- Index / Stage:
,git add了但沒有送出的檔案暫存區
- Repository:
,git commit入庫後的存儲本地倉庫
- Remote:
遠端倉庫
- Workspace:
2. 本地代碼一般操作
2.1 本地代碼庫初始化
- 進入本地代碼根目錄執行,系統會預設建立"master"分支
//假設代碼目錄有檔案不需要這一步 $touch 1.txt //初始化git環境 $git init
- 添加本地檔案到倉庫并送出(兩個指令)。兩個&的含義是,前面一個指令執行出錯,後面的就不會執行。注意: -m 表示本次送出的說明。一定要有
- 檢視分支,master已經出現并作為預設分支
$git branch * master
2.2 建立與檢視本地分支,*号代表目前代碼所在分支
- 從master作為“父分支”建立本地分支dev。注意繼承關系。從哪個分支建立子分支,代碼就從哪個分支繼承
$git branch dev
- 切換到本地分支dev
$git checkout dev
- 檢視本地分支(因為checkout到dev了,是以*号在dev分支上
$git branch * dev master
2.3 修改代碼并送出到本地分支“dev”
- 寫入"123"到a.txt,如果a.txt不存在系統會建立
$echo "123" > a.txt
- 執行status指令,檢視代碼狀态。可以看到提示“要把檔案加入倉庫追蹤”
$git status On branch dev Untracked files: (use "git add <file>..." to include in what will be committed) a.txt nothing added to commit but untracked files present (use "git add" to track)
- 根據提示把檔案加入追蹤并送出到本地
- 再次執行status,提示工作區是幹淨的
$git status On branch dev nothing to commit, working directory clean
2.4 代碼修改完畢後,合并到master分支
通過2.3我們改變了dev,改動完畢,這時候要合并代碼到master。但在合并到master之前需要先更新master代碼到dev。
目前通行且最佳的方案是采用rebase方案。rebase方案與merge的優劣我們不在這裡讨論,請自行搜尋。
簡單了解就是:rebase使得送出路線更加清晰,而merge會因為“分支”過多,合并過多導緻送出路線雜亂追蹤起來比較難。但rebase會丢失很多送出細節,也不是完美合并。
- 總之:非常難單一的使用哪個就能解決所有問題!
- 先統一名稱:上遊、下遊
- 如果
是從dev
建立出來的分支。那麼,master就是dev的master
,dev就是master的上遊
。下遊
- 下遊合并上遊,要盡可能的保持送出路徑簡潔,那麼采用"Rebase"
- 上遊合并下遊代碼,要盡可能的保持送出細節,那麼采用"merge"
想了解更多幫助了解,參考兩篇文章
- 動畫圖解 Git 指令
- GIT使用rebase和merge的正确姿勢
2.4.1 實際例子
- dev是從master建立的分支
$git branch dev $git checkout dev
- dev開發一段時間後,master已經被其它同僚修改了一些内容。dev本身也做了一些送出。這時,需要更新master代碼才能做dev的測試。這時候就是:“下遊合并上遊”。那麼采用
rebase
$git rebase master
- dev開發完畢了,這時候需要合并到master。這時候就是:“上遊合并下遊”。那麼采用
merge
$git checkout master $git merge dev
3. 将現有代碼納入管理
3.1 本地代碼從未納入過倉庫,倉庫也是空的
這種最簡單,按照如下執行即可
- 設定郵箱,使用者名
$git config --global user.name "smokelee" $git config --global user.email "[email protected]"
- 進入代碼的根目錄
//初始化本地代碼倉庫 $git init //将遠端倉庫主機命名為"origin",并與本地的master建立追蹤關系 //origin 是遠端主機`本地别名`,名字可以自定義的,不會影響到遠端 $git remote add origin ssh://gi[email protected]:10022/lihao/gitlearn.git //把本地代碼加入到代碼追蹤 $git add . //把本地代碼送出到本地倉庫 $git commit -m "Initial commit" //推送本地代碼到遠端主機“origin”的"master" //git push <遠端主機名> <本地分支名>:<遠端分支名> //遠端分支被省略,如上則表示将本地分支推送到與之存在追蹤關系的遠端分支。一般本地與 //遠端分支會同名 $git push -u origin master
這個要注意,第一次送出時采用了git push -u
,含義是同時設定本地分支“master”與遠端的"origin/master",建立追蹤關系。那麼以後再-u
代碼時,直接使用push
就可以了。git push
3.2 本地代碼,某個送出錯了,向撤回送出
用git reset 指令實作回退,但怎麼回退是個學問。
- 直接扔掉回退間的代碼是一種(Hard)
- 回退但保留指定回退間産生代碼是一種(Soft)
- 本質是移動git的HEAD指向
3.2.1 先來硬的
何為硬?不管 暫存區
有沒有追蹤但未送出的檔案,不管上次送出改了什麼,通通丢棄。對!就是你了解的丢掉。
- 想撤回
本次送出的上1個送出到
$git reset --hard HEAD^
- 想撤回
本次送出的上N個送出到
$git reset --hard HEAD~N
- 撤回
某個送出到
$git reset --hard 98abc5a
- 誤操作怎麼辦?reflog(30天内)
$git reflog b7057a9 HEAD@{0}: reset: moving to b7057a9 98abc5a HEAD@{1}: commit: more stuff added to foo
就是被98abc5a
掉的送出。硬
再次git log檢視。丢掉的内容回來了!git reset --hard 98abc5a
$git log 98abc5a (HEAD, master) more stuff added to foo
3.2.2 再來軟的
何為軟?與硬不同的是,軟隻回退送出,但中間産生的檔案不丢棄!
操作與hard一緻,不做更多說明
4. 連接配接遠端
4.1 從遠端下載下傳代碼,注意:隻會下載下傳 master
代碼
master
git clone ssh://xxxxxx/xxxx/prj.git
4.2 下載下傳後切換到分支
- 檢視所有分支
$git branch -a master remotes/origin/HEAD -> origin/master remotes/origin/dev remotes/origin/master
- 切換到
分支,并建立dev
與遠端分支
關聯本地分支
$git checkout -b dev origin/dev
- 更新遠端分支到本地
如果沒有走1、2兩步,不要用3。其它後面會講$git pull --rebase
4.3 本地建立分支,修改,并送出"遠端分支"
前提條件
dev
已經與遠端
origin/dev
建立關聯。請看4.2
- 在
上建立feature分支并修改dev
$git branch feature<jira編号>-smokelee-20200423 $git checkout feature<jira編号>-smokelee-20200423 $touch newfeature.java $git add . && git commit -m "add feature"
- 該下班了,還沒改完,送出到遠端伺服器(小變化無需上傳)
$git push origin feature<jira編号>-smokelee-20200423
- 第二天修改完了,合并到
。先更新dev
dev
$git checkout dev $git pull --rebase
- 合并feature到dev
$git merge f1 $git push
- 合并成功,沒有問題。删除遠端分支
$git checkout feature<jira編号>-smokelee-20200423 $git push origin :feature<jira編号>-smokelee-20200423
注意5中的第二條指令冒号前是空的,複習:git push <遠端主機名> <本地分支名>:<遠端分支名> 本地分支名不設定,就表示删除遠端分支
4.4 幹拉一個分支到本地
不從任何建立
本地分支
分支。并且不建立
feature
,
本地
遠端
分支關聯。
要建立關聯也簡單,git pull後設定
git branch --set-upstream-to=origin/dev feaure-xxx-xxxx
這裡純粹在示範完整用法,就是字打的多點
- git pull origin <遠端分支名>:<本地分支名>
$git pull origin master:feaure-xxx-xxxx //關聯遠端與本地分支 $git branch --set-upstream-to=origin/dev feaure-xxx-xxxx $git checkout feaure-xxx-xxxx
- 修改
并送出feaure-xxx-xxxx
$touch f1.java $git add . && git commit -m "dev1"
- 修改代碼測試完畢準備送出到
遠端分支
在關聯了$git pull origin dev:feaure-xxx-xxxx --rebase $git push origin feaure-xxx-xxxx.local:dev
與遠端
分支情況下語句簡單多了。本地
$git pull --reabase $git push