Git官網學習筆記,還是命令行方式操作比較舒服

Git學習筆記:

官網學習手冊參考

文件狀態:

官網參考
清楚的要操作的文件的狀態和三個區是操作git的關鍵

  • 未跟蹤[Untracked files], 新建的文件,使用git add 變爲跟蹤

  • 已跟蹤[use “git rm --cached <file>…” to unstage]根據提示,可以使用git rm --cached 變爲未跟蹤,

  • 未修改[nothing to commit, working tree clean] 整個文件都是和倉庫一致的

  • 已修改[Changes not staged for commit] 文件已修改,但是未暫存,使用git add 暫存, git checkout – . 可用於取消修改,查看執行git命令後的提示

  • 已暫存[Changes to be committed] 文件已暫存,可以提交,提交後文件狀態就變爲未修改,同時提示爲【use “git reset HEAD <file>…” to unstage】可以使用git reset 變爲取消暫存,那麼文件會變爲修改狀態,需求git add重新暫存,才能提交

三個區示意圖
在這裏插入圖片描述

文件狀態示意圖
在這裏插入圖片描述

主要的命令有:

開發中常用的已加粗,每個命令可能都有很多的可選參數,具體用時再查
  • git config 常用是配置用戶user.name、 user.email、 core.editor 非必須 參考官網
    • git config --global user.name “John Doe”
    • git config --global user.email [email protected]
    • git config --global color.ui true
      個人的一些快捷簡短命令配置【配置文件在用戶家目錄下的 .gitconfig 文件】,僅供參考
[user]
	name = hayashi
	email = [email protected]
[filter "lfs"]
	clean = git-lfs clean -- %f
	smudge = git-lfs smudge -- %f
	process = git-lfs filter-process
	required = true
[core]
	autocrlf = true
	excludesfile = .gitignoreglobal
[difftool "sourcetree"]
	cmd = '' \"$LOCAL\" \"$REMOTE\"
[mergetool "sourcetree"]
	cmd = "'' "
	trustExitCode = true
[color]
	ui = true
