Git之深入解析如何贮藏工作分支与清理工作目录

Posted Forever_wj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Git之深入解析如何贮藏工作分支与清理工作目录相关的知识,希望对你有一定的参考价值。

一、前言

二、贮藏工作

  • 为了演示贮藏,需要进入项目并改动几个文件,然后可以暂存其中的一个改动。如果运行 git status,可以看到有改动的状态:
$ git status
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	modified:   index.html

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:   lib/simplegit.rb
  • 现在想要切换分支,但是还不想要提交之前的工作,所以贮藏修改。将新的贮藏推送到栈上,运行 git stash 或 git stash push:
$ git stash
Saved working directory and index state \\
  "WIP on master: 049d078 added the index file"
HEAD is now at 049d078 added the index file
(To restore them type "git stash apply")
  • 可以看到工作目录是干净的:
$ git status
# On branch master
nothing to commit, working directory clean
  • 此时,可以切换分支并在其他地方工作,我们的修改被存储在栈上。要查看贮藏的东西,可以使用 git stash list:
$ git stash list
stash@{0}: WIP on master: 049d078 added the index file
stash@{1}: WIP on master: c264051 Revert "added file_size"
stash@{2}: WIP on master: 21d80a5 added number to log
  • 在本例中,有两个之前的贮藏,所以接触到了三个不同的贮藏工作,可以通过原来 stash 命令的帮助提示中的命令将刚刚贮藏的工作重新应用:git stash apply。如果想要应用其中一个更旧的贮藏,可以通过名字指定它,像这样:git stash apply stash@{2}。 如果不指定一个贮藏,Git 认为指定的是最近的贮藏:
$ git stash apply
On branch master
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:   index.html
	modified:   lib/simplegit.rb

no changes added to commit (use "git add" and/or "git commit -a")
  • 可以看到 Git 重新修改了当我们保存贮藏时撤消的文件。当尝试应用贮藏时有一个干净的工作目录,并且尝试将它应用在保存它时所在的分支,并不是必须要有一个干净的工作目录,或者要应用到同一分支才能成功应用贮藏。可以在一个分支上保存一个贮藏,切换到另一个分支,然后尝试重新应用这些修改。当应用贮藏时工作目录中也可以有修改与未提交的文件,如果有任何东西不能干净地应用,Git 会产生合并冲突。
  • 文件的改动被重新应用了,但是之前暂存的文件却没有重新暂存。想要那样的话,必须使用 --index 选项来运行 git stash apply 命令,来尝试重新应用暂存的修改。如果已经那样做了,那么将回到原来的位置:
$ git stash apply --index
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	modified:   index.html

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:   lib/simplegit.rb
  • 应用选项只会尝试应用贮藏的工作,在堆栈上还有它,可以运行 git stash drop 加上将要移除的贮藏的名字来移除它:
$ git stash list
stash@{0}: WIP on master: 049d078 added the index file
stash@{1}: WIP on master: c264051 Revert "added file_size"
stash@{2}: WIP on master: 21d80a5 added number to log
$ git stash drop stash@{0}
Dropped stash@{0} (364e91f3f268f0900bc3ee613f9f733e82aaed43)
  • 也可以运行 git stash pop 来应用贮藏然后立即从栈上扔掉它。

三、贮藏的创意性使用

  • 有几个贮藏的变种可能也很有用,第一个非常流行的选项是 git stash 命令的 --keep-index 选项,它告诉 Git 不仅要贮藏所有已暂存的内容,同时还要将它们保留在索引中。
$ git status -s
M  index.html
 M lib/simplegit.rb

$ git stash --keep-index
Saved working directory and index state WIP on master: 1b65b17 added the index file
HEAD is now at 1b65b17 added the index file

$ git status -s
M  index.html
  • 另一个经常使用贮藏来做的事情是像贮藏跟踪文件一样贮藏未跟踪文件。默认情况下,git stash 只会贮藏已修改和暂存的已跟踪文件,如果指定 --include-untracked 或 -u 选项,Git 也会贮藏任何未跟踪文件。然而,在贮藏中包含未跟踪的文件仍然不会包含明确忽略的文件,要额外包含忽略的文件,请使用 --all 或 -a 选项。
$ git status -s
M  index.html
 M lib/simplegit.rb
?? new-file.txt

$ git stash -u
Saved working directory and index state WIP on master: 1b65b17 added the index file
HEAD is now at 1b65b17 added the index file

$ git status -s
$
  • 最终,如果指定了 --patch 标记,Git 不会贮藏所有修改过的任何东西,但是会交互式地提示哪些改动想要贮藏、哪些改动需要保存在工作目录中。
