1. 程式人生 > >Git基礎常用功能

Git基礎常用功能

一、安裝

具體檢視 安裝Git

 

二、使用

基礎知識

  • 工作區(Workspace):就是你在電腦裡能看到的專案目錄。
  • 暫存區(Index / Stage):臨時存放更改的地方,使用命令"git add <.|file>"就是把檔案加入暫存區。一般存放在 ".git目錄下" 下的index檔案(.git/index)中,所以我們把暫存區有時也叫作索引(index)。
  • 版本庫(Repository):管理版本的檔案,使用"git commit -m 'description'"就是把暫存區的檔案提交到版本庫。工作區有一個隱藏目錄.git,這個不算工作區,而是Git的版本庫。
  • 遠端倉庫(Remote):託管程式碼的伺服器。可以簡單的認為是你專案組中的一臺電腦用於遠端資料交換

一張圖描述git的檔案如何在各個區域之前流轉:

origin:遠端倉庫庫預設別名

master:  倉庫預設分支的名稱  

本地專案初始化/和遠端倉庫操作

git init,把當前資料夾初始化位git工程 git remote add [<options>] <name> <url>  把當前資料夾關聯遠端倉庫並命名,比如git remote add origin git@server-name:path/repo-name.git; git remote -v 檢視遠端倉庫地址 git push <遠端主機名> <本地分支名>  <遠端分支名>,比如 git push origin dev dev git push -u origin master 如果當前分支與多個主機存在追蹤關係,則可以使用 -u 引數指定一個預設主機,這樣後面就可以不加任何引數使用git push  

基本操作:新增/提交/檢視記錄

"git add ."或者"git add <file>",將所有檔案或指定檔案從工作區新增到暫存區 git commit -m "description",將暫存區的所有檔案提交到版本庫 git show <commitId> <filename> :檢視提交詳情 git status,檢視當前工作區和暫存區的檔案狀態 git diff,檢視當前工作區對比暫存區的更改 git diff HEAD -- readme.txt命令可以檢視工作區和版本庫裡面最新版本的區別 “git log”或"git log <file>",檢視版本庫或者指定檔案的提交記錄 git log --graph命令可以看到分支合併圖。 git log --pretty=oneline --graph --abbrev-commit展示效果如下

 git cherry-pick <commitId>,複製一個特定的提交到當前分支,比如master分支的bug修復提交複製到dev分支

若要合併某個分支上的一系列提交,這種情況就cherry-pick就不適用了。 需要使用rebase指令進行合併操作 具體操作步驟: // 以**最後一次提交**為節點, 建立一個新的分支<newbranch 是新分支的名字> 1. git checkout -b newbranch 最後一次提交的id // 再 rebase 這個新分支的commit到目標分支上<--onto 目標分支>。<start_id> 指明你想從哪個特定的commit開始。 2. git rebase --onto 目標分支 start_id  

倉庫分支管理

檢視分支:git branch 建立分支:git branch <name> 切換分支:git checkout <name>或者git switch <name> 建立+切換分支:git checkout -b <name>或者git switch -c <name> 比如git checkout -b dev,切換並建立dev分支,相當於 $ git branch dev $ git checkout dev 合併某分支到當前分支:git merge <name> 正常合併如果能用fast-forward就會使用, 但這種模式下,刪除分支後,會丟掉分支資訊。可以使用--no-ff強制禁用ff模式 git merge --no-ff -m "merge with no-ff" dev 因為本次合併要建立一個新的commit,所以加上-m引數,把commit描述寫進去。 刪除分支:git branch -d <name>  

程式碼回退

看上面的幾個區域的圖基本就能明白

 "git reset HEAD" 或者"git reset HEAD <file>"命令,暫存區的目錄樹或檔案會被重寫,被 master 分支指向的目錄樹或檔案所替換,但是工作區不受影響。

git reset --hard HEAD^/git reset --hard 1094a,強制回退上一個版本/回退到指定版本號的版本,版本庫會直接回退(遠端倉庫不會回退),需要特別謹慎。版本號沒必要寫全,前幾位就可以了,Git會自動去找。當然也不能只寫前一兩位,因為Git可能會找到多個版本號,就無法確定是哪一個了

 "git rm --cached <file>" 命令,會直接從暫存區刪除檔案,工作區則不做出改變。

 "git checkout ." 或者 "git checkout -- <file>" 命令,會用暫存區全部或指定的檔案替換工作區的檔案。這個操作很危險,會清除工作區中未新增到暫存區的改動。

"git checkout HEAD ." 或者 "git checkout HEAD <file>" 命令時,會用 HEAD 指向的 master 分支中的全部或者部分檔案替換暫存區和以及工作區中的檔案。這個命令也是極具危險性的,因為不但會清除工作區中未提交的改動,也會清除暫存區中未提交的改動。

“git revert HEAD/git revert commitID”: 放棄已經push的指定版本的修改,會新增一條記錄,版本會遞增 "git reflog" , 用來檢視你的每一條命令,用來配合上面的命令恢復你的誤操作   例1:將單個檔案(a.js)回退到某一版本
  1. git  log a.js檢視a.js的更改記錄
  2. git reset   fcd2093  a.js 先將暫存區中的該檔案回退到歷史版本fcd2093
  3. git checkout -- a.js 暫存區中該檔案的歷史版本(fcd2093)覆蓋工作區中對應的檔案,此時(工作區、暫存區的檔案a.js是fcd2093版本)。