[alias]
	co = checkout
	ci = commit
	cl = clone
	ss = status
	mg = merge
	bh = branch
	pl = pull
	ph = push
	rb = rebase
	ii = init
	rs = reset
	ad = add
	fh = fetch
	sh = stash
	lg = log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit
  • git init 在本地初始化一個Git倉庫

  • git clone 從遠程拉取一個倉庫,git clone url localDir 即使localDir目錄不存在會自動建立,如果不加目錄就是拉取到當前目錄,實際上,默認情況下 git clone 命令本質上就是自動創建了本地的 master 分支用於跟蹤遠程倉庫中的 master 分支

  • git status 查看文件狀態,很常用,因爲要根據文件的狀態判斷應該執行具體的git命令

  • git add 跟蹤文件、暫存文件 git add -i參數可以交互式暫存操作參考

  • git checkout – fileName 拋棄文件修改,這條命令有些危險,所有對文件的修改都沒有了,所以在用這條命令前,請務必確定真的不再需要保留剛纔的修改, 如果只是想回退版本,同時保留剛纔的修改以便將來繼續工作,可以用stashing 和分支來處理,應該會更好些,參考git stash命令,任何已經提交到 Git 的都可以被恢復。即便在已經刪除的分支中的提交,或者用–amend 重新改寫的提交 ,都可以被恢復所以,你可能失去的數據,僅限於沒有提交過的,因爲對 Git 來說它們就像從未存在過一樣,Git沒有管理他們所以就有丟失的風險

  • git rm 必須要從已跟蹤文件清單中移除, 未跟蹤的文件git根本就沒有納入管理,所以就不存在使用git rm能操作未跟蹤的文件,如果是-f參數就會刪除文件【慎用】,–cached參數文件不會刪除但會取消跟蹤,如果手動刪除文件後,還需要執行git rm filename

  • git reset 將已暫存的取消暫存,在 “Changes to be committed” 下面,括號中有提示,可以使用 git reset HEAD <file>… 的方式取消暫存

  • git commit 提交,加上 -a 選項,Git 就會自動把所有已經跟蹤過的文件暫存起來一併提交,從而跳過 git add 步驟,或者撤銷提交 參考官網

    • 有時候我們提交完了才發現漏掉了幾個文件沒有加,或者提交信息寫錯了。想要撤消剛纔的提交操作,可以使用 --amend 選項重新提交 git commit --amend
  • git log 查看提交日誌, -p 選項展開顯示每次提交的內容差異,用 -2 則僅顯示最近的兩次更新 官網參考
    一些定製配置:
    + git log --graph --pretty=format:"%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr)%Creset" --abbrev-commit --date=relative

      + git log --pretty=format:"%h %ad | %s%d [%an]" --graph --date=short
      
      + 查看當前目錄每個文件的最後提交者。
      git ls-tree -r --name-only HEAD | while read filename; do
        echo "$(git log -1 --format="%an %ae" -- $filename) $filename"
      done
      
      + git log --no-merges --color --stat --graph --date=format:"%Y-%m-%d %H:%M:%S" --pretty=format:"%Cred%h%Creset -%C(yellow)%d%Cblue %s %Cgreen(%cd) %C(bold blue)<%an>%Creset" --abbrev-commit
      
      + git log --no-merges --color --graph --date=format:"%Y-%m-%d %H:%M:%S" --pretty=format:"%Cred%h%Creset -%C(yellow)%d%Cblue %s %Cgreen(%cd) %C(bold blue)<%an>%Creset" --abbrev-commit
      
      + git log --no-merges --color --stat --date=format:"%Y-%m-%d %H:%M:%S" --author="llb" --pretty=format:"%Cred%h%Creset -%C(yellow)%d%Cblue %s %Cgreen(%cd) %C(bold blue)<%an>%Creset" --abbrev-commit
      
      + git log --graph --pretty=format:"%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset" --abbrev-commit  
      
      + git log --pretty=format:"%C(auto)%h %C(magenta)<%cd> %C(green)[%an] %C(green bold)<%ce> %C(blue normal bold)| %Creset%s%C(auto)%d" --graph --date=short
    
	%H: commit hash
	%h: 縮短的commit hash
	%T: tree hash
	%t: 縮短的 tree hash
	%P: parent hashes
	%p: 縮短的 parent hashes
	%an: 作者名字
	%aN: mailmap的作者名字 (.mailmap對應,詳情參照git-shortlog(1)或者git-blame(1))
	%ae: 作者郵箱
	%aE: 作者郵箱 (.mailmap對應,詳情參照git-shortlog(1)或者git-blame(1))
	%ad: 日期 (--date= 制定的格式)
	%aD: 日期, RFC2822格式
	%ar: 日期, 相對格式(1 day ago)
	%at: 日期, UNIX timestamp
	%ai: 日期, ISO 8601 格式
	%cn: 提交者名字
	%cN: 提交者名字 (.mailmap對應,詳情參照git-shortlog(1)或者git-blame(1))
	%ce: 提交者 email
	%cE: 提交者 email (.mailmap對應,詳情參照git-shortlog(1)或者git-blame(1))
	%cd: 提交日期 (--date= 制定的格式)
	%cD: 提交日期, RFC2822格式
	%cr: 提交日期, 相對格式(1 day ago)
	%ct: 提交日期, UNIX timestamp
	%ci: 提交日期, ISO 8601 格式
	%d: ref名稱
	%e: encoding
	%s: commit信息標題
	%f: sanitized subject line, suitable for a filename
	%b: commit信息內容
	%N: commit notes
	%gD: reflog selector, e.g., refs/stash@{1}
	%gd: shortened reflog selector, e.g., stash@{1}
	%gs: reflog subject
	%Cred: 切換到紅色
	%Cgreen: 切換到綠色
	%Cblue: 切換到藍色
	%Creset: 重設顏色
	%C(...): 制定顏色, as described in color.branch.* config option
	%m: left, right or boundary mark
	%n: 換行
	%%: a raw %
	%x00: print a byte from a hex code
	%w([[,[,]]]): switch line wrapping, like the -w option of git-shortlog(1).
  • git diff 查看具體修改了什麼地方, 有一些需要注意的地方,自行查看官網說明

  • git mv 對文件改名,不過有時候用其他工具批處理改名的話,比如手動改名,要記得在提交前刪除老的文件名,再添加新的文件名,即刪除原名字文件,在跟蹤新文件名的文件,git rm olFileName 然後 git add newFileName

    • 運行 git mv 就相當於運行了下面三條命令:

      1. mv README.txt README
      2. git rm README.txt
      3. git add README
    • 關於mv的一個日誌輸出問題:

	G:\GitStudy (master)      
		$: git mv Test.java My.java
		
	G:\GitStudy (master)
		$: git status
	On branch master
	Changes to be committed:
	  (use "git reset HEAD <file>..." to unstage)
	           renamed:    Test.java -> My.java 改名後這裏顯示正確
	  		   new file:   he.txt
	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:   My.java

	G:\GitStudy (master)
		$: git add My.java

	G:\GitStudy (master)
		$: git status
	On branch master
	Changes to be committed:
	  (use "git reset HEAD <file>..." to unstage)
	       new file:   My.java
	   	   renamed:    Test.java -> he.txt 注意這裏,上面跟蹤修改後的My.java文件後,日誌就變成上面這樣了,顯示Test.java重命名爲he.txt了,可能是git的一個bug

