如何仅将分支中多个已更改文件之一存储?
git diff -- *filename* > ~/patch
然后git checkout -- *filename*
,以后您可以使用git apply ~/patch
git stash push [--] [<pathspec>...]
。
如何仅将分支中多个已更改文件之一存储?
git diff -- *filename* > ~/patch
然后git checkout -- *filename*
,以后您可以使用git apply ~/patch
git stash push [--] [<pathspec>...]
。
Answers:
免责声明:以下答案适用于git 2.13之前的git。对于git 2.13及更高版本,请进一步查找其他答案。
警告
正如评论中所指出的,这会将所有内容(无论已上演还是未上演)都置于藏匿处。在隐藏之后,--keep-index仅保留索引。当您稍后弹出存储时,这可能导致合并冲突。
这将存储您以前未添加的所有内容。只是git add
要保留的内容,然后运行它。
git stash --keep-index
例如,如果您要将一个旧的提交拆分为多个变更集,则可以使用以下过程:
git rebase -i <last good commit>
edit
。git reset HEAD^
git add <files you want to keep in this change>
git stash --keep-index
git add
任何更改。git commit
git stash pop
git rebase --continue
git stash save -k
,是的,索引(在中的绿色git stat
)被保留,但是整个变更集(绿色和红色)都进入存储区。这违反了OP的要求,“仅存储一些更改”。我只想藏一些红色(以备将来使用)。
git stash -p
正是我想要的。我想知道是否仅在最近才添加了此开关。
git stash --keep-index
已损坏。如果您进行更多更改,请稍后尝试git stash pop
合并冲突,因为隐藏文件包含您保留的更改文件,而不仅仅是您未保留的文件。例如:因为我要测试A中的更改,所以我更改文件A和B,然后隐藏B。我发现A问题,然后解决;我犯了A; 现在,我无法取消隐藏,因为旧版本的A处于隐藏状态,没有充分的理由导致合并冲突。在实践中,A和B可能有很多文件,甚至可能是二进制映像之类的东西,所以我基本上必须放弃并丢失
您也可以使用git stash save -p "my commit message"
。这样,您可以选择应将哪些块添加到存储中,也可以选择整个文件。
对于每个大块,系统将提示您一些操作:
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
stash -p
。我之所以能回答这个问题,是因为它仍然是最具交互性/用户友好性的。
git stash save -p my stash message
; 因为参数的顺序不是很直观...
git log -p
,我认为该-p
标志必须表示“做我想做的很酷的事情,但不知道如何表达”。
由于git从根本上讲是管理所有存储库内容和索引(而不是一个或多个文件)git stash
,因此毫不奇怪地进行交易,与所有工作目录。
实际上,从Git 2.13(2017年第二季度)开始,您可以使用以下方式存储单个文件git stash push
:
git stash push [--] [<pathspec>...]
当
pathspec
给'git stash push
'时,新存储区仅记录与pathspec匹配的文件的修改状态。有关更多信息,请参见“存储到特定文件的更改 ”。
简化示例:
git stash push path/to/file
此功能的测试案例显示了更多选项:
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的答案(2011年11月更新)提出了一个基于
git add
+git stash --keep-index
的更实际的解决方案。
去看看并支持他的答案,应该是官方的答案(而不是我的答案)。
关于该选项,chhh在注释中指出了另一种工作流程:
您应该
git reset --soft
在这样的存储之后进行恢复,
以恢复清晰的状态:为了恢复原始状态-这是一个清晰的过渡区域,并且只有部分未分级的选择修改,才能轻柔地重置索引以获取(无需承诺像你一样-布克佐-做了)。
(2010年6月的原始答案:手动藏书)
但是,git stash save --patch
可以允许您实现部分隐藏的操作:
使用
--patch
,您可以从HEAD与要隐藏的工作树之间的差异中交互选择块。
存储项的构造应使其索引状态与存储库的索引状态相同,并且其工作树仅包含交互式选择的更改。然后,所选更改将从工作树中回滚。
但是,这将保存完整的索引(这可能不是您想要的,因为它可能包括已被索引的其他文件)和一个局部的工作树(看起来像您要隐藏的树)。
git stash --patch --no-keep-index
可能更合适。
如果--patch
不起作用,则手动过程可能会:
对于一个或多个文件,一种中间解决方案是:
git stash
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 -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
。该修补程序会生成OK,但是我随后需要移至存储库根目录才能应用该修补程序。因此,如果您对此有疑问-只需确保从存储库根目录进行即可。
使用git stash push
,如下所示:
git stash push [--] [<pathspec>...]
例如:
git stash push -- my/file.sh
自2017年春季发布的Git 2.13开始可用。
git stash apply
来恢复隐匿的变化吗?
假设您有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。
另一种方法是:
# 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,因为您也将它们移开了)。
更新(2/14/2015)-我稍微重写了一下脚本,以更好地处理冲突的情况,现在应将其显示为未合并的冲突,而不是.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
现在,存储区包含一个新条目,其中仅包含您已暂存的更改,而工作树仍包含所有未暂存的更改。
在某些情况下,工作树更改可能取决于索引更改,因此,当您存储索引更改时,工作树更改会发生冲突。在这种情况下,您将获得通常的未合并冲突,可以使用git merge / git mergetool / etc解决。
pushd
的替代cd
和popd
在脚本,如果脚本成功结束后,用户在同一个目录中运行它之前结束。
由于在Git中创建分支很简单,因此您只需创建一个临时分支并将单个文件签入其中即可。
您可以简单地做到这一点:
git stash push "filename"
或带有可选消息
git stash push -m "Some message" "filename"
将以下代码保存到一个名为的文件中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(可能会使用类似的工具)而不是使用副本更容易:
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个步骤即可轻松完成此操作。
在SourceTree中只需几秒钟即可完成所有操作,您可以在其中单击要添加的文件(甚至单个行)。添加后,只需将其提交到临时提交即可。接下来,单击复选框以添加所有更改,然后单击存储以存储所有内容。随着隐藏的更改的进行,请浏览您的提交列表,并在临时提交之前记下该提交的哈希,然后运行“ 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)
:无效的命令当前,能够存储任何特定已跟踪/未跟踪文件的最合理方法是:
本地更改:
要创建仅在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}
做完了
您可以在步骤之间使用git status查看发生了什么。
当您尝试在两个分支之间切换时,会发生这种情况。
尝试使用“ git add filepath
” 添加文件。
稍后执行此行
git stash --keep-index
要隐藏单个文件,请使用git stash --patch [file]
。
这将提示:Stash this hunk [y,n,q,a,d,j,J,g,/,e,?]? ?
。只需键入a
(将此块以及所有以后的块存储在文件中)就可以了。
push
的内容git stash push --patch [file]
类似的情况。确实提交并意识到这不行。
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 . //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)
要在git中还原特定的更改文件,可以执行以下行:
git checkout <branch-name> -- <file-path>
这是一个实际的示例:
git checkout master -- battery_monitoring/msg_passing.py
git stash --keep-index
确实保留了索引,但是却隐藏了所有内容 –无论是索引内还是索引外。