从项目表单GIT中提取新版本后,如何检索特定存储文件的内容?

时间:2017-03-29 10:01:02

标签: git version-control git-pull git-stash

我对GIT并不是这样,我有以下问题。

我的项目中有一些未提交的文件,我已经被这个声明隐藏起来了:

git stash

然后我将存储库拉出了coolegue的工作,这似乎正确地覆盖了我的存储文件的更改。

现在我想检索特定存储文件的内容,而不会丢失对同事的修改。

我不想覆盖拉出的版本,但只能访问特定文件的藏匿版本的代码。

执行 git存储列表我获取:

$ git stash list
stash@{0}: WIP on master: fd2a59b First version of iterate/aggregate for data received from dataservice
stash@{1}: WIP on master: 4910263 DSS project added

我怎样才能从shell中做到这一点?

3 个答案:

答案 0 :(得分:3)

自己解决:

1)首先使用 git stash show 语句显示隐藏文件:

$ git stash show
 glis-toolkit/src/main/synapse-config/api/glisTest2.xml | 8 ++++++++
 1 file changed, 8 insertions(+)

2)然后我通过以下方式将此藏匿版本(从藏匿0)保存到另一个备份文件中:

$ git show stash@{0}:glis-toolkit/src/main/synapse-config/api/glisTest2.xml  >  glisTest2Bck.xml

答案 1 :(得分:2)

我不知道是否可以轻松地将特定文件的差异显示在藏匿处。

但是,要显示stash@{0}

的隐藏代码
git stash show stash@{0} -p

如果您对上一个命令的输出不满意,并且由于您的工作树是干净的,您可以从获取所需的存储开始

# say you want to see diff of file my/file1.txt in stash{0}
git stash pop stash@{0}

# To Check your file by showing the diff between your work and your collegue's
git diff my/file1.txt

回到第一步

git stash

希望有所帮助

答案 2 :(得分:0)

这个答案有几个部分,因为使用git stash可能会非常困难。在这种情况下你使用它的方式对于你的用例来说是正确的,但是这里有很多陷阱,对于那些粗心大意的人来说,以及那些对于Git人来说不那么陌生的人来说。

Stash进行多次提交

要知道的主要事情是:git stash进行提交。实际上,它至少提供了两个提交;如果您告诉它(使用-u-a),则进行第三次提交。 所有这些提交都在 no 分支上,但它们仍然是提交,因此行为类似于提交。这些提交的格式是它们看起来像其他Git命令,就像一种奇怪的合并提交,这意味着你通常希望保留其他Git命令仔细观察它们,并且大多使用git stash来处理它们。

索引和工作树以及git checkout

git stash提交的是索引工作树。到目前为止,工作树是最容易解释的:Git以内部的Git格式存储文件,因此要工作文件,你需要一个存放在正常情况下的地方电脑格式。那是工作树。您可以在此工作树中放置 not 的文件也将存储在Git中,这就是 index 首次出现的地方。

Git的索引有几个用途,但这是主要的用途:它是&#34;你在哪里构建下一个提交&#34;。也就是说,您可以在任何Git存储库中使用您运行git checkout的当前提交开始。 (在第一个git clone上,Git会为您运行git checkout master。嗯,它通常 master无论如何,但它绝对是<签出了 。这会选择一个分支名称,用它来查找分支的 tip 提交,然后创建该分支并提交 current 分支和提交。然后它填充索引 - 完全为空,这是第一次 - 来自该特定提交,所以现在索引中包含当前所有文件(或HEAD提交。将这些文件添加到索引时,Git也会将它们复制到工作树中,所以现在你的HEAD提交等于索引,它等于工作树。

如果您现在git checkout其他一些分支/提交,Git更改HEAD以考虑新分支和提示提交,删除旧文件(对于之前的HEAD) )从索引和工作树中,新的文件添加到索引和工作树中,再一次让HEAD提交等于索引等于到工作树。

请注意,在所有这些改组中,索引中的工作树中的任何文件都不会受到影响。这些是未跟踪的文件,以及文件未跟踪的含义:当且仅当文件位于索引中时才会跟踪文件。 (这只与git stash本身有点关系,但对于使用Git和.gitignore至关重要,因为.gitignore跟踪 file。)

要自己进行新提交,首先要修改工作树中的文件,然后使用git add将新版本复制到索引中。这使得新文件可以提交,并且在您运行git add时具有正确的数据。这将保留所有现有索引文件的方式,因此新提交仍将保持所有其他文件不变。要添加索引中已有的文件,请在工作树中创建该文件,然后再次运行git add。将文件复制到索引中,就像之前一样,但这次它不会覆盖现有副本。要删除文件,请运行git rm,将其从 索引工作树中删除。

当我们说 staging 文件用于提交时,这个向索引添加(覆盖现有或添加新)文件以及从索引和工作树中删除文件的过程就是我们的意思。这就是为什么索引也被称为&#34;暂存区域&#34;:我们将更新的工作树文件复制到其中,以便让它们上演。请注意,除非您git rm所有内容,否则索引本身实际上从未为空:它只是在您git commit索引,索引和之后你做了新的提交,现在匹配。 (这会使--allow-empty标记为git commit有点误导。)

返回git stash,特别是&#34;保存新藏匿&#34;子命令

