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

我当前的分支是branch1,我已经做了一些本地更改。然而,我现在意识到我实际上是想将这些更改应用到branch2。是否有一种方法可以应用/合并这些更改,使它们成为branch2上的本地更改,而无需在branch1上提交它们?


当前回答

警告:不适合git新手。

这在我的工作流程中出现得足够多,我几乎试图为它写一个新的git命令。通常的git隐藏流是要走的路,但有点尴尬。我通常先做一个新的提交,因为如果我一直在看变化,所有的信息都在我的脑海中是新鲜的,最好马上开始git提交我发现的东西(通常是我在一个功能分支工作时发现的属于master的错误修复)。

如果您经常遇到这样的情况,在当前目录旁边设置另一个工作目录总是签出主分支,这也是很有帮助的。

我是这样实现的:

Git立即提交更改,并提供一个好的提交消息。 git重置HEAD~1来撤销当前分支的提交。 (可选的)继续致力于该特性。

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

cd my-project-master,这是另一个共享。git的WD git reflog找到我刚刚做的bug修复。 git选择提交的SHA1。

可选的(仍然是异步的),你可以重新建立(或合并)你的特征分支来获得错误修复,通常当你准备提交PR并且已经清理了你的特征分支和WD时:

cd我的项目,这是我正在工作的主要WD。 Git重基master以获得错误修复。

这样我就可以不受干扰地继续工作,而不必担心git会存储任何东西,或者在git签出之前必须清理我的WD(然后再次检查功能分支),并且仍然有我所有的错误修复到master,而不是隐藏在我的功能分支中。

在我看来,git隐藏和git签出是一个真正的PIA,当你正在开发一些大功能时。

其他回答

因为你的文件还没有在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

上面是rbento回答的更长的更明确的版本:

git stash
git stash branch branch2

它使用:

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.


正如benjohn所评论的(见git stash手册页):

要保存当前未跟踪的(新添加的)文件,添加参数-u,这样:

git stash -u

警告:不适合git新手。

这在我的工作流程中出现得足够多,我几乎试图为它写一个新的git命令。通常的git隐藏流是要走的路,但有点尴尬。我通常先做一个新的提交,因为如果我一直在看变化,所有的信息都在我的脑海中是新鲜的,最好马上开始git提交我发现的东西(通常是我在一个功能分支工作时发现的属于master的错误修复)。

如果您经常遇到这样的情况,在当前目录旁边设置另一个工作目录总是签出主分支,这也是很有帮助的。

我是这样实现的:

Git立即提交更改,并提供一个好的提交消息。 git重置HEAD~1来撤销当前分支的提交。 (可选的)继续致力于该特性。

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

cd my-project-master,这是另一个共享。git的WD git reflog找到我刚刚做的bug修复。 git选择提交的SHA1。

可选的(仍然是异步的),你可以重新建立(或合并)你的特征分支来获得错误修复,通常当你准备提交PR并且已经清理了你的特征分支和WD时:

cd我的项目,这是我正在工作的主要WD。 Git重基master以获得错误修复。

这样我就可以不受干扰地继续工作,而不必担心git会存储任何东西,或者在git签出之前必须清理我的WD(然后再次检查功能分支),并且仍然有我所有的错误修复到master,而不是隐藏在我的功能分支中。

在我看来,git隐藏和git签出是一个真正的PIA,当你正在开发一些大功能时。

我发现这个答案很有用。

然而,由于该线程已关闭,无法作出评论,我有一个问题的答案。

当我应用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

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

什么是未跟踪的更改?

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

什么是被跟踪的变更?

当您更改之前(在以前的提交中)提交给repo的文件时。

程序快速讲解

因此,假设您在分支A上,但是您只想将对现有文件的更改提交到分支A,而新创建的文件(未跟踪的)应该提交到新的分支b。可以使用一些技巧来使用存储,并逐步解释。

添加脚本到.git/config

在.git文件夹中有一个配置文件。打开它,你会看到这样的东西:

[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(签出-b你立即访问它)

git checkout -b newBranchName

当使用隐藏弹出隐藏的变化被添加到您的当前分支。

git stash pop

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

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

警告:不适合git新手。

类似于chakrit的回答,我经常遇到这种情况:在一个特性分支上工作时,我发现了一个bug,想要修复它。但是修复属于主分支,而不是我的特性。将更改转化为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。请随意提出改进建议。

其工作原理如下:

进入分离HEAD状态 使用阶段性更改创建临时提交 隐藏所有其他更改(包括未跟踪的文件) 切换到目标分支 选择目标分支上的临时提交 切换回原来的分支 [可选]在目标分支上重构原始分支,以便在原始分支中包含bug修复 从stash恢复所有其他更改

如果任何命令失败,它将简单地停止在那里,并打印一些信息来帮助您恢复情况。如果您想了解更多细节,请查看脚本末尾的注释和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