合并、更新和拉取 Git 分支,无需使用签出

发布于 2024-09-08 17:14:09 字数 324 浏览 5 评论 0原文

我工作的项目有 2 个分支 A 和 B。我通常在分支 A 上工作,并合并分支 B 中的内容。对于合并,我通常会这样做:

git merge origin/branchB

但是,我还想保留分支的本地副本B,因为我有时可能会在不先与分支 A 合并的情况下检查分支。为此,我会这样做:

git checkout branchB
git pull
git checkout branchA

有没有一种方法可以在一个命令中执行上述操作,而无需来回切换分支?我应该使用 git update-ref 吗?如何?

I work on a project that has 2 branches, A and B. I typically work on branch A, and merge stuff from branch B. For the merging, I would typically do:

git merge origin/branchB

However, I would also like to keep a local copy of branch B, as I may occasionally check out the branch without first merging with my branch A. For this, I would do:

git checkout branchB
git pull
git checkout branchA

Is there a way to do the above in one command, and without having to switch branch back and forth? Should I be using git update-ref for that? How?

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

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

发布评论

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

评论(20

我最亲爱的 2024-09-15 17:14:09

简短的答案

只要您正在进行快进合并,那么您可以简单地使用

git fetch <remote> <sourceBranch>:<destinationBranch>

示例:

# Merge local branch foo into local branch master,
# without having to checkout master first.
# Here `.` means to use the local repository as the "remote":
git fetch . foo:master

# Merge remote branch origin/foo into local branch foo,
# without having to checkout foo first:
git fetch origin foo:foo

虽然 Amber 的答案 也适用于快进情况,以这种方式使用 git fetch 比仅仅强制移动分支引用更安全,因为 git fetch<只要您不在引用规范中使用 +,/code> 就会自动防止意外的非快进。

长答案

如果不先检查 A,则无法将分支 B 合并到分支 A,否则会导致非快进合并。这是因为需要工作副本来解决任何潜在的冲突。

但是,在快进合并的情况下,这是可能的,因为根据定义,此类合并永远不会导致冲突。要在不先签出分支的情况下执行此操作,您可以将 git fetch 与 refspec 结合使用。

如果您签出另一个分支 feature,则以下是更新 master(不允许非快进更改)的示例:

git fetch upstream master:master

此用例非常常见,因此您将可能想在你的 git 配置文件中为其创建一个别名,如下所示:

[alias]
    sync = !sh -c 'git checkout --quiet HEAD; git fetch upstream master:master; git checkout --quiet -'

这个别名的作用如下:

  1. git checkout HEAD:这会将你的工作副本放入分离头中状态。如果您想在签出 master 的同时更新它,这会很有用。我认为有必要这样做,因为否则 master 的分支引用将不会移动,但我不记得这是否真的是我的想法。

  2. git fetchupstreammaster:master:这会将您的本地master快进到与upstream/master相同的位置。

  3. git checkout - 签出您之前签出的分支(这就是 - 在本例中的作用)。

用于(非)快进合并的 git fetch 语法

如果您希望 fetch 命令在更新为非快进时失败,那么您只需使用 如果您想允许非快进更新,则可以

git fetch <remote> <remoteBranch>:<localBranch>

在 refspec 的前面添加一个 +

git fetch <remote> +<remoteBranch>:<localBranch>

请注意,您可以将本地存储库作为“远程”参数传递使用 .

git fetch . <sourceBranch>:<destinationBranch>

文档

来自 git fetch 文档的 解释这个语法(强调我的):

<参考规范>

参数的格式是可选的加上 +,后跟源引用 ,然后冒号 :,后跟目标引用

获取与 匹配的远程引用,如果 不是空字符串,则获取本地引用匹配使用 快进。如果使用可选的加号 +,则即使不会导致快进更新,也会更新本地引用。

另请参阅

  1. Git 签出和合并,无需触及工作树

  2. < a href="https://stackoverflow.com/questions/3408532/merging-without-change-the-working-directory">合并而不更改工作目录

The Short Answer

As long as you're doing a fast-forward merge, then you can simply use

git fetch <remote> <sourceBranch>:<destinationBranch>

Examples:

# Merge local branch foo into local branch master,
# without having to checkout master first.
# Here `.` means to use the local repository as the "remote":
git fetch . foo:master

# Merge remote branch origin/foo into local branch foo,
# without having to checkout foo first:
git fetch origin foo:foo

While Amber's answer will also work in fast-forward cases, using git fetch in this way instead is a little safer than just force-moving the branch reference, since git fetch will automatically prevent accidental non-fast-forwards as long as you don't use + in the refspec.

The Long Answer

You cannot merge a branch B into branch A without checking out A first if it would result in a non-fast-forward merge. This is because a working copy is needed to resolve any potential conflicts.

However, in the case of fast-forward merges, this is possible, because such merges can never result in conflicts, by definition. To do this without checking out a branch first, you can use git fetch with a refspec.

Here's an example of updating master (disallowing non-fast-forward changes) if you have another branch feature checked out:

git fetch upstream master:master

This use-case is so common, that you'll probably want to make an alias for it in your git configuration file, like this one:

[alias]
    sync = !sh -c 'git checkout --quiet HEAD; git fetch upstream master:master; git checkout --quiet -'

What this alias does is the following:

  1. git checkout HEAD: this puts your working copy into a detached-head state. This is useful if you want to update master while you happen to have it checked-out. I think it was necessary to do with because otherwise the branch reference for master won't move, but I don't remember if that's really right off-the-top of my head.

  2. git fetch upstream master:master: this fast-forwards your local master to the same place as upstream/master.

  3. git checkout - checks out your previously checked-out branch (that's what the - does in this case).

The syntax of git fetch for (non-)fast-forward merges

If you want the fetch command to fail if the update is non-fast-forward, then you simply use a refspec of the form

git fetch <remote> <remoteBranch>:<localBranch>

If you want to allow non-fast-forward updates, then you add a + to the front of the refspec:

git fetch <remote> +<remoteBranch>:<localBranch>

Note that you can pass your local repo as the "remote" parameter using .:

git fetch . <sourceBranch>:<destinationBranch>

The Documentation

From the git fetch documentation that explains this syntax (emphasis mine):

<refspec>

The format of a <refspec> parameter is an optional plus +, followed by the source ref <src>, followed by a colon :, followed by the destination ref <dst>.

The remote ref that matches <src> is fetched, and if <dst> is not empty string, the local ref that matches it is fast-forwarded using <src>. If the optional plus + is used, the local ref is updated even if it does not result in a fast-forward update.

See Also

  1. Git checkout and merge without touching working tree

  2. Merging without changing the working directory

2024-09-15 17:14:09

不,没有。签出目标分支是必要的,以便您可以解决冲突等问题(如果 Git 无法自动合并它们)。

但是,如果合并是快进的,则不需要检查目标分支,因为您实际上不需要合并任何内容 - 您所要做的就是更新分支以指向新头参考号您可以使用 gitbranch -f 来完成此操作:

git branch -f branch-b branch-a

将更新branch-b以指向branch-a的头部。

-f选项代表--force,这意味着branch-b将被覆盖。

警告:更安全的选择是使用git fetch,它只允许快进

这个方法可以像这样使用:

git branch -f branch-b branch-b@{Upstream}

或更短地

git branch -f branch-b branch-b@{U}

强制更新分支,而不检查它(假设它们在变基后是否有分歧)

No, there is not. A checkout of the target branch is necessary to allow you to resolve conflicts, among other things (if Git is unable to automatically merge them).

However, if the merge is one that would be fast-forward, you don't need to check out the target branch, because you don't actually need to merge anything - all you have to do is update the branch to point to the new head ref. You can do this with git branch -f:

git branch -f branch-b branch-a

Will update branch-b to point to the head of branch-a.

The -f option stands for --force, which means branch-b will be overwritten.

Caution: A safer option is using git fetch which will only allow a fast-forward.

This method can be used like so:

git branch -f branch-b branch-b@{Upstream}

or shorter

git branch -f branch-b branch-b@{U}

To force update a branch, without checking it out (say if they have diverged after rebase)

甩你一脸翔 2024-09-15 17:14:09

正如 Amber 所说,快进合并是唯一可以做到这一点的情况。可以想象,任何其他合并都需要经历整个三向合并、应用补丁、解决冲突交易——这意味着需要有文件。

我碰巧有一个脚本正好用于此目的:在不接触工作树的情况下进行快进合并(除非您合并到 HEAD 中)。它有点长,因为它至少有点健壮 - 它检查以确保合并将快进,然后在不检查分支的情况下执行它,但产生与您相同的结果 - 你看到diff --stat 更改摘要,并且引用日志中的条目与快进合并完全相同,而不是使用 branch -f。如果将其命名为 git-merge-ff 并将其放入 bin 目录中,则可以将其作为 git 命令调用:git merge-ff

#!/bin/bash

_usage() {
    echo "Usage: git merge-ff <branch> <committish-to-merge>" 1>&2
    exit 1
}

_merge_ff() {
    branch="$1"
    commit="$2"

    branch_orig_hash="$(git show-ref -s --verify refs/heads/$branch 2> /dev/null)"
    if [ $? -ne 0 ]; then
        echo "Error: unknown branch $branch" 1>&2
        _usage
    fi

    commit_orig_hash="$(git rev-parse --verify $commit 2> /dev/null)"
    if [ $? -ne 0 ]; then
        echo "Error: unknown revision $commit" 1>&2
        _usage
    fi

    if [ "$(git symbolic-ref HEAD)" = "refs/heads/$branch" ]; then
        git merge $quiet --ff-only "$commit"
    else
        if [ "$(git merge-base $branch_orig_hash $commit_orig_hash)" != "$branch_orig_hash" ]; then
            echo "Error: merging $commit into $branch would not be a fast-forward" 1>&2
            exit 1
        fi
        echo "Updating ${branch_orig_hash:0:7}..${commit_orig_hash:0:7}"
        if git update-ref -m "merge $commit: Fast forward" "refs/heads/$branch" "$commit_orig_hash" "$branch_orig_hash"; then
            if [ -z $quiet ]; then
                echo "Fast forward"
                git diff --stat "$branch@{1}" "$branch"
            fi
        else
            echo "Error: fast forward using update-ref failed" 1>&2
        fi
    fi
}

while getopts "q" opt; do
    case $opt in
        q ) quiet="-q";;
        * ) ;;
    esac
