首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么git-rebase给我合并冲突,而我所做的只是压缩提交?

为什么git-rebase给我合并冲突,而我所做的只是压缩提交?
EN

Stack Overflow用户
提问于 2010-06-28 14:54:13
回答 6查看 68.1K关注 0票数 204

我们有一个具有400多个提交的Git存储库,其中最初的几十个是大量的尝试和错误。我们希望通过将多个提交压缩为单个提交来清除这些提交。很自然,重设基地似乎是可行的。我的问题是,它以合并冲突告终,而这些冲突并不容易解决。我不明白为什么会有任何冲突,因为我只是压缩提交(而不是删除或重新安排)。很有可能,这说明我并不完全理解git-rebase是如何进行压缩的。

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

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

代码语言:javascript
复制
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使用):

代码语言:javascript
复制
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使用)

代码语言:javascript
复制
# 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

我会把“新信息”的内容留给你的想象。最初,我没有使用“--策略他们的”选项(即使用默认策略,如果我正确理解文档是递归的,但我不确定使用了哪种递归策略),它也不起作用。另外,我应该指出,使用repo_squash_helper.sh中的注释掉的代码,我保存了sed脚本工作的原始文件,并对它运行sed脚本,以确保它正在执行我希望它做的事情(它确实如此)。再说一次,我甚至不知道为什么会发生冲突,所以使用什么样的策略似乎无关紧要。任何建议或洞察力都是有帮助的,但大多数情况下,我只想让这个压扁的发挥作用。

经与杰弗罗米讨论后的补充资料更新:

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

当它失败时,我得到的信息是:

代码语言:javascript
复制
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,在再提交几次之后,我会得到一条非常类似的消息。如果我再这样做,在几十次提交之后,我会得到另一条非常类似的消息。如果我再次这样做,这一次它将经历大约100次提交,并产生以下消息:

代码语言:javascript
复制
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,就会得到:

代码语言:javascript
复制
# 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

对我来说,“两次修改”听起来都很奇怪,因为这只是一个选择的结果。值得注意的是,如果我看一下“冲突”,它归结为一行,其中一个版本以制表符字符开头,另一个以四个空格开头。这听起来可能是一个问题,我如何设置我的配置文件,但没有这类东西在其中。(我确实注意到core.ignorecase被设置为真,但显然git-克隆自动做到了这一点。考虑到最初的源代码在Windows机器上,我并不完全感到惊讶。)

如果我手动修复了file_X.cpp,那么它很快就会在另一个冲突中失败,这一次是一个版本认为应该存在的文件(CMakeLists.txt)与一个版本认为不应该存在的文件(CMakeLists.txt)之间的冲突。如果我通过说我想要这个文件来解决这个冲突(我确实需要),几次提交之后,我会得到另一个冲突(在同一个文件中),其中现在有一些相当重要的更改。它仍然只有大约25%的道路上的冲突。

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

更新2:

在百灵鸟(受杰弗罗米的评论影响)上,我决定将我的repo_squash.sh修改为:

代码语言:javascript
复制
rm -rf repo_squash
git clone repo repo_squash
cd repo_squash/
git rebase --strategy theirs -i bd6a09a484b8230d0810e6689cf08a24f26f287a

然后,我接受了原来的参赛作品。也就是说,“重新定位”不应该改变任何事情。其结果与前面描述的结果相同。

更新3:

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

代码语言:javascript
复制
git rebase -i bd6a09a484b8230d0810e6689cf08a24f26f287a

我不再得到“无事可做”的重新定位问题,但我仍然与其他冲突。

使用重新创建问题的玩具存储库进行更新:

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

代码语言:javascript
复制
#========================================================
# 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 HEAD@{7}
#========================================================

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

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

代码语言:javascript
复制
# 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

是的,我知道你们中的一些人看到我用emacs做退步编辑时会有些畏缩。

P.P.S.:我们确实知道,在重新基地之后,我们必须把现有存储库的所有克隆都吹走。(按照“发布后不得重新建立存储库”的思路。)

记者:有人能告诉我如何在这上面增加奖金吗?无论是在编辑模式还是视图模式,我都不会在此屏幕上看到该选项。

EN

回答 6

Stack Overflow用户

发布于 2017-06-27 20:29:15

如果您不介意创建一个新分支,那么我就是这样处理这个问题的:

主要:

代码语言:javascript
复制
# 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 main        

git commit -m "Squashed changes from original_messy_branch"
票数 136
EN

Stack Overflow用户

发布于 2015-09-06 06:40:34

我正在寻找一个类似的需求,即放弃我的开发分支的intermeiate提交,我发现这个过程对我是有效的。

在我的工作分支上

代码语言:javascript
复制
git reset –hard mybranch-start-commit
git checkout mybranch-end-commit . // files only of the latest commit
git add -a
git commit -m”New Message intermediate commits discarded”

中提琴,我们连接了最新的承诺,开始提交的分支!没有合并冲突的问题!在我的学习实践中,我得出了这样的结论,在现阶段,是否有更好的方法来达到这个目的。

票数 6
EN

Stack Overflow用户

发布于 2021-02-16 23:01:46

如果您想要在一个长的提交分支(其中一些是合并提交)中创建一个提交,最简单的方法是将您的分支重置到第一次提交之前的点,同时保留您的所有更改,然后重新建议它们:

代码语言:javascript
复制
git reset $(git merge-base origin/master @)
git add .
git commit

origin/master替换为分支的名称。

add .是必要的,因为新添加的文件在重置后显示为未跟踪的文件。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3133449

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档