再次,git stash save进行(至少)两次提交:首先,它提交索引本身 - 这非常简单,因为Git 总是如何进行提交 - 和然后它进行第二次提交,实际上包括git add所有被跟踪的工作树文件,即将它们复制到索引中,然后再次提交。但是,出于内部原因,它将第二次提交作为合并提交,合并HEAD和刚才提交的索引提交。 只要我们使用git stash来处理这种奇怪的合并,我们就不必关心。只有当我们走出git stash时才会这样做我们突然不得不关心它。

git stash进行这些提交之后,它大部分都相当于git reset --hard HEAD,尽管这里还有一些标志选项可以改变它。 (对于此过程可能过多 - 或许过多 - 请参阅How to recover from "git stash save --all"?git reset --hard HEAD做的是重新设置(因此git reset)三件事:

  1. 它将当前分支从当前提交移动(即重新设置)到指定的新提交。因为指定的新提交是HEAD,其中当前提交,这就像试图从你的厨房开车到你的厨房:你可能会匆匆忙忙一会儿,但你刚结束准确到达你的起点。

  2. 重新设置索引。也就是说,它使索引与HEAD提交匹配。这会取消所有暂存的更改,取消删除git rm - ed文件,取消添加任何全新文件,并从HEAD恢复您修改后的任何文件,然后暂存。< / p>

  3. 重新设置工作树。也就是说,它使工作树中的所有跟踪的文件与HEAD提交和(现在)索引中的版本相匹配。

  4. 尽管如此,作为一种心理捷径,您可以将其视为&#34;扩展索引和工作树&#34;。 stash代码只是保存它们两者,作为提交,所以现在可以安全地清除它们。现在索引和工作树看起来都像它们一样如果您刚刚在当前提交中运行git checkout,这就是为什么您现在可以使用git mergegit rebase(无论您是否从git pull运行它 - 请记住,git pull只是git fetch后跟在所有这些情况下合并或改变。)

    应用存储

    应用(或&#34;弹出&#34;)存储的过程可能更多比保存它的过程复杂,但在练习中,它往往很简单。好吧,除非它出错了,无论如何。您只需像以前一样进入(通常是干净的)commit-and-index-and-work-tree状态,然后运行:

    git stash apply
    

    这样做是运行几个git diff命令,以找出:

    • 保存的索引与git stash save保存该索引时当前提交的区别是什么?
    • 保存的工作树与git stash save保存工作树时当前提交的区别是什么?

    通常,对于每个文件,最多只有一个差异(通过保存的索引或通过保存的工作树):您要么暂存文件,所以区别显示在已保存的索引中,或者您没有显示,因此您所做的任何更改都会显示在已保存的工作树中(如果没有更改,则根本没有任何区别)。然后,对于每个文件,Git会将这些一起打碎,并将所有更改放入当前的工作树中。默认情况下,您当前的索引不会受到影响,但git stash apply有更好的方式。

    如果您对存储已正确应用感到满意,则可以运行git stash drop。这会丢弃两个已保存的提交(如果git stash save&#34;推送&#34;早先存入stash@{1},有效&#34;弹出&#34;其余时间退回以便先前存储现在是stash@{0},或者只是stash)。

    如果您确定要在应用后丢弃存储,而无需先检查正确性,则可以使用git stash pop。这在字面上只是在内部变成git stash apply && git stash drop。 (当然,如果您使用git stash pop stash@{n},它会通过特定的存储。)

    一些疑难案例,如XML文件

    将每个更改 - 每个git diff从提交 - 当时是HEAD - 应用到已保存的索引或保存的工作树 - 使用Git的完全合并功能的过程。这是一个简单的(ish)机械过程,但对大多数文件来说效果都非常好。遗憾的是,XML文件往往会击败Git的不完全超能力。

    在这种情况下,您可能希望完全按照此处的操作进行操作。

    因为git stash save只进行了两次提交(不在分支上),所以你可以使用所有常用的Git工具来处理这两个提交。但是一旦这样做,你必须要小心,因为工作树提交看起来像合并提交。 (嗯,事实上,合并提交。)幸运的是,git show <commit>:<path>并不关心提交是否是合并:它只是提取文件的保存版本。

    每个stash名称或reflog名称都指向已保存的工作树提交。因此:

    git show stash:path/to/file.xml
    

    打印该文件的已保存工作树内容。将其重定向到工作树中的新文件,可以检查保存的内容。所以这是一件好事。

    请注意git show stash。对于我们这些患有阅读障碍症的人来说, 1 使用它而不是git stash show非常容易。但如果git show <commit>是合并提交,则<commit> 会关注。虽然git stash show知道将工作树提交视为单独的非合并提交,git show - 它将stash视为提交ID,然后可以使用work-tree commit-try将其视为合并提交。它试图显示一个组合差异,它通常最终根本没有显示任何内容。 (最令人困惑的情况发生在 显示某些东西,但不是所有你所藏的东西时,这种情况会在你第一次上传文件时发生,然后在工作中再次修改它-tree。)

    TL; DR摘要(如果还不太晚):git show stash:path/to/file没问题,但git show stash总是错误的。大多数情况下,您需要git stash apply,但对于奇数情况,git show stash:path/to/file将为您提供已保存的工作树版本。而且,对于非常复杂的情况,请参阅my other longer answer并考虑使用git stash branch

    1 解开世界的诵读困难!