如何仅选择对某些文件的更改?

发布于 2024-11-02 06:57:02 字数 309 浏览 4 评论 0原文

如果我想将仅对特定提交中更改的某些文件所做的更改合并到 Git 分支中,其中包括对多个文件的更改,如何实现?

假设名为 stuff 的 Git 提交对文件 ABCD< /code> 但我只想合并 stuff 对文件 AB 的更改。这听起来像是 gitcherry-pick 的工作,但 cherry-pick 只知道如何合并整个提交,而不是文件的子集。

If I want to merge into a Git branch the changes made only to some of the files changed in a particular commit which includes changes to multiple files, how can this be achieved?

Suppose the Git commit called stuff has changes to files A, B, C, and D but I want to merge only stuff's changes to files A and B. It sounds like a job for git cherry-pick but cherry-pick only knows how to merge entire commits, not a subset of the files.

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

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

发布评论

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

评论(15

平生欢 2024-11-09 06:57:02

我会使用cherry-pick -n(--no-commit)来完成它,它可以让您在提交之前检查(和修改)结果:

git cherry-pick -n <commit>

# unstage modifications you don't want to keep, and remove the
# modifications from the work tree as well.
# this does work recursively!
git checkout HEAD <path>

# commit; the message will have been stored for you by cherry-pick
git commit

如果绝大多数修改是您不想要的,您可以将所有内容重置回来,而不是检查各个路径(中间步骤),然后添加您想要的内容:

# unstage everything
git reset HEAD

# stage the modifications you do want
git add <path>

# make the work tree match the index
# (do this from the top level of the repo)
git checkout .

I'd do it with cherry-pick -n (--no-commit) which lets you inspect (and modify) the result before committing:

git cherry-pick -n <commit>

# unstage modifications you don't want to keep, and remove the
# modifications from the work tree as well.
# this does work recursively!
git checkout HEAD <path>

# commit; the message will have been stored for you by cherry-pick
git commit

If the vast majority of modifications are things you don't want, instead of checking out individual paths (the middle step), you could reset everything back, then add in what you want:

# unstage everything
git reset HEAD

# stage the modifications you do want
git add <path>

# make the work tree match the index
# (do this from the top level of the repo)
git checkout .
爱的故事 2024-11-09 06:57:02

其他方法对我不起作用,因为提交有很多更改并且与许多其他文件发生冲突。我想出的只是

git show SHA -- file1.txt file2.txt | git apply -

它实际上并没有添加文件或为您进行提交,因此您可能需要跟进

git add file1.txt file2.txt
git commit -c SHA

或者如果您想跳过添加,您可以使用 < code>--cached 参数到 git apply

git show SHA -- file1.txt file2.txt | git apply --cached -

您也可以对整个目录执行相同的操作

git show SHA -- dir1 dir2 | git apply -

The other methods didn't work for me since the commit had a lot of changes and conflicts to a lot of other files. What I came up with was simply

git show SHA -- file1.txt file2.txt | git apply -

It doesn't actually add the files or do a commit for you so you may need to follow it up with

git add file1.txt file2.txt
git commit -c SHA

Or if you want to skip the add you can use the --cached argument to git apply

git show SHA -- file1.txt file2.txt | git apply --cached -

You can also do the same thing for entire directories

git show SHA -- dir1 dir2 | git apply -
や莫失莫忘 2024-11-09 06:57:02

我通常将 -p 标志与来自其他分支的 git checkout 一起使用,我发现这比我遇到的大多数其他方法更容易、更精细。

原则上:

git checkout <other_branch_name> <files/to/grab in/list/separated/by/spaces> -p

示例:

git checkout mybranch config/important.yml app/models/important.rb -p

然后您会看到一个对话框,询问您想要在“blob”中进行哪些更改,这几乎适用于您可以进行的连续代码更改的每个块每个代码块的信号y(是)n(否)等。

-ppatch 选项适用于 git 中的各种命令,包括 git stash save -p ,它允许您选择您想要的内容 当我做了很多工作

并且想将其分离出来并使用 git add -p 提交更多基于主题的提交并选择我想要的内容时,我有时会使用这种技术每次提交:)

I usually use the -p flag with a git checkout from the other branch which I find easier and more granular than most other methods I have come across.

In principle:

git checkout <other_branch_name> <files/to/grab in/list/separated/by/spaces> -p

example:

git checkout mybranch config/important.yml app/models/important.rb -p

