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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3040833/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 08:34:10  来源:igfitidea点击:

Stash only one file out of multiple files that have changed with Git?

gitgit-stash

提问by Rachel

How can I stash only one of multiple changed files on my branch?

如何仅在我的分支上存储多个已更改文件中的一个?

采纳答案by bukzor

Disclaimer: the following answer is for git before git 2.13. For git 2.13 and over, check out another answer further down.

免责声明:以下答案适用于 git 2.13 之前的 git。对于 git 2.13 及更高版本,请进一步查看另一个答案



Warning

警告

As noted in the comments, this puts everything into the stash, both staged and unstaged. The --keep-index just leaves the index alone after the stash is done. This can cause merge conflicts when you later pop the stash.

正如评论中所指出的,这会将所有内容都放入存储中,包括暂存和未暂存。--keep-index 在存储完成后只留下索引。当您稍后弹出存储时,这可能会导致合并冲突。



This will stash everything that you haven't previously added. Just git addthe things you want to keep, then run it.

这将隐藏您之前未添加的所有内容。只是git add你想保留的东西,然后运行它。

git stash --keep-index

For example, if you want to split an old commit into more than one changeset, you can use this procedure:

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

  1. git rebase -i <last good commit>
  2. Mark some changes as edit.
  3. git reset HEAD^
  4. git add <files you want to keep in this change>
  5. git stash --keep-index
  6. Fix things up as necessary. Don't forget to git addany changes.
  7. git commit
  8. git stash pop
  9. Repeat, from #5, as necessary.
  10. git rebase --continue
  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

回答by konrad.kruczynski

You can also use git stash save -p "my commit message". This way you can select which hunks should be added to stash, whole files can be selected as well.

您也可以使用git stash save -p "my commit message". 通过这种方式,您可以选择应将哪些大块添加到存储中,也可以选择整个文件。

You'll be prompted with a few actions for each hunk:

系统会提示您对每个大块执行一些操作:

   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

回答by VonC

Since git is fundamentally about managing a all repository contentand index (and not one or several files), git stashdeals, not surprisingly, with the all working directory.

由于 git 从根本上是关于管理所有存储库内容和索引(而不是一个或多个文件)git stash,因此毫不奇怪,与所有工作目录.

Actually, since Git 2.13 (Q2 2017), you can stash individual files, with git stash push:

实际上,从 Git 2.13(2017 年第二季度)开始,您可以使用以下命令存储单个文件git stash push

git stash push [--] [<pathspec>...]

When pathspecis given to 'git stash push', the new stash records the modified states only for the files that match the pathspec See "Stash changes to specific files" for more.

pathspec被赋予 ' git stash push' 时,新的 stash 仅记录与 pathspec 匹配的文件的修改状态有关更多信息,请参阅“ Stash changes to specific files”。

Simplified example:

简化示例:

 git stash push path/to/file

The test casefor this feature shows a few more options off:

此功能的测试用例显示了更多选项:

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


The original answer (below, June 2010) was about manually selecting what you want to stash.

最初的答案(下面,2010 年 6 月)是关于手动选择要隐藏的内容。

Casebashcomments:

Casebash评论:

This (the stash --patchoriginal solution) is nice, but often I've modified a lot of files so using patch is annoying

这(stash --patch原始解决方案)很好,但我经常修改很多文件,所以使用补丁很烦人

bukzor's answer(upvoted, November 2011) suggests a more practical solution, based on
git add+ git stash --keep-index.
Go see and upvote his answer, which should be the official one (instead of mine).

bukzor回答(赞成,2011 年 11 月)提出了一个更实用的解决方案,基于
git add+git stash --keep-index
去看看并赞成他的答案,这应该是官方的(而不是我的)。

About that option, chhhpoints out an alternative workflow in the comments:

关于该选项,chhh在评论中指出了另一种工作流程:

you should "git reset --soft" after such a stash to get your clear staging back:
In order to get to the original state - which is a clear staging area and with only some select un-staged modifications, one could softly reset the index to get (without committing anything like you - bukzor - did).

您应该git reset --soft在这样的存储之后“ ”恢复清晰的暂存状态:
为了获得原始状态 - 这是一个清晰的暂存区域,并且只有一些选择的未暂存修改,可以轻柔地重置索引以获取(没有像你一样犯下任何事 - bukzor - 做过)。



(Original answer June 2010: manual stash)

(2010 年 6 月的原始答案:手动存储)

Yet, git stash save --patchcould allows you to achieve the partial stashing you are after:

然而,git stash save --patch可以让你实现你所追求的部分藏匿:

With --patch, you can interactively select hunks from in the diff between HEAD and the working tree to be stashed.
The stash entry is constructed such that its index state is the same as the index state of your repository, and its worktree contains only the changes you selected interactively. The selected changes are then rolled back from your worktree.

使用--patch,您可以交互地从 HEAD 和要隐藏的工作树之间的差异中选择大块头。
存储条目的构造使其索引状态与存储库的索引状态相同,并且其工作树仅包含您交互选择的更改。然后,所选更改将从您的工作树中回滚。

However that will save the full index (which may not be what you want since it might include other files already indexed), and a partial worktree (which could look like the one you want to stash).

但是,这将保存完整索引(这可能不是您想要的,因为它可能包含其他已编入索引的文件)和部分工作树(可能看起来像您想要隐藏的那个)。

git stash --patch --no-keep-index

might be a better fit.

