最實用 Git 版本控制

git版本控制

  1. Git概念

1.1. Git庫中由三部分組成

   Git 倉庫就是那個.git 目錄,其中存放的是我們所提交的文檔索引內容,Git 可基於文檔索引內容對其所管理的文檔進行內容追蹤,從而實現文檔的版本控制。.git目錄位於工作目錄內。 

1) 工作目錄:用戶本地的目錄;

2) Index(索引):將工作目錄下所有文件(包含子目錄)生成快照,存放到一個臨時的存儲區域,Git 稱該區域爲索引。

3) 倉庫:將索引通過commit命令提交至倉庫中,每一次提交都意味着版本在進行一次更新。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-kP45d3y1-1587558359040)(http://img1.51cto.com/attachment/201102/10/2712776_1297350397Fmk7.jpg)]
1.2. 使用Git時的初始化事項

1.2.1. Git初始化配置

1) 配置使用git倉庫的人員姓名

   git config --global user.name "Your Name Comes Here" 

2) 配置使用git倉庫的人員email

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

3 )修改默認編譯器

git config --global core.editor vim

4)git 高亮

git config --global color.ui true

1.2.2. Git文檔忽略機制

工作目錄中有一些文件是不希望接受Git 管理的,譬如程序編譯時生成的中間文件等等。Git 提供了文檔忽略機制,可以將工作目錄中不希望接受Git 管理的文檔信息寫到同一目錄下的.gitignore 文件中。 (只有還沒有被添加到跟索引的文件纔有效,如果已經添加到索引,則需先從索引中刪除,然後再添加ignore文件纔有效)

1.3. Git與Repo的比較

   Git操作一般對應一個倉庫,而Repo操作一般對應一個項目,即一個項目會由若干倉庫組成。 

例如,在操作整個Recket項目時使用Repo,而操作其中的某個倉庫時使用Git。 在包含隱藏目錄.git的目錄下執行git操作。

2.Git help
Git help 獲取git基本命令
(如果要知道某個特定命令的使用方法,例如:使用Git help clone,來獲取git clone的使用方法)

3.Git本地操作基本命令
3.1. Git init
或者使用git init-db。
創建一個空的Git庫。在當前目錄中產生一個.git 的子目錄。以後,所有的文件變化信息都會保存到這個目錄下,而不像CVS那樣,會在每個目錄和子目錄下都創建一個CVS目錄。
在.git目錄下有一個config文件,可以修改其中的配置信息。
git init —bare:創建一個git庫,--bare是純淨的庫

推送git庫到遠程的方法

  1. git init
  2. git add .
  3. git commit -am “###” -------以上3步只是本地提交
    4.git remote add origin [email protected]:repos/xxx/xxx/xxx.git
    5.git push origin 本地分支:遠程分支

3.2. Git add /Git stage(同義命令)
將當前工作目錄中更改或者新增的文件加入到Git的索引中,加入到Git的索引中就表示記入了版本歷史中,這也是提交之前所需要執行的一步。
可以遞歸添加,即如果後面跟的是一個目錄作爲參數,則會遞歸添加整個目錄中的所有子目錄和文件。例如:
git add dir1 ( 添加dir1這個目錄,目錄下的所有文件都被加入 )
Git add f1 f2 ( 添加f1,f2文件)
git add . ( 添加當前目錄下的所有文件和子目錄 )

3.3. Git rm
從當前的工作目錄中和索引中刪除文件。
可以遞歸刪除,即如果後面跟的是一個目錄做爲參數,則會遞歸刪除整個目錄中的所有子目錄和文件。例如:
git rm –r * (進入某個目錄中,執行此語句,會刪除該目錄下的所有文件和子目錄)
git rm f1 (刪除文件f1,包含本地目錄和index中的此文件記錄)

git clean -df 刪除沒有加入add的文件

git rm --cached “文件路徑”,不刪除物理文件,僅將該文件從緩存中刪除;

git rm --f “文件路徑”,不僅將該文件從緩存中刪除,還會將物理文件刪除(不會回收到垃圾桶)

3.4. Git commit
提交當前工作目錄的修改內容。
直接調用git commit命令,會提示填寫註釋。通過如下方式在命令行就填寫提交註釋:git commit -m “Initial commit of gittutor reposistory”。 注意,和CVS不同,git的提交註釋必須不能爲空,否則就會提交失敗。
git commit還有一個 -a的參數,可以將那些沒有通過git add標識的變化一併強行提交,但是不建議使用這種方式。
每一次提交,git就會爲全局代碼建立一個唯一的commit標識代碼,用戶可以通過git reset命令恢復到任意一次提交時的代碼。
git commit –-amend –m “message” (在一個commit id上不斷修改提交的內容)
git commit --amend --author=‘Your Name [email protected]’ 修改最後一次提交的用戶名和密碼