:如果在操作是出現如下警告
warning: LF will be replaced by CRLF in Test.java   
參考1  
參考2

  • git remote [-v] 查看當前配置有哪些遠程倉庫,在克隆完某個項目後,至少可以看到一個名爲 origin 的遠程庫,Git 默認使用這個名字來標識你所克隆的原始倉庫 參考官網

    • git remote add [shortname] [url] 添加一個新的遠程倉庫,可以指定一個簡單的名字,以便將來引用
    • git remote show [remote-name] 查看某個遠程倉庫的詳細信息,如: git remote show origin
    • git remote rename oldName newName 修改某個遠程倉庫在本地的簡稱,注意,對遠程倉庫的重命名,也會使對應的分支名稱發生變化
    • git remote rm [shortname] 碰到遠端倉庫服務器遷移,或者原來的克隆鏡像不再使用,又或者某個參與者不再貢獻代碼,那麼需要移除對應的遠端倉庫
  • git fetch [remote-name] 從遠程倉庫抓取數據到本地,此命令會到遠程倉庫中拉取所有你本地倉庫中還沒有的數據,如果是克隆了一個倉庫,此命令會自動將遠程倉庫歸於 origin 名下,需要記住,fetch 命令只是將遠端的數據拉到本地倉庫,並不自動合併到當前工作分支,要更新所有分支直接git fetch

  • git merge 合併

  • git pull 自動抓取數據下來,然後將遠端分支自動合併到本地倉庫中當前分支,它等價於git fetch + git merge

  • git push [remote-name] [branch-name] 將本地倉庫中的數據推送到遠程倉庫, 如果要把本地的 master 分支推送到 origin 服務器上(再次說明下,克隆操作會自動使用默認的 master 和 origin 名字) git push origin master. 只有在所克隆的服務器上有寫權限,或者同一時刻沒有其他人在推數據,這條命令纔會如期完成任務。如果在你推數據前,已經有其他人推送了若干更新,那你的推送操作就會被駁回。你必須先把他們的更新抓取到本地,合併到自己的項目中,然後纔可以再次推送,也就是如果本地有修改需要先拉再推【即先pull,在push,一般在項目中就是這麼用】

  • git tag 列出現有標籤 參考官網

    • git tag -l ‘v1.4.2.*’ 用特定的搜索模式列出符合條件的標籤
    • git tag -a|-s 新建標籤,不同參數標籤不痛,具體遇到再查

忽略一些文件

參考官網

添加不需要提交的文件【即要忽略的文件】 :在.git的同級目錄下新建一個名爲.gitignore的文件,然後在文件中添加要忽略的文件或者目錄,可以使用*號通配符及一些匹配規則來忽略文件.

文件 .gitignore 的格式規範如下:
1. 所有空行或者以註釋符號 # 開頭的行都會被 Git 忽略。
2. 可以使用標準的 glob 模式匹配。
3. 匹配模式最後跟反斜槓(/)說明要忽略的是目錄。
4. 要忽略指定模式以外的文件或目錄,可以在模式前加上驚歎號(!)取反。

