【學了就忘】Git分支 — 44.分支切換的幾種情況

這個案例我們要對切換分支命令進行詳細說明。

在我們切換分支,執行git checkout master這條命令的時候,

Git做了如下兩件事情:

  1. 是使 HEAD 指回 master 分支。
  2. 將工作目錄中文件,恢復成 master 分支所指向提交的快照內容。

也就是說:分支切換會改變你工作目錄中的文件

說明:在切換分支時,一定要注意你工作目錄裏的文件會被改變。如果是切換到一個較舊的分支,你的工作目錄會恢復到該分支最後一次提交時的樣子。如果Git不能幹淨利落地完成這個任務,它將禁止切換分支。

下面我們就來詳細的進行說明。

1、演示分支切換會改變工作目錄中的文件

1)查看工作目錄中的狀態

# 1.1 乾淨的目錄
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ git status
On branch master
nothing to commit, working tree clean

# 1.2 只有一個分支
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ git branch
* master

# 1.3 有三個提交歷史
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ git log --oneline
b97ccfd (HEAD -> master) 第3次提交,新增內容:branch test v3
f72a9fe 第2次提交,新增內容:branch test v2
fa2439a 第1次提交,新增readme.txt文件

2)新建一個testing分支,並提交一個a.txt文件到版本庫

# 2.1 創建並切換到testing分支
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ git checkout -b testing
Switched to a new branch 'testing'

# 2.2 創建文件a.txt,並提交到版本庫
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (testing)
$ echo "a,txt v1" > a.txt

L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (testing)
$ git add a.txt
warning: LF will be replaced by CRLF in a.txt.
The file will have its original line endings in your working directory

L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (testing)
$ git commit -m '新增a.txt文件'
[testing 4e9f4d3] 新增a.txt文件
 1 file changed, 1 insertion(+)
 create mode 100644 a.txt

3)查看testing分支的文件

# 3.1 查看testing分支提交歷史
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (testing)
$ git log --oneline
4e9f4d3 (HEAD -> testing) 新增a.txt文件
b97ccfd (master) 第3次提交,新增內容:branch test v3
f72a9fe 第2次提交,新增內容:branch test v2
fa2439a 第1次提交,新增readme.txt文件

# 3.2 查看工作區狀態,乾淨
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (testing)
$ git status
On branch testing
nothing to commit, working tree clean

# 3.3 查看工作目錄中的文件,有兩個文件
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (testing)
$ ll
total 2
-rw-r--r-- 1 L 197121  9  4月 17 12:55 a.txt
-rw-r--r-- 1 L 197121 48  4月 17 12:36 readme.txt

# 3.4 查看暫存區中的文件,也有兩個文件
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (testing)
$ git ls-files
a.txt
readme.txt

# 版本庫中的文件(也就是.git/objects目錄中的文件)只會增加不會減少,所以用不看。
# 當然你可以通過命令`git ls-files --with-tree=HEAD`:
# 查看本地版本庫中,當前分支的文件列表。

4)切換到master分支

# 4.1 查看工作目錄中的文件狀態,是乾淨的
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (testing)
$ git status
On branch testing
nothing to commit, working tree clean

# 4.2 切換到master分支
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (testing)
$ git checkout master
Switched to branch 'master'

# 4.3 查看master分支提交歷史,改變了
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ git log --oneline
b97ccfd (HEAD -> master) 第3次提交,新增內容:branch test v3
f72a9fe 第2次提交,新增內容:branch test v2
fa2439a 第1次提交,新增readme.txt文件

# 4.4 查看工作目錄中的文件,只有一個文件了
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ ll
total 1
-rw-r--r-- 1 L 197121 48  4月 17 12:36 readme.txt

# 4.5 查看暫存區中的文件,也只有一個文件了
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ git ls-files
readme.txt

如上就可以證明了,切換分支時,工作目錄中的文件會發生改變。

2、分支切換工作目錄不乾淨的

如果切換分支的時候,該分支的工作目錄不是已提交狀態,那麼會出現如下兩種情況。

(1)工作區不乾淨

也就是有以修改或新增,未被追蹤的文件。

1)切換到testing分支

# 1.1 查看當前的工作分支
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ git branch
* master
  testing

# 1.2 工作目錄是乾淨的
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ git status
On branch master
nothing to commit, working tree clean

# 1.3 切換分支
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ git checkout testing
Switched to branch 'testing'

2)在testing分支新增一個文件b.txt,但不添加到暫存區

# 2.1 新增b.txt文件
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (testing)
$ echo 'b.txt v1' > b.txt

# 2.2 查看testing分支上,工作目錄中的文件
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (testing)
$ ll
total 3
-rw-r--r-- 1 L 197121 10  4月 17 13:58 a.txt
-rw-r--r-- 1 L 197121  9  4月 17 14:00 b.txt
-rw-r--r-- 1 L 197121 48  4月 17 12:36 readme.txt

# 2.3 查看testing分支上,暫存區中的文件,只有兩個文件
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (testing)
$ git ls-files
a.txt
readme.txt

# 2.4 查看testing分支工作目錄中的文件狀態
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (testing)
$ git status
On branch testing
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        b.txt

nothing added to commit but untracked files present (use "git add" to track)

顯示b.txt文件未被追蹤。

3)此時切換到master分支上

# 3.1 切換到master分支
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (testing)
$ git checkout master
Switched to branch 'master'

# 3.2 查看master分支工作目錄中的文件
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ git status
On branch master
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        b.txt

nothing added to commit but untracked files present (use "git add" to track)