done
shift $((OPTIND-1))

case $# in
    2 ) _merge_ff "$1" "$2";;
    * ) _usage
esac

PS如果有人发现该脚本有任何问题,请发表评论!这是一项写完就忘记的工作,但我很乐意改进它。

As Amber said, fast-forward merges are the only case in which you could conceivably do this. Any other merge conceivably needs to go through the whole three-way merge, applying patches, resolving conflicts deal - and that means there need to be files around.

I happen to have a script around I use for exactly this: doing fast-forward merges without touching the work tree (unless you're merging into HEAD). It's a little long, because it's at least a bit robust - it checks to make sure that the merge would be a fast-forward, then performs it without checking out the branch, but producing the same results as if you had - you see the diff --stat summary of changes, and the entry in the reflog is exactly like a fast forward merge, instead of the "reset" one you get if you use branch -f. If you name it git-merge-ff and drop it in your bin directory, you can call it as a git command: git merge-ff.

#!/bin/bash

_usage() {
    echo "Usage: git merge-ff <branch> <committish-to-merge>" 1>&2
    exit 1
}

_merge_ff() {
    branch="$1"
    commit="$2"

    branch_orig_hash="$(git show-ref -s --verify refs/heads/$branch 2> /dev/null)"
    if [ $? -ne 0 ]; then
        echo "Error: unknown branch $branch" 1>&2
        _usage
    fi

    commit_orig_hash="$(git rev-parse --verify $commit 2> /dev/null)"
    if [ $? -ne 0 ]; then
        echo "Error: unknown revision $commit" 1>&2
        _usage
    fi

    if [ "$(git symbolic-ref HEAD)" = "refs/heads/$branch" ]; then
        git merge $quiet --ff-only "$commit"
    else
        if [ "$(git merge-base $branch_orig_hash $commit_orig_hash)" != "$branch_orig_hash" ]; then
            echo "Error: merging $commit into $branch would not be a fast-forward" 1>&2
            exit 1
        fi
        echo "Updating ${branch_orig_hash:0:7}..${commit_orig_hash:0:7}"
        if git update-ref -m "merge $commit: Fast forward" "refs/heads/$branch" "$commit_orig_hash" "$branch_orig_hash"; then
            if [ -z $quiet ]; then
                echo "Fast forward"
                git diff --stat "$branch@{1}" "$branch"
            fi
        else
            echo "Error: fast forward using update-ref failed" 1>&2
        fi
    fi
}

while getopts "q" opt; do
    case $opt in
        q ) quiet="-q";;
        * ) ;;
    esac
