該文檔中的git status中的提示語和新版本的不一樣,新版本中不再是git reset相關的命令,而是換成了git restore相關的命令
許多網上的資料對同一個問題會有多個解決方案,因為git的命令也在不斷的更新
SVN是集中式版本控制的代表,git是分布式版本控制的代表。
git中全是Linux命令
為什么需要版本控制?
個人開發需要不斷的改進和迭代,團隊內部需要協作,這樣的需求就由版本控制工具來滿足。
git相對于SVN有一個特點:團隊外的人也能貢獻代碼,git能對團隊外的人有一個審核的權限
集中式的版本控制工具有一個缺點:單點故障(如果管理倉庫的那臺電腦故障了,那所有的歷史數據就都丟失了,本地的電腦是不會保存歷史版本的信息的)
相對于分布式的版本控制工具:每一個本地電腦都有完整的歷史記錄,在本地就可以進行版本控制,很好的避免了單點故障
分布式版本控制工具相對于集中式版本控制工具一個非常突出的優點就是可以避免單點故障。
git的優勢
- 大部分及操作在本地完成,不需要聯網(git是分布式版本控制,在本地是有本地庫的,在本地就可以完成版本控制,這一點集中式版本控制就完全做不到,比如SVN,要是斷網了跟服務器連不到,你根本進行不了任何的版本控制操作)
- 完整性保證(他會對每次提交的數據進行hash的操作,只要hash只是不變的,那就能保證數據時不變的,比如從git版本庫中取出一個文件,那么你就可以拿hash對這個文件進行驗證,你對這個文件做的hash和版本庫中的hash進行對比,只要是一致的,那就說明這個文件沒問題)
- 盡可能添加數據,而不是刪除或修改數據(因為如果版本庫中的數據有刪除或者是修改了,那你就找不回來了。那“盡可能的天添加數據”,就可以避免不可逆的操作,每一次的提交都是一個新的記錄)
- 分支操作非常流暢(跟git管理文件的方式有很大的關系,他內部其實是以快照的方式進行管理的,分支其實是對不同快照的不同指針而已,我們創建或切換分支其實很大程度上就是創建和切換指針而已)
- 與linux命令全面兼容(Linux是對任何一個程序員必備的技能,在git bash here打開的git命令行窗口中就可以使用Linux命令)
git 和 代碼及托管中心的關系
代碼托管中心的任務:維護遠程庫
有多中代碼托管中心:
- 在局域網環境下
- gitlab服務器
- 外網環境下
- GitHub
- 碼云
git 命令操作
本地庫初始化
1.在已有的文件夾repository1下
git init
2.直接在某個文件夾(例如test文件夾)下
git init repository2
就會在test下建一個repository2的文件夾,內面會有.git 隱藏文件夾
效果:在執行這個命令的文件夾內會會出現一個.git隱藏文件夾,.git文件中存放的是本地庫相關的子目錄和文件,不要隨意改動。
設置簽名
作用:區分不同開發人員的身份
注意:設置的簽名和登錄遠程代碼中心的賬號和密碼沒有任何關系,你可以設置任意的user.name 和user.email(胡亂設置的email也可以)
有兩種:
- 項目級別(倉庫級別)
- 系統用戶級別
項目級別(倉庫級別)
僅在當前本地倉庫范圍內生效
git config user.name tom_pro
git config user.email tome_pro@qq.com
信息保存位置:./.git/config 文件
系統用戶級別
登錄當前操作系統的用戶范圍內
git config --global user.name tom_glb
git config --global user.email tom_glb@qq.com
信息保存位置:~/.gitconfig文件
注:~代表C盤用戶文件夾
級別優先級
- 就近原則:項目級別優先于系統級別,二者都有時采用項目級別的簽名
- 如果只有系統用戶級別的,就已系統用戶級別的簽名為準
- 二者都沒有時,不允許提交
基本操作
狀態查看
git status
添加
//提交指定文件
git add [file1 name]…… [filen name]
//提交當前文件夾內的所有文件
git add .
提交
git commit -m "commit msg" [file name]
pro.txt被commit過,然后修改Pro.txt(添加了一行bbb)后git status就會有上圖。
如果使用上圖提示的git restore pro.txt后,就會發現工作區的pro.txt文件新增的bbb那一行沒有了(需要重新打開那個文件)(restore是恢復的意思),所以該命令是恢復工作區的內容到沒有修改之前
git commit -a -m "提交的描述信息"
(-a 和 -m的順序不可顛倒)
git commit 命令的-a 選項可只將所有被修改或者已刪除的且已經被git管理的文檔提交倒倉庫中。如果只是修改或者刪除了已被Git 管理的文檔,是沒必要使用git add 命令的。
同時因為是直接添加到本地庫并沒有添加到暫存區,所以是不可以撤銷的,暫存區存在也是有意義的,意義就是,如果你修改添加到暫存區,如果后悔的話還可以撤回來。
git add .命令除了能夠判斷出當前目錄(包括其子目錄)所有被修改或者已刪除的文檔,還能判斷用戶所添加的新文檔,并將其信息追加到索引中。
查看歷史記錄
//查看詳細提交信息(有時一屏放不下:空格向下翻頁,b向上翻頁,q退出)
git log
//一行顯示
//如果HEAD指針往后退了,那就只能看到HEAD指針之后的版本記錄,
git log --pretty=oneline
//一行顯示
//如果HEAD指針往后退了,那就只能看到HEAD指針之后的版本記錄,
git log --oneline
//可以看到所有提交的歷史記錄
//查看記錄在本地的HEAD和分支引用在過去指向的位置
git reflog
HEAD@{移動到當前版本需要多少步}
前進后退(git reset)
本質:head 指針在不同版本之前切換
- 基于索引值操作 [推薦]
- git reset --hard [局部索引值]
- 知道索引值就可以自由的在所有版本之間進行任意切
- 使用^符號:只能后退
- git reset --hard HEAD^
- 注:一個^表示后退一步,n個表示后退n步
- 只有~符號:只能后退
- git reset --hard HEAD~n
- 注:表示后退n步
- 使用^或~或[局部索引值]執行后退操作后,還可以git reset --hard [局部索引值]進行前進(因為他可以在任意版本之前切換)
- 使用git reset --hard HEAD就是切換到當前指針指向的位置
reset 命令的三個參數對比
- --soft
僅在本地庫移動HEAD指針(例如,你正在工作區修改內容,在文件尾部加了一行3,你再使用--soft倒退版本,這個時候工作區的內容是沒有任何影響的,文件尾部還是有3的,疑問:現在暫存區有內容嗎?如果有,是什么)
- --mixed
在本地庫移動HEAD指針,重置暫存區
- --hard
在本地庫移動HEAD指針,重置暫存區,重置工作區
- 不設置默認是mixed
撤銷操作
- 從暫存區撤銷回工作區
(把文件添加到暫存區后查看git status時,會有這條命令的提示)
git reset HEAD [filename]
- 撤銷對文件的修改
如果你并不想保留對 CONTRIBUTING.md 文件的修改怎么辦? 你該如何方便地撤消修改——將它還原成上次提交時的樣子(或者剛克隆完的樣子,或者剛把它放入工作目錄時的樣子)? 幸運的是,git status 也告訴了你應該如何做。 在最后一個例子中,未暫存區域是這樣:
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: CONTRIBUTING.md
它非常清楚地告訴了你如何撤消之前所做的修改。 讓我們來按照提示執行:
$ git checkout -- CONTRIBUTING.md
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
renamed: README.md -> README
可能新版本的git做出了改變(提示語變的和參考手冊不一樣了,但是按照參考手冊的操作,工作區的文件確實回到了上一次提交的時候):
請務必記得 git checkout -- <file> 是一個危險的命令。 你對那個文件在本地的任何修改都會消失——Git 會用最近提交的版本覆蓋掉它。 除非你確實清楚不想要對那個文件的本地修改了,否則請不要使用這個命令。
現在,假設你不但改錯了東西,還從暫存區提交到了版本庫,怎么辦呢?還記得版本回退一節嗎?可以使用git reset回退到上一個版本。不過,這是有條件的,就是你還沒有把自己的本地版本庫推送到遠程。還記得Git是分布式版本控制系統嗎?我們后面會講到遠程版本庫,一旦你把stupid boss
提交推送到遠程版本庫,你就真的慘了……
小結
又到了小結時間。
場景1:當你改亂了工作區某個文件的內容,想直接丟棄工作區的修改時,用命令git checkout -- file
。
場景2:當你不但改亂了工作區某個文件的內容,還添加到了暫存區時,想丟棄修改,分兩步,第一步用命令git reset HEAD <file>
,就回到了場景1,第二步按場景1操作。
場景3:已經提交了不合適的修改到版本庫時,想要撤銷本次提交,參考版本回退一節,不過前提是沒有推送到遠程庫。
git重置某些文件到指定版本
對這個博客中的一些解釋:
Git 中 git checkout -- <file>的真正用法:該指先是從緩存區中拉取版本還原,如果沒有再到版本庫中拉取還原。
--的意思是:
Do not interpret any more arguments as options.=》
不要將其他參數解釋為選項。
剛剛做了一些提交,但是你發現剛做的提交不完整或者有錯誤,想要重新編輯后再提交
git reset --soft HEAD^
先讓本地庫回到上一個版本,然后在工作區重新編輯后
git commit -a -c ORIG_HEAD
-a 參數設置修改文件后不需要執行 git add 命令,直接來提交
-C(大寫)重用日志消息和作者信息(包括時間戳)
-c(小寫) 重用日志消息和作者信息(包括時間戳),會調用編輯器,以便用戶可以進一步編輯提交消息。
針對某些危險操作,Git通過記錄HEAD指針的上次所在的位置ORIG_HEAD提供了回退的功能。當你發現某些操作失誤了,比如錯誤的reset到了一個很早很早的版本,可以使用git reset --hard ORIG_HEAD回退到上一次reset之前。(就是上一次HEAD指針指向的地方)參考文章
也可以使用git commit --amend,具體使用方法:
適用場景(參考文章鏈接):
場景1.本地開發代碼已提交,提交后發現這次提交的代碼有問題,或者漏提交了一些文件,此時,希望達到以下目的:
①修改有問題的代碼。
②補足漏提交的文件(一般是新增的文件沒有git add .)
③把以上2點相關的代碼,和前一次提交的代碼合并成1個提交。
④給合并后的這個提交添加新的注釋。
解決辦法:
--》修改問題代碼
--》git add . (把漏提交的文件假如暫存區)
--》執行git commit --amend -m "這里填寫提交的注釋"
場景2.新接到需求,需要基于master分支拉取一個feature分支,且這個feature分支只有你自己使用(這一點極其重要),由于開發周期較長,你不想每一次都產生一個新的commit,而是每一次commit都修改前一次提交,這樣做的好處是,等到你的feature分支提測時,就只有1個干凈的commit,沒有亂七八糟的提交歷史,你只要把這1個commit合并到master里就好了 。
解決辦法:在feature分支上,
第1次提交代碼時,使用git commit -am "第1次提交的注釋"
第2次以后提交代碼時,使用git commit --amend -m "這里填寫提交的注釋"
這樣,整個分支可以只有1個commit
刪除文件并找回
前提:刪除前,文件存在時的狀態提交到了本地庫
操作:git reset --hard [指針位置]
本質就是,回到該文件還沒有被刪除的記錄上
刪除操作已經提交到本地庫:指針位置指向歷史記錄
刪除操作尚未提交到本地庫:指針位置使用HEAD
注: git reset HEAD可以將添加到暫存區的文件取消暫存
已提交到本地庫的文件,在工作區刪除后,添加到暫存區,這時候如何撤回
還是 git reset --hard HEAD
因為 --hard就是代表在本地庫移動HEAD指針,重置暫存區,重置工作區
比較文件差異
- git diff [文件名]
將工作區的文件和暫存區的進行比較
git diff [本地庫中歷史版本] [文件名]
例如:git diff HEAD -- readme.txt
將工作區的文件和本地庫歷史記錄進行比較git diff
不帶文件名:比較多個文件
注:git branch 是查看本地的所有分支 git branch -a 是查看本地分支和遠程分支
創建分支
git branch [分支名]
查看分支
git branch -v
切換分支
git checkout [分支名]
合并分支
- 第一步:切換到接受修改的分支(被合并,增加新內容)上:git checkout [被合并分支]
- 第二步:git merge [有新內容分支名]
例如在master分支合并dev分支:
git merge --no-ff -m "merge with no-ff" dev
--no-ff代表生成一個新的提交節點
參考
解決沖突
- 本地分支操作沖突
例如master分支和dev分支都修改了demo.txt文件,在master分支上將dev分支的內容merge過來時,就會有沖突,這時只要在master分支上將沖突文件修改到滿意程度,保存退出。然后正常add和commit就可以了。
- 多人協作操作沖突
遠程分支上的demo.txt已經有新的內容了,但是本地沒有拉取下來,直接在本地的demo.txt上修改了,然后推送到本地倉庫,這時是沒有沖突的,但是將本地倉庫push到遠程時就會提示沖突。這時現將遠程pull下來,然后就可以看到沖突的文件,進行修改后推送到遠程就可以了。
- 第一步:編輯文件,刪除特殊符號
- 第二步:把文件修改到滿意程度,保存退出
- 第三步:git add [文件名]
- 第四步:git commit -m "日志信息"
- 注意此時commit 一定不能帶具體文件名
和遠程之間的交互
例如你是先建立了一個本地庫,在內面做了一些提交,現在要把它推送到遠程庫:
- git init
- 設置user.nane 和user.email(如果曾經設置過全局的,就可以跳過這一步)
- edit文件
- git add 。
- git commit -m "msg"
- 現在要辦本地庫的信息推送到遠程庫,其實本地庫和遠程庫的名字可以不同。先在遠程庫中建立一個倉庫,注意不要添加readme文件,避免和本地庫沖突,創建好后就可以進行推送了
-
先給遠程庫設置別名,因為你之后的推送要告訴本地庫推送到哪個地址
20201126193339 - git remote -v查看遠程庫列表
-
20201126193557
fetch表示這個地址用來取回,push代表這個地址用來推送
- git push origin master代表將master分支推到遠程(origin是上一步設置的遠程倉庫的別名),之后會彈出github登錄框(但是我操作的時候并沒有,因為我之前已經登錄過github,他會自動將賬號和密碼保存在Windows憑據中,如下圖,刪掉后就要重新登錄)(如果是別人clone下來想要提交,那必須遠程倉庫的owner將他添加為開發人員)
- 別人拉取這個遠程庫就可以git clone https://github.com/diamondooo/demo2.git,這個clone命令有以下做用:一、創建origin遠程地址別名(git remote -v可以看到origin帶表的地址)。二、完整的把遠程庫下載到本地(git branch -v可以看到除了本地的master分支外還可以看到origin/master這個遠程分支)。三、初始化本地庫。
- git fetch origin master把遠程庫的最新操作拉取下來,但只是拉取到本地庫(拉取到本地庫的origin/master),工作區的內容不會變化,因為你現在在本地的master分支上,不是在本地的origin/master分支上,所以看不到遠程庫的內容
- 在fetch之后,想要看遠程庫到底做了哪些修改,就可以使用 git checkout origin/master 檢出origin的mater,就可以在工作區看到最新的文件,但這只是查看。git checkout master回到本地的master還是舊的內容,git merge origin/master將遠程的master合并到本地的master(執行這個操作時是在本地的master分支上),這樣本地的master分支就有最新的內容了。git pull其實是git fetch加上git merge的效果。
pull=fetch + merge
git fetch [遠程庫地址別名] [遠程分支名]
git merge [遠程庫地址別名/遠程分支名]
git pull [遠程庫地址別名] [遠程分支名]
SSH免密登錄
因為windows自帶的票據管理,第一次登錄過GitHub后就會將賬號和密碼保存到本地,之后的推送就不用登錄了,如果系統不帶這個功能,那么每次推送都需要登錄,很麻煩,這時就用SSH免密登錄
輸入 ssh-keygen -t rsa -C 登錄GitHub的郵箱,然后一路回車,就可以了。這個命令要在C盤登錄這個電腦的賬號下輸入(和全局的user.name 和 user.email 同一個目錄)。這時就會有.ssh隱藏文件夾。
復制 id_rsa.pub文件的所有內容,粘貼到自己的GitHub的SSH and GPG keys內
如果想用ssh登錄,就要做如上操作,往ssh路徑上推。
標簽
git push 的 -u 參數具體適合含義?
比如遠程庫A上有3個分支branch1、branch2、branch3。遠程庫B上有3個分支branchx、branchy、branchz。本地倉庫有2個分支local1和local2。那么當初始狀態時,local1和local2和任何一個分支都沒有關聯,也就是沒有upstream。當通過git branch --set-upstream-to A/branch1 local1命令執行后,會給local1和branch1兩個分支建立關聯,也就是說local1的upstream指向的是branch1。這樣的好處就是在local1分支上執行git push(git pull同理)操作時不用附加其它參數,Git就會自動將local1分支上的內容push到branch1上去。同樣,local2分支也可以和遠程庫A和遠程庫B上的任何一個分支建立關聯,只要給local2分支設置了upstream,就可以在local2分支上用git push(git pull同理)方便地與目標分支推拉數據。
綜上所述,upstream與有幾個遠程庫沒有關系,它是分支與分支之間的流通道。
再來說說git push -u和git branch --set-upstream-to指令之間的區別。
舉個例子:我要把本地分支mybranch1與遠程倉庫origin里的分支mybranch1建立關聯。
(如果使用下列途徑1的話,首先,你要切換到mybranch1分支上(git checkout mybranch1))
兩個途徑:1. git push -u origin mybranch1 2. git branch --set-upstream-to=origin/mybranch1 mybranch1
這兩種方式都可以達到目的。但是1方法更通用,因為你的遠程庫有可能并沒有mybranch1分支,這種情況下你用2方法就不可行,連目標分支都不存在,怎么進行關聯呢?所以可以總結一下:git push -u origin mybranch1 相當于 git push origin mybranch1 + git branch --set-upstream-to=origin/mybranch1 mybranch1
簡單來說使用git push -u origin master以后就可以直接使用不帶別的參數的git pull從之前push到的分支來pull。
作者:王軒
鏈接:https://www.zhihu.com/question/20019419/answer/48434769
來源:知乎
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
git push origin
上面命令表示,將當前分支推送到origin主機的對應分支。
如果當前分支只有一個追蹤分支,那么主機名都可以省略。
git push
如果當前分支與多個主機存在追蹤關系,那么這個時候-u選項會指定一個默認主機,這樣后面就可以不加任何參數使用git push。
git push -u origin master
上面命令將本地的master分支推送到origin主機,同時指定origin為默認主機,后面就可以不加任何參數使用git push了。
不帶任何參數的git push,默認只推送當前分支,這叫做simple方式。此外,還有一種matching方式,會推送所有有對應的遠程分支的本地分支.Git 2.0版本之前,默認采用matching方法,現在改為默認采用simple方式。
git rebase
翻譯為"變基"
通過git rebase -i 將本地的多次提交合并為一個,以簡化提交歷史。本地有多個提交時,如果不進行這一步,在git rebase master時會多次解決沖突(最壞情況下,每一個提交都會相應解決一個沖突)
git 操作的疑問:
1.本地檢出一個新分支后,如何推送到遠程
2.添加到暫存區的文件,如何撤回到工作區
3.提交到本地庫的文件,如何撤回到暫存區/工作區,這兩種有何區別
4.git reset 和git revert 有和區別
5.遠程的新分支如何拉取到本地
6.git reset 的hard 和soft 和mixed有何區別
7.查看提交記錄有幾種方式,有git log 、git reflog ……
8.git diff有幾種方式
9.git 的簡寫有哪些,比如 git st 代表git status 等等
10.git checkout hash 檢出這個版本后,就可以直接在這個版本上修改了嗎,修改之后的提交會覆蓋這個版本之后的版本嗎?這種也算是一種吃后悔藥的方式嗎?
11.加上ssh文件夾和直接使用git賬號登錄有什么區別?
12.常用命令有哪些(盡可能列出所有)
13.git的撤銷操作:從暫存區撤回到工作區(未提交過的文件和已提交過的文件有區別),從倉庫撤回到暫存區,從倉庫撤回到工作區
14.git reset --hard [版本號] 和git checkout 版本號有什么區別