代码之家  ›  专栏  ›  技术社区  ›  Kartick Vaddadi

如何将已提交的更改从分支移动到主控形状作为挂起的更改?

  •  1
  • Kartick Vaddadi  · 技术社区  · 6 年前

    我正在实现一个新的特性,为此我创建了一个新的分支,并对它进行了一些提交,然后进行了推送。现在,我希望以挂起/未提交更改的形式继续在master中处理此功能。挂起,因为在我提交之前它需要更多的工作。我该怎么做?

    当我最终提交时,master的修订历史应该只指示一次提交,就好像我从未创建过其他分支或进行过中间提交一样。我该怎么做?

    手动方式是创建第二个Git工作区,在其中一个中打开master,在另一个中打开branch,然后复制粘贴每个修改过的文件。有没有一种自动化的方法来做这个?

    3 回复  |  直到 6 年前
        1
  •  3
  •   torek    6 年前

    首先,我将给出命令,然后给出它们真正在做什么,以及为什么这会实现您想要的。我假设下面的功能分支是刚刚调用的 branch _ git merge 如果它有别的名字。

    git status               # and make sure everything is committed on your branch
                             # do any extra commits here if required
    
    git checkout master      # change the current branch/commit, index, and work-tree
    git merge --squash --no-commit branch
    

    合并分支 , --squash 暗示 --no-commit 总之,所以您可以在这里省略第二个标志参数。我把它放在里面做了更多的说明。此外, --壁球 方法 在索引树和工作树中执行合并操作,但不要进行合并提交。 )

    根据你的工具,你可能想做 git reset (默认为 --mixed 重置 HEAD 作为承诺)复制 提交回索引,以便 git diff 向你展示一切, git status 将所有内容显示为 未准备提交 .

    重要的是,在这里,没有真正的 悬而未决的变化 . Git不存储 变化 完全。什么是Git商店 提交 ,并且每个提交都是所有文件的完整快照。当你问吉特的时候 什么改变 ,你必须告诉Git 提交,或者至少提交两个充满文件的树。然后,Git从这两个输入中计算出快照A和快照B的不同之处。然后Git告诉您这些不同之处,但A和B仍然是完整的快照。在某些方面,这些都不重要,你可以在需要的时候看到变化,在需要的时候看到快照。但是,如果你的心理模型与Git的实际做法相匹配,你就没有什么秘密可言了:你自己的工作会更容易。最重要的方法是记住: 要查看更改或差异,必须提供两个输入。 有时,其中一个输入是隐含的。有时, 二者都 其中有暗含的!

    最后一个例子是 差异比较 git diff --cached / git diff --staged :git将索引与工作树进行比较(普通 差异比较 ) 提交到索引( --staged --cached )。选项(如果有)决定两个输入。也就是说,Git从这个列表中选择了三件事中的两件:

    • 这个 commit,这是一个真正的commit,包含特殊的git-only、冻结/只读形式的所有文件;
    • 索引,本质上是 建议下一次提交 ,并包含所有文件的副本,也为仅git格式,但不完全冻结;
    • 工作树,它以普通有用的形式保存您的文件。

    手上有两件东西,Git会比较它们,告诉你有什么不同。这个 GIT状态 作为其工作的一部分,命令运行, 二者都 这两个 差异比较 S(总是设置某些选项,例如 --name-status --find-renames=50% )并总结了结果:输出来自 Git Diff--阶段 为提交而准备的更改 以及 差异比较 未准备提交的更改 .

    您也可以手动运行 git diff HEAD . 这个选择 你的工作树作为两个输入:你明确地命名了其中一个, 在论点中,另一个是隐含的。比较冷冻的 内容以解冻、正常格式、工作目录树内容显示,并向您显示不同之处。同样,Git正在比较完整快照: 第二 一个是活的工作树,通过比较的过程来捕捉。

    (旁白:在我看来,你想做的可能是错误的做法。你可以通过早点和经常地承诺,使你自己的工作更容易。执行diff是一个好主意,但是您可以从基本提交到tip提交,也就是说,跨一个提交范围来评估总体结果。然后,您可以使用一个交互式的REBASE,或“我的首选方法”附加分支,将较小的承诺重新构建成更合理的一系列承诺。但其中大部分是个人偏好。听起来你的xcode工具比现在的工作要好得多;你使用它的方式不是 错误的 ,这是非常有限的。)

    如何以及为什么这样做

    我开始写一篇较长的文章,但它失控了,所以我只想说:看看我的其他StackOverflow答案,了解Git是如何从索引中提交的,而不是工作树,以及这些提交是如何更新分支名称的。 附上。

    Git的合并本身也是一个相当大的主题。但是,我们可以说合并使用 指数 以实现其合并结果, 工作树 起次要作用,主要针对存在合并冲突的情况。

    真正的合并,即 合并分支 这将进行完全的三向合并,最终将进行类型为的新提交 合并提交 _ 父母。这两个双亲是计算合并结果的三个输入中的两个。第三个输入由另外两个隐含;它是 合并基础 . Git使用提交图自行查找合并基。然后Git将合并基与 --ours --theirs 分支提示,好像使用两个 git diff --find-renames 命令:一个从基地到我们的,一个从基地到他们的。

    忽略诸如添加、删除或重命名文件之类的问题,比较这三个提交将生成一个谁更改了哪些文件的列表。如果 我们 更改了一些他们没有更改的文件,或者 他们 更改了一些我们没有的文件,合并这些文件很容易:Git可以只获取我们的文件,或者他们的文件。如果我们两个都没有更改文件,Git可以获取文件的三个版本中的任何一个(合并库、我们的或他们的)。

    对于困难的情况,我们都更改了一些文件,git从合并基础开始,和 组合 我们的更改及其更改,并将组合的更改应用于合并基副本。如果我们的改变和他们的改变有所不同 线 结合很简单,Git宣布结果是成功的(即使它在现实中毫无意义)。如果我们和他们都改变了 相同的 行,git声明合并冲突。

    合并冲突是最棘手的。给你,吉特走了 所有三个输入文件 在索引中,并将冲突合并写入工作树。你的工作,作为人类 合并分支 ,就是提出正确的合并,不管你喜欢什么。您可以使用文件的三个索引副本,或者工作树副本,或者所有这些副本。您自己解决合并,然后使用 git add 要将正确的结果写入索引,请将三个未合并的副本替换为一个合并副本。解决了这个冲突;一旦解决了所有冲突,就可以完成合并。

    如果你跑 合并分支 具有 --没有承诺 ,Git将尽可能多地自行进行合并,这可能就是全部合并,然后停止,就像合并冲突一样。如果没有冲突,这将使索引树和工作树都处于准备提交状态。(如果有冲突, --没有承诺 选项没有任何效果:Git已经停止了,留下了混乱,但仍然停止了,剩下的混乱让你来解决。)

    然而,在所有这些情况下,Git在 .git 目录,告诉Git 下一个 承诺 git merge --continue git commit _ 父母。这使得新的承诺 合并提交 将两个分支连接在一起:

                 I--J   [master pointed to J when we started]
                /    \
    ...--F--G--H      M   <-- master (HEAD)
                \    /
                 K--L   <-- branch
    

    这不是你想要的。所以,我们使用 git merge --squash ,它告诉Git: 像往常一样进行合并,但不要 合并 提交,安排下一个提交成为 普通的 承诺。 也就是说,如果Git要做出新的承诺 M ,如下所示:

                 I--J--M   <-- master (HEAD)
                /
    ...--F--G--H
                \
                 K--L   <-- branch
    

    没有特别好的理由, --壁球 即使合并顺利,也会禁止提交。所以之后 Git合并--挤压 ,将更新索引和工作树,但可以对工作树进行更多更改,使用 Git添加 要将更新后的文件复制到索引中,并且仅在完成后,才使用 GIT提交 做出新的承诺。

    (对于更简单的合并,Git将默认执行快进, --壁球 也禁止快进模式,好像 git merge --no-ff . 所以 --壁球 ,没有 --no-ff 而没有 --没有承诺 够了。

    决赛 Git复位 ,如果使用和需要,只需复制 提交回索引。也就是说,您可能希望您的工具比较 提交到工作树,就好像您正在运行 GIT差速器头 . 如果工具将索引与工作树进行比较,则可以通过取消更新索引以匹配来获得相同的效果。 之后 --壁球 操作更新了它。

        2
  •  1
  •   benhorgen    6 年前

    你考虑过合并吗 master 然后使用首选的diff工具对提交历史进行diff?

    合并成 主人 将是一个承诺。但只要你不 push 对远程(例如“源”)的更改您可以始终使用重置合并 git reset HEAD~2 放弃合并提交。

    另一个注意事项是,“head~2”是提交历史记录中要重置回的提交数的示例。如果合并提交将“x”个提交数放在远程之前,则将“2”替换为提交数a git status 报告你在你的遥控器前面。

        3
  •  1
  •   salchint    6 年前

    我相信有很多有效的方法可以做到这一点。我想描述一个简短的 补片 从功能分支传输代码更改。

    cd $the-root-of-your-project
    git checkout feature-branch
    git format-patch <the-commit-since-you-began-the-feature>
    

    这将创建一个 补丁 每次提交文件。(提示:在最后一个命令中需要输入的提交是 之前 你要转的第一个。见 since revision range 在里面 https://git-scm.com/docs/git-format-patch 详情。

    其次,我建议你 cat 所有这些 *.patch 文件成一体。

    第三,得到累积的变化 补丁 文件到的索引中 主人 :

    git checkout master
    patch -p1 < accumulated.patch
    git diff
    git add .
    ...
    

    patch 是来自 猛击 -p1 需要在 补丁 文件关闭。

    推荐文章