如何将本地未提交的更改合并到另一个 Git 分支中?

发布于 2024-07-13 08:59:12 字数 149 浏览 6 评论 0原文

我如何在 Git 中执行以下操作?

我当前的分支是branch1,我做了一些本地更改。 然而,我现在意识到我实际上打算将这些更改应用到branch2。 有没有办法应用/合并这些更改,以便它们成为branch2上的本地更改,而无需在branch1上提交它们?

How can I do the following in Git?

My current branch is branch1 and I have made some local changes. However, I now realize that I actually meant to be applying these changes to branch2. Is there a way to apply/merge these changes so that they become local changes on branch2 without committing them on branch1?

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

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

发布评论

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

评论(9

别挽留 2024-07-20 08:59:13

如果是关于已提交的更改,您应该看看 git-rebase,但正如 VonC 的评论中指出的那样,当您谈论本地更改时,git-stash 肯定是执行此操作的好方法。

If it were about committed changes, you should have a look at git-rebase, but as pointed out in comment by VonC, as you're talking about local changes, git-stash would certainly be the good way to do this.

就是爱搞怪 2024-07-20 08:59:13

以下是我遵循的步骤:

  • git clone {link}
  • cd {repofolder}

您可以检查状态以及您正在使用的分支:

  • git status
  • gitbranch
  • gitbranch -a

注意:如果您之前在本地存储库中进行了更改,请在此处查看移动到新分支,以下步骤应该仍然有效。

如果“git分支”显示master,并且您想创建+​​移动到另一个分支:

  • git checkout -b {branch name}

使用“git分支”再次检查分支
现在应该显示您位于新分支中。

现在添加、提交并推送:

  • git add 。
  • git commit -m“添加新分支”
  • git push origin {分支名称}

当我在移动到新的本地分支之前进行更改或在移动到新分支之后进行更改时,上述步骤对我来说都适用。
我希望它可以帮助遇到类似情况的人们。

These are the steps I follow:

  • git clone {link}
  • cd {repo folder}

You can check the status and which branch you are on using:

  • git status
  • git branch
  • git branch -a

Note: Here if you make changes in your local repo before moving to the new branch, the following steps should still work.

If "git branch" shows master, and you want to create+move to another branch:

  • git checkout -b {branch name}

Check branch again using "git branch"
It should now show that you are in the new branch.

Now add, commit and push:

  • git add .
  • git commit -m "added new branch"
  • git push origin {branch name}

The above steps work for me in both the situation when I have made changes before moving to the new local branch or making changes after moving to the new branch.
I hope it helps people running into similar situations.

骄兵必败 2024-07-20 08:59:13

如果未提交的更改是未跟踪跟踪更改的混合

什么是未跟踪更改?

当您创建例如新文件时。 例如,VSCode 在文件资源管理器中的文件旁边显示一个 U

什么是跟踪变更?

当您对之前提交到存储库的文件进行更改时(在之前的提交中)。

过程的快速解释

假设您位于分支 A 上,但您只想将对现有文件的更改提交到分支 A,而新创建的文件(未跟踪)应该是提交到新分支B。 可以通过一些技巧来使用隐藏,逐步解释。

将脚本添加到 .git/config

.git 文件夹内有一个 config 文件。 打开它,您将看到类似这样的内容:

[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
    ignorecase = true
    precomposeunicode = true
[remote "origin"]
    url = https://github.com/...
    fetch = +refs/heads/*:refs/remotes/origin/*
[branch "main"]
    remote = origin
    merge = refs/heads/main

将配置文件更改为:

[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
    ignorecase = true
    precomposeunicode = true
[alias]
    stash-untracked = "!f() {    \
                git stash;               \
                git stash -u;            \
                git stash pop stash@{1}; \
            }; f"
[remote "origin"]
    url = https://github.com/...
    fetch = +refs/heads/*:refs/remotes/origin/*
[branch "main"]
    remote = origin
    merge = refs/heads/main

现在,您将能够在分支 A 上使用以下命令。

git stash-untracked

您将看到新文件消失了,如果您正在使用像 VSCode 这样的编辑器(它现在已隐藏),

当仍在分支 A 阶段并将更改提交到现有文件时:

git add .
git commit -m "committing tracked changes to current branch"

下一步是创建一个新的分支 B(使用 checkout -b 您访问立即)

git checkout -b newBranchName

当使用 stash pop 时,隐藏的更改将添加到您当前的分支中。

git stash pop

剩下的唯一事情就是在新分支 B 上暂存并提交更改

git add .
git commit -m "created new file"

If the uncommitted changes are a mix of untracked and tracked changes

What are untracked changes?

When you created e.g a new file. VSCode e.g displays a U next to the file in the file explorer.

What are tracked changes?

When you make changes to files that were committed to the repo earlier (in previous commits).

Quick explanation of procedure

So imagine you are on branch A, but you want to commit only changes to existing files to branch A, while the newly created file (untracked) should be committed to a new branch B. It's possible to use stashing with a few tricks, explained step by step.

Add script to .git/config

Inside the .git folder there is a config file. Open it up and you will see something like this:

[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
    ignorecase = true
    precomposeunicode = true
[remote "origin"]
    url = https://github.com/...
    fetch = +refs/heads/*:refs/remotes/origin/*
[branch "main"]
    remote = origin
    merge = refs/heads/main

change the config file to:

[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
    ignorecase = true
    precomposeunicode = true
[alias]
    stash-untracked = "!f() {    \
                git stash;               \
                git stash -u;            \
                git stash pop stash@{1}; \
            }; f"
[remote "origin"]
    url = https://github.com/...
    fetch = +refs/heads/*:refs/remotes/origin/*
[branch "main"]
    remote = origin
    merge = refs/heads/main

Now you will be able to use the following command while you are on branch A.

git stash-untracked

You will see that the new file disappeared, if you are using a editor like VSCode (it's now stashed)

While still on branch A stage and commit the changes to the existing files:

git add .
git commit -m "committing tracked changes to current branch"

Next step is creating a new branch B (with checkout -b you visit it immediately)

git checkout -b newBranchName

When using stash pop the stashed changes get added to your current branch.

git stash pop

The only thing left is to stage and commit the changes on the new branch B

git add .
git commit -m "created new file"
山人契 2024-07-20 08:59:13

我发现这个答案很有用。

然而,由于该线程已关闭并且无法发表评论,我对该答案有疑问。

当我应用 git checkout other_branch 时,我收到以下错误

error: pathspec 'other_branch' did not match any file(s) known to git

因此,我没有应用该命令,而是使用它解决了我的问题

git branch other_branch
git checkout other_branch

I have found this answer useful.

However, as that thread is closed and is unable to make comments I have an issue with that answer.

When I applied git checkout other_branch I got the following error

error: pathspec 'other_branch' did not match any file(s) known to git

So instead of applying the command, I rather use which fixed my problem

git branch other_branch
git checkout other_branch
绝情姑娘 2024-07-20 08:59:13

警告:不适合 git 新手。

chakrit 的回答类似,我经常遇到这种情况:在功能分支上工作,我发现一个错误并想要修理它。 但修复属于 main 分支,而不是 my-feature。 将更改更改为 main 的整个序列是 7 个或更多 git 命令,这确实非常烦人且容易出错,

因为我找不到执行此操作的脚本,我自己写的。 只需将其放在 $PATH 中的某个位置(例如 /usr/local/bin/$HOME/.local/bin 或其他内容),然后您可以执行以下操作:

用法

# currently working on branch `my-feature`
$ git add some-file       # use git add -p if you want only some changes
$ git commit-branch main --rebase -m 'Fixed some nasty bug in some-file'

然后它将打印一些进度消息:

Committing your staged changes to branch 'main'.
+ git checkout --quiet HEAD~0
+ git commit --quiet -m 'Fixed some nasty bug in some-file'
++ git rev-parse HEAD
+ commit_hash=82513091473646a09d541893b8bd60a0f98b765d
+ git stash push --quiet
+ git checkout --quiet main
+ git cherry-pick --quiet 82513091473646a09d541893b8bd60a0f98b765d
[main 1c5d96e] Fixed some nasty bug in some-file
 Date: Mon Feb 6 15:04:03 2023 +0100
 1 file changed, 2 insertions(+)
+ git checkout --quiet my-feature
+ git rebase --quiet main
+ git stash pop --quiet
+ set +x
Success.

脚本

这是文件 git-commit-branch 的源代码。 将其放入 $PATH 后,不要忘记执行 chmod +x。 该脚本也在 github 上: https://github.com/fritzw/git-utils 。 请随意提出改进建议。

它的工作方式如下:

  1. 进入分离的 HEAD 状态
  2. 使用分阶段更改创建临时提交
  3. 存储所有其他更改(包括未跟踪的文件)
  4. 切换到目标分支
  5. 择优选择目标分支上的临时提交
  6. 切换回原始分支
  7. [可选] 在目标分支上重新设置原始分支的基础,以便在原始分支中包含错误修复
  8. 从存储中恢复所有其他更改

如果任何命令失败,它只会在那里停止并打印一些信息以帮助您恢复情况。 如果您想了解更多详细信息,请查看脚本末尾的注释和 git 命令序列。

#!/usr/bin/env bash

set -o errexit
set -o nounset

usage() {
    echo "Usage: git commit-branch <target-branch> [--rebase|-r] [ <git-commit-options>... ]"
    echo ""
    echo "Commits your staged changes to <target-branch>, discarding them from your current branch."
    echo "Use --rebase or -r to rebase your current branch on the new commit in <target-branch>,"
    echo "and thus include the changes in your current branch as well."
    echo ""
    echo "Example usage working on branch my-feature:"
    echo "  git add some-file"
    echo "  git commit-branch main --rebase -m 'Fixed a bug in some-file'"
}

if [[ $# -lt 1 ]]; then
    usage
    exit 1
fi
target_branch="$1"; shift # Remove first argument
if ! git rev-parse --verify "$target_branch" >/dev/null; then
    echo "fatal: '$target_branch' is not a branch in this git repository."
    usage
    exit 1
fi

rebase_command=''
if [[ $# -gt 0 ]] && [[ "$1" == "-r" || "$1" == "--rebase" ]]; then
    rebase_command="git rebase --quiet $target_branch"
    shift # Remove -r/--rebase argument
fi

current_branch="$(git branch --show-current)"
if ! [[ "$current_branch" ]]; then
    echo "fatal: Unable to determine current branch. You must be on a branch to use git commit-branch."
    exit 1
fi

commit_hash='not-committed-yet'
print_error_message() {
    set +x
    echo
    echo "Something went wrong in the last command. :-("
    echo "Your unstaged changes and untracked files should be in the last stash."
    echo "Your previously staged changes should be in the following commit: $commit_hash"
    echo "Please check which commands were executed and try to undo them manually."
    echo
}

echo "Committing your staged changes to branch '$target_branch'."
trap 'print_error_message' ERR # Print some hopefully helpful info if something fails
set -x # Print all executed commands
git checkout --quiet 'HEAD~0' # Go into 'detached HEAD' state to avoid changing current branch
git commit --quiet "$@" # Create temporary commit
commit_hash="$(git rev-parse HEAD)" # Note temporary commit ID
git stash push --include-untracked --quiet # Save all other changes from working tree
git checkout --quiet "$target_branch" # Move to target branch
git cherry-pick --quiet "$commit_hash" # Apply changes from temporary commit to target branch
git checkout --quiet "$current_branch" # Switch back to current branch
$rebase_command # Execute git rebase if --rebase flag is present
git stash pop --quiet # Re-apply untracked changes to working tree
set +x # Stop printing executed commands
echo "Success."
if ! [[ "$rebase_command" ]]; then
    echo ""
    echo "If you want to include those changes in your current branch, you can run:"
    echo "  git stash; git rebase $target_branch; git stash pop"
    echo "or"
    echo "  git stash; git merge $target_branch; git stash pop"
    echo ""
fi

WARNING: Not for git newbies.

Similar to chakrit's answer, I run into this situation quite often: Working on a feature branch, I find a bug and want to fix it. But the fix belongs on the main branch, not my-feature. The whole sequence to get the changes into main is 7 or more git commands, which is really quite annoying and easy to get wrong

Since I could not find a script to do it, I wrote it myself. Simply place it somewhere in $PATH (e.g. /usr/local/bin or /$HOME/.local/bin or something), then you can do the following:

Usage

# currently working on branch `my-feature`
$ git add some-file       # use git add -p if you want only some changes
$ git commit-branch main --rebase -m 'Fixed some nasty bug in some-file'

It will then print some progress messages:

Committing your staged changes to branch 'main'.
+ git checkout --quiet HEAD~0
+ git commit --quiet -m 'Fixed some nasty bug in some-file'
++ git rev-parse HEAD
+ commit_hash=82513091473646a09d541893b8bd60a0f98b765d
+ git stash push --quiet
+ git checkout --quiet main
+ git cherry-pick --quiet 82513091473646a09d541893b8bd60a0f98b765d
[main 1c5d96e] Fixed some nasty bug in some-file
 Date: Mon Feb 6 15:04:03 2023 +0100
 1 file changed, 2 insertions(+)
+ git checkout --quiet my-feature
+ git rebase --quiet main
+ git stash pop --quiet
+ set +x
Success.

The script

Here's the source code for the file git-commit-branch. Don't forget to do chmod +x after placing it in $PATH. The script is also on github: https://github.com/fritzw/git-utils. Feel free to suggest improvements.

The way it works is as follows:

  1. Go into detached HEAD state
  2. Create a temporary commit with the staged changes
  3. Stash all other changes (including untracked files)
  4. Switch to target branch
  5. Cherry-pick the temporary commit on the target branch
  6. Switch back to original branch
  7. [optional] Rebase original branch on target branch, in order to include the bugfix in the original branch
  8. Restore all other changes from stash

If any command fails it will simply stop there and print some info to help you recover the situation. If you want more details, look at the comments and the sequence of git commands at the end of the script.

#!/usr/bin/env bash

set -o errexit
set -o nounset

usage() {
    echo "Usage: git commit-branch <target-branch> [--rebase|-r] [ <git-commit-options>... ]"
    echo ""
    echo "Commits your staged changes to <target-branch>, discarding them from your current branch."
    echo "Use --rebase or -r to rebase your current branch on the new commit in <target-branch>,"
    echo "and thus include the changes in your current branch as well."
    echo ""
    echo "Example usage working on branch my-feature:"
    echo "  git add some-file"
    echo "  git commit-branch main --rebase -m 'Fixed a bug in some-file'"
}

if [[ $# -lt 1 ]]; then
    usage
    exit 1
fi
target_branch="$1"; shift # Remove first argument
if ! git rev-parse --verify "$target_branch" >/dev/null; then
    echo "fatal: '$target_branch' is not a branch in this git repository."
    usage
    exit 1
fi

rebase_command=''
if [[ $# -gt 0 ]] && [[ "$1" == "-r" || "$1" == "--rebase" ]]; then
    rebase_command="git rebase --quiet $target_branch"
    shift # Remove -r/--rebase argument
fi

current_branch="$(git branch --show-current)"
if ! [[ "$current_branch" ]]; then
    echo "fatal: Unable to determine current branch. You must be on a branch to use git commit-branch."
    exit 1
fi

commit_hash='not-committed-yet'
print_error_message() {
    set +x
    echo
    echo "Something went wrong in the last command. :-("
    echo "Your unstaged changes and untracked files should be in the last stash."
    echo "Your previously staged changes should be in the following commit: $commit_hash"
    echo "Please check which commands were executed and try to undo them manually."
    echo
}

echo "Committing your staged changes to branch '$target_branch'."
trap 'print_error_message' ERR # Print some hopefully helpful info if something fails
set -x # Print all executed commands
git checkout --quiet 'HEAD~0' # Go into 'detached HEAD' state to avoid changing current branch
git commit --quiet "$@" # Create temporary commit
commit_hash="$(git rev-parse HEAD)" # Note temporary commit ID
git stash push --include-untracked --quiet # Save all other changes from working tree
git checkout --quiet "$target_branch" # Move to target branch
git cherry-pick --quiet "$commit_hash" # Apply changes from temporary commit to target branch
git checkout --quiet "$current_branch" # Switch back to current branch
$rebase_command # Execute git rebase if --rebase flag is present
git stash pop --quiet # Re-apply untracked changes to working tree
set +x # Stop printing executed commands
echo "Success."
if ! [[ "$rebase_command" ]]; then
    echo ""
    echo "If you want to include those changes in your current branch, you can run:"
    echo "  git stash; git rebase $target_branch; git stash pop"
    echo "or"
    echo "  git stash; git merge $target_branch; git stash pop"
    echo ""
fi
妄想挽回 2024-07-20 08:59:12

由于您的文件尚未在 branch1 中提交:

git stash
git checkout branch2
git stash pop

git stash
git checkout branch2
git stash list       # to check the various stash made in different branch
git stash apply x    # to select the right one

以上是 rbento答案

git stash
git stash branch branch2

它使用:

git stash 分支[<隐藏>]

  • 从最初创建 的提交开始,创建并签出名为 的新分支,
  • 中记录的更改应用到新的工作树和索引。

如果成功,并且 stash@{} 形式的引用,则会删除 <隐藏>

如果您运行 git stash push 的分支发生了足够大的变化,导致 git stash apply 由于冲突而失败,这非常有用。
由于存储条目应用于运行 git stash 时处于 HEAD 的提交之上,因此它会恢复最初存储的状态,不会发生冲突。


正如评论的作者:benjohn(请参阅git stash 手册页):

要同时存储当前未跟踪(新添加)的文件,请添加参数 -u,因此:

git stash -u

Since your files are not yet committed in branch1:

git stash
git checkout branch2
git stash pop

or

git stash
git checkout branch2
git stash list       # to check the various stash made in different branch
git stash apply x    # to select the right one

Above is the longer more explicit version of rbento's answer:

git stash
git stash branch branch2

It uses:

git stash branch <branchname> [<stash>]

  • Creates and checks out a new branch named <branchname> starting from the commit at which the <stash> was originally created,
  • applies the changes recorded in <stash> to the new working tree and index.

If that succeeds, and <stash> is a reference of the form stash@{<revision>}, it then drops the <stash>.

This is useful if the branch on which you ran git stash push has changed enough that git stash apply fails due to conflicts.
Since the stash entry is applied on top of the commit that was HEAD at the time git stash was run, it restores the originally stashed state with no conflicts.


As commented by benjohn (see git stash man page):

To also stash currently untracked (newly added) files, add the argument -u, so:

git stash -u
醉城メ夜风 2024-07-20 08:59:12

隐藏、临时提交和变基可能都有些过头了。 如果您尚未将更改的文件添加到索引中,那么您也许可以只签出另一个分支。

git checkout branch2

只要您正在编辑的文件在branch1 和branch2 之间不存在不同,此操​​作就有效。 它将让您留在branch2,并保留您的工作更改。 如果它们不同,那么您可以指定要将本地更改与通过使用 -m 选项切换分支来签出而引入的更改合并。

git checkout -m branch2

如果您已对索引添加了更改,那么您需要首先通过重置来撤消这些更改。 (这将保留您的工作副本,只会删除暂存的更改。)

git reset

Stashing, temporary commits and rebasing may all be overkill. If you haven't added the changed files to the index, yet, then you may be able to just checkout the other branch.

git checkout branch2

This will work so long as no files that you are editing are different between branch1 and branch2. It will leave you on branch2 with you working changes preserved. If they are different then you can specify that you want to merge your local changes with the changes introduced by switching branches with the -m option to checkout.

git checkout -m branch2

If you've added changes to the index then you'll want to undo these changes with a reset first. (This will preserve your working copy, it will just remove the staged changes.)

git reset
我最亲爱的 2024-07-20 08:59:12

已接受答案的更短替代方案是:

暂时将更改移至存储区。

  1. git 存储

创建并切换到一个新分支,然后只需一步即可将存储库弹出到该分支。

  1. git stashbranch new_branch_name

然后只需添加提交对此新分支的更改。

A shorter alternative to the accepted answer would be:

Temporarily move the changes to a stash.

  1. git stash

Create and switch to a new branch and then pop the stash to it in just one step.

  1. git stash branch new_branch_name

Then just add and commit the changes to this new branch.

攒一口袋星星 2024-07-20 08:59:12

警告:不适合 git 新手。

这在我的工作流程中出现得足够多,以至于我几乎尝试为其编写一个新的 git 命令。 通常的 git stash 流程是可行的方法,但是有点尴尬。 我通常会先进行新的提交,因为如果我一直在查看更改,所有信息都在我的脑海中记忆犹新,并且最好开始 git commit - 执行什么我立即发现了(通常是我在处理功能分支时发现的属于 master 的错误修复)。

如果你经常遇到这样的情况,那么 另一个工作目录与当前目录并列,始终检出 master 分支。

因此,我如何实现这一点是这样的:

  1. git commit 立即进行更改并提供良好的提交消息。
  2. git reset HEAD~1 撤消当前分支的提交。
  3. (可选)继续开发该功能。

有时稍后(异步),或立即在另一个终端窗口中:

  1. cd my-project-master 这是另一个共享相同 .git
  2. git reflog 的 WD > 找到我刚刚修复的错误。
  3. 提交的 gitcherry-pick SHA1

或者(仍然是异步),您可以重新设置(或合并)您的功能分支来修复错误,通常是在您准备提交 PR 并已经清理了您的功能分支和 WD 时:

  1. cd my-project 这是我正在研究的主要 WD。
  2. git rebase master 来修复错误。

这样我就可以不间断地继续开发该功能,而不必担心 git stash-ing 任何东西,或者必须在 git checkout 之前清理我的 WD(然后让再次检查功能分支退出。)并且我的所有错误修复仍然会转到 master 而不是隐藏在我的功能分支中。

在我看来,当您正在开发某些重要功能时,git stashgit checkout 是真正的 PIA。

WARNING: Not for git newbies.

This comes up enough in my workflow that I've almost tried to write a new git command for it. The usual git stash flow is the way to go but is a little awkward. I usually make a new commit first since if I have been looking at the changes, all the information is fresh in my mind and it's better to just start git commit-ing what I found (usually a bugfix belonging on master that I discover while working on a feature branch) right away.

It is also helpful—if you run into situations like this a lot—to have another working directory alongside your current one that always have the master branch checked out.

So how I achieve this goes like this:

  1. git commit the changes right away with a good commit message.
  2. git reset HEAD~1 to undo the commit from current branch.
  3. (optional) continue working on the feature.

Sometimes later (asynchronously), or immediately in another terminal window:

  1. cd my-project-master which is another WD sharing the same .git
  2. git reflog to find the bugfix I've just made.
  3. git cherry-pick SHA1 of the commit.

Optionally (still asynchronous) you can then rebase (or merge) your feature branch to get the bugfix, usually when you are about to submit a PR and have cleaned your feature branch and WD already:

  1. cd my-project which is the main WD I'm working on.
  2. git rebase master to get the bugfixes.

This way I can keep working on the feature uninterrupted and not have to worry about git stash-ing anything or having to clean my WD before a git checkout (and then having the check the feature branch backout again.) and still have all my bugfixes goes to master instead of hidden in my feature branch.

IMO git stash and git checkout is a real PIA when you are in the middle of working on some big feature.

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