git merge:删除我想保留的文件!

发布于 2024-08-04 08:29:59 字数 1151 浏览 6 评论 0原文

如何在 git 中合并两个分支,并保留分支中的必要文件?

合并两个分支时,如果一个文件在一个分支中被删除,而在另一个分支中没有被删除,则该文件最终将被删除。

例如:

  • 当您创建一个新分支时,master 中存在一个文件,
  • 您从 master 中删除该文件,因为我们还不需要它,
  • 您在分支中进行更改以添加一个功能,这依赖于现有的文件
  • 你在 master 中修复了错误(不能丢弃)
  • 你有一天合并,文件就消失了!

如何重现:

  1. 使用一个文件创建一个 git 存储库。

    <前><代码>git init 回显“测试”>测试.txt git 添加 . git commit -m“初始提交”
  2. 创建分支

    git分支branchA
    
  3. 删除master中的文件

    git rm test.txt
    git commit -m“从主控中删除了文件”
    
  4. 在branchA中进行任何不触及已删除文件的更改(必须保持不变以避免冲突)

    git checkout 分支A
    触摸某物.txt
    git 添加 .
    git commit -m“一些分支更改”
    

从这里开始,我发现合并这两个分支的任何方法,test.txt文件被删除。假设我们branchA依赖该文件,这是一个大问题。


失败示例:

合并 1

git checkout branchA
git merge master
ls test.txt

合并 2

git checkout master
git merge branchA
ls test.txt

重新设置基准 1

git checkout branchA
git rebase master
ls test.txt

How can you merge two branches in git, retaining necessary files from a branch?

When merging two branches, if a file was deleted in one branch and not in another, the file is ultimately deleted.

For example:

  • A file exists in master when you make a new branch
  • you remove the file from master since we don't need it (yet)
  • you make changes in the branch to add a feature, which relies on the file existing
  • you make bug fixes in master (cannot be discarded)
  • you merge some day, and the file is gone!

How to Reproduce:

  1. Create a git repo with one file.

    git init
    echo "test" > test.txt
    git add .
    git commit -m "initial commit"
    
  2. Create a branch

    git branch branchA
    
  3. Delete the file in master

    git rm test.txt
    git commit -m "removed file from master"
    
  4. Make ANY changes in branchA that don't touch the deleted file (it has to be unchanged to avoid Conflict)

    git checkout branchA
    touch something.txt
    git add .
    git commit -m "some branch changes"
    

From here, any way I've found to merge these two branches, the test.txt file is deleted. Assuming we were relying on the file for branchA, this is a big problem.


Failing examples:

Merge 1

git checkout branchA
git merge master
ls test.txt

Merge 2

git checkout master
git merge branchA
ls test.txt

Rebase 1

git checkout branchA
git rebase master
ls test.txt

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

月下伊人醉 2024-08-11 08:29:59

这是一个有趣的问题。因为您在创建 BranchA 之后删除了该文件,然后将 master 合并到 BranchA 中,所以我不确定 Git 如何能够意识到存在冲突。

错误合并后,您可以撤消,然后重新合并,但添加回文件:

git checkout HEAD@{1} .
git merge --no-commit master
git checkout master test.txt
git add test.txt
git commit

This is an interesting issue. Because you deleted the file after BranchA was created, and then are merging master into BranchA, I'm not sure how Git would be able to realize there is a conflict.

After the bad merge you can undo, and then re-merge, but add back the file:

git checkout HEAD@{1} .
git merge --no-commit master
git checkout master test.txt
git add test.txt
git commit
昇り龍 2024-08-11 08:29:59

Casey 的示例不适用于我的案例 - 我无法从 master 中签出 test.txt,因为它不再位于该分支:

$ git checkout master test.txt
error: pathspec 'test.txt' did not match any file(s) known to git.

很高兴我可以从 branchA 自己的 HEAD 中提取文件:

$ git checkout branchA
$ git merge --no-commit master
$ git checkout HEAD test.txt
$ git add test.txt
$ git commit

