首页 文章

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

提问于
浏览
2577

如何在我的分支上只隐藏多个已更改文件中的一个?

27 回答

  • 0

    这里的每个答案都是如此复杂......

    这个“藏匿”怎么样:

    git diff /dir/to/file/file_to_stash > /tmp/stash.patch
    git checkout -- /dir/to/file/file_to_stash
    

    这将弹出文件更改回:

    git apply /tmp/stash.patch
    

    与存储一个文件并将其弹回的完全相同的行为 .

  • 1

    我会用 git stash save --patch . 我没有发现交互性令人讨厌,因为在它期间有选项将所需操作应用于整个文件 .

  • 26

    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
    
  • 44

    您也可以使用 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
    
  • 53

    由于git基本上是关于管理所有存储库内容和索引(而不是一个或多个文件),所以 git stash 毫不奇怪地与所有工作目录进行交易 .

    实际上,自Git 2.13(2017年第2季度)以来,您可以使用git stash push存储单个文件:

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

    当pathpec被赋予'git stash push'时,新的stash仅记录与pathspec匹配的文件的修改状态

    有关更多信息,请参阅“Stash changes to specific files” .

    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原始解决方案)很不错,但我经常修改了很多文件所以使用补丁很烦人

    bukzoranswer(upvoted,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提出interesting alternative

    • git stash

    • 将它们复制回来

    • git stash #这次,只有你想要的文件被隐藏起来

    • git stash pop stash@{1} #重新应用所有文件修改

    • git checkout -- afile #在任何本地修改之前将文件重置为HEAD内容

    在相当繁琐的过程结束时,您将只有一个或几个文件被藏起来 .

  • 1

    使用 git stash push ,如下所示:

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

    例如:

    git stash push -- my/file.sh
    

    自2017年 Spring 季发布的Git 2.13开始提供此功能 .

  • 3

    Warning

    正如评论中所指出的,这会将所有内容都放入存储中,无论是分阶段还是非分阶段 . -step-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

    • 根据需要从#5开始重复 .

    • git rebase --continue

  • 79

    假设你有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 .

  • 6

    另一种方法:

    # 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作为“某处”(结果,最后还有一个额外的步骤:删除你放在藏匿处的cahnges,因为你也将它们移开了) .

  • 1

    更新(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
    

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

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

  • 2784

    由于在Git中创建分支是微不足道的,因此您可以创建一个临时分支并将单个文件检入其中 .

  • 10

    万一你使用 git stash 实际意味着 discard changes (并且真的不使用git stash暂时存放它),在这种情况下你可以使用

    git checkout -- <file>
    

    [ NOTE ]

    那个 git stash 只是分支和做事的一种快速而简单的替代方案 .

  • 1241

    将以下代码保存到文件中,例如,名为 stash . 用法是 stash <filename_regex> . 参数是文件完整路径的正则表达式 . 例如,要存储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
        }
      }
    }
    
  • 0

    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

    • git stash

    • tar xvf /tmp/stash.tar

    • 等(见VonC 's `intermediate'建议)

  • 0

    使用SourceTree可以在3个步骤中轻松完成 .

    • 暂时提交您不想要藏匿的所有内容 .

    • Git添加其他所有内容,然后将其存储起来 .

    • 通过运行git reset来弹出临时提交,在临时提交之前定位提交 .

    这可以在SourceTree中在几秒钟内完成,您可以在其中单击要添加的文件(甚至单独的行) . 添加后,只需将它们提交给临时提交 . 接下来,单击复选框以添加所有更改,然后单击存储以存储所有内容 . 通过隐藏的更改,浏览提交列表并在临时提交之前记下提交的哈希,然后运行'git reset hash_b4_temp_commit',这基本上就像通过将分支重置为“弹出”提交在它之前提交 . 现在,你只剩下你不想藏匿的东西 .

  • 12

    有时候,在我提交之前,我已经在我的分支上做了一个无关的更改,我想将它移动到另一个分支并单独提交(如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 分支,但前提是没有冲突 . 此外,如果要为部分更改创建新分支,则需要存储 .

    假设没有冲突且没有新分支,您可以简化它:

    git checkout master
    git add <files that you want to commit>
    git commit -m 'Minor feature'
    git checkout topic1
    ...<resume work>...
    

    藏匿甚至不需要......

  • 5

    我已经回顾了这个和许多类似线程的答案和评论 . 请注意,以下任何命令都不能用于存储 any specific tracked/untracked files

    • 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 .

  • 6

    解决方案

    地方变化:

    • 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来查看正在进行的操作 .

  • 23

    在这种情况下我 git add -p (交互式), git commit -m blah 然后在必要时存储剩下的内容 .

  • 7

    类似的情况 . 提交并意识到它不行 .

    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
    
  • 1

    我不知道如何在命令行上执行此操作,仅使用SourceTree . 假设您已经更改了文件A,并且在文件B中有两个更改块 . 如果您只想隐藏文件B中的第二个块并保持其他所有内容不变,请执行以下操作:

    • 舞台一切

    • 对工作副本执行更改,撤消文件A中的所有更改 . (例如,启动外部差异工具并使文件匹配 . )

    • 使文件B看起来好像只对其应用了第二次更改 . (例如,启动外部差异工具并撤消第一次更改 . )

    • 使用"Keep staged changes"创建存储 .

    • 取消所有内容

    • 完成!

  • 277

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

    尝试使用“ git add filepath ”添加文件 .

    稍后执行此行

    git stash --keep-index

  • 1

    要存储单个文件,请使用 git stash --patch [file] .

    这将提示: Stash this hunk [y,n,q,a,d,j,J,g,/,e,?]? ? . 只需输入 a (将此大块以及所有后来的文件藏在文件中)就可以了 .

  • 2
    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)
    
  • 17

    一个复杂的方法是首先提交一切:

    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^
    

    是的,有点尴尬......

  • 7

    我发现没有答案是我需要的,这很简单:

    git add -A
    git reset HEAD fileThatYouWantToStash
    git commit -m "committing all but one file"
    git stash
    

    这只存储了一个文件 .

  • 3

    快速回答


    要在git中还原特定的已更改文件,您可以执行以下操作:

    git checkout <branch-name> -- <file-path>
    

    这是一个实际的例子:

    git checkout master -- battery_monitoring/msg_passing.py
    

相关问题