例如:

  • 要忽略所有的.class文件,那麼就可以使用 *.class,

  • *.[oa] 忽略所有以 .o 或 .a 結尾的文件

  • *~ 忽略所有以波浪符(~)結尾的文件

  • 更多例子:

    \# 此爲註釋 – 將被 Git 忽略
    
    • # 忽略所有 .a 結尾的文件

      *.a

    • # 但 lib.a 除外

      !lib.a

    • # 僅僅忽略項目根目錄下的 TODO 文件,不包括 subdir/TODO

      /TODO

    • # 忽略 build/ 目錄下的所有文件

      build/

    • # 會忽略 doc/notes.txt 但不包括 doc/server/arch.txt

      doc/*.txt

    • # 忽略 doc/ 目錄下所有擴展名爲 txt 的文件

      doc/**/*.txt

Git使用技巧

參考官網

  • 自動補全腳本, 不及可以提示命令,還可以提示可選參數,需要執行一些操作,官網自行參考,Windows上默認好像就有提示
  • 給字符長的命令起別名,用 git config 爲命令設置別名, 如:git config --global alias.co checkout co以後就可以代替checkout使用了這種技術還可以創造出新的命令,比方說取消暫存文件時的輸入比較繁瑣, 如: git config --global alias.unstage ‘reset HEAD --’, 這樣一來,下面的兩條命令完全等同:git unstage fileA 和 git reset HEAD fileA;顯然,使用別名的方式看起來更清楚。另外,我們還經常設置 last 命令:git config --global alias.last ‘log -1 HEAD’ ,來看最後一次的提交信息

分支模型【重要】

參考官網
Git 鼓勵在工作流程中頻繁使用分支與合併,理解分支的概念並熟練運用後,你纔會意識到爲什麼 Git 是一個如此強大而獨特的工具,並從此真正改變你的開發方式, Git 保存的不是文件差異或者變化量,而只是一系列文件快照

  • git branch 查看所有分支【前面有*號的就是當前分支,實際在命令行,文件路徑末尾也會顯示當前的工作分支是哪一個】或者創建一個新的分支, 但不會自動切換到這個分支中去,這會在當前 commit 對象上新建一個分支指針

  • git checkout 要切換到其他分支

  • git merge 在當前分支合併指定的其他分支

    實際工作中大體也會用到這樣的工作流程:
    1. 開發某個網站。
    2. 爲實現某個新的需求,創建一個分支。
    3. 在這個分支上開展工作。

    假設此時,你突然接到一個電話說有個很嚴重的問題需要緊急修補,那麼可以按照下面的方式處理:

    1. 返回到原先已經發布到生產服務器上的分支。
    2. 爲這次緊急修補建立一個新分支,並在其中修復問題。
    3. 通過測試後,回到生產服務器所在的分支,將修補分支合併進來,然後再推送到生產服務器上。
    4. 切換到之前實現新需求的分支,繼續工作。

首先,我們假設你正在項目中愉快地工作,並且已經提交了幾次更新

現在,你決定要修補問題追蹤系統上的 #53 問題 。這裏爲了說明要解決的問題,才把新建的分支取名爲 iss53[這裏這個分支是保留53問題解決之前的一個分支]。要新建並切換到該分支,運行 git checkout 並加上 -b 參數:

  1. git checkout -b iss53 這相當於執行下面這兩條命令:git branch iss53 和 git checkout iss53
    :切換分支之前,留心你當前分支的暫存區或者工作目錄裏,那些還沒有提交的修改,它會和你即將檢出的分支產生衝突從而阻止 Git 爲你切換分支。切換分支的時候最好保持一個清潔的工作區域,解決方法是:稍後會介紹幾個繞過這種問題的辦法(分別叫做 stashing 和 commit amending)

    接着開始修復問題,完成後提交【假設我們有個index.html文件,裏面的就是 #53 bug存在的文件】

  2. git commit -m "added a new footer [issue 53]"

  3. 目前已經提交了所有的修改,所以接下來可以正常轉換到 master 分支: git checkout master
    此時工作目錄中的內容和你在解決問題 #53 之前一模一樣, 即在master分支上 #53 問題是沒有解決的,因爲解決是在iss53分支上操作的

  4. 接下來,你得進行緊急修補。我們創建一個緊急修補分支 hotfix 來開展工作
    git checkout -b hotfix
    修復問題,完成後提交【index.html文件中】

  5. 然後回到 master 分支並把它合併進來,然後發佈到生產服務器
    git checkout master
    git merge hotfix

  6. 在那個超級重要的修補發佈以後,你想要回到被打擾之前的工作。由於當前 hotfix 分支和 master 都指向相同的提交對象,所以 hotfix 已經完成了歷史使命,可以刪掉了
    使用 git branch 的 -d 選項執行刪除操作: git branch -d hotfix

  7. 現在回到之前未完成的 #53 問題修復分支上繼續工作: git checkout iss53
    : 值得注意的是之前 hotfix 分支的修改內容尚未包含到 iss53 中來【也就是各個分支直接的操作是互不影響的,彼此隔離,但是他們又有內在的關係,即來自同一個祖先分支master】。如果需要納入此次修補,可以用 git merge master 把 master 分支合併到 iss53;或者等 iss53 完成之後,再將 iss53 分支中的更新併入 master

  8. 在問題 #53 相關的工作完成之後,可以合併回 master 分支
    git checkout master
    git merge iss53

  9. 既然之前的工作成果已經合併到 master 了,那麼 iss53 也就沒用了。你可以就此刪除它
    git branch -d iss53