Casey's example didn't work for my case - I couldn't checkout test.txt from master, because it was no longer in that branch:

$ git checkout master test.txt
error: pathspec 'test.txt' did not match any file(s) known to git.

Happily I could pull the file out of branchA's own HEAD:

$ git checkout branchA
$ git merge --no-commit master
$ git checkout HEAD test.txt
$ git add test.txt
$ git commit
铁憨憨 2024-08-11 08:29:59

在这种情况下,为了快速修复,请“git revert”删除该文件的提交。

当将来出现这种情况时,更好的处理方法是确保新文件的创建发生在分支上。然后,当您合并时,它会添加到 master 上,但同时您没有该文件位于 master 中。

For a quick fix in this case, "git revert" the commit that deleted the file.

When this situation comes up in the future, the better way to handle it is to ensure that the creation of the new file happens on the branch. Then it gets added on master when you merge, but you don't have the file lying around in master in the meantime.

霓裳挽歌倾城醉 2024-08-11 08:29:59

我的解决方案是简单地修改我需要保留的文件(添加无论如何都需要的注释)并在目标分支上提交这些更改,从而生成合并冲突,可以使用 git add 轻松解决/code> 和正常提交。

我的历史是这样的。为了保护无辜者,分支名称已更改。

  1. 创建并提交要掌握的新功能的文件,
  2. 意识到这一添加将比最初计划的更复杂,因此,分支到 feature_branch
  3. 从 master 中删除文件,以免破坏 RB 的正常工作流程,这样的
  4. 时间流逝,master 上的更多提交, none on feature_branch
  5. 恢复该功能的工作,git merge master on feature_branch 导致原始文件被删除(当然),git reset --hard 到合并之前
  6. 应用了上述解决方案

My solution to this was to simply modify the files I needed to keep (added a comment which was needed anyway) and commit those changes on the target branch, thus generating a merge conflict which could easily be resolved with a git add and a normal commit.

My history went something like this. Branch names have been changed to protect the innocent.

  1. create and commit files for a new feature to master
  2. realize this addition going to be more involved than originally planned, thus, branched to feature_branch
  3. Removed files from master so as not to disrupt normal workflow with RBs and such
  4. Time passes, more commits on master, none on feature_branch
  5. Resume work on the feature, git merge master on feature_branch causes original files to be removed (of course), git reset --hard to before the merge
  6. Applied the solution described above
哥,最终变帅啦 2024-08-11 08:29:59

需要修改branch中的文件,以免与trunk中的delete发生合并冲突。

例如,如果您删除主干中头文件中某些内容的声明(因为没有任何东西需要它),并将对该声明的依赖项添加到分支中的某些非头文件中,则会发生完全相同的事情。当您合并时,由于分支不会触及标题(的那部分),因此它只会删除声明,并且事情将会中断。

每当您在多个地方拥有相互依赖且需要保持同步的内容时,合并就很容易默默地引入问题。这只是合并时必须了解和检查的事情之一。理想情况下,您使用编译时断言或其他构建时检查,这将使任何故障立即显现出来。

You need to modify the file in the branch, so that there's a merge conflict with the delete in the trunk.

The exact same thing will happen if you, for example, delete a declaration for something in a headerfile in the trunk (because nothing needs it), and add a dependency on that declaration to some non-header file(s) in the branch. When you merge, since the branch doesn't touch (that part of) the header, it will just delete the declaration and things will break.

Whenever you have stuff in multiple places that is interdependent and needs to be kept in sync, its very easy for a merge to silently introduce problems. Its just one of the things you have to know about and check when merging. Ideally, you use compile-time asserts or other build time checks that will make any failures immediately apparent.

娇柔作态 2024-08-11 08:29:59

git 也有同样的问题。当时正在分支机构开发一项功能,然后我的工作决定暂时搁置该功能以供稍后使用。因此,相关的功能文件已从 master 分支中删除,以允许应用程序部署时没有不必要的文件......暂时。现在我的工作需要我完成旧功能,当我尝试将旧分支合并或变基到当前主分支时,它会删除我需要的文件。