$ git stash --patch
diff --git a/lib/simplegit.rb b/lib/simplegit.rb
index 66d332e..8bb5674 100644
--- a/lib/simplegit.rb
+++ b/lib/simplegit.rb
@@ -16,6 +16,10 @@ class SimpleGit
         return `#{git_cmd} 2>&1`.chomp
       end
     end
+
+    def show(treeish = 'master')
+      command("git show #{treeish}")
+    end

 end
 test
Stash this hunk [y,n,q,a,d,/,e,?]? y

Saved working directory and index state WIP on master: 1b65b17 added the index file

四、从贮藏创建一个分支

  • 如果贮藏了一些工作,将它留在那儿了一会儿,然后继续在贮藏的分支上工作,在重新应用工作时可能会有问题。如果应用尝试修改刚刚修改的文件,会得到一个合并冲突并不得不解决它。如果想要一个轻松的方式来再次测试贮藏的改动,可以运行 git stash branch 以指定的分支名创建一个新分支,检出贮藏工作时所在的提交,重新在那应用工作,然后在应用成功后丢弃贮藏:
$ git stash branch testchanges
M	index.html
M	lib/simplegit.rb
Switched to a new branch 'testchanges'
On branch testchanges
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	modified:   index.html

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:   lib/simplegit.rb

Dropped refs/stash@{0} (29d385a81d163dfd45a452a2ce816487a6b8b014)
  • 这是在新分支轻松恢复贮藏工作并继续工作的一个很不错的途径。

五、清理工作目录

  • 对于工作目录中一些工作或文件,想做的也许不是贮藏而是移除,git clean 命令就是用来干这个的。清理工作目录有一些常见的原因,比如说为了移除由合并或外部工具生成的东西,或是为了运行一个干净的构建而移除之前构建的残留。
  • 但是,需要谨慎地使用这个命令,因为它被设计为从工作目录中移除未被追踪的文件。如果改变主意,可能也不一定能找回来那些文件的内容,一个更安全的选项是运行 git stash --all 来移除每一样东西并存放在栈中。
  • 可以使用 git clean 命令去除冗余文件或者清理工作目录,使用 git clean -f -d 命令来移除工作目录中所有未追踪的文件以及空的子目录,-f 意味着“强制(force)”或“确定要移除”,使用它需要 Git 配置变量 clean.requireForce 没有显式设置为 false。
  • 如果只是想要看看它会做什么,可以使用 --dry-run 或 -n 选项来运行命令,这意味着“做一次演习然后告诉你将要移除什么”:
$ git clean -d -n
Would remove test.o
Would remove tmp/
  • 默认情况下,git clean 命令只会移除没有忽略的未跟踪文件,任何与 .gitignore 或其他忽略文件中的模式匹配的文件都不会被移除。如果也想要移除那些文件,例如为了做一次完全干净的构建而移除所有由构建生成的 .o 文件,可以给 clean 命令增加一个 -x 选项。
$ git status -s
 M lib/simplegit.rb
?? build.TMP
?? tmp/

$ git clean -n -d
Would remove build.TMP
Would remove tmp/

$ git clean -n -d -x
Would remove build.TMP
Would remove test.o
Would remove tmp/
  • 如果不知道 git clean 命令将会做什么,在将 -n 改为 -f 来真正做之前总是先用 -n 来运行它做双重检查。另一个小心处理过程的方式是使用 -i 或 “interactive” 标记来运行它,将会以交互模式运行 clean 命令,这种方式下可以分别地检查每一个文件或者交互地指定删除的模式。
$ git clean -x -i
Would remove the following items:
  build.TMP  test.o
*** Commands ***
    1: clean                2: filter by pattern    3: select by numbers    4: ask each             5: quit
    6: help
What now>
  • 在一种奇怪的情况下,可能需要格外用力才能让 Git 清理工作目录。如果恰好在工作目录中复制或克隆了其他 Git 仓库(可能是子模块),那么即便是 git clean -fd 都会拒绝删除这些目录。这种情况下,需要加上第二个 -f 选项来强调。

以上是关于Git之深入解析如何贮藏工作分支与清理工作目录的主要内容,如果未能解决你的问题,请参考以下文章

Git之深入解析如何使用Git的分布式工作流程与如何管理多人开发贡献的项目

Git之深入解析如何通过GPG签署和验证工作

Git之深入解析如何在应用中嵌入Git

Git之深入解析如何借助Git的配置方法和钩子机制来自定义Git需求

Git之深入解析如何重写提交历史

Git之深入解析如何选择修订的版本