You then get a dialog asking you which changes you want in "blobs" this pretty much works out to every chunk of continuous code change which you can then signal y (Yes) n (No) etc for each chunk of code.

The -p or patch option works for a variety of commands in git including git stash save -p which allows you to choose what you want to stash from your current work

I sometimes use this technique when I have done a lot of work and would like to separate it out and commit in more topic based commits using git add -p and choosing what I want for each commit :)

葬﹪忆之殇 2024-11-09 06:57:02

情况:

您在自己的分支上,比如说master,并且您在任何其他分支上都有提交。您必须从该特定提交中仅选择一个文件。

方法:

第1步:在所需分支上结帐。

git checkout master

第 2 步:确保您已复制所需的提交哈希。

git checkout commit_hash path\to\file

第 3 步: 现在,您已在所需分支上对所需文件进行了更改。您只需要添加并提交它们。

git add path\to\file
git commit -m "Your commit message"

The situation:

You are on your branch, let's say master and you have your commit on any other branch. You have to pick only one file from that particular commit.

The approach:

Step 1: Checkout on the required branch.

git checkout master

Step 2: Make sure you have copied the required commit hash.

git checkout commit_hash path\to\file

Step 3: You now have the changes of the required file on your desired branch. You just need to add and commit them.

git add path\to\file
git commit -m "Your commit message"
一腔孤↑勇 2024-11-09 06:57:02

也许这种方法相对于 Jefromi 的优势答案是你不必记住git重置的行为是正确的:)

 # Create a branch to throw away, on which we'll do the cherry-pick:
 git checkout -b to-discard

 # Do the cherry-pick:
 git cherry-pick stuff

 # Switch back to the branch you were previously on:
 git checkout -

 # Update the working tree and the index with the versions of A and B
 # from the to-discard branch:
 git checkout to-discard -- A B

 # Commit those changes:
 git commit -m "Cherry-picked changes to A and B from [stuff]"

 # Delete the temporary branch:
 git branch -D to-discard

Perhaps the advantage of this method over Jefromi's answer is that you don't have to remember which behaviour of git reset is the right one :)

 # Create a branch to throw away, on which we'll do the cherry-pick:
 git checkout -b to-discard

 # Do the cherry-pick:
 git cherry-pick stuff

 # Switch back to the branch you were previously on:
 git checkout -

 # Update the working tree and the index with the versions of A and B
 # from the to-discard branch:
 git checkout to-discard -- A B

 # Commit those changes:
 git commit -m "Cherry-picked changes to A and B from [stuff]"

 # Delete the temporary branch:
 git branch -D to-discard
迟到的我 2024-11-09 06:57:02

Cherry pick 是从特定的“提交”中挑选更改。最简单的解决方案是选择某些文件的所有更改,方法是使用

 git checkout source_branch <paths>...

示例:

$ git branch
* master
  twitter_integration
$ git checkout twitter_integration app/models/avatar.rb db/migrate/20090223104419_create_avatars.rb test/unit/models/avatar_test.rb test/functional/models/avatar_test.rb
$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   new file:   app/models/avatar.rb
#   new file:   db/migrate/20090223104419_create_avatars.rb
#   new file:   test/functional/models/avatar_test.rb
#   new file:   test/unit/models/avatar_test.rb
#
$ git commit -m "'Merge' avatar code from 'twitter_integration' branch"
[master]: created 4d3e37b: "'Merge' avatar code from 'twitter_integration' branch"
4 files changed, 72 insertions(+), 0 deletions(-)
create mode 100644 app/models/avatar.rb
create mode 100644 db/migrate/20090223104419_create_avatars.rb
create mode 100644 test/functional/models/avatar_test.rb
create mode 100644 test/unit/models/avatar_test.rb

来源和完整解释http://jasonrudolph.com/blog /2009/02/25/git-tip-how-to-merge-specific-files-from-another-branch/

更新:

使用此方法,git 不会合并文件,它只会覆盖目标分支上所做的任何其他更改。您需要手动合并更改:

$ git diff HEAD 文件名

Cherry pick is to pick changes from a specific "commit". The simplest solution is to pick all changes of certain files is to use

 git checkout source_branch <paths>...

In example:

$ git branch
* master
  twitter_integration