快速的解决方案是:修改需要保留在功能分支中的文件,添加并提交,然后与主分支合并。现在,这将导致合并冲突,而不是合并时的删除模式。现在您可以保留“我们的”对文件的更改。

问题是 git 将 HEAD 中的文件删除视为未更改,并将默认进入删除模式。具体来说:修改你需要的文件后,会输出deleted in master and modded in HEAD

重现解决方案:

  1. 将分支重置为已删除文件的旧版本:git reset --hard origin/old_branch
  2. 修改需要保留的文件。不要让它们保持不变。
  3. 将当前的 master 合并到功能分支中:git merge master

自动合并失败;修复冲突,然后提交结果。

  1. 解决冲突时保留“我们的”更改。
  2. git add .git commit -m "fix业已删除的 HEAD"
  3. 完成合并:git merge master

Same issue with git. Was working on a feature in a branch, then my job decided to sideline the feature for later. Thus the relevant feature files were deleted from master branch to allow app deployment without unnecessary files ... for the time being. Now my job needs me to finish the old feature and when I try to merge or rebase the old branch into the current master it deletes the files I need.

The quick solution is: Modify the files you need to keep in your feature branch, add and commit, and then merge with your master. This will now cause a merge conflict as opposed to deletion mode when merging. Now you can keep "our" changes to the files.

The problem is git sees the file deletion in HEAD as not being changed and will default into deletion mode. Specifically: deleted in master and modified in HEAD is outputted after you modify the files you need.

Reproduce the solution:

  1. Reset a branch to the older version with deleted files: git reset --hard origin/old_branch
  2. Modify the files you need to keep. Do not leave them the same.
  3. Merge your current master into the feature branch: git merge master

Automatic merge failed; fix conflicts and then commit the result.

  1. Keep "our" changes when fixing conflicts.
  2. git add . and git commit -m "fix deleted HEAD"
  3. Finish merging: git merge master
仅此而已 2024-08-11 08:29:59

您可以在提交到当前合并分支之前签出文件,而不是反转合并(用户 Todd 的建议在 Alex Dean 解决方案上方的评论部分):

  git checkout; -- path/to/file

例如,

  git checkout 08ac9cf08f --classify.cpp

然后您可以推送您的分支。

Instead reversing merging, you could checkout file(s) from just before commit into your current merged branch (user Todd's suggestion at the comment section above Alex Dean's solution):

  git checkout <commit hash or branch name> -- path/to/file

For example,

  git checkout 08ac9cf08f -- classify.cpp

and then you could push your branch.

魂归处 2024-08-11 08:29:59

所以,我找到了另一个解决方案,我已经测试过它并且它有效:

  1. git log master..feature/; --oneline --reverse 列出错误分支的所有提交,因为它是从 master 创建的(注意:--reverse 将为您提供旧提交的列表,到底部最新的)
  2. git show --name-only 列出您使用之前的命令获得的每个提交修改的所有文件
  3. 获取每个提交的最近提交文件(我在文本文件上手动完成)
  4. 从 master 创建一个新分支并切换到其中。
  5. git checkout; -- 手动将每个文件添加到新分支
  6. 提交并推送

这肯定类似于“逐个手动添加文件”,但如果您想确保较旧的提交不会优先于新分支掌握情况,就是这样。
顺便说一句,它肯定可以编写脚本。

So, I've found another solution, which I've tested and it works:

  1. git log master..feature/<branch> --oneline --reverse List all commits of the bad branch, since it was created from master (NOTE: --reverse will give you a list from the older commit, to the newest at the bottom)
  2. git show --name-only <hash> List all files modified by every commit you obtained with the command before
  3. Take the most RECENT commit, of each file (I did it manually on a text file).
  4. Create a new branch from master and switch into it.
  5. git checkout <most_recent_commit_hash> -- <file_path> Add manually each file to the new branch
  6. Commit and push

This is for sure like "adding manually files one by one" but if you want to be sure that older commits don't prevail to the master situation, this is the way to go.
BTW, It could for sure be scripted.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文