3.5. Git status
查看版本庫的狀態。可以得知哪些文件發生了變化,哪些文件還沒有添加到git庫中等等。 建議每次commit前都要通過該命令確認庫狀態。
最常見的誤操作是, 修改了一個文件, 沒有調用git add通知git庫該文件已經發生了變化就直接調用commit操作, 從而導致該文件並沒有真正的提交。這時如果開發者以爲已經提交了該文件,就繼續修改甚至刪除這個文件,那麼修改的內容就沒有通過版本管理起來。如果每次在 提交前,使用git status查看一下,就可以發現這種錯誤。因此,如果調用了git status命令,一定要格外注意那些提示爲 “Changed but not updated:”的文件。 這些文件都是與上次commit相比發生了變化,但是卻沒有通過git add標識的文件。

3.6. Git log
查看歷史日誌,包含每次的版本變化。每次版本變化對應一個commit id。
Git log -1
-1的意思是隻顯示一個commit,如果想顯示5個,就-5。不指定的話,git log會從該commit一直往後顯示。
Git log --stat –summary (顯示每次版本的詳細變化)
在項目日誌信息中,每條日誌的首行(就是那一串字符)爲版本更新提交所進行的命名,我們可以將該命名理解爲項目版本號。項目版本號應該是唯一的,默認由 Git 自動生成,用以標示項目的某一次更新。如果我們將項目版本號用作git-show 命令的參數,即可查看該次項目版本的更新細節。例如:

  1. Git log
    git log --pretty=oneline 文件名
    顯示單獨一個文件被修改的log

2)Git show
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-8IBllxcn-1587558359042)(http://img1.51cto.com/attachment/201102/10/2712776_1297351668uhjL.jpg)]
實際上,上述命令並非是真正的進行版本號自定義,只是製造了一個tag對象而已,這在進行項目版本對外發布時比較有用。

3.7. Git merge
把服務器上下載下來的代碼和本地代碼合併。或者進行分支合併。
例如:當前在master分支上,若想將分支dev上的合併到master上,則git merge dev
注意:git merge nov/eclair_eocket (是將服務器git庫的eclair_eocket分支合併到本地分支上)
git rebase nov/eclair_eocket (是將服務器git庫的eclair_eocket分支映射到本地的一個臨時分支上,然後將本地分支上的變化合併到這個臨時分支,然後再用這個臨時分支初始化本地分支)

git merge —squash branch:把從分支所有修改變成一次提交合併到主分支上,但不會生成committed

3.8. Git diff
把本地的代碼和index中的代碼進行比較,或者是把index中的代碼和本地倉庫中的代碼進行比較。
1) Git diff
比較工作目錄和Index中的代碼。
2) Git diff - - cached
比較index和本地倉庫中的代碼。
3)只比較文件git diff HEAD — file

3.9. Git checkout
3.9.1. 切換到分支
checkout 會重寫工作區

  1. 創建一個新分支,並切換到該分支上
    Git checkout –b 新分支名
    2)切換到某個已經建立的本地分支local_branch
    Git checkout local_branch
    (使用cat .git/HEAD後,顯示refs:refs/heads/ local_branch)
  2. 切換到服務器上的某個分支remote_branch
    Git checkout remote_branch
    (遠程分支remote_branch可以通過 git branch –r 列出)
  3. 切換到某個commit id
    Git checkout commit_id
    (使用cat .git/HEAD後,顯示commit_id)
  4. 切換到某個tag
    Git checkout tag
    (使用cat .git/HEAD後,顯示tag)
    注意: 除了1)和2)外,其餘三種都只是切換到了一個臨時的( no branch )狀態 (this head is detached),這時用 git branch 可以看到處於(no branch)上, cat .git/HEAD 看到指向相應的commit id。 這個(no branch)只是臨時存在的,並不是一個真正建立的branch。 如果此時執行2),則這個(no branch)就自動消失了;如果執行1), 則創建新分支 new branch,並把這個(no branch)掛到這個新分支上,此時cat .git/refs/heads/new_branch 可以看到已經指向了剛纔那個commit id。