done
shift $((OPTIND-1))

case $# in
    2 ) _merge_ff "$1" "$2";;
    * ) _usage
esac

P.S. If anyone sees any issues with that script, please comment! It was a write-and-forget job, but I'd be happy to improve it.

绮烟 2024-09-15 17:14:09

仅当合并是快进时才可以执行此操作。如果不是,那么 git 需要签出文件,以便合并它们!

仅用于快进

git fetch <branch that would be pulled for branchB>
git update-ref -m "merge <commit>: Fast forward" refs/heads/<branch> <commit>

其中 是获取的提交,即您想要快进的提交。这基本上就像使用 gitbranch -f 移动分支一样,只不过它还会将其记录在引用日志中,就像您实际进行了合并一样。

请,请,不要对非快进的内容执行此操作,否则您只是将分支重置为其他提交。 (要进行检查,请查看 git merge-base是否给出了分支的 SHA1。)

You can only do this if the merge is a fast-forward. If it's not, then git needs to have the files checked out so it can merge them!

To do it for a fast-forward only:

git fetch <branch that would be pulled for branchB>
git update-ref -m "merge <commit>: Fast forward" refs/heads/<branch> <commit>

where <commit> is the fetched commit, the one you want to fast-forward to. This is basically like using git branch -f to move the branch, except it also records it in the reflog as if you actually did the merge.

