merge和git - git rebase冲突



为什么git-rebase在我所做的只是压缩提交时给了我合并冲突? (4)

好,我有足够的信心抛出一个答案。 也许将不得不编辑它,但我相信我知道你的问题是什么。

你的玩具回购测试案例有一个合并 - 更糟的是,它与冲突合并。 而且你正在重组合并。 没有-p (不完全与-i工作),合并将被忽略。 这意味着,无论你在冲突解决方案中做了什么,在基础架构尝试挑选下一个提交时都不存在 ,因此它的补丁可能不适用。 (我认为这是一个合并冲突,因为git cherry-pick可以通过在原始提交,当前提交和共同祖先之间进行三方合并来应用修补程序。)

不幸的是,正如我们在评论中指出的那样, -i-p (保留合并)不会相处得很好。 我知道编辑/改编工作,而重新排序工作则不行。 不过,我相信它适用于南瓜。 这没有记录,但它适用于我在下面描述的测试案例。 如果你的情况比较复杂,你可能会遇到很多麻烦,尽管它仍然是可能的。 (故事的道德: 合并之前rebase -i清理。)

所以,让我们假设我们有一个非常简单的例子,我们想把A,B和C压在一起:

- o - A - B - C - X - D - E - F (master)
   \             /
    Z -----------

现在,就像我所说的,如果X中没有冲突,那么git rebase -i -p按照您的预期工作。

如果有冲突,事情会变得有点棘手。 它会做很好的压缩,但是当它试图重新创建合并时,冲突将再次发生。 你必须再次解决它们,将它们添加到索引中,然后使用git rebase --continue继续前进。 (当然,您可以通过检查原始合并提交的版本来再次解决它们。)

如果你碰巧在你的repo中启用rererererere.enabled设置为true),这将会更容易rerere.enabled将能够从最初发生冲突时重新使用re- re re解决方案,并且你只需要做是检查它,以确保它正常工作,将文件添加到索引,并继续。 (你甚至可以更进一步,打开rerere.autoupdate ,它会为你添加它们,所以合并甚至不会失败)。 不过,我猜测你并没有启用rerere,所以你将不得不自己解决冲突。*

*或者,你可以从git-contrib尝试rerere-train.sh脚本,它试图“从现有的合并提交中提取数据库” - 基本上,它检查出所有的合并提交,试图合并它们,以及如果合并失败,它会抓取结果并将它们显示为git-rerere 这可能是耗时的,我从来没有真正使用它,但它可能是非常有帮助的。

https://ffff65535.com

我们有一个超过400个提交的Git仓库,其中的第一批是很多反复试验。 我们希望通过将许多压缩成单个提交来清理这些提交。 当然,git-rebase似乎是要走的路。 我的问题是,它最终会导致合并冲突,而这些冲突并不容易解决。 我不明白为什么应该有任何冲突,因为我只是压制提交(不删除或重新排列)。 很可能,这表明我不完全理解git-rebase如何做它的南瓜。

以下是我正在使用的脚本的修改版本:

repo_squash.sh(这是实际运行的脚本):

rm -rf repo_squash
git clone repo repo_squash
cd repo_squash/
GIT_EDITOR=../repo_squash_helper.sh git rebase --strategy theirs -i bd6a09a484b8230d0810e6689cf08a24f26f287a

repo_squash_helper.sh(此脚本仅由repo_squash.sh使用):

if grep -q "pick " $1
then
#  cp $1 ../repo_squash_history.txt
#  emacs -nw $1
  sed -f ../repo_squash_list.txt < $1 > $1.tmp
  mv $1.tmp $1
else
  if grep -q "initial import" $1
  then
    cp ../repo_squash_new_message1.txt $1
  elif grep -q "fixing bad import" $1
  then
    cp ../repo_squash_new_message2.txt $1
  else
    emacs -nw $1
  fi
fi

repo_squash_list.txt :(此文件仅由repo_squash_helper.sh使用)

# Initial import
s/pick \(251a190\)/squash \1/g
# Leaving "Needed subdir" for now
# Fixing bad import
s/pick \(46c41d1\)/squash \1/g
s/pick \(5d7agf2\)/squash \1/g
s/pick \(3da63ed\)/squash \1/g

我会把“新消息”的内容留给你的想象力。 最初,我没有使用“--strategy theirs”选项(即使用默认策略,如果我正确理解文档是递归的,但我不确定使用哪种递归策略),并且它也没有做到这一点。工作。 另外,我应该指出,使用repo_squash_helper.sh中注释掉的代码,我保存了sed脚本所处理的原始文件,并运行sed脚本来确保它正在执行我想要的操作(它是)。 再次,我甚至不知道为什么会有冲突,所以使用哪种策略似乎并不重要。 任何建议或见解都会有所帮助,但大多数情况下我只是想让这种挤压工作。

与Jefromi讨论的额外信息更新:

在开发我们庞大的“真实”存储库之前,我在测试存储库上使用了类似的脚本。 这是一个非常简单的存储库,测试工作干净。

我失败时得到的消息是:

Finished one cherry-pick.
# Not currently on any branch.
nothing to commit (working directory clean)
Could not apply 66c45e2... Needed subdir

这是第一次壁球提交后的第一次选择。 运行git status产生一个干净的工作目录。 如果我然后做一个git rebase --continue ,在几次提交之后,我会收到一个类似的消息。 如果我再做一次,在几十次提交之后,我会得到另一个非常类似的消息。 如果我再做一次,这一次它经历了大约一百次提交,并产生这样的信息:

Automatic cherry-pick failed.  After resolving the conflicts,
mark the corrected paths with 'git add <paths>', and
run 'git rebase --continue'
Could not apply f1de3bc... Incremental