L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ ll
total 3
-rw-r--r-- 1 L 197121  9  4月 17 12:55 a.txt
-rw-r--r-- 1 L 197121  9  4月 17 14:00 b.txt
-rw-r--r-- 1 L 197121 48  4月 17 12:36 readme.txt

# 3.3 查看master分支,暫存區中的文件
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ git ls-files
a.txt
readme.txt

我們從上面可以看到,在testing分支上創建的,新增未被追蹤的b.txt文件,被同步到了master分支上。

因爲git checkout命令執行時,會將工作目錄裏的文件改變到指定的提交狀態。

又因爲你在testing分支上創建的b.txt文件,既沒有被提交也沒有被暫存,說明b.txt文件還未被Git管理。在這種情況下,你進行切換分支操作,你將丟失在testing分支對b.txt文件編寫。Git認爲這樣是非常不安全的操作,會默認的把該狀態的文件,一起帶入所切換到的分支中。

所以git checkout命令還是很智能的,可以我們一般不會用該功能,這個功能用來會非常的混亂,可能會污染到其他分支,儘管Git是好意。

(2)工作區和暫存區不乾淨

也就是暫存區有新增的文件時,但還未提交到本地版本庫。

(接上面示例,繼續演示)

1)切換到testing分支上,把b.txt文件添加到暫存區

# 1.1 切換分支
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ git checkout testing
Switched to branch 'testing'

# 1.2 把b.txt文件添加到暫存區中
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (testing)
$ git add b.txt
warning: LF will be replaced by CRLF in b.txt.
The file will have its original line endings in your working directory

# 1.3 查看工作目錄裏中的文件,可以看到有三個文件
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (testing)
$ ll
total 3
-rw-r--r-- 1 L 197121 10  4月 17 14:21 a.txt
-rw-r--r-- 1 L 197121  9  4月 17 14:00 b.txt
-rw-r--r-- 1 L 197121 48  4月 17 12:36 readme.txt

# 1.4 查看暫存區中的文件,可以看到有三個文件
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (testing)
$ git ls-files
a.txt
b.txt
readme.txt

# 1.5 查看工作目錄中文件的狀態
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (testing)
$ git status
On branch testing
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   b.txt

2)此時切換到master分支上

# 2.1 切換分支
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (testing)
$ git checkout master
Switched to branch 'master'
A       b.txt   # 提示你帶有一個增加的文件 b.txt
# 發現也是可以進行分支切換的。

# 2.2 查看工作目錄中文件的狀態
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   b.txt

# 2.3 查看工作目錄裏中的文件,可以看到有b.txt文件
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ ll
total 2
-rw-r--r-- 1 L 197121 10  4月 17 14:21 a.txt
-rw-r--r-- 1 L 197121  9  4月 17 14:00 b.txt
-rw-r--r-- 1 L 197121 48  4月 17 12:36 readme.txt

# 2.4 查看暫存區中的文件,可以看到有b.txt文件
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ git ls-files
a.txt
b.txt
readme.txt

發現暫存區中存儲的文件,只要未被提交,也會隨着分支的切換,加入到其他分支中。

3、不能切換分支的情況

(接上面示例,繼續演示)

1)切換到testing分支上,把b.txt文件提交到版本庫

# 1.1 切換分支
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ git checkout testing
Switched to branch 'testing'
A       b.txt

# 1.2 b.txt文件提交到版本庫
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (testing)
$ git commit -m '新增文件 b.txt'
[testing 33f327c] 新增文件 b.txt
 1 file changed, 1 insertion(+)
 create mode 100644 b.txt
 
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (testing)
$ git log --oneline
33f327c (HEAD -> testing) 新增文件 b.txt
4e9f4d3 新增a.txt文件
b97ccfd (master) 第3次提交,新增內容:branch test v3
f72a9fe 第2次提交,新增內容:branch test v2
fa2439a 第1次提交,新增readme.txt文件

2)繼續修改b.txt文件,不提交到版本庫中,然後切換到master分支

# 2.1 修改`b.txt`文件
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (testing)
$ echo 'b.txt v2' >> b.txt

# 2.2 查看testing文件工作目錄中文件狀態
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (testing)
$ git status
On branch testing
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   b.txt

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

# 2.3 切換到master分支
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (testing)
$ git checkout master
error: Your local changes to the following files would be overwritten by checkout:
        b.txt
Please commit your changes or stash them before you switch branches.
Aborting

說明:

error: Your local changes to the following files would be overwritten by checkout:b.txt

錯誤提示:b.txt文件在本地的更改,將隨着切換分支的操作,被版本庫所覆蓋(也就是文件被還原)

Please commit your changes or stash them before you switch branches.

提示你,在切換分支之前,請先提交更改。(不提交不讓你切換分支)

注意:在暫存區,未提交,也是同理。

這是什麼原因?

因爲b.txt文件已經被Git管理過了,如果b.txt文件還處於修改未追蹤狀態,你就必須b.txt文件修改完成並提交後,再去其他分支工作。

3、總結

使用git checkout命令進行分支的切換,實際上有三個地方更改了

  1. HEAD指針進行了移動,指向了新的分支上。
  2. 暫存區恢復到新分支上,最新提交版本的狀態。
  3. 工作目錄也恢復到新分支上,最新提交版本的狀態。

而切換分支的最佳實踐:每次切換分支前,確保當前分支一定得是乾淨的(已提交狀態)。

因爲要避免一下情況:

在切換分支時,如果當前分支上有新增且未暫存的修改(第一次),或者有新增,暫存,但未提交的修改(第一次)時,分支可以切換成功,但是這種操作可能會污染其地分叉。

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