我可以一次性提交父分支+ rebase吗?

时间:2017-02-28 15:17:55

标签: git branch rebase git-commit

我有一个分支develop,并从中分支了一个名为next的大功能。

next中,有一个连续的流程来编辑最初来自develop的文件,以及仅在next中创建新文件的文件。

TL; DR:您可以跳过下一部分直接转到问题。

(a)next对从develop继承的文件的更改始终是向后兼容的,并且始终在那里提交。

(b)与此同时,develop本身也正在发展,这些变化也应该在next中可见。因此,next时不时会develop重新定位。

提交回develop导致合并冲突,因为(b)和rebase导致合并冲突,因为(a)。后者可以通过-X theirs来修复,因为冲突已经在第一步中解决了。

但这效率不高。

有没有办法自动:

  1. 将最初来自父分支的文件提交到父分支(例如develop
  2. 将父分支上不存在的文件提交到当前分支(例如next
  3. 重新启动父分支上的当前分支以冒泡更改?
  4. 可能的复杂解决方案

    我可以想象一些'简单'(r)git-foo是可能的,因为这个愿望并不是唯一的。但如果没有,可能会有一些bash脚本。例如,以下命令:

    git ls-tree -r develop --name-only
    

    将显示确实位于develop的文件列表。不在该列表中的文件只能在next

    我想如果所有其他方法都失败了,我可以创建一个shellcript来:

    1. 首先将develop上存在的所有文件提交到develop
    2. 然后将所有其他文件提交到next
    3. next
    4. 上的Rebase develop

      但它并不像听起来那么简单。

3 个答案:

答案 0 :(得分:1)

与往常一样,我会首先建议您在#34;之前绘制(已知)"和(#);"""首先提交图形。好吧,也许第二个:第一个,决定是否要允许这些操作使用"脏工作树"和/或"脏指数" (与当前HEAD,提交不匹配的那个。

但是,在这种情况下,您可能希望使用有关每个中所需的快照tree对象的辅助标记来扩充图形,尤其是有关如何处理(现有)提交中的文件的示例问题,vs整个过程开始时可能在索引和/或工作树中的文件。这可能有助于决定如何(根据Git机制和可编写脚本的命令)继续进行。

一旦你掌握了这些,请记住,Git是你可以随意使用的一大盒工具。这些工具包括以下功能:

  • new 提交作为其父级,无论提交是HEAD还是当时索引中的任何提交作为其树。但是还要看git commit -a,它将从工作树中获取索引中路径已经的文件的新文件版本,或者从工作中缺少的索引路径中删除-tree。

    当然,仅在索引或工作树中的文件很容易被删除。提交现有索引使其与任何提交一样永久(见下文)。所以一般来说,如果你有未提交的工作,首先要做的就是提交它。新提交将旧提交作为其父提交,新提交现在位于HEAD - 或者通常位于HEAD引用的分支名称中(以便git rev-parse HEAD找到新ID,但含义 git rev-parse refs/heads/next或其他任何内容。

  • 分支名称只是指向提交提交。然后每个提交指回其直接父级(或者用于合并提交,父级,复数)。以命名 tip 提交结束的提交链也称为分支(请参阅What exactly do we mean by "branch"?)。您可以使用分离的HEAD进行没有名称​​尚未的新提交,如果方便的话:您只需要将ID保存在某处(使用git rev-parse HEAD创建它们,例如,将ID复制到shell变量中,以便您可以命名它们。你必须在两周的默认修剪期限内给它们永久名称 - 通常是分支名称 - 以防止它们被垃圾收集所收获。

  • git stash,如果您选择使用它,可以将当前索引保存为提交,然后将当前工作树保存为另一个提交,然后选择保存未跟踪,甚至未跟踪 - 并忽略,将文件作为第三个​​提交。这三个提交都不在任何分支上;相反,特殊名称refs/stash指向这些两个或三个提交中的一个(然后用于查找其他提交,以及HEADgit stash同时进行的提交git rebase或所有这三个)。这些提交参与git stash。如果您需要干净的工作树和/或索引,则无需使用git rebase --onto target limit及其复杂功能。如果没有,你可能想要它,或做类似的事情。

  • 运行limit..HEAD将复制--cherry-pick --right-only --no-merges limit...HEAD选择的提交(但通常会丢弃合并和预先选择的提交,即这确实使用-m,但具体情况有所不同还有一些类型的rebase,包括-i-k-ptarget参数(如果给出的话)。 limit 默认为 <upstream> 参数提供的提交(rebase文档调用develop)。通常这是恰当和充分的;在您的情况下可能会或可能不会,这取决于您添加提交的方式和时间。

我之前如何做到这一点

所有这一切,我之前已经处理过类似的事情,我将描述我更喜欢这样做的方式。这是否适合你是另一个问题。

你有一个&#34;基础分支&#34;,在你的情况next,我假设一个更大的团队正在努力。你还有一个功能或主题分支(你称之为project/0,但我通常会给出一个更具体的名称,project-mac or whatever(虽然我自己从来没有在麻省理工学院......)。我所做的是编号我的分支。

  1. project-0(或git checkout -b project/0 develop,我并不一致):我的第一次刺伤。这基本上是project/1,然后破解并提交一段时间。

  2. project-1(或git rebase):一些经验教训,我&#34; rebase&#34;在当前的主要分支上,通过挑选或重写或其他。通常在0到1之间,没有足够的可挽救代码来打扰像project/2这样的工具。

  3. 现在有些部分已经足够扎实了,我自己提交进入主分支(并根据工作等情况,让他们审核或通过测试或其他)。现在我在Git中做git checkout -b project/2 project/1 git rebase develop

    develop

    这会自动抛出已经完全被git log project/1(由我作为第3步的第一部分)挑选出来的提交,并且给我合并冲突的部分是&#34;不干净的挑选& #34;或者与我解决的其他工作发生冲突。在困难的情况下,我可以轻松git show和{{1}}来自那里的具体提交,如果我需要记住我做了什么以及为什么我这样做。如果我对提交消息很满意,那么它们就是必要的提醒。

  4. 冲洗并重复恶心。

  5. 请注意,这些分支实际上都不会被重新定位,除非在初始步骤中从旧版本创建新的编号风味。这意味着它们可以轻松地在多个克隆之间共享,这在必须在不同操作系统上测试或分布在多个人之间时非常有用。

答案 1 :(得分:0)

必须分多步完成。提交next,然后重新绑定和/或合并以将所有内容重新导入develop。 Git没有能力一次性完成这项工作

答案 2 :(得分:0)

我知道没有内置这样做的方法,虽然我会想象这很受欢迎。所以我去了一些bash黑客并想出了这个。

注意,只有在进行更改之前重新进行重新定位时,这只会在没有合并冲突的情况下有效。

为了分隔哪些文件应该提交给父(develop)分支以及哪些文件应该提交给功能(next),这些是最重要的命令:

  • 列出所有已更改,已删除,(已重命名)和新文件:
    • git ls-files -mdo --exclude-standard
  • 列出父分支(develop)中存在的所有文件:
    • git ls-tree -r develop --name-only
  • 相交这些列表以找出父分支中存在哪些已更改的文件:
    • sort <(git ls-tree -r develop --name-only | sort) <(git ls-files -mdo --exclude-standard | sort) | uniq -d

所以我们想要做的是:

    我们想要提交给父分支(develop)的
  • 阶段文件:
    sort <(git ls-tree -r develop --name-only | sort) <(git ls-files -mdo --exclude-standard | sort) | uniq -d | xargs git add
    注意现在是手动添加重命名文件的时间,因为此时仅暂存文件删除。
  • 藏匿(1)所有内容!我们希望稍后将它们提交到此分支(next)。但保留暂存的文件 git stash --keep-index -u
  • 隐藏(2)暂存文件。我们想将它们提交给父分支(developgit stash
  • 结帐父母分支(develop
    git checkout develop
  • Pop 存储(2)
    git stash pop
  • 提交弹出的藏匿件
    git commit -am "<commit message>"
  • 再次
  • 结帐功能分支(nextgit checkout next
  • 弹出剩余的藏匿处(1) git stash pop
  • 舞台所有(新)文件
    git add -A
    git commit -m "<commit message>"
  • Rebase 此功能取消了它的父级 git rebase develop

完成! developnext现在都使用最新代码进行更新。

如果您保证不重命名文件,您可以放心地将其放入脚本中以自动执行此操作。

mergedowncommit.sh

#!/usr/bin/env bash
# By Redsandro (http://www.Redsandro.com/)
# 2017-03-03

if [ -z "$3" ]; then
    echo "No commit message supplied."
    echo "Usage: mergedowncommit.sh <parent> <feature> <commit message>"
    exit 1
fi

sort <(git ls-tree -r "$1" --name-only | sort) <(git ls-files -mdo --exclude-standard | sort) | uniq -d | xargs git add
git stash --keep-index -u
git stash
git checkout "$1"
git stash pop
git commit -am "$3"
git checkout "$2"
git stash pop
git add -A
git commit -m "$3"
git rebase "$2"

if [ $? -eq 0 ]; then
    echo "Looks like it worked. :)"
else
    echo "Looks like some files were not freshly rebased prior to running this script."
    echo "Please manually solve merge conflicts, and run \"git rebase --continue\"."
fi

用作:

mergedowncommit.sh <parent> <feature> <commit message>

E.g:

mergedowncommit.sh develop next "This is my commit message"

您可以根据自己的工作流程进行调整。也许添加您最喜欢的difftool来解决合并冲突。我可以想象,当develop也处于工作状态时,你至少有一个,它包含一个包含版本信息的文件。

注意:使用风险自负。