-Git 使用技巧 總結 MD

Markdown版本筆記 個人GitHub首頁 個人博客 個人微信 個人郵箱
MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina.com

目錄

Bash下的快捷操做

經常使用命令

  • cd:change directory 改變目錄,bash中不帶參數時默認進入【/c/Users/當前用戶】目錄,cmd中不帶參數時等價於pwd
  • cd -:回到前一個目錄,cmd中沒有此命令
  • cd ..:回到父目錄
  • cd aaa:進入指定目錄,能夠是相對目錄或絕對目錄
  • pwd:打印工做目錄路徑
  • lsll:列出當前目錄中的全部文件,cmd中沒有ll命令
  • touch aaa.txt:在當前目錄下新建一個文件
  • mkdir aaa:在當前目錄下新建一個目錄
  • rm aaa.txt:刪除指定的文件
  • rm -r aaa:刪除指定的目錄,參數r爲recusive是遞歸的意思
  • mv aaa.txt bbb:將文件移到指定目錄下
  • q:結束一個命令
  • explorer aa:打開指定的目錄或文件

經常使用操做

  • 複製內容:選中後就已經複製了(勾選了"選擇時複製"),或 Ctrl + Insert
  • 粘貼內容:點擊鼠標中鍵,或 Shift + Insert
  • 搜索內容:Alt + F3,按EnterShift + Enter選中下/上一個匹配內容
  • 縮放文字:Ctrl + 【+/-】
  • 窗口清屏:Alt + F8(重置),cmd 下的命令是 cls【重要】
  • 窗口全屏:Alt + F11,再按一次還原

移動光標

  • 一個單詞一個單詞向左/右移動光標:Alt + B/F【重要】
  • 移動光標到整條命令的起始/結束位置:Ctrl + A/E【重要】
  • 一個字符一個字符向左/右移動光標:Ctrl + B/F

刪除輸入內容

  • 刪除光標左/右側的全部內容:Ctrl + U/K【重要】
  • 刪除光標側的單詞:Ctrl + W【重要】
  • 刪除光標側的單詞:Alt + D
  • 刪除光標左/右側的字符:Ctrl + H/D(或backspace鍵、delete鍵)

Tab鍵的做用

  • 輸入內容(文件名或命令)的前幾個字母時,按tab,若是有內容能夠匹配,它就會顯示出完整的內容
  • 若是有多個內容匹配到,它會顯示最早找到的一個,再按一次tab,它就會匹配的下一個
  • 咱們能夠不停地按Tab鍵在匹配的內容中來回切換,直到找到咱們文件名爲止

Git默認Vim編輯器基本使用

Git默認的編輯器是Vim,在不少情境下會遇到它,例如commit提交,若是提供-m指令,直接在後面寫上這次提交的說明信息;若是不提供-m指令,默認將會彈出Vim編輯器,以下:github

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.

此編輯器和平時所用編輯器差距很大,Vim編輯器命令不少,下面介紹一下簡單操做,以完成基本的Git操做。shell