可能更合适。



If --patchdoesn't work, a manual process might:

如果--patch不起作用,手动过程可能会:

For one or several files, an intermediate solution would be to:

对于一个或多个文件,中间解决方案是:

  • copy them outside the Git repo
    (Actually, eleotlecramproposes an interesting alternative)
  • git stash
  • copy them back
  • git stash# this time, only the files you want are stashed
  • git stash pop stash@{1}# re-apply all your files modifications
  • git checkout -- afile# reset the file to the HEAD content, before any local modifications
  • 将它们复制到 Git 存储库之外
    (实际上,eleotlecram提出了一个有趣的替代方案
  • git stash
  • 把它们复制回来
  • git stash# 这一次,只有你想要的文件被藏起来
  • git stash pop stash@{1}# 重新应用所有文件修改
  • git checkout -- afile# 在任何本地修改之前将文件重置为 HEAD 内容

At the end of that rather cumbersome process, you will have only one or several files stashed.

在这个相当繁琐的过程结束时,您将只保存一个或几个文件。

回答by blueyed

When git stash -p(or git add -pwith stash --keep-index) would be too cumbersome, I found it easier to use diff, checkoutand apply:

git stash -p(或git add -pwith stash --keep-index)太麻烦时,我发现它更易于使用diffcheckout并且apply

To "stash" a particular file/dir only:

仅“隐藏”特定文件/目录:

git diff path/to/dir > stashed.diff
git checkout path/to/dir

Then afterwards

然后之后

git apply stashed.diff

回答by sandstrom

Use git stash push, like this:

使用git stash push,像这样:

git stash push [--] [<pathspec>...]

For example:

例如:

git stash push -- my/file.sh


This is available since Git 2.13, released in spring 2017.

这是自 2017 年春季发布的 Git 2.13 以来可用的。

回答by venkatareddy

Let's say you have 3 files

假设您有 3 个文件

a.rb
b.rb
c.rb

and you want to stash only b.rb and c.rb but not a.rb

并且您只想存储 b.rb 和 c.rb 而不是 a.rb

you can do something like this

你可以做这样的事情

# 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

And you are done! HTH.

你已经完成了!哈。

回答by Jasper

Another way to do this:

另一种方法来做到这一点:

# 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">

I came up with this after I (once again) came to this page and didn't like the first two answers (the first answer just doesn't answer the question and I didn't quite like working with the -pinteractive mode).

在我(再次)来到这个页面并且不喜欢前两个答案之后我想出了这个(第一个答案只是没有回答问题,我不太喜欢使用-p交互模式)。

The idea is the same as what @VonC suggested using files outside the repository, you save the changes you want somewhere, remove the changes you don't want in your stash, and then re-apply the changes you moved out of the way. However, I used the git stash as the "somewhere" (and as a result, there's one extra step at the end: removing the cahnges you put in the stash, because you moved these out of the way as well).

这个想法与@VonC 建议使用存储库外的文件的想法相同,您将所需的更改保存在某处,删除您不想要的更改,然后重新应用您移开的更改。但是,我将 git stash 用作“某处”(因此,最后还有一个额外的步骤:删除您放入 stash 中的更改,因为您也将它们移开了)。

回答by JesusFreke

Update (2/14/2015) - I've rewritten the script a bit, to better handle the case of conflicts, which should now be presented as unmerged conflicts rather than .rej files.

更新 (2/14/2015) - 我稍微重写了脚本,以更好地处理冲突的情况,现在应该将其显示为未合并的冲突而不是 .rej 文件。



I often find it more intuitive to do the inverse of @bukzor's approach. That is, to stage some changes, and then stash only those staged changes.

我经常发现与@bukzor 的方法相反更直观。也就是说,暂存一些更改,然后只存储那些暂存的更改。

Unfortunately, git doesn't offer a git stash --only-index or similar, so I whipped up a script to do this.

不幸的是,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

You can save the above script as git-stash-indexsomewhere on your path, and can then invoke it as git stash-index

您可以将上述脚本保存在git-stash-index路径上的某个位置,然后可以将其作为 git stash-index 调用

# <hack hack hack>
git add <files that you want to stash>
git stash-index

Now the stash contains a new entry that only contains the changes you had staged, and your working tree still contains any unstaged changes.

现在存储包含一个新条目,该条目仅包含您已暂存的更改,并且您的工作树仍包含任何未暂存的更改。

In some cases, the working tree changes may depend on the index changes, so when you stash the index changes, the working tree changes have a conflict. In this case, you'll get the usual unmerged conflicts that you can resolve with git merge/git mergetool/etc.

在某些情况下,工作树更改可能取决于索引更改,因此当您存储索引更改时,工作树更改会发生冲突。在这种情况下,您将获得可以使用 git merge/git mergetool/etc 解决的常见未合并冲突。

回答by sealocal

If you do not want to specify a message with your stashed changes, pass the filename after a double-dash.

如果您不想指定带有隐藏更改的消息,请在双破折号后传递文件名。

$ git stash -- filename.ext

If it's an untracked/new file, you will have to stage it first.

如果它是未跟踪/新文件,则必须先将其暂存。

This method works in git versions 2.13+

此方法适用于 git 版本 2.13+

回答by shangxiao

Since creating branches in Git is trivial you could just create a temporary branch and check the individual files into it.

由于在 Git 中创建分支很简单,您只需创建一个临时分支并将单个文件签入其中即可。