将已存在但未提交的工作移动到Git中的新分支

3895

我开始着手开发一个新功能,编码了一段时间后,决定将此功能放到自己的分支中。

我该如何将现有的未提交更改移动到新分支并重置我的当前分支?

我想在保留新功能上的现有工作的同时重置我的当前分支。


3
这个有趣的主题和这个链接中的一样吗?https://dev59.com/rXRB5IYBdhLWcg3wroyB - Gilberto
13个回答

4556

更新2020 / Git 2.23

Git 2.23增加了新的switch子命令,旨在消除由于checkout命令被多种用途重载而导致的混淆(切换分支,恢复文件,解开HEAD等)。

从这个Git版本开始,将checkout命令替换为:

git switch -c <new-branch>

行为相同且保持不变。


2020更新/ Git 2.23之前

使用以下内容:

git checkout -b <new-branch>

这将保留您当前的分支状态,创建并切换到一个新的分支,并保留所有更改。然后,您可以对文件中的更改进行暂存以提交:

git add <files>

并使用以下命令将更改提交到你的新分支

git commit -m "<Brief description of this commit>"

工作目录下的更改和索引中暂存的更改尚未属于任何分支。这会影响修改将要落在哪个分支上。

您不需要重置原来的分支,它仍保持不变。 <old-branch> 上的最后一个提交仍然是相同的。因此,您需要使用checkout -b 然后再进行提交。


21
确认一下,我需要在重置我的原始分支之前提交未完成的功能吗?还是这些未提交的文件会被保留,不管是否提交? - Dane O'Connor
215
请注意:工作目录中所做的更改和索引中暂存的更改不属于任何分支。使用 git checkout -b <new branch> 命令可以将这些更改归为新分支。 - Jakub Narębski
161
如果你已经有一个分支并想将更改移动到现有分支,请查阅https://dev59.com/rXRB5IYBdhLWcg3wroyB。请注意,这是英语翻译的中文版本,可能不完全准确或自然。 - Chirantan
18
如果您想将新的分支推送到远程仓库,请执行以下操作:https://dev59.com/W3E85IYBdhLWcg3wdDSz - Dewayne
12
@JDSmith:未提交的更改不属于任何分支。它们只驻留在工作目录中。使用“git checkout .”或“git reset --hard”命令将无法恢复地删除它们。 - knittl
显示剩余28条评论

416

或者:

  1. 将当前更改保存到临时贮藏:

    $ git stash

  2. 基于此贮藏创建一个新的分支,并切换到新的分支:

    $ git stash branch <new-branch> stash@{0}

提示: 使用Tab键缩短输入贮藏名称的时间。


76
如果另一个分支已经存在,您可以使用checkout切换到该分支,然后使用git stash apply - Archonic
6
我不明白提示中的“小技巧:使用 Tab 键来减少输入隐藏名字的次数。”。难道“stash@{0}”不是名称吗?我无法成功运行它。 - Herbert
9
为什么这个回答比 https://dev59.com/7XM_5IYBdhLWcg3wZSPX#1394804 更好? - Chris Page
12
我不明白为什么这个方法比 git checkout -b <新分支名> 的被接受的回答更好。 - Noitidart
7
储藏前不需要执行 git add -A - vichle
显示剩余12条评论

62

如果您在编码过程中一直在主分支上提交代码,但现在想将这些提交移到另一个分支,这是一种快速的方法:

  1. 将当前的历史记录复制到一个新分支上,并带上任何未提交的更改:

  2.  git checkout -b <new-feature-branch>
    
  3. 现在强制将原始的“混乱”分支回退:(无需切换到它)

  4.  git branch -f <previous-branch> <earlier-commit-id>
    
    例如:
     git branch -f master origin/master
    

    或者如果您已经进行了4次提交:

     git branch -f master HEAD~4
    

警告:git branch -f master origin/master重置该分支的跟踪信息。因此,如果您已经将master分支配置为推送到其他位置而不是origin/master,则该配置将丢失。

警告:如果在创建分支后进行变基操作,则可能会丢失一些提交记录,详情可以参考此处。避免此情况的唯一方法是使用cherry-pick创建新的历史记录。该链接描述了最安全的、万无一失的方法,尽管不太方便。(如果您有未提交的更改,则可能需要在开始时使用git stash命令,在结束时使用git stash pop命令。)


7
这篇回答略有不同于提问者的问题。我决定把这个答案放在这里,因为当我正在寻找答案时,谷歌带我来到了这里。实际上,处理这种情况的问题在这里。 - joeytwiddle

