git - git - 如何仅合并特定文件
问题描述
我有三个提交 ID commit1
,commit2
和commit3
.
commit3
是我们 repo 中的一个提交,而另外两个是上游的提交——一个commit1
是旧的稳定版本,commit2
一个是新的稳定版本。
我正在尝试获取自旧的稳定上游合并以来我们更改的文件列表,然后将这些文件合并到新的稳定版本(commit2
)。
第一部分很简单,git diff --name-only
不包括我们从未接触过的文件夹列表;假设我得到了 100 个文件的列表。
现在我将我们的提交合并到新版本 - 合并commit3
到commit2
. 此时有 1000 个文件受此合并影响,但我知道它应该只有 100 个文件,因此,理论上,我可以还原不在我获得的 100 个文件的初始列表中的文件的更改git diff
。
重置它们的最佳方法是什么?我可以运行git ls-files
以获取 repo 中的所有文件,然后遍历此列表,检查该文件是否不在先前检索到的 100 个受影响文件的列表中,并且git reset --hard -- <filespec>
.
我也试过了git checkout commit2 <filespec>
。在这两种情况下,我都以某种方式留下了 500 个受影响的文件,但我希望只有 100 个或更少的文件。我做错了什么?丢弃合并对除 100 之外的所有文件所做的任何更改的正确方法是什么?
EDIT001:添加一些代码来展示我如何尝试解决上述问题可能是个好主意
#!/usr/bin/env python3
import os
import subprocess
import sys
def execute_git_command(*args):
arguments = ['git']
for arg in args:
arguments.append(arg)
git_command = subprocess.Popen(arguments, stdout=PIPE, stderr=PIPE)
git_stdout, git_stderr = git_command.communicate()
if git_command.returncode != 0:
sys.stderr.write(
'Git command "{0}" failed with code {2}. Reason: {1}'.format(' '.join(arguments), git_stderr.decode(),
git_command.returncode))
exit()
return git_stdout.decode()
def just_execute_git_command(*args):
arguments = ['git']
for arg in args:
arguments.append(arg)
git_command = subprocess.Popen(arguments, stdout=PIPE, stderr=PIPE)
git_stdout, git_stderr = git_command.communicate()
return git_stdout.decode()
if len(sys.argv) != 4:
print("Usage: {0} previous_upstream_commit new_upstream_commit our_commit_for_merge".format(sys.argv[0]))
exit()
old_upstream_commit = sys.argv[1]
new_upstream_commit = sys.argv[2]
our_commit_to_merge = sys.argv[3]
PIPE = subprocess.PIPE
print("Trying to merge commit id {0} to {1}".format(our_commit_to_merge, new_upstream_commit))
changed_by_us = execute_git_command('diff',
'--name-only',
old_upstream_commit + ".." + our_commit_to_merge,
'--',
'./',
':(exclude)./some/folders/to/exclude/*')
affected_files = set()
for line in changed_by_us.splitlines():
affected_files.add(line)
print("{0} files affected by our changes".format(len(affected_files)))
print("Checkingout commit id " + new_upstream_commit)
execute_git_command('checkout', new_upstream_commit)
execute_git_command('submodule', 'sync', '--recursive')
execute_git_command('submodule', 'update', '--init', '--recursive')
print("Creating new branch for it upstream_merge_" + new_upstream_commit)
just_execute_git_command('checkout', '-b', "upstream_merge_" + new_upstream_commit)
just_execute_git_command('merge', our_commit_to_merge)
gitBranch = execute_git_command('branch', '--show-current')
print("Commit {0} merged to branch {1}".format(our_commit_to_merge, gitBranch))
mergeAffectedFiles = execute_git_command('ls-files')
if len(mergeAffectedFiles.splitlines()) > 0:
print("Will checkout files not affected by ours changes in upstream favor")
for full_path in mergeAffectedFiles.splitlines():
# print(conflictingFile)
# full_path = conflictingFile
# filename = os.path.basename(full_path)
if full_path not in affected_files:
just_execute_git_command('reset', '--hard', '--', full_path)
mergeAffectedFiles = execute_git_command('ls-files', '--unmerged')
print("{0} conflicting files left for manual resolution.".format(len(mergeAffectedFiles.splitlines())))
免责声明,我不熟悉python :)
EDIT002:再想一想,如果我对所有这 100 个文件进行虚假提交,然后将其挑选到新的稳定版本 (commit2) 会怎样。技术上可行吗?
解决方案
一种可能性是:从commit3
,构建一个新分支,其中只包含您想要集成到的更改commit2
。
该建议与@LasseVKarlsen 的评论方向相同:
你没有合并文件,这是合并分支的副产品,你正在合并分支。
这是一种使用要合并的内容构建分支并合并该分支的方法。
该分支将commit2
在同一点分叉commit3
:git merge-base commit2 commit3
以下是如何执行此操作的概述:
# 1. from commit3, create a branch 'wip3' :
git checkout -b wip3 commit3
# 2. reset that branch to the merge base :
git reset --soft $(git merge-base commit2 commit3)
# now all modifications are stored in the index :
# 3. discard all the modifications you do not want to keep
# by hand :
git reset that/directory
git reset that/other/directory
git reset that/file
...
# or using the list you got from `git diff commit1 commit3` :
git diff --cached --name-only | grep -v -f filelist.txt | xargs git reset
# 4. create a commit on branch wip3 :
git commit
# 5. you can now merge wip3 into commit2 :
git checkout commit2
git merge wip3
注意3. 4.
:您可以多次运行步骤:在分支上wip3
时,您始终可以恢复或重新应用对某些文件的修改和commit --amend
.
推荐阅读
- python-3.x - 在不到 1 秒的时间内计算出大数的算术序列的总结果
- python - 允许用户在 DJango 中拥有他们的产品
- excel - 当值为零时隐藏列中的单元格
- sql - 翻译 unix 风格的按位整数的 Oracle 查询
- css - 如何使用 React 和 Material io 修复 Ipad 或移动设备上的焦点背景颜色
- string - 如何根据给定的要求拆分/标记字符串?
- reactjs - React Lifting State Up - 为什么在父级重新渲染时不调用子级的构造函数?
- c++ - 我在 Linux VSCode (gcc) 和 Windows Clion (visual c++) 上的相同代码有不同的输出
- html - 响应方块的动态网格:
- ios - 如何在 url 加载时显示图像