遇到衝突時的分支合併

參考官網

有時候合併操作並不會如此順利。如果在不同的分支中都修改了同一個文件的同一部分,Git 就無法乾淨地把兩者合到一起(譯註:邏輯上說,這種問題只能由人來裁決。)即需要人工解決衝突

merge是發生衝突時的日誌輸出
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.

Git 作了合併,但沒有提交,它會停下來等你解決衝突。要看看哪些文件在合併時發生衝突,可以用 git status 查閱:

$ git status
On branch master
You have unmerged paths.
  (fix conflicts and run "git commit")

Unmerged paths:
  (use "git add <file>..." to mark resolution)

        both modified:      index.html

no changes added to commit (use "git add" and/or "git commit -a")

任何包含未解決衝突的文件都會以未合併(unmerged)的狀態列出。Git 會在有衝突的文件里加入標準的衝突解決標記,可以通過它們來手工定位並解決這些衝突。可以看到此文件包含類似下面這樣的部分:

<<<<<<< HEAD
<div id="footer">contact : [email protected]</div>
=======
<div id="footer">
  please contact us at [email protected]
</div>
>>>>>>> iss53

可以看到 ======= 隔開的上半部分,是 HEAD(即 master 分支,在運行 merge 命令時所切換到的分支)中的內容,下半部分是在 iss53 分支中的內容。解決衝突的辦法無非是二者選其一或者由你親自整合到一起。比如你可以通過把這段內容替換爲下面這樣來解決:

<div id="footer">
	please contact us at [email protected]
</div>

這個解決方案各採納了兩個分支中的一部分內容,而且還需刪除了 <<<<<<<=======>>>>>>> 這些行。在解決了所有文件裏的所有衝突後,運行 git add 將把它們標記爲已解決狀態【git add的另外的一個功能】(譯註:實際上就是來一次快照保存到暫存區域。)。因爲一旦暫存,就表示衝突已經解決

如果覺得滿意了,並且確認所有衝突都已解決,也就是進入了暫存區,就可以用 git commit 來完成這次合併提交

分支管理

參考官網

  • git branch 命令不僅僅能創建和刪除分支,如果不加任何參數,它會給出當前所有分支的清單, git branch -r/-a 查看遠程分支、本地遠程所有的分支
  • 若要查看各個分支最後一個提交對象的信息,運行 git branch -v
  • 要從該清單中篩選出你已經(或尚未)與當前分支合併的分支,可以用 --merged【已被併入當前分支】 和 --no-merged【查看尚未合併的工作】 選項,比如用 git branch --merged 查看哪些分支已被併入當前分支(譯註:也就是說哪些分支是當前分支的直接上游。)
  • 分支中如果還包含着尚未合併進來的工作成果,直接簡單地用 git branch -d 刪除該分支會提示錯誤,因爲那樣做會丟失數據

利用分支進行開發的工作流程

參考官網本章
長期分支
可以同時擁有多個開放的分支,每個分支用於完成特定的任務,隨着開發的推進,你可以隨時把某個特性分支的成果併到其他分支中

