git - 尽早在分支上重新排序提交而不发生冲突

问题描述 投票:0回答:4

我将如何在没有任何冲突的情况下尽早将提交移至分支上(无需太多手动工作,例如 rebase -i)?

例如

A-B-C-D-X

应该成为

A-B-X-C-D

如果将 X 与 C 和 D 交换没有冲突,但将 X 与 B 交换则会导致冲突。

谢谢。

git conflict rebase
4个回答
2
投票

使用

git rebase -i X~
,其中
X~
X
之前的修订版。

然后将变基日志中的行重新排序为您想要的顺序。

有关交互式变基的更多信息


2
投票

这是我经过 15 分钟的黑客攻击后得到的演示。这不是所提出问题的完整解决方案,但它应该减少所涉及的工作。

目标是使用

git bisect
找到未来提交的最早无冲突合并点。该解决方案利用
git bisect
固有的二分搜索功能来减少步骤。

不幸的是,这并不能阻止以后的提交发生冲突,因此需要交互式变基来审查结果(但这就是重点,无论如何)。

一个缺点/警告是,当你在测试补丁时指示 git 该步骤是失败还是成功时,你必须颠倒头脑中

good
bad
的含义。

如果以下任何步骤不清楚,请告诉我,我会尽力详细说明。

首先在一系列提交中创建以下文件。每次提交都应添加一系列四个相同的行(a、然后 b、然后 c、然后 d)。

a
a
a
a
b
b
b
b
c
c
c
c
d
d
d
d

此时,

git log
应该输出类似:

commit 6f2b809863632a86cc0523df3a4bcca22cf5ab17
Author: Todd Sundsted <...>
Date:   Tue Dec 20 22:45:44 2011 -0500

    Added d.

commit 91ba7e6f19db74adb6ce79e7b85ea965788f6b88
Author: Todd Sundsted <...>
Date:   Tue Dec 20 22:44:26 2011 -0500

    Added c.

commit f83beee55d6e060536584852ebb55c5ac3b850b2
Author: Todd Sundsted <...>
Date:   Tue Dec 20 22:44:00 2011 -0500

    Added b.

commit d6d924b0a30a9720f6e01dcc79dc49097832a587
Author: Todd Sundsted <...>
Date:   Tue Dec 20 22:43:38 2011 -0500

    Added a.

commit 74d41121470108642b1a5df087bc837fdf77d31c
Author: Todd Sundsted <...>
Date:   Tue Dec 20 22:43:11 2011 -0500

    Initial commit.

现在编辑文件,使其包含以下内容,然后提交:

a
a
a
a
b
x
x
b
c
x
x
c
d
d
d
d

日志现在应该包含另一次提交:

commit 09f247902a9939cb228b580d39ed2622c3211ca6
Author: Todd Sundsted <...>
Date:   Tue Dec 20 22:46:36 2011 -0500

    Replaced a few lines with x.

现在为

X
提交生成补丁。

git diff -p master~ > x.patch

启动

bisect
——记得在补丁失败时使用
git bisect good
,在补丁成功时使用
git bisect bad

$ git bisect start
$ git bisect good 74d41121470108642b1a5df087bc837fdf77d31c
$ git bisect bad master
Bisecting: 2 revisions left to test after this (roughly 1 step)
[f83beee55d6e060536584852ebb55c5ac3b850b2] Added b.
$ patch --dry-run -p1 < x.patch 
patching file file.txt
Hunk #1 FAILED at 3.
1 out of 1 hunk FAILED -- saving rejects to file file.txt.rej
$ git bisect good
Bisecting: 0 revisions left to test after this (roughly 1 step)
[6f2b809863632a86cc0523df3a4bcca22cf5ab17] Added d.
$ patch --dry-run -p1 < x.patch 
patching file file.txt
$ git bisect bad
Bisecting: 0 revisions left to test after this (roughly 0 steps)
[91ba7e6f19db74adb6ce79e7b85ea965788f6b88] Added c.
$ patch --dry-run -p1 < x.patch 
patching file file.txt
Hunk #1 succeeded at 3 with fuzz 2.
$ git bisect bad
91ba7e6f19db74adb6ce79e7b85ea965788f6b88 is the first bad commit
commit 91ba7e6f19db74adb6ce79e7b85ea965788f6b88
Author: Todd Sundsted <...>
Date:   Tue Dec 20 22:44:26 2011 -0500

    Added c.

$ git bisect reset

正如预期的那样,提交

X
中的编辑可以在提交
C
后立即移动。交互式变基证实了这一点:

91e92489 * Added d.
6c082b1f * Replaced a few lines with x.
a60ae2a9 * Added c.
4d5e78f2 * Added b.
7d2ff759 * Added a.
74d41121 * Initial commit.

0
投票

嗯,这几乎有效,但需要一些清理。

使用一段时间后,我遇到了另一个问题,我已将其发布在here

#!/bin/sh -e

# todo: 与 git 集成
GIT_DIR=./.git/

提交ID=$1

如果[“$1”=“”];然后
   echo 用法: $0 commitid
   1号出口
菲

tmpdir="$GIT_DIR/气泡工作"
/bin/rm -rf "$tmpdir"
mkdir“$tmpdir”

# 签出带有分离头的提交
git checkout -q $commitid^0 ||死亡“无法分离头部”

而[1=1];做

# todo 管道输出以避免临时文件
# 查看 git-rebase.sh

patchfile=`git format-patch -k --full-index --src-prefix=a/ --dst-prefix=b/ --no-renames -o "$tmpdir" HEAD~1`
回显补丁= $补丁文件

git checkout -q HEAD~2
git am --rebasing "$patchfile" ||死了“git 失败了”
/bin/rm -f "$补丁文件"

回声循环
完毕



/bin/rm -rf "$tmpdir"


0
投票

我们确实需要逐个提交,以便找到相关提交和所有后来的提交适用的最早点。有效地做到这一点的一种方法是向后迭代提交列表。

下面的(非常粗略的)脚本找到了这一点并打印了有关它的有用信息,这有助于决定您是否真的想将提交移到那么远。要实际移动提交,请使用

git rebase -i
。虽然这可以自动化,但对过程的一些控制在这里似乎实际上很有用。该脚本需要在命令行进行提交,如果未给出,则使用最后一次提交。

冒泡提交是相关的,可以通过向前迭代来实现。

#!/bin/sh

set -ex

top_level=$(git rev-parse --show-toplevel)
# TODO: Does this always exist?
git_dir=${top_level}/.git
tmpdir="git_dir/bubble-work"
/bin/rm -rf "$tmpdir"
git clone "$top_level" "$tmpdir"

start_commit=$(git rev-parse HEAD)

if [ -n "$1" ]; then
  my_commit=$1
else
  my_commit=$start_commit
fi

git -C $tmpdir reset --hard ${my_commit}^

# FIXME: ask Git for list of commit instead of using loop
for step in $(seq 1 100); do
  current_commit=$(git rev-parse ${my_commit}~$step)
  git -C $tmpdir revert --no-edit $current_commit
  if ! git -C $tmpdir cherry-pick --no-commit $my_commit; then
    # Show info that helps decide if this is really the right place
    # to move that commit to, and to navigate in the subsequent `git rebase -i`
    git --no-pager show $current_commit
    git --no-pager show $my_commit
    git log --oneline -n 1 $current_commit
    git log --oneline -n 1 $my_commit
    exit 1
  fi
  git -C $tmpdir reset --hard HEAD
done

echo "End reached, increase loop range"
git reset --hard $my_commit
© www.soinside.com 2019 - 2024. All rights reserved.