Vim主要有以下兩種模式:vim

  • Normal 模式:命令模式,按 ESCCtrl + [ 進入,此模式下沒法輸入內容,可是能夠複製、黏貼、保存、退出
    • :w表示保存
    • :q表示離開,若是未保存會有提示
    • :q!表示不保存離開
    • :wq表示保存並離開(用的最多)
  • Insert 模式:編輯模式,點擊i、a 或 o 鍵能夠進入

Git 使用場景

合併多個commit:rebase -i【s】

基本步驟:bash

  • 執行git rebase -i HEAD~影響的最少commit數git rebase -i 前一個commitId
  • 須要合併的那條commit前面的pick改成s,保存後退出
  • 修改commit日誌,保存後退出

如下是詳細操做微信


在使用 Git 做爲版本控制的時候,咱們可能會因爲各類各樣的緣由提交了許多臨時的 commit,而這些 commit 拼接起來纔是完整的任務。那麼咱們爲了不太多的 commit 而形成版本控制的混亂,一般咱們推薦將這些 commit 合併成一個。app

首先你要知道本身想合併的是哪幾個提交,可使用 git log 命令來查看提交歷史,假如最近 4 條歷史以下:編輯器

commit 8b5cbda494a68582164048159e605e731f357444 (HEAD -> master)
commit a472755058e78a33595390f87d03d855fc25da84
commit 6ab13045d47157842961fae70baa7ef25e1856b1
commit 00b8fe51079ac0ba1d5a87e9c0b51c9e851d233f (origin/master, origin/HEAD)

歷史記錄是按照時間排序的,時間近的排在前面。gradle

若是想要合併第 2 和第 3 條記錄,有兩個方法,這兩個方法效果是一致的:優化

  • 從HEAD版本開始往過去數 3 個版本
git rebase -i HEAD~3
  • 指名要合併的版本以前的版本號
git rebase -i 00b8fe51079ac0ba1d5a87e9c0b51c9e851d233f

請注意 00b8fe51079ac0ba1d5a87e9c0b51c9e851d233f 這個版本是不參與合併的,能夠把它當作一個座標

執行了 rebase 命令以後,會彈出一個窗口,內容以下:

pick 6ab1304 11111111
pick a472755 222222222
pick 8b5cbda 3333333

# Rebase 00b8fe5..8b5cbda onto 00b8fe5 (3 commands)
#
# Commands:
# p, pick = use commit
# r, reword(改寫) = use commit, but edit the commit message
# e, edit = use commit, but stop for amending(修正)
# s, squash(塞入) = use commit, but meld into(融入) previous commit
# f, fixup(修正) = like "squash", but discard(丟棄) this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out(被註釋掉的)

能夠看到,裏面有詳細的命令提示。咱們將須要合併的那條commit前面的pick改成s,以後保存並關閉文本編輯窗口便可。改完以後文本內容以下:

pick 6ab1304 11111111
s a472755 222222222
pick 8b5cbda 3333333

而後保存退出。若是沒有衝突,或者衝突已經解決,則會出現以下的編輯窗口:

# This is a combination of 2 commits.
# This is the 1st commit message:

11111111

# This is the commit message #2:

222222222

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit(空消息會終止提交).
#
# Date:      Sun Jul 7 21:14:02 2019 +0800
#
# interactive(互動) rebase in progress; onto 00b8fe5
# Last commands done (2 commands done):
#    pick 6ab1304 11111111
#    squash a472755 222222222
# Next command to do (1 remaining command):
#    pick 8b5cbda 3333333
# You are currently rebasing branch 'master' on '00b8fe5'.
#
# Changes to be committed:
#       modified:   build.gradle

若是不作任何修改的話,默認是保留兩次 commit 的日誌,中間有一個空白行,你能夠隨意修改合併後的日誌。

保存並退出後再次輸入 git log 查看 commit 歷史信息,你會發現這兩個 commit 已經合併了。

commit 9adb987d31f11f8d38f8d817096d2d21a7390a1d (HEAD -> master)
commit 052ea3ea0b30c375e79ad9e891c5e5202768b11b
commit 00b8fe51079ac0ba1d5a87e9c0b51c9e851d233f (origin/master, origin/HEAD)

雖然咱們只是合併了第 2 條和第 3 條的commit,可是第 1 條的 commitId 也變了。

若是有衝突,須要修改。修改的時候要注意,保留最新的歷史,否則咱們的修改就丟棄了。

修改之後要記得敲下面的命令:

git add .
git rebase --continue

若是你想放棄此次壓縮的話,執行如下命令:

git rebase --abort

刪除多個commit:rebase -i【d】

和上面的操做基本一致。

例如個人提交歷史以下:

commit 831be8ec644c4943374adca03880732c7ec9d6bd (HEAD -> master)
commit 6a8ecb529a4ec6b6e0fc83e0789043b7785e73fe
commit 3b228d8af9e52806c106ef3f0c27e622b5407faf
commit 9adb987d31f11f8d38f8d817096d2d21a7390a1d (origin/master, origin/HEAD)

我想刪除第2條和第3條提交,基本步驟:

  • 執行git rebase -i HEAD~影響的最少commit數git rebase -i 前一個commitId
  • 須要刪除的那幾條commit前面的pick改成d,保存後退出
  • 修改commit日誌,保存後退出

注意,這個操做感受出現衝突的機率比較大,例如我上面三次commit都是在同一個文件的第一行插入一行新的文字:

//添加3
//添加2
//添加1

執行rebase後就會提示衝突了:

git rebase -i 9adb987d31f11f8d38f8d817096d2d21a7390a1d
Auto-merging build.gradle
CONFLICT (content): Merge conflict in build.gradle
error: could not apply 831be8e... 333

Resolve all conflicts manually手動, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".

Could not apply 831be8e... 333

解決衝突後按如下操做:

git add .
git rebase --continue

能夠發現,相應 commit 都還原了,包括修改的文件以及提交的commit記錄。

修改多個commit:rebase -i【r】

和上面的操做基本一致。

例如個人提交歷史以下:

commit 442... (HEAD -> master)
commit 5a1...
commit 305...
commit f30... (origin/master, origin/HEAD)

我想修改第2條和第3條提交,基本步驟:

  • 執行git rebase -i HEAD~影響的最少commit數git rebase -i 前一個commitId
  • 須要修改的那幾條commit前面的pick改成r,保存後退出
  • 每一個改成reword的提交都會提示你一個編輯窗口讓你修改commit日誌,修改保存後退出

注意,修改後會生成新的commitId

挑選多個commit:cherry-pick

cherry-pick 的翻譯是擇優挑選,使用git cherry-pick命令,能夠選擇將現有的一個或者多個提交的修改引入當前內容。

cherry-pick 官方文檔

git cherry-pick <commitid> <commitid>

挑選多個提交合並,提交之間用空格相隔。

git cherry-pick <start-commit>..<end-commit>

挑選一個範圍內的多個提交合並,不包含start-commit(最先的提交),包含end-commit(最近的提交)。另外要注意兩個 commit 之間要求有連續關係的,而且前者要在後者以前,順序不能顛倒。

git cherry-pick <start-commit>^..<end-commit>

這個和上面同樣,區別就是加了一個^符號,就變成閉區間了,包含 start-commit。

git cherry-pick <branch name>

挑選 branch 最頂端的提交。

git cherry-pick --continue  //繼續下個操做
git cherry-pick --quit //退出
git cherry-pick --abort //中止本次操做

當 cherry-pick 多個 commit 時,假設遇到衝突:

  • --continue繼續進行下個
  • --quit結束 cherry-pick 操做可是不會影響衝突以前多個提交中已經成功的
  • --abort直接打回原形,回到 cherry-pick 前的狀態,包括多個提交中已經成功的

使用 git branch -d 刪除分支的條件

參考:git branch -d 和 git branch -D 的區別

結論:
在使用-d刪除分支時,該分支必須徹底和它的上游分支merge完成,若是沒有上游分支,必需要和HEAD徹底merge。

出現的案例一

  • 一、現有一個本地分支 v0.1,我作一些修改後 commit (沒有 commit或stash 是不能切換到其餘分支的)
  • 二、而後切到其餘分支(由於不能刪除當前分支)後刪除 v0.1 試試 ,能夠發現刪除失敗
git branch -d v0.1
error: The branch 'v0.1' is not fully merged.
If you are sure you want to delete it, run 'git branch -D v0.1'.

三、而後切到 v0.1 上,將修改推送到遠端:git push origin v0.1
四、而後再切到其餘分支後刪除 v0.1 試試,能夠發現刪除成功,可是有警告

git branch -d v0.1
warning: deleting branch 'v0.1' that has been merged to 'refs/remotes/origin/v0.1', but not yet merged to HEAD.
Deleted branch v0.1 (was 4a79623).

上面的步驟進行一些優化:
四、假如咱們後面刪除前是切到了 master 分支,因此當前HEAD爲 master 分支("因此"這個詞用的對嗎?)
五、將 v0.1 上的修改 merge 過來git merge v0.1,而後再刪除 v0.1 試試,能夠發現刪除成功且沒有警告

出現的案例二

  • 一、首先我基於當前分支 v0.1 建立了一個分支 v0.1_copy:git branch v0.1_copy(此分支並無上游分支)
  • 二、而後切到 v0.1_copy 上,並進行一些修改,而後 commit
  • 三、而後切到 v0.1 後刪除 v0.1_copy 試試,能夠發現刪除失敗
git branch -d v0.1_copy
error: The branch 'v0.1_copy' is not fully merged.
If you are sure you want to delete it, run 'git branch -D v0.1_copy'.

五、而後切到 v0.1 上,並將 v0.1_copy 上的修改 merge 過來git merge v0.1_copy
六、而後再刪除 v0.1_copy 試試,能夠發現刪除成功且沒有警告

git branch -d v0.1_copy
Deleted branch v0.1_copy (was 03cb1c6).

總結

簡單來講就是這麼一個設計思想:

  • 若是一個分支有和遠端分支關聯(有上游分支),那麼在刪除此分支前須要將此分支上的commit push到遠端,否則在分支被刪除時在其上所作的 commit 也一併被刪除了,設計者認爲這樣的操做風險極大
  • 若是一個分支沒有和遠端分支關聯(沒有上游分支),因爲在此分支上的 commit 不能 push 到遠端,那麼爲了防止 commit 也一併被刪除了,設計者要求必需要和HEAD徹底merge才能刪除

總之一句話,刪除分支不能致使有任何已作的 commit 沒法追蹤,若是你想這麼作,必須使用 -D 達到你的目的

解決 push 時提示 Everything up-to-date 問題

參考 stackoverflow 上的答案

一、如今有一個本地分支 v0.1,且其和遠端分支 v0.1 關聯,此時你在本地 v0.1 作的任何修改均可以經過git push origin v0.1推到遠端,這很正常

二、而後你經過git branch v0.1_backup建立了一個備份分支,而後 checkout 到此分支後作了一些修改,當你 commit 後 push 到遠端的 v0.1 時問題就出現了

git push origin v0.1
Everything up-to-date

其實這裏的 "Everything up-to-date(最新)", 的含義是:
"all the branches you've told me how to push are up to date".
也就是說遠端的v0.1是最新的

而且此時其實並無push到遠端的

git status
On branch v0.1_backup
Your branch is ahead of 'origin/v0.1' by 1 commit.

緣由是很簡單的,分支 v0.1_backup 並無和遠端分支關聯

$ git branch -vv
  master      de18ed6 [origin/master] 修改1
  v0.1        03cb1c6 [origin/v0.1] 修改2
* v0.1_backup 88eb433 修改3

三、如今你經過git branch -u origin/v0.1 v0.1_backup能夠將其和遠端的 v0.1 關聯

$ git branch -vv
  master      de18ed6 [origin/master] 修改1
  v0.1        03cb1c6 [origin/v0.1] 修改2
* v0.1_backup 88eb433 [origin/v0.1: ahead 1] 修改3

四、而後再 push 到遠端的 v0.1 會發現,問題依舊

解決方式有三個

一、更名,將本地分支名 v0.1_backup 改成和遠程分支名同樣的 v0.1 就能夠了。神馬,同名的分支已存在?那你爲何不在已存在的那個分支上操做呢?

二、merge,好比上面說的和遠程分支同名的本地分支 v0.1 已存在時,能夠先將 v0.1_backup 的修改 merge 到 v0.1 上,而後再在 v0.1 上 push 就能夠了。雖然麻煩,可是這是標準操做(我的感受)。

三、使用下面的命令也能夠

git push origin v0.1_backup:v0.1

Author 與 Committer 有什麼區別

參考

  • Author 是實際的修改者(patch 的做者),Committer 是提交者(把 patch 應用到 repository 裏的人)
  • 不少項目限制只有少數人能夠提交 patch,但你們(patch 的做者)均可以把 patch 發送給這些人
  • committer 只能經過 commit 獲得,經過 git commit --reset-author 或者 --author="Name" 能夠修改 Author(通常不會修改)

2019-7-14

相關文章
相關標籤/搜索