Git - 进一步向下徘徊 [英] Git - remerging further down the line

查看:100
本文介绍了Git - 进一步向下徘徊的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

合并与重新组合的主要缺点在于合并结果在一个混乱的树中。如果主人经常更新,那么每次进行重大更新时都会精通合并,从而产生大量不必要的提交。现在,大多数时候,实际上并没有任何需要。请考虑以下存储库:

  Master A\  -  B  -  C\  -  D\ --- ------ E 
Branch l - m --- n --- o - p - q

这里n是一个合并,我们必须解决大量的冲突,我们希望避免再次解决。我们希望在不创建新的合并提交的情况下将E合并回来。所以我们回到o合并E并在顶部选择p和q:

  Master A\  -  B  -  C\  -  D\ -------- E\ 
Branch l - m --- n\ - o - p - q \
Tmp ------------- o'-pq

如果这个工作没有错误,我们可以删除旧的分支。



如果我是第一个想到这种工作流程的人,我会感到惊讶。有没有可以自动执行此操作的任何git扩展?



我已经开始编写脚本来执行此操作,但主要问题是选择o。 :/ ^合并 - 在大多数情况下会选择o,但如果没有更好的方法避免依赖不是以合并单词开始的提交消息,将会感到惊讶。 要追溯启用rerere,请参阅此处。在这个答案中的脚本不会变成rerere,并且在 E 的历史记录(见下文)中会出现与rerere不同的表现, code> n ... D - 解决了 o 中的冲突问题。 rerere 执行 n ... E 合并并应用任何 n ... D >仍然有效的解决方案,而此脚本执行标准 o ... E 合并(但替换父< o < code $> $ o



复制图形以供参考: / em>

 之前需要之后
主A \ - B - C\ - D \\ \\ .... E \主A \ - B - C \ - D ... E \
分支l - m --- n --- o - p-- q / Branch l - m --- n ------ o' - p' - q'

rerere将因此绕过 E -reverted n ... D 冲突,while该剧本将把复归视为进一步的变化。这两个脚本都生成了上图中的期望之后图,但是它们通过不同的路线到达那里。

一个小时的尝试没有产生任何更多



我不清楚rerere或脚本的行为 b

当我做的时候

blockquote>

返回o,合并E

加上

  git checkout o 
git merge E



  Master A\  -  B  -  C\  -  D\ ---- ----- E 
分支l - m --- n --- o \ -p - q \
HEAD`-------- o'

o 用于 o '的父母。您确实需要 o'内容(以保留您已在 o 中应用的任何冲突解决方案),但您希望它具有 n E 作为父母,而不是 o E 。这实际上相当简单。



所以完整的程序是,
$ b

 #!/ bin / sh 

#1.确定$ 1
#中最近的合并。确认它来自$ 2
#3。将合并更新为$ 2的当前状态
#4.保留已经完成
#5的任何冲突解决方案,然后选择所有内容。

#最近的$ 1
update =`git rev-list -1 --min-parents = 2 $ 1`

#验证最近的合并是从正确的合并基础
test`git merge-base $ 1 $ 2`=`git rev-parse $ update ^ 2`\
|| {echo最近的合并不是从$ 2中的$ 1;出口1; }

set -e#立即出错
git checkout $ update
git merge $ 2
git checkout $(
#这会产生一个新的提交用HEAD的提交信息和树
#但是用$ update ^和$ 2作为父母
git cat-file -p HEAD \
| sed 1,/ ^ $ / d \
| git commit-tree -p $ update ^ -p $ 2 HEAD ^ {tree}

test $ update =`git rev-parse $ 1` || git cherry-pick $ update .. $ 1
git checkout -B $ 1

你可以改变(从 set -e

  set -e 
git checkout $ update ^
git merge $ 2
test $ update =`git rev-parse $ 1` || git cherry-pick $ update .. $ 1
git checkout -B $ 1

在一个子框架中,退出并继续执行,不会有任何麻烦,你可以通过这样做来减少它的脆弱性。

  git合并$ 2 \ 
|| {echo解决冲突和\exit\`,或\`exit 1 \`不能继续; $ SHELL; }

编辑:更新来处理更新合并时没有任何樱桃挑选。


The main disadvantage of merging vs. rebasing is that merging results in a messy tree. If the master is frequently being updated, then merging in mastery every time there has been a significant update will create a whole host of unnecessary commits. Now, most of the time, there isn't actually any need for this. Consider the repository as follows:

Master A\--B--C\--D\---------E
Branch   l--m---n---o--p--q

Here n is a merge where we had to resolve a significant amount of conflicts which we want to avoid resolving again. We want to merge E back in without creating a new merge commit

So we go back to o, merge E and cherry-pick p and q on top:

Master A\--B--C\--D\--------E\
Branch   l--m---n\--o--p--q   \
Tmp               -------------o'-p-q

If this works without an error, we can then remove the old branch.

I would be surprised if I was the first person to think of this kind of workflow. Are there any git extensions that can automate this?

I've started working on a script to do this, but the main issue is selecting o. ":/^Merge" - will select o in most cases, but it would be surprised if there wasn't a better way that avoids relying on commit messages not starting with the word Merge.

解决方案

edit: To retroactively enable rerere, see here.. The script in this answer doesn't turn rerere on and will behave differently than rerere would in the presence of further changes, in E's history (see below), to n...D-conflicted hunks resolved in o. rerere does an n...E merge and applies any n...D resolutions that are still valid, while this script does an standard o...E merge (but replaces parent o with o)

Copying the graph for reference:

      before                                 desired after
Master A\--B--C\--D\....E             \  Master A\--B--C\-D...E\
Branch   l--m---n---o--p--q         /    Branch   l--m---n------o'--p'--q'

rerere will thus bypass E-reverted n...D conflicts, while the script will treat the reversion as a further change. Both scripts produce the "desired after" graph above, but they get there by different routes.

An hour's trying hasn't produced any more comprehensible further textual description of the differences than simply looking at the graphs and deducing.

It's not clear to me that either rerere's or the script's behavior is always better.


When I do

go back to o, merge E

with

git checkout o
git merge E

I get

Master A\--B--C\--D\---------E
Branch   l--m---n---o\-p--q   \
HEAD                  `--------o'

with o for o''s parent. You do want the o' content (to preserve any conflict resolutions you'd already applied in o), but you want it to have n and E as parents, not o and E. That's actually fairly easy.