3.9.2. 用已有分支初始化新分支
執行下面的命令,在切換到某個已經建立的local branch或者某個remote branch或者某個commit id 或者某個tag的同時,創建新分支new_branch,並且掛到這個新分支上。
1) 切換到某個已經建立的本地分支local_branch,並且使用此分支初始化一個新分支new_branch。
git checkout –b new_branch local_branch
2) 切換到某個遠程分支remote_branch,並且用此分支初始化一個新分支new_branch。
Git checkout –b new_branch remote_branch
3) 切換到某個commit id,並建立新分支new_branch
Git checkout –b new_branch commit_id
4) 切換到某個tag,並建立新分支new_branch
Git checkout –b new_branch tag
git checkout --track origin/master 把服務器代碼更新到本地

3.9.3. 還原代碼
例如 “git checkout app/model/user.rb” 就會將user.rb文件從上一個已提交的版本中更新回來,未提交的工作目錄中的內容全部會被覆蓋。

3.9.4 當有衝突時,用本地還是合併分支
git checkout --theirs file 用合併的分支
git checkout --ours file 用本地的分支

3.10. Git-ls-files
查看當前的git庫中有那些文件。
3.11. Git mv
重命名一個文件、目錄或者鏈接。
例如:Git mv helloworld.c helloworld1.c (把文件helloworld.c 重命名爲 helloworld1.c)
3.12. Git branch
3.12.1. 總述
在 git 版本庫中創建分支的成本幾乎爲零,所以,不必吝嗇多創建幾個分支。當第一次執行git init時,系統就會創建一個名爲“master”的分支。 而其它分支則通過手工創建。
下面列舉一些常見的分支策略:
創建一個屬於自己的個人工作分支,以避免對主分支 master 造成太多的干擾,也方便與他人交流協作;
當進行高風險的工作時,創建一個試驗性的分支;
合併別人的工作的時候,最好是創建一個臨時的分支用來合併,合併完成後再“fetch”到自己的分支。
對分支進行增、刪、查等操作。
注意:分支信息一般在.git/refs/目錄下,其中heads目錄下爲本地分支,remotes爲對應服務器上的分支,tags爲標籤。

3.12.2. 查看分支
git branch 列出本地git庫中的所有分支。在列出的分支中,若分支名前有*,則表示此分支爲當前分支。
git branch –r 列出服務器git庫的所有分支。

3.12.3. 查看當前在哪個分支上
cat .git/HEAD

3.12.4. 創建一個分支
1) git branch 分支名
雖然創建了分支,但是不會將當前工作分支切換到新創建的分支上,因此,還需要命令“git checkout 分支名” 來切換,

2) git checout –b 分支名
不但創建了分支,還將當前工作分支切換到了該分支上。

3.12.5. 切換到某個分支:git checkout 分支名
切換到主分支:git checkout master

3.12.6. 刪除分支
git branch –D 分支名
注意: 刪除後,發生在該分支的所有變化都無法恢復。強制刪除此分支。

3.12.7. 比較兩個分支上的文件的區別
git diff master 分支名 (比較主分支和另一個分支的區別)

3.12.8. 查看分支歷史
git-show-branch (查看當前分支的提交註釋及信息)
git-show-branch -all(查看所有分支的提交註釋及信息)例如:

  • [dev] d2
    ! [master] m2
  • [dev] d2
  • [dev^] d1
  • [dev~2] d0
    *+ [master] m2
    在上述例子中, “–”之上的兩行表示有兩個分支dev和master, 且dev分支上最後一次提交的日誌是“d2”,master分支上最後一次提交的日誌是 “m2”。 “–”之下的幾行表示了分支演化的歷史,其中 dev表示發生在dev分支上的最後一次提交,dev^表示發生在dev分支上的倒數第二次提交。dev~2表示發生在dev分支上的倒數第三次提交。

3.12.9. 查看當前分支的操作記錄
git whatchanged

3.12.10. 合併分支
法一:
git merge “註釋” 合併的目標分支 合併的來源分支
如果合併有衝突,git會有提示。
例如:git checkout master (切換到master分支)
git merge HEAD dev~2 (合併master分支和dev~2分支)或者:git merge master dev~2
法二:
git pull 合併的目標分支 合併的來源分支
例如: git checkout master (切換到master分支)
git pull . dev2(合併當前分支和dev2分支)

3.13. Git rebase
一般在將服務器最新內容合併到本地時使用,例如:在版本C時從服務器上獲取內容到本地,務修改了本地內容,此時想把本地修改的內容提交到服務器上;但發現服器上的版本已經變爲G了,此時就需要先執行Git rebase,將服務器上的最新版本合併到本地。例如:

用下面兩幅圖解釋會比較清楚一些,rebase命令執行後,實際上是將分支點從C移到了G,這樣分支也就具有了從C到G的功能。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-U1sSxstE-1587558359045)(http://img1.51cto.com/attachment/201102/10/2712776_1297351681RizB.jpg)]

3.14. Git reset
庫的逆轉與恢復除了用來進行一些廢棄的研發代碼的重置外,還有一個重要的作用。比如我們從遠程clone了一個代碼庫,在本地開發後,準備提交回遠程。但 是本地代碼庫在開發時,有功能性的commit,也有出於備份目的的commit等等。總之,commit的日誌中有大量無用log,我們並不想把這些 log在提交回遠程時也提交到庫中。 因此,就要用到git reset。
git reset的概念比較複雜。它的命令形式:git reset [–mixed | --soft | --hard] []
命令的選項:
–mixed 這個是默認的選項。如git reset [–mixed] dev(dev的定義可以參見2.6.5)。它的作用僅是重置分支狀態到dev1^, 但是卻不改變任何工作文件的內容。即,從dev1到dev1的所有文件變化都保留了,但是dev1到dev1之間的所有commit日誌都被清除了, 而且,發生變化的文件內容也沒有通過git add標識,如果您要重新commit,還需要對變化的文件做一次git add。 這樣,commit後,就得到了一份非常乾淨的提交記錄。 (回退了index和倉庫中的內容)
–soft相當於做了git reset –mixed,後,又對變化的文件做了git add。如果用了該選項, 就可以直接commit了。(回退了倉庫中的內容)
–hard這個命令就會導致所有信息的回退, 包括文件內容。 一般只有在重置廢棄代碼時,才用它。 執行後,文件內容也無法恢復回來了。(回退了工作目錄、index和倉庫中的內容)
例如:
切換到使用的分支上;
git reset HEAD^ 回退第一個記錄
git reset HEAD~2 回退第二個記錄
如果想把工作目錄下的文件也回退,則使用git reset - - hard HEAD^ 回退第一個記錄
git reset - - hard HEAD~2 回退第二個記錄
還可以使用如下方法:
將當前的工作目錄完全回滾到指定的版本號,假設如下圖,我們有A-G五次提交的版本,其中C的版本號是 bbaf6fb5060b4875b18ff9ff637ce118256d6f20,我們執行了’git reset bbaf6fb5060b4875b18ff9ff637ce118256d6f20’那麼結果就只剩下了A-C三個提交的版本
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-4L0Xpjyv-1587558359046)(http://img1.51cto.com/attachment/201102/10/2712776_12973516984wUp.jpg)]

3.15. Git revert

還原某次對版本的修改,例如:git revert commit_id (其中commit_id爲commit代碼時生成的一個唯一表示的字符串)

例如:(3.6中)git revert dfb02e6e4f2f7b573337763e5c0013802e392818 (執行此操作,則還原上一次commit的操作)
回退到原來的提交,但是跟reset 不同,不會刪除之前的提交,而是作爲一個新的提交push

3.16. Git config

利用這個命令可以新增、更改Git的各種設置,例如 “git config branch.master.remote origin” 就將master的遠程版本庫設置爲別名叫做origin版本庫。

3.17. Git show

顯示對象的不同類型。
git show commitid file
顯示指定commitid的文件修改

3.18. Git tag

創建、列出、刪除或者驗證一個標籤對象(使用GPG簽名的)。

可以將某個具體的版本打上一個標籤,這樣就不需要記憶複雜的版本號哈希值字符串了,例如你可以使用 “git tag revert_version bbaf6fb5060b4875b18ff9ff637ce118256d6f20” 來標記這個被你還原的版本,那麼以後你想查看該版本時,就可以使用 revert_version標籤名,而不是哈希值了。
刪除tag

git tag -d Remote_Systems_Operation
刪除遠程tag

git push origin :refs/tags/Remote_Systems_Operation

創建 Annotated tag

git tag -a

創建 Signed Tag

git tag -s

推送到服務器

push tag

git push ssh://USER@HOST:PORT/PROJECT tag v1.0

3.19.Git stash
保存當前進度。如果開發的功能還沒完成,不想commit可以通過這個命令把當前的進度保存下來
3.19.1git stash list
顯示所有stash列表

3.19.2.git stash pop
從最近的保存進度進行恢復
git stash pop stash@{0}

3.19.3.git stash drop[]
刪除一個存儲的進度。默認刪除最新的進度
4. Git服務器操作命令(與服務器交互)
(1)將本地代碼庫作爲遠程庫
git remote add name url(name 是遠程庫的名字,url是遠程庫的地址)
git remote add origin ssh:[email protected]/~/Desktop/VLess/app_of_Android/OVWifi_android_SDK_34213/android/appnew/.git
(2)git clone 克隆遠程庫代碼
git clone [email protected]/~/Desktop/VLess/app_of_Android/OVWifi_android_SDK_34213/android/appnew/.git

4.1. Git clone
取出服務器的倉庫的代碼到本地建立的目錄中(與服務器交互)
通過git clone獲取遠端git庫後,.git/config中的開發者信息不會被一起clone過來。仍然需要爲本地庫的.git/config文件添加開發者信息。此外,開發者還需要自己添加 . gitignore文件。
通過git clone獲取的遠端git庫,只包含了遠端git庫的當前工作分支。如果想獲取其它分支信息,需要使用 “git branch –r” 來查看, 如果需要將遠程的其它分支代碼也獲取過來,可以使用命令 “ git checkout -b 本地分支名 遠程分支名”,其中,遠程分支名爲 “git branch –r” 所列出的分支名, 一般是諸如“origin/分支名”的樣子。如果本地分支名已經存在, 則不需要“-b”參數。

4.2. Git pull
從服務器的倉庫中獲取代碼,和本地代碼合併。(與服務器交互,從服務器上下載最新代碼,等同於: Git fetch + Git merge)
從其它的版本庫(既可以是遠程的也可以是本地的)將代碼更新到本地,例如:“git pull origin master ”就是將origin這個版本庫的代碼更新到本地的master主分支。
git pull可以從任意一個git庫獲取某個分支的內容。用法如下:
git pull username@ipaddr:遠端repository名遠端分支名 本地分支名。這條命令將從遠端git庫的遠端分支名獲取到本地git庫的一個本地分支中。其中,如果不寫本地分支名,則默認pull到本地當前分支。
需要注意的是,git pull也可以用來合併分支。 和git merge的作用相同。 因此,如果你的本地分支已經有內容,則git pull會合並這些文件,如果有衝突會報警。

4.3. Git push
強制提交:git push -f origin master
git push origin develop:develop//將本地的develop分支提交到遠程的develop分支上
將本地commit的代碼更新到遠程版本庫中,例如 “git push origin”就會將本地的代碼更新到名爲orgin的遠程版本庫中。
git push和git pull正好想反,是將本地某個分支的內容提交到遠端某個分支上。用法: git pushusername@ipaddr:遠端repository名本地分支名 遠端分支名。這條命令將本地git庫的一個本地分支push到遠端git庫的遠端分支名中。
需要格外注意的是,git push好像不會自動合併文件。因此,如果git push時,發生了衝突,就會被後push的文件內容強行覆蓋,而且沒有什麼提示。 這在合作開發時是很危險的事情。
刪除遠程分支:git push origin --delete branchname
刪除遠程標籤:git push origin --delete tagname

4.4. Git fetch
從服務器的倉庫中下載代碼。(與服務器交互,從服務器上下載最新代碼)
相當於從遠程獲取最新版本到本地,不會自動merge,比Git pull更安全些。
使用此方法來獲取服務器上的更新。
例如:如果使用git checkout nov/eclair_rocket (nov/eclair_rocket爲服務器上的分支名),則是獲取上次使用git fetch命令時從服務器上下載的代碼;如果先使用 git fetch ,再使用git checkout nov/eclair_rocket,則是先從服務器上獲取最新的更新信息,g然後從服務器上下載最新的代碼。

5 git blame file

知道“file”這個文件每一行是誰修改的

6git reflog

可以找回被誤刪的branch分支,commit等

63ee781 HEAD@{1}: commit: test3:q

git reset --hard 63ee781,可以使用reset來找回分支

7.git patch 補丁

創建補丁:一是用git diff生成的標準patch,二是git format-patch生成的Git專用Patch

7.1git diff生成的標準patch
git diff master > patch

7.2git apply patch 應用patch

如果要支持二進制圖片需要加上參數
git diff HEAD^…HEAD --binary > foobar.patch

7.3git apply --check patch 查看補丁是否能夠乾淨順利地應用到當前分支中

8 git cherry-pick
git cherry-pick用於把另一個本地分支的commit修改應用到當前分支。
git cherry-pick

如果提示處於merge無法git cherry-pik
git cherry-pick -m 1

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