【注】git reset [選項]  [版本號]  [回退物件]命令,當回退物件是檔案時選項不能為hard 【注】2、3步可以合併成一步git checkout fcd2093 a.js 此時,如果git commit 提交暫存區的資料到版本庫,則會重新生成一條記錄   例2:將整個專案(遠端倉庫和本地倉庫當前版本一致)回退到某個版本,並push到遠端倉庫,讓遠端倉庫也回退。   例如,版本庫最新的幾條提交記錄是:aaaa -> bbbb -> cccc;cccc是最新的提交記錄,要回退到aaaa並push
  1. git reset --hard aaaa 強制將版本庫回退到aaaa,但是遠端倉庫還是cccc
  2. git reset cccc 將head移到最新的版本(和遠端的head保持一致,實際就是將遠端暫存區的內容更新到最新版本cccc,工作區的內容還是保持在aaaa),此時aaaa和cccc的差異便作為本次更改的內容。
  3. git add / git commit / git push 提交後生成新的版本號dddd

此時git log 看到的最近的提交記錄就是:aaaa -> bbbb -> cccc -> dddd

【注】也可以使用git revert cccc 和 git revert bbbb來實現,不過會新增兩條回滾記錄

 

保留半成品現場(儲存臨時現場)

主要用在目前還不想提交的但是已經修改的內容進行儲存至堆疊中,後續可以在某個分支上恢復出堆疊中的內容 git stash 儲存臨時現場 git stash list 檢視工作臨時現場 一是用git stash apply恢復,但是恢復後,stash內容並不刪除,你需要用git stash drop來刪除; 另一種方式是用git stash pop,恢復的同時把stash內容也刪了 你可以多次stash,恢復的時候,先用git stash list檢視,然後恢復指定的stash,用命令: git stash apply stash@{0}    

子模組

有時工程太過龐大想要分出子工程單獨管理,或者納入一個子工程到當前工程來,就可能用到子模組功能。

git子模組配置處理(即git的B倉庫被作為A倉庫的子目錄),兩個倉庫可以各自管理和提交 git submodule add <path> <name>:將<path>對應的倉庫作為當前倉庫A的<name>子目錄 git status:在A中檢視發現多了<name>和 .gitmodules(這個檔案中是子模組的相關配置) git diff --cached <name>:在A中看到無法查詢子模組的提交記錄, 取而代之的是,Git 將它記錄成來自B倉庫的一個特殊的提交(這個提交在克隆的該專案時,進入子模組就是進入到這個提交) 例如,子模組B的名稱為subproject_demo:
$ git diff --cached subproject_demo
diff --git a/subproject_demo b/subproject_demo
new file mode 160000
index 0000000..aa1eeb0
--- /dev/null
+++ b/subproject_demo
@@ -0,0 +1 @@
+Subproject commit aa1eeb06e67608d7a2af179a7dfd9e594777e90f
git commit -m 'first commit with submodule xxx': 結果中注意 subproject_demo條目的 160000 模式。這在Git中是一個特殊模式,基本意思是你將一個提交記錄為一個目錄項而不是子目錄或者檔案。 當你使用clone克隆該專案(父工程A)時,會發現子模組的資料夾內容為空,需要做: git submodule init: 初始化你的本地配置檔案 git submodule update:從子模組B拉取所有資料並檢出你上層專案裡所列的合適的提交(保持子模組是最新的那個) 進入子模組,發現子模組是那個專案的 你先前提交的確切狀態的分支
chen_@DESKTOP-TJKEMKG MINGW64 /c/works/demo/subproject_demo  ((aa1eeb0...))
// 發現沒:aa1eeb0就是之前的哪個提交

如果你在專案中改了子模組的程式碼,準備提交到對應的分支(add和commit已經執行過),使用:

git push origin HEAD:<branch>   這樣就把程式碼提交到對應的分支 ,和 git push origin <localBranch> <remoteBranch>類似

如果其他人有修改這個子模組並提交到A工程,你可以重新pull A專案分支,然後執行git submodule update保證子模組也是最新的 git clone --recurse-submodules <repositary> ,他就會自動初始化並更新倉庫的每一個子模組   【注】使用時要注意,最好保證在父工程A中來自B的提交永遠來自同一個B的分支,比如master分支。所以B的分支程式碼更改完畢並測試完畢合併到master後,再在A提交來自B的master分支的提交

【注】引入私有git工程還可以又其他方式,比如和npm配合:《2018 年了,你還是隻會 npm install 嗎》檢視“私有 git 共享 package”部分

 

https和ssh使用

檢視連結:https://blog.csdn.net/qq_42108192/article/details/90168968

 

https模式下新增git賬號到專案,push不用每次輸入賬號密碼

開啟.git檔案的下的 vim .git/config新增以下內容

[user]
name = [email protected]
email = [email protected]
[credential]
helper=store

 

 

三、踩坑

[remote rejected]  (hook declined)

完整日誌:

$ git push
Enumerating objects: 25, done.
Counting objects: 100% (24/24), done.
Delta compression using up to 8 threads
Compressing objects: 100% (13/13), done.
Writing objects: 100% (13/13), 1.20 KiB | 1.20 MiB/s, done.
Total 13 (delta 11), reused 0 (delta 0)
remote: git: 'refs/heads/web2.0' is not a git command. See 'git --help'.
remote: error: hook declined to update refs/heads/web2.0
To https://e.coding.net/tops/front-www.git
 ! [remote rejected] web2.0 -> web2.0 (hook declined)
error: failed to push some refs to 'https://e.coding.net/tops/front-www.git'

百度檢視幫助,找到類似的問題:https://blog.csdn.net/weixin_39278265/article/details/102248258

本人的問題解決辦法

git config --global --unset branch.web2.0.merge

然後再push