So the complete procedure is,

#!/bin/sh

# 1. identify the most recent merge on $1
# 2. verify that it's from $2
# 3. update the merge to $2's current state, 
# 4. preserving any conflict resolutions that were already done
# 5. and cherry-pick everything since.

# most recent merge in $1
update=`git rev-list -1 --min-parents=2 $1`

# verify most recent merge is from correct merge base
test "`git merge-base $1 $2`" = "`git rev-parse $update^2`" \
|| { echo "most recent merge isn't of $1 from $2"; exit 1; }

set -e  # exit immediately on error
git checkout $update
git merge $2 
git checkout $(
      # this makes a new commit with HEAD's commit message and tree
      # but with $update^ and $2 as parents
      git cat-file -p HEAD \
      | sed 1,/^$/d \
      | git commit-tree -p $update^ -p $2 HEAD^{tree}
   )
test $update = `git rev-parse $1` || git cherry-pick $update..$1
git checkout -B $1

If you're willing to lose any conflict resolutions done in o you can instead do (from the set -e)

set -e
git checkout $update^
git merge $2
test $update = `git rev-parse $1` || git cherry-pick $update..$1
git checkout -B $1

If doing work in a subshell and exiting from that to continue isn't any trouble you can make this much less fragile by doing

git merge $2 \
|| { echo "Resolve conflicts and \`exit\`, or \`exit 1\` to not continue"; $SHELL; }

edit: update to handle updating the merge when there's nothing to cherry-pick.

这篇关于Git - 进一步向下徘徊的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