如果我然后运行git status ,我会得到:

# Not currently on any branch.
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
# modified:   repo/file_A.cpp
# modified:   repo/file_B.cpp
#
# Unmerged paths:
#   (use "git reset HEAD <file>..." to unstage)
#   (use "git add/rm <file>..." as appropriate to mark resolution)
#
# both modified:      repo/file_X.cpp
#
# Changed but not updated:
#   (use "git add/rm <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
# deleted:    repo/file_Z.imp

“这两个修改”位听起来很奇怪,因为这只是一个选择的结果。 另外值得一提的是,如果我看一下“冲突”,可以归结为一行,其中一个版本以[tab]字符开始,另一个版本以四个空格开始。 这听起来像是我设置我的配置文件可能是一个问题,但它没有任何类型的。 (我注意到core.ignorecase设置为true,但显然git-clone会自动做到这一点。我并不完全意识到,原来的源代码是在Windows机器上。)

如果我手动修复file_X.cpp,那么随后会发生另一个冲突,这次是一个文件(CMakeLists.txt),一个版本认为应该存在,一个版本认为不应该。 如果我通过说我确实想要这个文件(我这么做)来解决这个冲突,稍后的一些提交,我会得到另一个冲突(在同一个文件中),现在有一些相当不重要的更改。 它仍然只有通过冲突的25%。

我也应该指出,因为这可能是非常重要的,这个项目开始在一个svn仓库。 该初始历史很可能是从该svn存储库导入的。

更新#2:

在云雀(受Jefromi的评论影响),我决定做我的repo_squash.sh更改为:

rm -rf repo_squash
git clone repo repo_squash
cd repo_squash/
git rebase --strategy theirs -i bd6a09a484b8230d0810e6689cf08a24f26f287a

然后,我只是接受原始条目。 也就是说,“rebase”不应该改变一件事情。 它以前面描述的相同结果结束。

更新#3:

或者,如果我省略策略并将最后一个命令替换为:

git rebase -i bd6a09a484b8230d0810e6689cf08a24f26f287a

我不再得到“没有什么可承诺”的重组问题,但我仍然留下了其他冲突。

玩具资料库更新,重现问题:

test_squash.sh(这是你实际运行的文件):

#========================================================
# Initialize directories
#========================================================
rm -rf test_squash/ test_squash_clone/
mkdir -p test_squash
mkdir -p test_squash_clone
#========================================================

#========================================================
# Create repository with history
#========================================================
cd test_squash/
git init
echo "README">README
git add README
git commit -m"Initial commit: can't easily access for rebasing"
echo "Line 1">test_file.txt
git add test_file.txt
git commit -m"Created single line file"
echo "Line 2">>test_file.txt 
git add test_file.txt 
git commit -m"Meant for it to be two lines"
git checkout -b dev
echo Meaningful code>new_file.txt
git add new_file.txt 
git commit -m"Meaningful commit"
git checkout master
echo Conflicting meaningful code>new_file.txt
git add new_file.txt 
git commit -m"Conflicting meaningful commit"
# This will conflict
git merge dev
# Fixes conflict
echo Merged meaningful code>new_file.txt
git add new_file.txt
git commit -m"Merged dev with master"
cd ..

#========================================================
# Save off a clone of the repository prior to squashing
#========================================================
git clone test_squash test_squash_clone
#========================================================

#========================================================
# Do the squash
#========================================================
cd test_squash
GIT_EDITOR=../test_squash_helper.sh git rebase -i [email protected]{7}
#========================================================

#========================================================
# Show the results
#========================================================
git log
git gc
git reflog
#========================================================

test_squash_helper.sh(由test_sqash.sh使用):

# If the file has the phrase "pick " in it, assume it's the log file
if grep -q "pick " $1
then
  sed -e "s/pick \(.*\) \(Meant for it to be two lines\)/squash \1 \2/g" < $1 > $1.tmp
  mv $1.tmp $1
# Else, assume it's the commit message file
else
# Use our pre-canned message
  echo "Created two line file" > $1
fi

PS:是的,当我看到使用emacs作为后退编辑器时,我知道你们中有些人会畏缩。

PPS:我们确实知道在重新绑定之后,我们必须将现有存储库中的所有克隆都删除。 (沿着“你不应该在版本发布后重新定义版本库”)。

PPPS:任何人都可以告诉我如何为此添加赏金? 无论我处于编辑模式还是查看模式,我都无法在此屏幕上的任何位置看到该选项。


如果你不介意创建一个新的分支,这是我处理这个问题的方法:

作为主人:

# create a new branch
git checkout -b new_clean_branch

# apply all changes
git merge original_messy_branch

# forget the commits but have the changes staged for commit
git reset --soft master        

git commit -m "Squashed changes from original_messy_branch"

我遇到了一个更简单但相似的问题,我在这里解决了一个本地分支上的合并冲突,2)继续工作,增加了更多的小提交,3)想要重新分配,并发生合并冲突。

对我来说, git rebase -p -i master工作。 它保持了最初的冲突解决方案提交,并允许我挤压其他人。

希望能帮助别人!


请注意, -X和策略选项在交互式底座中使用时被忽略。

请参阅提交db2b3b820e2b28da268cc88adff076b396392dfe (2013年7月,git 1.8.4+),

不要忽略交互式转化中的合并选项

合并策略及其选项可以在git rebase指定,但是-- interactive ,它们完全被忽略。

签名:Arnaud Fontaine

这意味着-X和策略现在可以与互动式底图以及普通底图一起使用,而且现在您的初始脚本可以更好地工作。





git-checkout