​ 使用 Git 的開發者都喜歡用這種方式來開展工作,比如僅在 master 分支中保留完全穩定的代碼,即已經發布或即將發佈的代碼。與此同時,他們還有一個名爲 develop 或 next 的平行分支,專門用於後續的開發,或僅用於穩定性測試 — 當然並不是說一定要絕對穩定,不過一旦進入某種穩定狀態,便可以把它合併到 master 裏。這樣,在確保這些已完成的特性分支(短期分支,比如之前的 iss53 分支)能夠通過所有測試,並且不會引入更多錯誤之後,就可以併到主幹分支中,等待下一次的發佈【穩定分支總是比較老舊】

特性分支
在任何規模的項目中都可以使用特性(Topic)分支。一個特性分支是指一個短期的,用來實現單一特性或與其相關工作的分支

​ 上節的例子裏已經見過這種用法了。我們創建了 iss53 和 hotfix 這兩個特性分支,在提交了若干更新後,把它們合併到主幹分支,然後刪除。該技術允許你迅速且完全的進行語境切換 — 因爲你的工作分散在不同的流水線裏,每個分支裏的改變都和它的目標特性相關,瀏覽代碼之類的事情因而變得更簡單了。你可以把作出的改變保持在特性分支中幾分鐘,幾天甚至幾個月,等它們成熟以後再合併,而不用在乎它們建立的順序或者進度。

遠程分支【重要】

參考官網本章

遠程分支(remote branch)是本地對遠程倉庫中的分支的索引, 我們用 (遠程倉庫名)/(分支名) 這樣的形式表示遠程分支

比如我們想看看上次同 origin 倉庫通訊時 master 分支的樣子,就應該查看 origin/master 分支。如果你和同伴一起修復某個問題,但他們先推送了一個 iss53 分支到遠程倉庫,雖然你可能也有一個本地的 iss53 分支,但指向服務器上最新更新的卻應該是 origin/iss53 分支

舉例說明。假設你們團隊有個地址爲 git.ourcompany.com 的 Git 服務器。如果你從這裏克隆,Git 會自動爲你將此遠程倉庫命名爲 origin,並下載其中所有的數據,建立一個指向它的 master 分支的指針,在本地命名爲 origin/master,但你無法在本地更改其數據。接着,Git 建立一個屬於你自己的本地 master 分支,始於 origin 上 master 分支[遠程分支]相同的位置,你可以就此開始工作
在這裏插入圖片描述
如果你在本地 master 分支做了些改動,與此同時,其他人向 git.ourcompany.com 推送了他們的更新,那麼服務器上的 master 分支就會向前推進,而與此同時,你在本地的提交歷史正朝向不同方向發展。不過只要你不和服務器通訊,你的 origin/master 指針仍然保持原位不會移動
在這裏插入圖片描述
可以運行 git fetch origin 來同步遠程服務器上的數據到本地。該命令首先找到 origin 是哪個服務器(本例爲 git.ourcompany.com),從上面獲取你尚未擁有的數據,更新你本地的數據庫,然後把 origin/master 的指針移到它最新的位置上
在這裏插入圖片描述

爲了演示擁有多個遠程分支(在不同的遠程服務器上)的項目是如何工作的,我們假設你還有另一個僅供你的敏捷開發小組使用的內部服務器 git.team1.ourcompany.com。可以用 git remote add 命令把它加爲當前項目的遠程分支之一。我們把它命名爲 teamone,以便代替完整的 Git URL 以方便使用
在這裏插入圖片描述
現在你可以用 git fetch teamone 來獲取小組服務器上你還沒有的數據了。由於當前該服務器上的內容是你 origin 服務器上的子集,Git 不會下載任何數據,而只是簡單地創建一個名爲 teamone/master 的遠程分支,指向 teamone 服務器上 master 分支所在的提交對象 31b8e
在這裏插入圖片描述
要想和其他人分享某個本地分支,你需要把它推送到一個你擁有寫權限的遠程倉庫。你創建的本地分支不會因爲你的寫入操作而被自動同步到你引入的遠程服務器上,你需要明確地執行推送分支的操作。換句話說,對於不想分享的分支,你儘管保留爲私人分支好了,而只推送那些協同工作要用到的特性分支。

