“git stash”内部“提交”到我的本地仓库吗?

时间:2017-10-30 02:26:01

标签: git git-commit git-stash

我只是在commit远程仓库之前手动push到我的本地仓库。

但更多时候我pull来获取编码伙伴的更改。

有时我们都在同一个文件上工作并且存在冲突。在这些情况下,他告诉我在git stash之前git pull然后在git stash pop之后做pull

但有时这导致git告诉我下次我不能commit因为我有未合并的文件。这些通常是我本地树中的实验性更改,我不希望pushstash

有几次我需要发送我的工作,结果是远程仓库的中间修订,包括我本地的实验,调试代码等,我从来没有希望发送。我想避免制造这样的混乱。

这是由于.env修改我的本地回购吗?如果是这样,我该如何避免呢?如果没有,还有什么可能导致它?我是git的总菜鸟,只使用这几个命令。

2 个答案:

答案 0 :(得分:2)

Stash实际在临时框not in your working tree中提交/保存您的本地更改。

$ git stash

您可以看到藏匿列表 -

$ git stash --list

在进行更改之前,请确保完全隐藏所有不必要/实验性更改。

$ git stash save 'provide stash message'       # better give a stash message
$ git stash     # see if all the changes are stashed

您也可以apply存储而不是pop(如果不想删除它)。您也可以删除存储而不通过git stash drop应用它(删除#1存储)。  基本上, pop = apply + drop

$ git stash apply stash@{0}     # get back the last (#1) stash changes
$ git stash apply stash@{1}     # get back the #2 stash changes

答案 1 :(得分:2)

我想在这里首先提到术语 index 临时区域意思相同,你应该记住三个 >文件版本&#34;活跃&#34;在任何时候:HEAD版本,索引或&#34;上演&#34;版本和工作树版本。当您第一次运行git checkout <branch>时,通常会将所有三个版本都匹配起来。任何已提交的版本都是永久性的,与commit一样永久且不可更改:您无法触及当前提交中存储的版本。您可以随时覆盖索引和工作树版本,但正常模式是:

  1. 查看已提交的版本:将提交复制到索引,然后索引到工作树。
  2. 处理工作树版本。
  3. 使用git add将工作树版本复制回索引。
  4. 重复步骤2和3直到满意为止;或使用git add --patch建立一个类似工作树版本的索引版本,但不同。 (通常一个人这样做是为了制作某个文件的可提交版本,在运行调试版本时,它没有额外的调试内容。)这确实意味着索引和工作树可以彼此不同HEAD提交的<和em>。

    如果您运行git commit,则会从索引/暂存区域中的任何内容进行提交,然后。这就是为什么你必须始终保持git add,从工作树复制到索引。

    作为Sajib Khan answeredgit stash save会进行提交。更确切地说,如果git stash save执行任何(有时它什么都不做,如果没有任何更改),则至少进行两次提交。如果您使用--untracked--all标志,则会进行三次提交。 The git stash documentation has a small diagram of this under its DISCUSSION section.与文档一样,我们通常会忽略第三次提交。 1

    这些提交的不寻常之处在于它们位于 no 分支上。特殊引用名称refs/stash指向新创建的w(工作树)提交。它至少有两个父项,一个是HEAD提交,另一个是i(索引)提交。使用--untracked--all时,会有第三个父级(我称之为u)持有额外的未跟踪文件。

    除了一个案例 2 之外,我们在这里也忽略了,在i和{{1}中保存了每个文件的索引和工作树版本之后然后,w运行git stash save以使用git reset --hard HEAD提交中存储的版本替换这些文件的索引和工作树版本。因此,您的工作现在已保存,可以在以后恢复,但在索引(也称为暂存区域)或工作树中不再存在。

    1 如果(并且仅当)使用HEAD--all选项来创建第三次提交,Git还会运行--untracked并使用适当的选项删除存储在第三个父级中的文件。请记住这一点:任何现有的未跟踪文件(无论是否被忽略)都从不包含在git cleani中。除非您使用这些额外选项,否则它们保存,因此也不会被清除。请注意,未跟踪文件的定义只是任何不在索引现在 中的文件。最后两个词也很重要,如果你还没有遇到,但最终可能会遇到。

    2 使用w选项时会出现一种情况。在这种情况下,--keep-index代码做了一些相当棘手的事情:在进行git stash savei提交后,而不是将索引和工作树重置为w,它会重置他们到HEAD提交中的内容。这样做的目的是安排工作树来保存建议的新提交,以便测试工作树文件的程序可以测试&#34;是否已提交&#34;版本的文件。不过,这里有几个陷阱,但是:请参阅How do I properly git stash/pop in pre-commit hooks to get a clean working tree for tests?

    你出错的地方

    一旦你有一个存储 - 即ii提交保存,你可以大部分安全地运行w 3 或更好, git pull。这将获得其他Git的新提交,让您将Git记住为git fetch,通过originorigin/master以及origin/develop记住它们,依此类推。然后,origin/feature/tall的第二步,即pullrebase,将重新绑定 - 即,如果您有任何提交,则复制您现有的提交,或者如果您有任何提交,则合并您现有的提交,在/带有您带来的最新提交,并调整您自己的当前分支以指向结果。

    到目前为止,一切都进展顺利,正是你正在做的事情。但现在我们遇到了棘手的问题。

    现在您正在运行merge,正如您的同事/编码合作伙伴所建议的那样。我建议从git stash pop而不是git stash apply开始,但是当它失败时 - 它失败了,给出了你提到的其他内容 - 这并不重要。 4 无论哪种方式,Git都会尝试应用已保存的提交,以便恢复您在索引和/或工作树中保存的更改。但正如我刚才所说,这很棘手,因为提交是快照,而不是更改。 (另外,默认情况下,git stash pop / git stash apply会抛弃git stash pop提交。使用i,它会尝试将--index提交还原到索引中。)

    为了将i commit 恢复为而不是快照,Git使用其合并机制。存储脚本中包含以下实际行:

    w

    效果就好像您运行了git merge-recursive $b_tree -- $c_tree $w_tree - 甚至更近,git merge - 命令。 Git将您的隐藏工作树git cherry-pick(提交$w_tree)与wHEAD)的提交进行比较,以查看&#34;您更改的内容&#34;,以及将您当前的索引转换为针对同一$b_tree的部分提交($c_tree),以查看&#34;他们更改了什么&#34;,并合并它们。

    与任何合并一样,此合并可能会因合并​​冲突而失败。这就是你所描述的:

      

    ...因为我有未合并的档案而无法拉动......

    当合并失败时,它会将部分合并的结果保留在工作树和索引中的原始文件集中。例如,假设文件$b_tree存在合并冲突。现在代替三个版本的foo.txt - foo.txt(当前提交),索引和工作树 - 您有五个版本!这些是:

    • HEAD,一如既往;
    • 索引阶段1,合并基础版本:这是从HEAD获取的版本,这是与您运行时提交的$b_tree中提交的树一起使用的树HEAD;
    • 索引阶段2或git stash save:当您启动失败的--ours / git stash apply时,这就是索引中的内容。 (这可能与git stash pop版本匹配。)
    • 索引阶段3或HEAD:这是--theirs中的任何内容,即您隐藏的更改;和
    • 工作树中留下的版本,带有合并冲突标记。

    请注意,就像使用$w_treegit rebase一样,我们/他们的git cherry-pick标志在这里有所改变。

    一旦你处于这个烦人的&#34;未合并的索引条目&#34;除了完成它或完全中止操作之外,你几乎无能为力。

    在这种特殊情况下,git checkout已经在应用中途停止,因此已经中止了后续的git stash apply。因此,您仍然拥有您的存储,并可以运行git stash drop以中止尝试应用存储。或者,您可以编辑工作树文件以完成Git无法执行的合并,并git reset --hard HEAD将文件复制到索引中,以便索引具有(单个)合并条目工作树,取代三个更高阶段的条目。

    这对于任何失败的合并都必须执行相同的过程:您要么中止它,然后找出以后要做什么;或者你现在完成它。

    请注意,一般情况下,不应仅仅git add工作树文件&#34;按照&#34;完成冲突标记。虽然这解决了&#34;不能X,但你有未合并的索引条目&#34;,它会给你留下充满冲突标记的文件,这些标记实际上并没有用。

    如果Git需要将某些提交与其他人的提交合并,那么当您运行git add时,也会发生这类合并失败(合并冲突)。或者,Git可以成功自己进行合并(或者认为它至少成功),然后进行新的合并提交。在这种情况下,系统将提示您输入提交消息:

      

    我注意到git pull之后的pull的副作用有时会打开vi,让我输入提交消息。

    这表示您已在分支上进行了正常提交,并且stash已运行git pull,它认为它成功合并,现在需要提交此新合并提交的消息

    您可能希望在此使用git merge而不是git rebase。如果您使用git merge后跟第二个Git命令,而不是使用git fetch,则会更容易。

    请注意,如果您使用git pull(并学习它,尤其是非常方便的git rebase),您可以随意进行各种临时提交,包括:

      

    ......本地实验,调试代码等......

    当你进行改变时,你会将这些提交复制到另一个人的提交之上,让你的工作成为你自己的工作;你最终可以使用git rebase -i来&#34;挤压&#34;临时承诺支持一个大决赛&#34;真实&#34;承诺。你必须要小心,不要不小心git rebase -i他们(一旦你这样做,复制到处都是,并且让其他人放弃它是非常困难的。)

    3 我建议使用git push:相反,将其拆分为其组成部分。首先,运行git pull以从另一个Git获取新的提交。一旦你有了提交,如果你愿意,你可以查看它们。然后使用git fetchgit rebase将这些提交合并到您的分支中。每个分支需要一个git mergegit rebase,但在所有分支之前只需要一个git merge

    一旦你非常熟悉它将为你工​​作的两个组成部分如何工作,你就可以安全地运行git fetch,知道出现问题时 - 最终会发生什么事情 - 你&#39;我会认识到发生了什么以及哪一步失败了,并且会知道如何解决这个问题。

    4 但为了完整起见,请注意git pull仅表示git stash pop。也就是说,试图应用藏匿处;然后,如果 Git 认为进展顺利,立即放下藏匿处。但有时Git认为它没有问题,但事实并非如此。在这种特殊情况下,仍然可以使用藏匿方式很好,git stash apply && git stash drop使得它很难恢复。