57
常见的场景是这样的:我忘记为新功能创建新分支,而是在旧功能分支上完成了所有工作。我已将所有“旧”工作提交到主分支,并希望我的新分支从“主”分支开始增长。我还没有为我的新工作做出任何提交。
这是分支结构:
“master”->“Old_feature”
git stash 
git checkout master
git checkout -b "New_branch"
git stash apply

"git switch -c <new-branch>" 清除了未暂存文件的更改(仅保留新文件);如果您想要恢复所有本地文件,那么使用stash方式会更好。 - Bee Chow
那不是我的经历 - 正如其他人所写的,您本地未暂存的更改会保留在新分支中。(我必须承认我使用了checkout -b而不是switch -c,但这两个命令应该是相同的) - ckapilla

22

如果你提交了它,你也可以挑选单个提交ID。当我开始在主分支上工作时,我经常这样做,然后想在推送到我的origin/之前创建一个本地分支。

git cherry-pick <commitID>

你可以在这里了解到关于 cherry-pick 的很多用法,但这可能是适用于你的一个使用场景。


4
将部分更改移动到新分支的更好解决方案是:由于现在可以只提交需要的更改,将所有其他更改存储起来,检出要创建新分支的分支,将该提交复制到新分支上,返回原始分支,进行一个硬重置退回一个提交,然后进行“存储弹出”,添加,提交,最后高声唱赞歌。 - Meredith
3
@Meredith,哈哈,是的,就像那样。这很好,除非你提前计划了你的变化……可是谁会这么做呢 ;) - password

8

选项1(使用现有分支)

git stash (from main/any-branch)
git checkout your-existing-branch
git stash apply 

选项2(创建一个新分支)

git switch -c your-new-branch

7

对于使用 Visual Studio Community 2022(以及可能的早期版本)的用户,在您有未提交的更改时创建一个新分支,您将看到如下对话框:

enter image description here

只需选择第一个选项将更改带到'[your-new-branch-name]' 并单击继续结帐。新分支将被创建,您可以在那里继续提交更改。

5

现在使用GitHub Desktop实现这个功能非常容易,而且我认为以前并没有这个功能。

你只需要在GitHub Desktop中切换到新分支,它会提示你将更改留在当前分支(会被存储),或者将更改带到新分支。选择第二个选项,将更改带到新分支中,然后像往常一样进行提交即可。

GitHub Desktop


3
这可能对所有使用GIT工具的人有所帮助。 命令 转换分支 - 它将把你的更改移动到新分支。然后你可以提交更改。
 $ git checkout -b <new-branch>

TortoiseGIT

右键单击您的代码库,然后使用TortoiseGit->Switch/Checkout

enter image description here enter image description here

SourceTree

使用“Checkout”按钮切换分支。在单击分支后,您将在顶部看到“checkout”按钮。来自当前分支的更改将自动应用。然后您可以提交它们。

enter image description here


1

这是唯一一个告诉你使用git stash -k的答案,如果你已经花了一个小时用git add -p,然后决定在实际提交之前测试你添加到索引中的内容。在这种情况下,不要使用普通的git stash

相反,做如下操作:

git stash -k

这将保留索引并删除其余仍在工作目录中且尚未添加到索引中的内容。正是您想要的。

现在,您可以尝试编译/测试和提交。例如:

make
git commit -m 'Yay!'

然后使用以下命令获取未提交的更改:
git stash pop

如果你发现它无法编译,那么对其进行更改并添加这些更改到索引中并提交可能会让git stash pop混淆。当涉及合并时,它并不是很好用。在这种情况下,你可能应该直接提交;因此:

make
git commit -m 'Grrrr'

然后创建一个新分支,

git switch -c tmpbranch

在那里完成你的工作(更改代码,进行测试和提交更多内容)

/* blood sweat and tears */

一旦所有东西都正常工作,请将其提交到新分支

commit -a -m 'Finally!'

回到旧分支,然后使用与推送到存储区时相同的工作目录执行git stash pop

git checkout youknowwhatbranchyouwereonright
git stash pop

提交这个也要,否则你无法合并tmpbranch。 然后合并你创建的临时分支。

git commit -a -m 'Still working on this.'
git merge tmpbranch
/* fix collisions and commit */

现在你可以进行一次变基操作,将“仍在处理中”的提交放在顶部,并将其余的提交压缩/修复为单个注释。例如:

git rebase -i

可能会给你:

pick 540623a Grrr
pick a8589d3 Still working on this.
pick d3b602c Finally

然后将其更改为:

reword 540623a Grrr
fixup d3b602c Finally
pick a8589d3 Still working on this.

最后撤销上一次提交(即“仍在处理中”)

git reset HEAD~1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接