如何在我的分支上仅存储多个更改文件中的一个?
git diff -- *filename* > ~/patch
然后 git checkout -- *filename*
和稍后您可以使用 git apply ~/patch
重新应用补丁
git stash push [--] [<pathspec>...]
支持。
git stash push -p -m "my commit message"
-p
让您选择应该隐藏的大块;也可以选择整个文件。
系统会提示您针对每个大块执行一些操作:
y - stash this hunk
n - do not stash this hunk
q - quit; do not stash this hunk or any of the remaining ones
a - stash this hunk and all later hunks in the file
d - do not stash this hunk or any of the later hunks in the file
g - select a hunk to go to
/ - search for a hunk matching the given regex
j - leave this hunk undecided, see next undecided hunk
J - leave this hunk undecided, see next hunk
k - leave this hunk undecided, see previous undecided hunk
K - leave this hunk undecided, see previous hunk
s - split the current hunk into smaller hunks
e - manually edit the current hunk
? - print help
免责声明:以下答案适用于 git 2.13 之前的 git。对于 git 2.13 及更高版本,请查看 another answer further down。
警告
正如评论中所指出的,这会将所有内容都放入存储中,包括分阶段和非分阶段。 --keep-index 只是在存储完成后单独保留索引。当您稍后弹出存储时,这可能会导致合并冲突。
这将隐藏您之前未添加的所有内容。只需git add
您想要保留的内容,然后运行它。
git stash --keep-index
例如,如果要将旧提交拆分为多个变更集,则可以使用以下过程:
git rebase -i
git stash save -k
时,是的,索引(git stat
中的绿色)被保留,但 整个 变更集(绿色和红色)进入存储区。这违反了 OP 的要求,“仅存储一些更改”。我想存储一些红色(以备将来使用)。
git stash -p
正是我想要的。我想知道这个开关是不是最近才添加的。
git stash --keep-index
已损坏。如果您进行了更多更改,那么稍后再尝试 git stash pop
,您会遇到合并冲突,因为存储区包括您保留的已更改文件,而不仅仅是您未保留的文件。例如:我更改了文件A和B,然后stash B,因为我想测试A中的更改;我发现了 A 的问题,然后我修复了;我承诺 A;现在我无法取消存储,因为旧版本的 A 无缘无故地在存储中导致合并冲突。在实践中A和B可能是很多文件,甚至可能是二进制图像什么的,所以我基本上不得不放弃并失去B。
从 Git 2.13(2017 年第二季度)开始,您可以使用 git stash push
存储单个文件:
git stash push [-m <message>] [--] [<pathspec>...]
当 pathspec 被赋予 'git stash push' 时,新的 stash 仅记录与 pathspec 匹配的文件的修改状态。有关更多信息,请参阅“将更改存储到特定文件”。
简化示例:
git stash push path/to/file
此功能的 The test case 显示了更多关闭选项:
test_expect_success 'stash with multiple pathspec arguments' '
>foo &&
>bar &&
>extra &&
git add foo bar extra &&
git stash push -- foo bar &&
test_path_is_missing bar &&
test_path_is_missing foo &&
test_path_is_file extra &&
git stash pop &&
test_path_is_file foo &&
test_path_is_file bar &&
test_path_is_file extra
最初的答案(如下,2010 年 6 月)是关于手动选择要存储的内容。
Casebash 条评论:
这个(stash --patch 原始解决方案)很好,但我经常修改很多文件,所以使用补丁很烦人
bukzor 的 answer(2011 年 11 月投票)提出了一个更实用的解决方案,基于
git add
+ git stash --keep-index
。
去看看他的回答并投票,这应该是官方的(而不是我的)。
关于该选项,chhh 在评论中指出了另一种工作流程:
您应该在这样的存储之后“git reset --soft”以使您的清晰暂存恢复:为了回到原始状态 - 这是一个清晰的暂存区域并且只有一些选择的未暂存修改,可以软重置要获取的索引(没有像你这样 - bukzor - 所做的事情)。
(2010 年 6 月的原始答案:手动存储)
然而,git stash save --patch
可以让您实现您所追求的部分存储:
使用 --patch,您可以交互地从 HEAD 和要隐藏的工作树之间的差异中选择块。存储条目的构造使其索引状态与存储库的索引状态相同,并且其工作树仅包含您以交互方式选择的更改。然后从您的工作树中回滚选定的更改。
但是,这将保存完整索引(这可能不是您想要的,因为它可能包含其他已编入索引的文件)和部分工作树(可能看起来像您想要存储的那个)。
git stash --patch --no-keep-index
可能更合适。
如果 --patch
不起作用,手动过程可能会:
对于一个或多个文件,中间解决方案是:
将它们复制到 Git 存储库之外(实际上,eleotlecram 提出了一个有趣的替代方案)
混帐藏匿
把它们复制回来
git stash # 这次只存放你想要的文件
git stash pop stash@{1} # 重新应用所有文件修改
git checkout -- afile # 在任何本地修改之前将文件重置为 HEAD 内容
在这个相当繁琐的过程结束时,您将只存储一个或多个文件。
git reset
(混合)
git is fundamentally about managing a all repository content and index and not one or several files
- 实现掩盖了正在解决的问题;这是一个解释,但不是一个理由。任何源代码控制系统都是关于“管理多个文件”的。看看哪些评论最受好评。
git stash --keep-index
;正如对 bukzor 答案的评论中所指出的那样,它根本不会像您认为的那样做。创建两个文件,foo
和 bar
。提交他们。为每个添加一行。 git add foo
。 git stash --keep-index
。现在想要的结果是您已隐藏对 bar
的更改,并且您对 foo
的更改仍然存在并暂存。现实情况是,您对 foo
的更改已呈现并暂存,但您对 both 文件的更改已隐藏。如果您 git reset
并修改 foo
,由于冲突,您现在不能 git stash pop
。
使用 git stash push
,如下所示:
git stash push [--] [<pathspec>...]
例如:
git stash push -- my/file.sh
这是自 2017 年春季发布的 Git 2.13 以来可用的。
git stash push
。我在这里详细介绍了新的 Git 2.13 命令:stackoverflow.com/a/42963606/6309。
git stash apply
来恢复隐藏的更改?
当 git stash -p
(或 git add -p
与 stash --keep-index
)过于繁琐时,我发现使用 diff
、checkout
和 apply
更容易:
仅“存储”特定文件/目录:
git diff path/to/dir > stashed.diff
git checkout path/to/dir
然后之后
git apply stashed.diff
git add -p
的有趣替代方案。 +1。
git diff > file.diff
和 git apply
是我常用的部分存储工具。对于更大的变更集,我可能不得不考虑切换到 git stash -p
。
patch = log --pretty=email --patch-with-stat --reverse --full-index --binary
。但是请注意,这需要您对要提交的补丁所做的更改。
../../foo/bar.txt
,这对我来说不是很干净。补丁生成正常,但我需要移动到存储库根目录才能应用补丁。因此,如果您遇到问题 - 只需确保您是从存储库根目录执行此操作。
假设您有 3 个文件
a.rb
b.rb
c.rb
并且您只想存储 b.rb 和 c.rb 而不是 a.rb
你可以做这样的事情
# commit the files temporarily you don't want to stash
git add a.rb
git commit -m "temp"
# then stash the other files
git stash save "stash message"
# then undo the previous temp commit
git reset --soft HEAD^
git reset
你完成了! HTH。
如果您不想在隐藏的更改中指定消息,请在双破折号后传递文件名。
$ git stash -- filename.ext
如果它是一个未跟踪的/新文件,您必须先暂存它。
此方法适用于 git 版本 2.13+
如果您只想存储部分更改的文件,只需在 Stage 中添加其他文件,然后执行 git stash push --keep-index
它将存储所有未暂存的更改文件
另一种方法:
# Save everything
git stash
# Re-apply everything, but keep the stash
git stash apply
git checkout <"files you don't want in your stash">
# Save only the things you wanted saved
git stash
# Re-apply the original state and drop it from your stash
git stash apply stash@{1}
git stash drop stash@{1}
git checkout <"files you put in your stash">
在我(再次)来到这个页面并且不喜欢前两个答案之后我想出了这个(第一个答案只是没有回答问题,我不太喜欢使用 -p
交互模式)。
这个想法与@VonC 建议使用存储库外部文件的想法相同,您将所需的更改保存在某处,删除您不想要的更改,然后重新应用您移开的更改。但是,我将 git stash 用作“某处”(因此,最后还有一个额外的步骤:删除您放入 stash 的 cahnges,因为您也将它们移开了)。
你可以简单地这样做:
git stash push "filename"
或带有可选消息
git stash push -m "Some message" "filename"
git stash push -- <filepath>
对我有用,并在最近的 GIT 版本 (v2.13>) 中添加为要走的路。你可以得到<文件路径>如果你运行 git status。
更新(2015 年 2 月 14 日)- 我稍微重写了脚本,以更好地处理冲突的情况,现在应该将其显示为未合并的冲突而不是 .rej 文件。
我经常发现与@bukzor 的方法相反更直观。也就是说,先进行一些更改,然后仅存储那些已分阶段的更改。
不幸的是,git 没有提供 git stash --only-index 或类似的功能,所以我编写了一个脚本来执行此操作。
#!/bin/sh
# first, go to the root of the git repo
cd `git rev-parse --show-toplevel`
# create a commit with only the stuff in staging
INDEXTREE=`git write-tree`
INDEXCOMMIT=`echo "" | git commit-tree $INDEXTREE -p HEAD`
# create a child commit with the changes in the working tree
git add -A
WORKINGTREE=`git write-tree`
WORKINGCOMMIT=`echo "" | git commit-tree $WORKINGTREE -p $INDEXCOMMIT`
# get back to a clean state with no changes, staged or otherwise
git reset -q --hard
# Cherry-pick the index changes back to the index, and stash.
# This cherry-pick is guaranteed to succeed
git cherry-pick -n $INDEXCOMMIT
git stash
# Now cherry-pick the working tree changes. This cherry-pick may fail
# due to conflicts
git cherry-pick -n $WORKINGCOMMIT
CONFLICTS=`git ls-files -u`
if test -z "$CONFLICTS"; then
# If there are no conflicts, it's safe to reset, so that
# any previously unstaged changes remain unstaged
#
# However, if there are conflicts, then we don't want to reset the files
# and lose the merge/conflict info.
git reset -q
fi
您可以将上述脚本另存为 git-stash-index
在路径中的某处,然后可以将其作为 git stash-index 调用
# <hack hack hack>
git add <files that you want to stash>
git stash-index
现在 stash 包含一个新条目,其中仅包含您已暂存的更改,并且您的工作树仍包含任何未暂存的更改。
在某些情况下,工作树的更改可能依赖于索引的更改,因此当您存储索引更改时,工作树的更改会发生冲突。在这种情况下,您将获得可以使用 git merge/git mergetool/etc 解决的常见未合并冲突。
pushd
而不是 cd
和 popd
,这样如果脚本成功,用户将在与运行之前相同的目录中结束。
由于在 Git 中创建分支很简单,您可以创建一个临时分支并将各个文件签入其中。
以防万一您实际上是指 discard changes 每当您使用 git stash
(并且不要真正使用 git stash 临时存储它),在这种情况下,您可以使用
git checkout -- <file>
[笔记]
git stash
只是分支和执行操作的一种更快速、更简单的替代方法。
将以下代码保存到文件中,例如,名为 stash
。用法是 stash <filename_regex>
。参数是文件完整路径的正则表达式。例如,存储 a/b/c.txt、stash a/b/c.txt
或 stash .*/c.txt
等。
$ chmod +x stash
$ stash .*.xml
$ stash xyz.xml
要复制到文件中的代码:
#! /usr/bin/expect --
log_user 0
set filename_regexp [lindex $argv 0]
spawn git stash -p
for {} 1 {} {
expect {
-re "diff --git a/($filename_regexp) " {
set filename $expect_out(1,string)
}
"diff --git a/" {
set filename ""
}
"Stash this hunk " {
if {$filename == ""} {
send "n\n"
} else {
send "a\n"
send_user "$filename\n"
}
}
"Stash deletion " {
send "n\n"
}
eof {
exit
}
}
}
VonC 将文件复制到 Git 存储库外部的“中间”解决方案的问题是您丢失了路径信息,这使得稍后将一堆文件复制回来有点麻烦。
发现使用 tar (类似的工具可能会做)而不是复制更容易:
tar cvf /tmp/stash.tar path/to/some/file path/to/some/other/file (... etc.)
git checkout path/to/some/file path/to/some/other/file
混帐藏匿
tar xvf /tmp/stash.tar
等等(参见 VonC 的“中级”建议)
checkout -f
不需要,checkout
(没有 -f
)就足够了,我已经更新了答案。
有时我在提交之前对我的分支进行了不相关的更改,我想将其移动到另一个分支并单独提交(如 master)。我这样做:
git stash
git checkout master
git stash pop
git add <files that you want to commit>
git commit -m 'Minor feature'
git stash
git checkout topic1
git stash pop
...<resume work>...
注意第一个 stash
& stash pop
可以删除,您可以在结帐时将所有更改转移到 master
分支,但前提是没有冲突。此外,如果您为部分更改创建新分支,您将需要存储。
假设没有冲突并且没有新分支,您可以简化它:
git checkout master
git add <files that you want to commit>
git commit -m 'Minor feature'
git checkout topic1
...<resume work>...
甚至不需要藏匿...
这可以使用 SourceTree 分 3 步轻松完成。
暂时提交您不想隐藏的所有内容。 Git 添加其他所有内容,然后将其隐藏。通过运行 git reset 弹出你的临时提交,在你的临时提交之前定位提交。
在 SourceTree 中,这一切都可以在几秒钟内完成,您只需单击要添加的文件(甚至单独的行)。添加后,只需将它们提交到临时提交。接下来,单击复选框以添加所有更改,然后单击 stash 以存储所有内容。随着隐藏的更改,浏览您的提交列表并在临时提交之前记下提交的哈希,然后运行“git reset hash_b4_temp_commit”,这基本上就像通过将分支重置为“弹出”提交在它之前提交。现在,你只剩下不想藏起来的东西了。
我会使用 git stash save --patch
。我不觉得交互性很烦人,因为在交互过程中有一些选项可以将所需的操作应用于整个文件。
git stash -p
允许您快速存储整个文件并在之后退出。
这里的每一个答案都很复杂......
这要“藏起来”怎么办:
git diff /dir/to/file/file_to_stash > /tmp/stash.patch
git checkout -- /dir/to/file/file_to_stash
这将弹出文件更改:
git apply /tmp/stash.patch
与存储一个文件并将其重新弹出完全相同的行为。
git apply
我没有错误但更改也没有恢复
我已经审查了这个问题的答案和评论以及许多类似的主题。请注意,对于能够存储任何特定跟踪/未跟踪文件的目的,以下命令均不正确:
git stash -p (--patch):手动选择大块,不包括未跟踪的文件
git stash -k (--keep-index): 存储所有被跟踪/未跟踪的文件并将它们保存在工作目录中
git stash -u (--include-untracked): 存储所有跟踪/未跟踪的文件
git stash -p (--patch) -u (--include-untracked): 无效命令
目前,能够存储任何特定跟踪/未跟踪文件的最合理方法是:
临时提交您不想存储的文件
添加和存储
弹出临时提交
I wrote a simple script for this procedure in an answer to another question,还有 steps for performing the procedure in SourceTree here。
当您尝试在两个分支之间切换时,就会出现这种情况。
尝试使用“git add filepath
”添加文件。
稍后执行此行
git stash --keep-index
解决方案
局部变化:
file_A(已修改)未暂存
file_B(已修改)未暂存
file_C(已修改)未暂存
要创建仅对 file_C 进行更改的存储“my_stash”:
1. git add file_C
2. git stash save --keep-index temp_stash
3. git stash save my_stash
4. git stash pop stash@#{1}
完毕。
解释
将 file_C 添加到暂存区 创建一个名为“temp_stash”的临时存储并保留对 file_C 的更改 创建想要的存储(“my_stash”),仅对 file_C 进行更改 在本地应用“temp_stash”(file_A 和 file_B)中的更改编码并删除存储
您可以在步骤之间使用 git status 来查看发生了什么。
要存储单个文件,请使用 git stash --patch [file]
。
这将提示:Stash this hunk [y,n,q,a,d,j,J,g,/,e,?]? ?
。只需键入 a
(将这个大块和所有后来的大块存储在文件中)就可以了。
push
,如 git stash push --patch [file]
push
仅适用于 Git 的更多 recent versions,以前是 save
。在任何一种情况下,调用 stash
都暗示了 push
或 save
:“调用不带任何参数的 git stash 等同于 git stash push”,docs
类似的情况。确实提交并意识到这不好。
git commit -a -m "message"
git log -p
根据答案,这对我有所帮助。
# revert to previous state, keeping the files changed
git reset HEAD~
#make sure it's ok
git diff
git status
#revert the file we don't want to be within the commit
git checkout specs/nagios/nagios.spec
#make sure it's ok
git status
git diff
#now go ahead with commit
git commit -a -m "same|new message"
#eventually push tu remote
git push
在这种情况下,我git add -p
(交互式)、git commit -m blah
,然后在必要时存储剩余的内容。
我不知道如何在命令行上执行此操作,仅使用 SourceTree。假设您更改了文件 A,并在文件 B 中有两个更改块。如果您只想将第二个块存储在文件 B 中,而其他所有内容都保持不变,请执行以下操作:
暂存所有内容 对您的工作副本执行更改以撤消文件 A 中的所有更改。(例如,启动外部差异工具并使文件匹配。)使文件 B 看起来好像只应用了第二次更改。 (例如,启动外部差异工具并撤消第一次更改。)使用“保持分阶段更改”创建一个存储。 Unstage 一切完成!
git add . //stage all the files
git reset <pathToFileWillBeStashed> //unstage file which will be stashed
git stash //stash the file(s)
git reset . // unstage all staged files
git stash pop // unstash file(s)
对于 VS Code 的用户。 Git 侧边栏视图中更改组的存储按钮将仅存储组中的文件。因此,如果您将一些文件移出该组,则可以存储剩余的文件。我知道在不恢复更改的情况下将一些文件移出那里的唯一方法是暂存它们。所以:
暂存您不想暂存的文件 单击更改组标题中的暂存按钮 取消暂存您已移开的文件
一种复杂的方法是首先提交所有内容:
git add -u
git commit // creates commit with sha-1 A
重置回原始提交,但从新提交中签出 the_one_file:
git reset --hard HEAD^
git checkout A path/to/the_one_file
现在您可以存储 the_one_file:
git stash
通过将提交的内容保存在文件系统中来进行清理,同时重置为原始提交:
git reset --hard A
git reset --soft HEAD^
是的,有点尴尬……
我没有找到我需要的答案,这很简单:
git add -A
git reset HEAD fileThatYouWantToStash
git commit -m "committing all but one file"
git stash
这仅存储一个文件。
不定期副业成功案例分享
stash -p
。我奖励这个答案是因为它仍然是最具交互性/用户友好性的。git stash save -p my stash message
;因为参数的顺序不是很直观......git log -p
之间,我认为-p
标志必须表示“做我想做但不知道如何表达的酷事”。git stash push -m <stash_name> <file_path_to_stash>