舉例:如果你有個叫 serverfix 的分支需要和他人一起開發,可以運行 git push (遠程倉庫名) (分支名): git push origin serverfix

也可以運行 git push origin serverfix:serverfix 來實現相同的效果,它的意思是 上傳我本地的 serverfix 分支到遠程倉庫中去,仍舊稱它爲 serverfix 分支”。通過此語法,你可以把本地分支推送到某個命名不同的遠程分支:若想把遠程分支叫作 awesomebranch,可以用 git push origin serverfix:awesomebranch 來推送數據

從遠程分支 checkout 出來的本地分支,稱爲 跟蹤分支 (tracking branch)。跟蹤分支是一種和某個遠程分支有直接聯繫的本地分支。在跟蹤分支裏輸入 git push,Git 會自行推斷應該向哪個服務器的哪個分支推送數據。同樣,在這些分支裏運行 git pull 會獲取所有遠程索引,並把它們的數據都合併到本地分支中來

在克隆倉庫時,Git 通常會自動創建一個名爲 master 的分支來跟蹤 origin/master。這正是 git push 和 git pull 一開始就能正常工作的原因。當然,你可以隨心所欲地設定爲其它跟蹤分支,比如 origin 上除了 master 之外的其它分支。剛纔我們已經看到了這樣的一個例子:git checkout -b [分支名] [遠程名]/[分支名] 還可以用 --track 選項簡化: git checkout --track origin/serverfix
要爲本地分支設定不同於遠程分支的名字,只需在第一個版本的命令裏換個名字: git checkout -b sf origin/serverfix

如果不再需要某個遠程分支了,比如搞定了某個特性並把它合併進了遠程的 master 分支(或任何其他存放穩定代碼的分支),可以用這個非常無厘頭的語法來刪除它:git push [遠程名] :[分支名]。如果想在服務器上刪除 serverfix 分支,運行下面的命令: git push origin :serverfix

分支的變基

官網本章參考V2

把一個分支中的修改整合到另一個分支的辦法有兩種:merge 和 rebase

回顧之前有關合並見下圖,你會看到開發進程分叉到兩個不同分支,又各自提交了更新
在這裏插入圖片描述
最容易的整合分支的方法是 merge 命令,它會把兩個分支最新的快照(C3 和 C4)以及二者最新的共同祖先(C2)進行三方合併,合併的結果是產生一個新的提交對象(C5)
在這裏插入圖片描述

其實,還有另外一個選擇:你可以把在 C3 裏產生的變化補丁在 C4 的基礎上重新打一遍。在 Git 裏,這種操作叫做變基(rebase)。有了 rebase 命令,就可以把在一個分支裏提交的改變移到另一個分支裏重放一遍。

在上面這個例子中,運行:
git checkout experiment
git rebase master

它的原理是回到兩個分支最近的共同祖先,根據當前分支(也就是要進行變基的分支 experiment)後續的歷次提交對象(這裏只有一個 C3),生成一系列文件補丁,然後以基底分支(也就是主幹分支 master)最後一個提交對象(C4)爲新的出發點,逐個應用之前準備好的補丁文件,最後會生成一個新的合併提交對象(C3’),從而改寫 experiment 的提交歷史,使它成爲 master 分支的直接下游
在這裏插入圖片描述

現在回到 master 分支,進行一次快進合併

在這裏插入圖片描述
變基能產生一個更爲整潔的提交歷史, 一般我們使用變基的目的,是想要得到一個能在遠程分支上乾淨應用的補丁 — 比如某些項目你不是維護者,但想幫點忙的話,最好用變基:先在自己的一個分支裏進行開發,當準備向主項目提交補丁的時候,根據最新的 origin/master 進行一次變基操作然後再提交,這樣維護者就不需要做任何整合工作(譯註:實際上是把解決分支補丁同最新主幹代碼之間衝突的責任,化轉爲由提交補丁的人來解決。),只需根據你提供的倉庫地址作一次快進合併,或者直接採納你提交的補丁,請注意,合併結果中最後一次提交所指向的快照,無論是通過變基,還是三方合併,都會得到相同的快照內容,只不過提交歷史不同罷了。變基是按照每行的修改次序重演一遍修改,而合併是把最終結果合在一起

