从Git中更改的多个文件中只存储一个文件?

我怎么能只存储我的分支上多个更改的文件之一?

警告

正如在评论中指出的那样,这将所有东西放到藏起来,既上演也不搁置。 – 保持索引仅仅在索引完成后离开索引。 这可能会导致合并冲突,当你以后popup存储。


这将存储您以前没有添加的所有内容。 只要git add你想保留的东西,然后运行它。

 git stash --keep-index 

例如,如果要将旧提交拆分为多个变更集,可以使用以下过程:

  1. git rebase -i <last good commit>
  2. 将某些更改标记为edit
  3. git reset HEAD^
  4. git add <files you want to keep in this change>
  5. git stash --keep-index
  6. 根据需要进行修复。 不要忘记git add任何更改。
  7. git commit
  8. git stash pop
  9. 从#5重复,如有必要。
  10. 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 -pstash --keep-index )会太麻烦,我发现使用diffcheckoutapply会更容易:

只“藏”一个特定的文件/目录:

 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.txtstash .*/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>... 

请注意,第一个stashstash 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三个步骤轻松完成。

  1. 暂时提交你不想隐藏的所有东西。
  2. Git添加一切,然后把它藏起来。
  3. 通过运行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中的第二个区块,并且保留其他所有的东西,

  1. 阶段一切
  2. 对您的工作副本执行更改,以撤消文件A中的所有更改(例如启动外部差异工具并使文件匹配)。
  3. 使文件B看起来好像只有第二个更改应用于它。 (例如,启动外部差异工具并撤消第一次更改。)
  4. 使用“保持分段更改”创build一个存储。
  5. 卸下一切
  6. 完成!

当您尝试在两个分支之间切换时,会出现这种情况。

尝试使用“ 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} 

完成。


说明

  1. 将file_C添加到临时区域
  2. 创build一个名为“temp_stash”的存储并将更改保留在file_C上
  3. 创build想要的存储(“my_stash”),只有file_c上的更改
  4. 将“temp_stash”(file_A和file_C)中的更改应用于本地代码并删除存储

您可以在步骤之间使用git status来查看发生了什么。