Please, please, please don't do this for something that's not a fast-forward, or you'll just be resetting your branch to the other commit. (To check, see if git merge-base <branch> <commit> gives the branch's SHA1.)

﹏半生如梦愿梦如真 2024-09-15 17:14:09

在您的情况下,您可以使用

git fetch origin branchB:branchB

which 执行您想要的操作(假设合并是快进的)。如果分支由于需要非快进合并而无法更新,则此操作会安全失败并显示一条消息。

这种形式的获取也有一些更有用的选项:

git fetch <remote> <sourceBranch>:<destinationBranch>

请注意,可以是本地存储库可以是一个跟踪分支。因此,您可以更新本地分支,即使它尚未签出,无需访问网络

目前,我的上游服务器访问是通过缓慢的 VPN 进行的,因此我定期连接,git fetch 来更新所有遥控器,然后断开连接。然后,如果远程主控发生了变化,我可以

git fetch . remotes/origin/master:master

安全地将本地主控更新为最新,即使我当前签出了其他一些分支。无需网络访问。

In your case you can use

git fetch origin branchB:branchB

which does what you want (assuming the merge is fast-forward). If the branch can't be updated because it requires a non-fast-forward merge, then this fails safely with a message.

This form of fetch has some more useful options too:

git fetch <remote> <sourceBranch>:<destinationBranch>

Note that <remote> can be a local repository, and <sourceBranch> can be a tracking branch. So you can update a local branch, even if it's not checked out, without accessing the network.