變基舉例:
變基也可以放到其他分支進行,並不一定非得根據分化之前的分支。以圖 3-31 的歷史爲例,我們爲了給服務器端代碼添加一些功能而創建了特性分支 server,然後提交 C3 和 C4。然後又從 C3 的地方再增加一個 client 分支來對客戶端代碼進行一些相應修改,所以提交了 C8 和 C9。最後,又回到 server 分支提交了 C10
在這裏插入圖片描述

假設在接下來的一次軟件發佈中,我們決定先把客戶端的修改併到主線中,而暫緩併入服務端軟件的修改(因爲還需要進一步測試)。這個時候,我們就可以把基於 client 分支而非 server 分支的改變(即 C8 和 C9),跳過 server 直接放到 master 分支中重演一遍,但這需要用 git rebase 的 --onto 選項指定新的基底分支 master: git rebase --onto master server client

這好比在說:“取出 client 分支,找出 client 分支和 server 分支的共同祖先之後的變化,然後把它們在 master 上重演一遍”。是不是有點複雜?不過它的結果如圖 3-32 所示,非常酷(譯註:雖然 client 裏的 C8, C9 在 C3 之後,但這僅表明時間上的先後,而非在 C3 修改的基礎上進一步改動,因爲 server 和 client 這兩個分支對應的代碼應該是兩套文件,雖然這麼說不是很嚴格,但應理解爲在 C3 時間點之後,對另外的文件所做的 C8,C9 修改,放到主幹重演。):
在這裏插入圖片描述
現在可以快進 master 分支了
git checkout master
git merge client

在這裏插入圖片描述

現在我們決定把 server 分支的變化也包含進來。我們可以直接把 server 分支變基到 master,而不用手工切換到 server 分支後再執行變基操作 — git rebase [主分支] [特性分支] 命令會先取出特性分支 server,然後在主分支 master 上重演:git rebase master server

於是,server 的進度應用到 master 的基礎上
在這裏插入圖片描述
然後就可以快進主幹分支 master 了
git checkout master
git merge server

現在 client 和 server 分支的變化都已經集成到主幹分支來了,可以刪掉它們了。最終我們的提交歷史會變成圖 3-35 的樣子:
git branch -d client
git branch -d server
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-KsVxaiu0-1590383520934)(https://git-scm.com/book/en/v2/images/interesting-rebase-5.png "最終的提交歷史")]

變基的風險
用它得遵守一條準則:一旦分支中的提交對象發佈到公共倉庫,就千萬不要對該分支進行變基操作[即不要對在你的倉庫外有副本的分支執行變基]

變基操作的實質是丟棄一些現有的提交,然後相應地新建一些內容一樣但實際上不同的提交。 如果你已經將提交推送至某個倉庫,而其他人也已經從該倉庫拉取提交併進行了後續工作,此時,如果你用 git rebase 命令重新整理了提交併再次推送,你的同伴因此將不得不再次將他們手頭的工作與你的提交進行整合,接下來你還要拉取並整合他們修改過的提交,事情就會變得一團糟

  • git stash 經常有這樣的事情發生,當你正在進行項目中某一部分的工作,裏面的東西處於一個比較雜亂的狀態,而你想轉到其他分支上進行一些工作。問題是,你不想提交進行了一半的工作,否則以後你無法回到這個工作點。解決這個問題的辦法就是git stash命令,git stash list現有的儲藏,git stash save “comment”

git stash apply 應用儲藏,如果你想應用更早的儲藏,你可以通過名字指定它,像這樣:git stash apply stash@{2}。如果你不指明,Git 默認使用最近的儲藏並嘗試應用它,運行 git stash drop,加上你希望移除的儲藏的名字,取消之前所應用儲藏git stash show -p stash@{0} | git apply -R
,同樣的,如果你沒有指定具體的某個儲藏,Git 會選擇最近的儲藏git stash show -p | git apply -R
新建一個別名,在你的 Git 裏增加一個 stash-unapply 命令,這樣更有效率git config --global alias.stash-unapply '!git stash show -p | git apply -R’

  • git clean 對於工作目錄中一些工作或文件,你想做的也許不是儲藏而是移除

  • git grep 從提交歷史或者工作目錄中查找一個字符串或者正則表達式

一般的工作中的Git操作流程博客參考

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