$ git checkout twitter_integration app/models/avatar.rb db/migrate/20090223104419_create_avatars.rb test/unit/models/avatar_test.rb test/functional/models/avatar_test.rb
$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   new file:   app/models/avatar.rb
#   new file:   db/migrate/20090223104419_create_avatars.rb
#   new file:   test/functional/models/avatar_test.rb
#   new file:   test/unit/models/avatar_test.rb
#
$ git commit -m "'Merge' avatar code from 'twitter_integration' branch"
[master]: created 4d3e37b: "'Merge' avatar code from 'twitter_integration' branch"
4 files changed, 72 insertions(+), 0 deletions(-)
create mode 100644 app/models/avatar.rb
create mode 100644 db/migrate/20090223104419_create_avatars.rb
create mode 100644 test/functional/models/avatar_test.rb
create mode 100644 test/unit/models/avatar_test.rb

Sources and full explanation http://jasonrudolph.com/blog/2009/02/25/git-tip-how-to-merge-specific-files-from-another-branch/

UPDATE:

With this method, git will not MERGE the file, it will just override any other change done on the destination branch. You will need to merge the changes manually:

$ git diff HEAD filename

红尘作伴 2024-11-09 06:57:02

为了完整起见,对我来说最有效的是:

git show YOURHASH --no-color -- file1.txt file2.txt dir3 dir4 | git apply -3 --index -

它完全符合OP的要求。它会在需要时解决冲突,与 merge 的做法类似。它会 git add 但不会 git commit 您的新更改,因此请检查您的 git status

For the sake of completness, what works best for me is:

git show YOURHASH --no-color -- file1.txt file2.txt dir3 dir4 | git apply -3 --index -

It does exactly what OP wants. It does conflict resolution when needed, similarly how merge does it. It does git add but not git commit your new changes, so check your git status.

有时,使用签出从提交中获取特定文件可能会更容易。在我看来,它给了你更多的控制权。

我会这样做:

git checkout <branch|hash> -- path/to/file1 path/to/filen

然后取消必要的更改以适应代码并在提交之前对其进行测试。如果一切按预期进行,则提交。

Sometimes it could be easier to use checkout to bring specific files from a commit. In my opinion it gives you more control.

I would do it like this:

git checkout <branch|hash> -- path/to/file1 path/to/filen

Then unstage the necessary changes to adapt the code and test it before do commit. If everything works as expected, then commit.

朕就是辣么酷 2024-11-09 06:57:02

我会挑选所有内容,然后执行以下操作:

git reset --soft HEAD^

然后我会恢复我不想要的更改,然后进行新的提交。

I would just cherry-pick everything, then do this:

git reset --soft HEAD^

Then I would revert the changes I don't want, then make a new commit.

寄与心 2024-11-09 06:57:02

使用 git merge --squashbranch_name ,这将从其他分支获取所有更改,并为您准备提交。
现在删除所有不需要的更改并保留您想要的更改。并且 git 不会知道有合并。

Use git merge --squash branch_name this will get all changes from the other branch and will prepare a commit for you.
Now remove all unneeded changes and leave the one you want. And git will not know that there was a merge.

梦里°也失望 2024-11-09 06:57:02

我找到了另一种方法,可以防止在挑选时出现任何冲突的合并,在我看来,这种方法很容易记住和理解。由于您实际上不是在挑选提交,而是其中的一部分,因此您需要先将其拆分,然后创建一个适合您的需求的提交并挑选它。

首先从要拆分的提交创建一个分支并签出它:

$ git checkout COMMIT-TO-SPLIT-SHA -b temp

然后恢复以前的提交:

$ git reset HEAD~1

然后添加要挑选的文件/更改:

$ git add FILE

并提交它:

$ git commit -m "pick me"

记下提交哈希,我们将其称为 PICK-SHA 并继续回到你的主分支,master 例如强制签出:

$ git checkout -f master

并挑选提交:

$ git cherry-pick PICK-SHA

现在你可以删除临时分支:

$ git branch -d temp -f

I found another way which prevents any conflicting merge on cherry-picking which IMO is kind of easy to remember and understand. Since you are actually not cherry-picking a commit, but part of it, you need to split it first and then create a commit which will suit your needs and cherry-pick it.

First create a branch from the commit you want to split and checkout it:

$ git checkout COMMIT-TO-SPLIT-SHA -b temp

Then revert previous commit:

$ git reset HEAD~1

Then add the files/changes you want to cherry-pick:

$ git add FILE

and commit it:

$ git commit -m "pick me"

note the commit hash, let's call it PICK-SHA and go back to your main branch, master for example forcing the checkout:

$ git checkout -f master

and cherry-pick the commit:

$ git cherry-pick PICK-SHA

now you can delete the temp branch:

$ git branch -d temp -f
腻橙味 2024-11-09 06:57:02

您可以使用:

git diff <commit>^ <commit> -- <path> | git apply

符号 ^ 指定 的(第一个)父级。因此,此 diff 命令会选择提交 中对 所做的更改。

请注意,这还不会提交任何内容(如 gitcherry-pick 所做的那样)。所以如果你想要这样,你必须这样做:

git add <path>
git commit

You can use:

git diff <commit>^ <commit> -- <path> | git apply

The notation <commit>^ specifies the (first) parent of <commit>. Hence, this diff command picks the changes made to <path> in the commit <commit>.

Note that this won't commit anything yet (as git cherry-pick does). So if you want that, you'll have to do:

git add <path>
git commit
残龙傲雪 2024-11-09 06:57:02

将一个分支合并到新分支(squash)并删除不需要的文件:

git checkout master
git checkout -b <branch>
git merge --squash <source-branch-with-many-commits>
git reset HEAD <not-needed-file-1>
git checkout -- <not-needed-file-1>
git reset HEAD <not-needed-file-2>
git checkout -- <not-needed-file-2>
git commit

Merge a branch into new one (squash) and remove the files not needed:

git checkout master
git checkout -b <branch>
git merge --squash <source-branch-with-many-commits>
git reset HEAD <not-needed-file-1>
git checkout -- <not-needed-file-1>
git reset HEAD <not-needed-file-2>
git checkout -- <not-needed-file-2>
git commit
上课铃就是安魂曲 2024-11-09 06:57:02

自动化程度更高:

#!/usr/bin/env bash

filter_commit_to_files() {
    FILES="$1"
    SHA="$2"
    git show "$SHA" -- $FILES | git apply --index -
    git commit -c "$SHA"
}

示例用法:

filter_commit_to_files "file1.txt file2.txt" 07271c5e

我通过从这里复制并粘贴到我的 shell 中来定义它。您不需要此处文档

Automating a bit more:

#!/usr/bin/env bash

filter_commit_to_files() {
    FILES="$1"
    SHA="$2"
    git show "$SHA" -- $FILES | git apply --index -
    git commit -c "$SHA"
}

Example usage:

filter_commit_to_files "file1.txt file2.txt" 07271c5e

I define it via copy and paste from here right into my shell. You don't need a here document.

弄潮 2024-11-09 06:57:02

使用补丁标志签出

完成您所描述的内容的一种简单方法是通过签出 --patch。修改我在顶部提供的四个变量。该脚本执行以下操作:

  1. 克隆包含您的提交的分支(源分支)
  2. 签出您希望将文件移动到的分支(目标分支)
  3. 签出所需提交修订的源分支,提供补丁标志和文件的相对位置作为参数。
  4. 添加、提交、推送

这对我来说一直是最简单的方法。步骤#3确实创建了一个交互式shell,但是如果你想破坏目标,你可以默认选择整个事情。

source_branch=branch_with_file_you_want
destination_branch=file_go_here
rev=757c47d4
relative_file_path=structures/serializers/node.py
message="Patching a file from $source_branch to $destination_branch"

git clone https://github.com/yourepo/app.git -b $source_branch $source_branch
cd $source_branch
git checkout $destination_branch
git checkout $rev --patch $source_branch $relative_file_path
git add $relative_file_path
git commit -m "$message"
git push

如果您是远程 GitLab,则需要 MR,可以使用 git push -o merge_request.create

Checkout with Patch Flag

An easy way to accomplish what you are describing is through a checkout --patch. Modify the four variables I provided at the top. The script does the following:

  1. Clones the branch that contains your commit ( source branch )
  2. Checkout the branch you wish to move the file to ( target branch )
  3. Checkout the source branch at desired commit revision, supply the patch flag and relative location to the file as a parameter.
  4. Add, commit, push

This has always been the easiest method for me. Step #3 does create an interactive shell though, but you can default option the entire thing if you want to clobber the destination.

source_branch=branch_with_file_you_want
destination_branch=file_go_here
rev=757c47d4
relative_file_path=structures/serializers/node.py
message="Patching a file from $source_branch to $destination_branch"

git clone https://github.com/yourepo/app.git -b $source_branch $source_branch
cd $source_branch
git checkout $destination_branch
git checkout $rev --patch $source_branch $relative_file_path
git add $relative_file_path
git commit -m "$message"
git push

If you're remote is GitLab you can use git push -o merge_request.create if you need an MR

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