Currently, my upstream server access is via a slow VPN, so I periodically connect, git fetch to update all remotes, and then disconnect. Then if, say, the remote master has changed, I can do

git fetch . remotes/origin/master:master

to safely bring my local master up to date, even if I currently have some other branch checked out. No network access required.

淡紫姑娘! 2024-09-15 17:14:09

另一种无可否认的相当粗暴的方法是重新创建分支:

git fetch remote
git branch -f localbranch remote/remotebranch

这会丢弃本地过时的分支并重新创建同名的分支,因此请小心使用......

Another, admittedly pretty brute way is to just re-create the branch:

git fetch remote
git branch -f localbranch remote/remotebranch

This throws away the local outdated branch and re-creates one with the same name, so use with care ...

羁〃客ぐ 2024-09-15 17:14:09

您可以克隆存储库并在新存储库中进行合并。在同一文件系统上,这将硬链接而不是复制大部分数据。通过将结果拉入原始存储库来完成。

You can clone the repo and do the merge in the new repo. On the same filesystem, this will hardlink rather than copy most of the data. Finish by pulling the results into the original repo.

很糊涂小朋友 2024-09-15 17:14:09

输入git-forward-merge

无需签出目的地,git-forward-merge 将源合并到目标分支。

https://github.com/schuyler1d/git-forward-merge

仅适用于自动合并,如果存在冲突则需要使用常规合并。

Enter git-forward-merge:

Without needing to checkout destination, git-forward-merge <source> <destination> merges source into destination branch.

https://github.com/schuyler1d/git-forward-merge

Only works for automatic merges, if there are conflicts you need to use the regular merge.

呆橘 2024-09-15 17:14:09

对于许多 GitFlow 用户来说,最有用的命令是:

git fetch origin master:master --update-head-ok
git fetch origin dev:dev --update-head-ok

--update-head-ok 标志允许在 dev 或 master 分支上使用相同的命令。

.gitconfig 中的一个方便的别名:

[alias]
    f=!git fetch origin master:master --update-head-ok && git fetch origin dev:dev --update-head-ok

For many GitFlow users the most useful commands are:

git fetch origin master:master --update-head-ok
git fetch origin dev:dev --update-head-ok

The --update-head-ok flag allows using the same command while on dev or master branches.

A handy alias in .gitconfig:

[alias]
    f=!git fetch origin master:master --update-head-ok && git fetch origin dev:dev --update-head-ok
随遇而安 2024-09-15 17:14:09

我在这个问题中遗漏了一些东西,如果您无意处理它,为什么需要签出本地 branchB ?在您的示例中,您只想更新本地 branchB,同时保留在 branchA 上?

我最初假设您这样做是为了 fetch origin/branchB,您已经可以使用 git fetch 来做到这一点,所以这个答案实际上是基于这。在您需要处理之前,无需拉取 branchB,并且当您需要从 origin/branchB 合并时,您始终可以获取 origin >。

如果您想跟踪branchB 在某个时间点的位置,您可以从最新获取的origin/branchB 创建一个标签或另一个分支。

因此,您需要从 origin/branchB 合并:

git fetch
git merge origin/branchB

然后下次您需要在 branchB 上工作时:

git checkout branchB
git pull

此时您将获得更新的本地副本。虽然有一些方法可以在不检查的情况下完成此操作,但这种方法很少有用,并且在某些情况下可能不安全。现有的答案涵盖了这一点。

详细答案:

git pull 执行获取+合并。它与下面的两个命令大致相同,其中 通常是 origin (默认),远程跟踪分支以 开头。 / 后跟远程分支名称:

git fetch [<remote>]
git merge @{u}

@{u} 表示法是为当前分支配置的远程跟踪分支。如果 branchB 跟踪 origin/branchB,则来自 branchB@{u} 与输入 origin 相同/branchB (有关更多信息,请参阅 git rev-parse --help)。

由于您已经与 origin/branchB 合并,因此缺少的只是 git fetch (可以从任何分支运行)来更新该远程跟踪分支。

