从Git中更改的多个文件中只存储一个文件?
我怎么能只存储我的分支上多个更改的文件之一?
警告
正如在评论中指出的那样,这将所有东西放到藏起来,既上演也不搁置。 – 保持索引仅仅在索引完成后离开索引。 这可能会导致合并冲突,当你以后popup存储。
这将存储您以前没有添加的所有内容。 只要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
- 从#5重复,如有必要。
-
git rebase --continue
你也可以使用git stash -p
。 这样你可以select应该添加哪些垃圾箱,也可以select整个文件。
系统会提示您为每个人做一些操作:
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基本上是pipe理所有的存储库内容和索引(而不是一个或几个文件),所以并不奇怪, 与所有的工作目录 。
实际上,自Git 2.13(2017年第2季度)以来,您可以隐藏单个文件:
git stash push [--] [<pathspec>...]
有关更多信息,请参阅“ 隐藏对特定文件的更改 ”。
原来的答案(下面,2010年6月)是关于手动select你想存储的东西。
Casebash评论说:
这(
stash --patch
原来的解决scheme)是不错,但我经常修改了很多文件,所以使用补丁是烦人的
bukzor的回答 (upvoted,2011年11月)提出了一个更实际的解决scheme,基于
git add
+ git stash --keep-index
。
去看看,并提出他的答案,这应该是正式的(而不是我的)。
关于这个选项, chhh在评论中指出了另一个工作stream程:
你应该在这样一个
git reset --soft
之后“git reset --soft
”来获得清晰的升级:
为了达到原来的状态 – 这是一个清晰的舞台区域,只有一些select性的非阶段性的修改,可以轻轻地重置索引来获取(不需要像你这样的任何东西 – bukzor – )。
(原始回答2010年6月:手动藏匿)
然而, git stash save --patch
可以让你实现部分git stash save --patch
:
使用
--patch
,你可以交互式地从HEAD和正在工作的树之间的差异中select被隐藏的块。
存储条目的构build方式使其索引状态与存储库的索引状态相同,其工作树仅包含交互select的更改。 所选的更改将从您的工作树中回滚。
但是,这将保存完整的索引(这可能不是你想要的,因为它可能包括已经索引的其他文件),和一个部分工作树(可能看起来像你想存储的那个)。
git stash --patch --no-keep-index
可能会更合适。
如果 – --patch
不起作用,手动过程可能会:
对于一个或多个文件,中间解决scheme将是:
- 把它们复制到Git仓库之外
(实际上, eleotlecram提出了一个有趣的select ) -
git stash
- 把它们复制回来
-
git stash
#这一次,只有你想要的文件被隐藏 -
git stash pop stash@{1}
#重新应用所有的文件修改 -
git checkout -- afile
#在任何本地修改之前将文件重置为HEAD内容
在那个繁琐的过程结束时,你将只有一个或几个文件隐藏。
当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
假设你有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
交互模式) 。
这个想法与@VonCbuild议使用仓库以外的文件的想法是一样的,您可以保存所需的更改,删除不需要的更改,然后重新应用您移除的更改。 但是,我用git存储作为“某处”(因此,最后还有一个额外的步骤:删除存储在存储器中的cahnge,因为您也将它们移除了)。
更新(2/14/2015) – 我已经重写了脚本,以更好地处理冲突的情况,现在应该将其呈现为未合并冲突而不是.rej文件。
我经常发现@ bukzor方法的反例更直观。 也就是说,要进行一些更改,然后只保留这些分阶段的更改。
不幸的是,git并没有提供一个git-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
到你的path的某个地方,然后可以调用它作为git stash-index
# <hack hack hack> git add <files that you want to stash> git stash-index
现在隐藏包含一个新的条目,只包含您已进行的更改,并且您的工作树仍包含任何unstaged更改。
在某些情况下,工作树的更改可能取决于索引更改,所以当您存储索引更改时,工作树更改会有冲突。 在这种情况下,你会得到通常可以用git merge / git mergetool / etc解决的未合并冲突。
由于在Git中创build分支是微不足道的,你可以创build一个临时分支,并检查单个文件。
将下面的代码保存到一个文件,例如,名为stash
。 用法stash <filename_regex>
。 参数是文件完整path的正则expression式。 例如,要隐藏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 } } }
使用git stash push
,像这样:
git stash push [--] [<pathspec>...]
例如:
git stash push -- my/file.sh
这是从Git 2.13开始的,2017年春季发布。
以防万一你使用'git stash'(而不是真的使用git stash来暂时存储)时,你实际上是指“放弃更改”,在这种情况下,你可以使用
git checkout -- <file>
注意,git存储只是分支和执行任务的一个更快,更简单的select。
VonC将文件复制到Git仓库之外的“中间”解决scheme的问题在于,您丢失了path信息,这使得稍后复制一堆文件变得麻烦一些。
发现它更容易使用焦油(类似的工具可能会),而不是复制:
- tar cvf /tmp/stash.tar path / to / some / file path / to / some / other / file(…等等)
- git checkout path / to / some / file path / to / some / other / file
- git存储
- tar xvf /tmp/stash.tar
- 等等(见VonC的“中间”build议)
有时我在分支之前做了一个无关的更改,我想将它移动到另一个分支并单独提交(如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
分支,但前提是没有冲突。 此外,如果您正在创build一个新的分支部分更改,您将需要藏匿。
你可以简化它,假设没有冲突,没有新的分支:
git checkout master git add <files that you want to commit> git commit -m 'Minor feature' git checkout topic1 ...<resume work>...
藏匿甚至不需要…
这可以通过使用SourceTree三个步骤轻松完成。
- 暂时提交你不想隐藏的所有东西。
- Git添加一切,然后把它藏起来。
- 通过运行git resetpopup临时提交,在临时提交之前定位提交。
这可以在SourceTree中几秒钟内完成,您只需点击要添加的文件(甚至单个行)即可。 一旦添加,只需将它们提交给临时提交。 接下来,点击checkbox添加所有更改,然后点击存储以隐藏所有内容。 随着隐藏的变化,看看你的提交列表,并注意你的临时提交前的提交哈希,然后运行“git reset hash_b4_temp_commit”,这基本上就像通过重置您的分支“popup”提交到承诺之前。 现在,你只剩下你不想隐藏的东西了。
这里的每个答案都非常复杂
这个怎么样“藏起来”:
git diff /dir/to/file/file_to_stash > /tmp/stash.patch git checkout -- /dir/to/file/file_to_stash
这个popup文件改回来:
git apply /tmp/stash.patch
与存储一个文件并将其弹回相同的行为。
在这种情况下,我git add -p
(交互式), git commit -m blah
,然后隐藏什么是如果有必要的。
我会使用git stash save --patch
。 我没有发现交互性令人讨厌,因为有选项可以将所需的操作应用于整个文件。
类似的情况。 提交并意识到它不好。
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
我不知道如何在命令行上使用SourceTree。 假设你已经改变了文件A,并且在文件B中有两个变更区域。如果你只想保存文件B中的第二个区块,并且保留其他所有的东西,
- 阶段一切
- 对您的工作副本执行更改,以撤消文件A中的所有更改(例如启动外部差异工具并使文件匹配)。
- 使文件B看起来好像只有第二个更改应用于它。 (例如,启动外部差异工具并撤消第一次更改。)
- 使用“保持分段更改”创build一个存储。
- 卸下一切
- 完成!
当您尝试在两个分支之间切换时,会出现这种情况。
尝试使用“ git add filepath
”添加文件。
稍后执行这一行
git stash --keep-index
我已经回顾了这个和许多类似的线程的答案和评论。 请注意,以下任何命令都无法存储任何特定的跟踪/未跟踪文件 :
-
git stash -p (--patch)
:手动selectgit stash -p (--patch)
,排除未跟踪的文件 -
git stash -k (--keep-index)
:git stash -k (--keep-index)
所有跟踪/未跟踪的文件并将其保存在工作目录中 -
git stash -u (--include-untracked)
:隐藏所有跟踪/未跟踪的文件 -
git stash -p (--patch) -u (--include-untracked)
:无效的命令
目前,能够隐藏任何特定跟踪/未跟踪文件的最合理的方法是:
- 临时提交您不想存储的文件
- 添加并隐藏
- popup临时提交
我在另一个问题的答案中为这个过程写了一个简单的脚本,在这里有一些在SourceTree中执行这个过程的步骤 。
一个复杂的方法是首先承诺一切:
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
这只存储一个文件。
解
本地更改:
- file_A(修改)不分段
- file_B(修改)不分段
- file_C(修改)不上演
要创build只有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添加到临时区域
- 创build一个名为“temp_stash”的存储并将更改保留在file_C上
- 创build想要的存储(“my_stash”),只有file_c上的更改
- 将“temp_stash”(file_A和file_C)中的更改应用于本地代码并删除存储
您可以在步骤之间使用git status来查看发生了什么。