创建新分支,在 Master 中保留未暂存的更改

Create new branch keeping unstaged changes in Master

我对 Git 在正常提交过程之外的经验相当缺乏。

现在我在主分支上,有 8 个未暂存的更改。我想做的是用最后一次提交创建一个新分支(即没有 8 个未暂存的更改),但我想保存未暂存的更改,以便以后可以重新访问它们。

我该怎么做?

如果您还没有提交这些新更改,它们对分支是不可见的,您可以直接从 master 分支出来:

$ git branch newbranch

或者,更明确地说:

$ git branch newbranch master

你可以简单地做

git checkout -b newbranch

这将从 master 创建一个新分支,将您签到 newbranch 并且您将按原样进行 unstaged/uncommited 更改。

如果您想在分支之间切换时保留更改但不想提交,请使用 git stash

正如其他人在答案和评论中提到的那样,至少有三个选项。它们之间有相当多的重叠,并且各有利弊:

  1. 创建新分支es(复数)
  2. 隐藏更改
  3. 添加工作树(worktree)

创建新分支

分支几乎不需要任何成本,因此最简单的选择是创建新分支,而不会对您现有的工作流程进行真正的更改。如果您不确定某天是否会想要某些东西,将它提交到 "work-in-progress" 或 "experimental" 分支通常不会有什么坏处。

在你的特定情况下,我建议创建一个新分支来保存你的 8 个未暂存的更改(我们称它们为实验性的)和另一个新分支 master 用于你想做的其他工作(我们称之为新功能) :

git checkout -b experimental/foo
git add --all
git commit -m 'Trying a new structure for Foo'
git checkout master
git checkout -b feature/bar

如果您想暂时保存您的 8 个更改(或者如果您不确定要多久才能返回到它们),我会推荐这种方法。您甚至可以将实验分支推送到您的上游存储库以获得额外的冗余或在其上进行协作。

注1最后两条命令可以合为一行git checkout -b feature/bar master。它更聪明(并且可以说更明确),但我喜欢保持简单,并且在从它创建新分支之前总是检查一个分支

注释 2 "experimental/" 和 "feature/" 命名空间是可选的,但我发现它们有助于我以后了解过去的想法。并写一个good commit message,以后的你会感谢过去的你:)

隐藏更改

另一种选择是暂时“stash”更改,然后将隐藏的更改重新应用到您的主分支(甚至其他分支)。

在你的情况下,我会隐藏更改(带有描述性消息),创建新的功能分支,然后,稍后你可以回来并将隐藏的更改应用到 master:

git stash --include-untracked save 'Trying a new structure for Foo'
git checkout -b feature/bar
...
<make a few changes in feature/bar and commit or discard them>
...
git checkout master
git stash apply

存储有点复杂,但它可以非常灵活。创建分支的主要区别在于存储只是本地的;他们不能被推到上游。如果您知道您需要存储提供的额外灵活性,或者如果存储的寿命很短,基本上是快速剪切和粘贴,我只会推荐此选项。

注意 1 默认情况下,存储仅包含修改过的文件,如果您的更改包含任何新文件,--include-untracked 选项很重要。您也可以使用 --all(就像我们在上面使用 git add 一样),但这也会隐藏被忽略的文件。

注 2 以上假设您在此期间没有存放任何其他东西。使用 git stash list 来检查您此后没有进行过其他藏匿。完成此存储后,您可以使用 git stash drop 将其删除。 git stash pop 只需一条命令即可申请和投放。

注释 3如果您想了解更多,Atlassian 有一个 pretty useful tutorial on how to use git stash

添加工作树(Worktree)

另一个(稍微)更复杂但更灵活的选项是添加 working tree(从现在开始我将只使用 "worktree" 来反映命令的名称)。您的工作树是未暂存更改存在的地方,在您结帐和在分支之间移动时与您一起移动。默认情况下,只有一个 "main" 工作树,但您可以添加一个或多个 "linked" 工作树,让您同时签出多个分支,并在每个工作树中进行不同的未暂存更改。

在上面的场景中,我可能会基于 master 创建一个新的工作树(和分支),然后切换到新的工作树目录。您未暂存的更改将保留在您的主工作树中,您只需切换回该目录即可返回继续处理它们:

git worktree add -b feature/bar ../app-name-bar
cd ../app-name-bar

因为这允许您一次签出多个分支,所以它可以实现一些非常好的工作流程。例如,您可以打开两个不同的终端 and/or 编辑器 windows/tabs,并排查看两个分支。这是我会为任何事情选择的解决方案,除非我可能会使用存储的非常短期的需求。

注 1 使用此选项您还创建了一个新分支。这基本上是选项 1 的特例。

注 2 不能在两个不同的工作树中激活同一个分支。如果出于某种原因需要复制分支或 运行 与 --detach 分离的第二个分支(有关详细信息,请参阅 this article

注释 3 上述命令将创建一个新文件夹 "app-name-bar",与您当前的存储库处于同一级别。因此,假设您的应用程序名为 "todos",您最终会在文件系统中得到另一个 "todos" 的副本,名为 "todos-bar"(尽管您可以随意调用它)。为了让事情井井有条,我更喜欢为我所有的工作树文件夹创建一个包含文件夹。以下步骤展示了如何将您当前的存储库从 todos 移动和重命名为 todos/main,这样您就可以拥有一个或多个额外的链接工作树与您的主工作树并存:

# Do these steps just once
mv todos/ main/
mkdir todos
mv main todos/
cd todos/main

# Do these steps every time you want to add a worktree...
cd todos/main
git worktree add -b feature/bar ../bar
cd ../bar

# ...and you'll end up with this directory structure
# └─ todos/
#   ├─ main/
#   | └─ ...
#   └─ bar/
#     └─ ...