但请注意,如果在拉入本地 branchB 时创建了任何合并,您应该在从 branchB 拉取后将 branchB 合并到 branchA 中。 code>branchB (并最终将更改推送回 orign/branchB,但只要它们快进,它们就会保持不变)。

请记住,本地 branchB 在您切换到它并执行实际拉取之前不会更新,但是只要没有本地提交添加到该分支,它就会保持快进状态远程分支。

There is something I am missing from the question, why would you need to checkout the local branchB if you have no intent on working on it? In your example you just want to update the local branchB while on remaining on branchA?

I originally assumed you were doing so to fetch origin/branchB, which you can already do with git fetch, so this answer is really based on this. There is no need to pull branchB until you need to work on it, and you can always fetch origin when you need to merge from origin/branchB.

If you want to keep track of where branchB is at at a point in time, you can create a tag or another branch from the latest fetch of origin/branchB.

So all you should need ever need to merge from origin/branchB:

git fetch
git merge origin/branchB

Then next time you need to work on branchB:

git checkout branchB
git pull

At this point you will get an updated local copy. While there are ways to do it without checking out, this is the rarely useful and can be unsafe in some cases. There are existing answers covering this.

Detailed answer:

git pull does a fetch + merge. It's roughly the the same the two commands below, where <remote> is usually origin (default), and the remote tracking branch starts with <remote>/ followed by the remote branch name:

git fetch [<remote>]
git merge @{u}

The @{u} notation is the configured remote tracking branch for the current branch. If branchB tracks origin/branchB then @{u} from branchB is the same as typing origin/branchB (see git rev-parse --help for more info).

Since you already merge with origin/branchB, all that is missing is the git fetch (which can run from any branch) to update that remote-tracking branch.

Note though that if there was any merge created while pulling into local branchB, you should rather merge branchB into branchA after having done a pull from branchB (and eventually push the changes back to orign/branchB, but as long as they're fast-forward they would remain the same).

Keep in mind the local branchB will not be updated until you switch to it and do an actual pull, however as long as there are no local commits added to this branch it will just remain a fast-forward to the remote branch.

怪我闹别瞎闹 2024-09-15 17:14:09

对于许多情况(例如合并),您可以只使用远程分支,而无需更新本地跟踪分支。在转发日志中添加一条消息听起来有些过分,而且会阻止它变得更快。为了更容易恢复,请将以下内容添加到您的 git 配置中,

[core]
    logallrefupdates=true

然后键入

git reflog show mybranch

以查看分支的最近历史记录

For many cases (such as merging), you can just use the remote branch without having to update the local tracking branch. Adding a message in the reflog sounds like overkill and will stop it being quicker. To make it easier to recover, add the following into your git config

[core]
    logallrefupdates=true

Then type

git reflog show mybranch

to see the recent history for your branch

牵你手 2024-09-15 17:14:09

我为每天在项目中遇到的类似用例编写了一个 shell 函数。这基本上是让本地分支与公共分支保持同步的捷径,例如在打开 PR 之前进行开发等。

即使您不想使用checkout,也要发布此内容,以防其他人不介意该限制。

glmh(“git pull并合并到这里”)会自动checkoutbranchBpull最新的,重新< code>签出branchA,并合并branchB

没有解决保留branchA本地副本的需要,但可以通过在签出branchB之前添加一个步骤来轻松修改以实现此目的。
就像...

git branch ${branchA}-no-branchB ${branchA}

对于简单的快进合并,这会跳到提交消息提示。

对于非快进合并,这会将您的分支置于冲突解决状态(您可能需要干预)。

要进行设置,请添加到 .bashrc.zshrc 等:

glmh() {
    branchB=$1
    [ $# -eq 0 ] && { branchB="develop" }
    branchA="$(git branch | grep '*' | sed 's/* //g')"
    git checkout ${branchB} && git pull
    git checkout ${branchA} && git merge ${branchB} 
}

用法:

# No argument given, will assume "develop"
> glmh

# Pass an argument to pull and merge a specific branch
> glmh your-other-branch

注意:这不够足够强大,无法将分支名称之外的参数移交给git merge

I wrote a shell function for a similar use case I encounter daily on projects. This is basically a shortcut for keeping local branches up to date with a common branch like develop before opening a PR, etc.

Posting this even though you don't want to use checkout, in case others don't mind that constraint.

glmh ("git pull and merge here") will automatically checkout branchB, pull the latest, re-checkout branchA, and merge branchB.

Doesn't address the need to keep a local copy of branchA, but could easily be modified to do so by adding a step before checking out branchB.
Something like...

git branch ${branchA}-no-branchB ${branchA}

For simple fast-forward merges, this skips to the commit message prompt.

For non fast-forward merges, this places your branch in the conflict resolution state (you likely need to intervene).

To setup, add to .bashrc or .zshrc, etc:

glmh() {
    branchB=$1
    [ $# -eq 0 ] && { branchB="develop" }
    branchA="$(git branch | grep '*' | sed 's/* //g')"
    git checkout ${branchB} && git pull
    git checkout ${branchA} && git merge ${branchB} 
}

Usage:

# No argument given, will assume "develop"
> glmh

# Pass an argument to pull and merge a specific branch
> glmh your-other-branch

Note: This is not robust enough to hand-off of args beyond branch name to git merge

柳絮泡泡 2024-09-15 17:14:09

只是为了拉出 master 而不检查 master 我使用

git fetch origin master:master

just to pull the master without checking out the master I use

git fetch origin master:master

指尖上得阳光 2024-09-15 17:14:09
git worktree add [-f] [--detach] [--checkout] [--lock] [-b <new-branch>] <path> [<commit-ish>]

您可以尝试 git worktree 让两个分支打开另一方面,这听起来可能就是您想要的,但与我在这里看到的其他一些答案非常不同。

通过这种方式,您可以在同一个 git 存储库中跟踪两个单独的分支,因此您只需获取一次即可在两个工作树中获取更新(而不是必须 git clone 两次并在每个分支上 git pull)

Worktree 将创建一个新的工作目录对于您的代码,您可以同时签出不同的分支,而不是就地交换分支。

当你想删除它时,你可以用

git worktree remove [-f] <worktree>
git worktree add [-f] [--detach] [--checkout] [--lock] [-b <new-branch>] <path> [<commit-ish>]

You can try git worktree to have two branches open side by side, this sounds like it might be what you want but very different than some of the other answers I've seen here.

In this way you can have two separate branches tracking in the same git repo so you only have to fetch once to get updates in both work trees (rather than having to git clone twice and git pull on each)

Worktree will create a new working directory for your code where you can have a different branch checked out simultaneously instead of swapping branches in place.

When you want to remove it you can clean up with

git worktree remove [-f] <worktree>
傲影 2024-09-15 17:14:09

有效执行此操作的另一种方法是:

git fetch
git branch -d branchB
git branch -t branchB origin/branchB

因为它是小写的 -d,所以只有当数据仍然存在于某处时才会将其删除。它与 @kkoehne 的答案类似,只是它不强制。由于 -t 它将再次设置遥控器。

我的需求与 OP 略有不同,即在合并拉取请求后,从 develop (或 master)创建一个新功能分支。这可以在不强制的情况下通过一行完成,但它不会更新本地 develop 分支。只需检查一个新分支并使其基于 origin/develop 即可:

git checkout -b new-feature origin/develop

Another way to effectively do this is:

git fetch
git branch -d branchB
git branch -t branchB origin/branchB

Because it's a lower case -d, it will only delete it if the data will still exist somewhere. It's similar to @kkoehne's answer except it doesn't force. Because of the -t it will set up the remote again.

I had a slightly different need than OP, which was to create a new feature branch off develop (or master), after merging a pull request. That can be accomplished in a one-liner without force, but it doesn't update the local develop branch. It's just a matter of checking out a new branch and having it be based off origin/develop:

git checkout -b new-feature origin/develop
梦旅人picnic 2024-09-15 17:14:09

完全可以在没有 git checkout 的情况下进行任何合并,甚至是非快进合并。 @grego 的 worktree 回答是一个很好的提示。扩展一下:

cd local_repo
git worktree add _master_wt master
cd _master_wt
git pull origin master:master
git merge --no-ff -m "merging workbranch" my_work_branch
cd ..
git worktree remove _master_wt

您现在已将本地工作分支合并到本地 master 分支,而无需切换结账。

It is absolutely possible to do any merge, even non-fast forward merges, without git checkout. The worktree answer by @grego is a good hint. To expand on that:

cd local_repo
git worktree add _master_wt master
cd _master_wt
git pull origin master:master
git merge --no-ff -m "merging workbranch" my_work_branch
cd ..
git worktree remove _master_wt

You have now merged the local work branch to the local master branch without switching your checkout.

唱一曲作罢 2024-09-15 17:14:09

如果您想保留与要合并的分支之一相同的树(即不是真正的“合并”),您可以这样做。

# Check if you can fast-forward
if git merge-base --is-ancestor a b; then
    git update-ref refs/heads/a refs/heads/b
    exit
fi

# Else, create a "merge" commit
commit="$(git commit-tree -p a -p b -m "merge b into a" "$(git show -s --pretty=format:%T b)")"
# And update the branch to point to that commit
git update-ref refs/heads/a "$commit"

If you want to keep the same tree as one of the branch you want to merge (ie. not a real "merge"), you can do it like this.

# Check if you can fast-forward
if git merge-base --is-ancestor a b; then
    git update-ref refs/heads/a refs/heads/b
    exit
fi

# Else, create a "merge" commit
commit="$(git commit-tree -p a -p b -m "merge b into a" "$(git show -s --pretty=format:%T b)")"
# And update the branch to point to that commit
git update-ref refs/heads/a "$commit"
溺孤伤于心 2024-09-15 17:14:09

这实际上是我日常工作流程中非常重要的功能。应该记录在这里以供参考。

假设我正在 feat1 分支中工作,但我有一些东西应该提交到 feat2 中,它是当前 HEAD 后面的分支。我曾经执行以下步骤:首先签出 feat2,然后执行 git rebase feat。但这通常会导致我正在运行的开发服务器检测到更改并重新渲染到旧版本,如果您的工作树与当前分支差异太大,通常会崩溃。为了避免工作树发生巨大变化,在停留在分支 feat1 上时,我只需执行 git fetch;:,在上述情况下将是:

git fetch . HEAD:feat2

git fetch . feat1:feat2

之后 feat2 将指向与 feat1 相同的提交。然后,您可以安全地签出 feat2,而不会导致开发服务器崩溃。

This is actually quite important feature in my daily workflow. Should be documented here for reference.

Suppose I am working in a feat1 branch but I have something that should be committed into feat2, which is a branch way behind the current HEAD. I used to be doing these steps: first checkout feat2, then do a git rebase feat. But that would usually cause my running development server to detect a change and re-render to the old version, which will usually crash if your working tree is too different from the current branch. To avoid huge change of the working tree, while staying on branch feat1, I just do git fetch <repo> <src>:<dst>, in the above case that would be:

git fetch . HEAD:feat2

or

git fetch . feat1:feat2

After that feat2 will be pointing to same commit as feat1. You can then safely checkout feat2 without crashing your development server.

鱼忆七猫命九 2024-09-15 17:14:09

我使用以下别名:

[alias]
sync = !git fetch && git fetch -u . $(git for-each-ref --format='%(push):%(refname)' refs/heads)

有关详细说明,请参阅 https://stackoverflow.com/a/76267753/9878263

I use the following alias:

[alias]
sync = !git fetch && git fetch -u . $(git for-each-ref --format='%(push):%(refname)' refs/heads)

See https://stackoverflow.com/a/76267753/9878263 for the detailed explanation

一张白纸 2024-09-15 17:14:09

您只需git pull originbranchB到您的branchA中,git就会为您完成任务。

You can simply git pull origin branchB into your branchA and git will do the trick for you.

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