繁体   English   中英

Git:如何更新master分支,一步切换到master分支?

[英]Git: How to update the master branch and switch to it in one step?

我正在处理一个托管在 GitLab 上的项目,并使用问题/工作分支和合并请求在完成后将该工作带入主分支。 通常我在问题分支上工作。 当它被 GitLab 合并后,我需要切换到当前 master 在本地进行构建。

我的工作流程是这样的:

  • 转主
  • 从远程拉取(--ff-only)
  • 删除陈旧的远程跟踪分支
  • 同时删除他们的本地跟踪分支

还有一个客户端工具可以监视代码目录并更新一些文件(CSS、JavaScript)。 当它看到第一步发生变化(切换到master)时,我首先需要等待它完成再继续(避免混淆)。 如果 issue 分支和旧 master 之间存在差异,那么在更新 master 时差异很可能会消失(因为该 issue 分支现在已合并)。

我正在寻找一种方法来一步切换到已经更新的 master 分支。 我如何使用git命令执行此操作? 我想将所有这些操作捆绑在一个批处理文件中,以避免每次都在 TortoiseGit 中重复所有这些手动步骤。

这个问题和建议的不同,本地master分支已经存在了。 我不是从远程切换到一个新分支,而是切换到一个已经存在的分支,它就在远程后面

长话短说

除非您编写自己的脚本(或使用 Git 别名来运行多个命令和/或脚本),否则您无法将其简化为单个命令,但可以更接近。 请参阅许多警告的长部分:最大的一个是它假设您在执行此操作时还没有master 如果是,则第二步将不起作用(请参阅详细部分了解会发生什么)。

git fetch -p &&
    git fetch . refs/remotes/origin/master:refs/heads/master &&
    git checkout master

将通过单个工作树更新git checkout step处理前三个要点(顺序不同)。

(请注意,出于发布目的,我将其分成三行,但作为使用!的 Git 别名,它实际上是一大行。)

有几种方法,包括实际的文字批处理文件(类 Unix 系统上的 shell 脚本,或 .BAT 文件,或其他)和别名(如Joe 在评论中所建议的那样)。

还有一个客户端工具可以监视代码目录并更新一些文件......

这……不一定是个好主意,比方说。 :-)

git checkout master运行时,它正在更改各种文件。 假设由于某种原因,它更改了观察者观看的几个文件之一,但随后它暂停了几分钟(或几秒、几微秒,或无论如何是某个时间单位)。 暂停时,观察者会尝试合并现在不同步的多个文件。

当 Git 取消暂停并完成结帐时,这可能是 OK 和自我更正 - 但如果您可以确保更新仅在结帐完成时发生,则可能会更好。

除此之外,让我们看一下这个特定的命令系列,并非常具体地说明您正在使用哪个 Git 命令:

  • 转主

我假设这是git checkout master

从远程拉取(--ff-only)

我假设这是git pull origin master --ff-only或者可能只是git pull --ff-only

  • 删除陈旧的远程跟踪分支

我现在假设这是git fetch --prune 如果您正在做不同的事情,则应将其包含在您的问题中。

  • 同时删除他们的本地跟踪分支

如果我明白你的意思,这需要一个脚本。 请注意,这有点危险:假设您有自己的分支X ,您正在其上进行开发。 这个X与其他任何人的X无关。 然后有人创建了他们自己的X使用相同的名称——并将其发送到你git fetch的机器。 你现在有了origin/X 然后他们删除他们的X (因为他们已经完成了)并删除origin/X 如果你现在让你的脚本删除你的X ,因为origin/X消失了,那可能很糟糕。

如果您仅在X明确将origin/X设置为其上游时才将其删除,则不会发生这种特殊情况——但如果有人不小心删除了您的origin/X并认为这是他们的origin/X ,同样的问题会再次出现,而这次特定的保护不起作用。

无论如何,撇开所有这些不谈,让我们看看我上面建议的变体。

git fetch -p

这会更新您所有的origin/*名称, 1包括origin/master ,而不会影响工作树中的任何文件 -p--prune的缩写,因此它会删除在 Git 中不再具有相应分支的所有origin/*名称,这些名称存储在名称origin下的 URL 中。


1我在这里假设您只有一个遥控器,名为origin 如果您有多个遥控器,请使用git fetch origin -p确保您专门从名为origin的遥控器中获取。 我还假设您没有将 Git 配置为单分支克隆。


git fetch. refs/remotes/origin/master:refs/heads/master

这个看起来很神奇的命令告诉你的 Git 调用它自己 也就是特殊的名字. 指的是你自己的 Git 仓库 我们正在使用它来欺骗您的 Git 根据您更新的origin/master快进您的master分支。 最后一个论点是这样做的:我们对你的 Git 说:好的,我的 Git,当你与另一个 Git 交谈时,找出它的refs/remotes/origin/master标识的提交。 然后,如果这是一个快进操作,请更新我的refs/heads/master以匹配。

当然,你的 Git 正在与之交谈的“其他 Git”就是它本身——所以这意味着快进 my master从 my origin/master 2大致相当于:

git checkout master && git merge --ff-only origin/master && git checkout -

除了没有实际签出发生:工作树中的文件没有更改。


2您可能想知道为什么其中一些使用origin/master而另一些使用refs/remotes/origin/master 较长的只是名称的完整拼写 使用git fetch时,最好使用完整拼写。 事实上,一般来说,在脚本中,您可能希望更频繁地使用完整拼写,但特别是git fetch可能会变得混乱,例如,如果您与之交谈的另一个Git 不小心同时具有同名的分支和标签。 所以我用git fetch来说明全名。 您将使用它与您自己的 Git 通话,因此如果您不混淆标签和分支名称或以其他方式造成歧义,您实际上不需要全名。 但这是git fetch的好习惯。


如果你在你的master身上,上面的失败

git fetch命令将拒绝提取到您签出的任何分支名称。 所以如果你master上,这个git fetch. 技巧会失败。

在某种程度上,这没问题! 如果你你的master上,你应该做的是运行:

git merge --ff-only origin/master

或任何等效的东西。 这就是你的git pull --ff-only所做的:首先它运行git fetch (没有-p并且仅限于仅获取其他 Git 的master ); 然后它运行git merge --ff-only

更完整的版本

那么,这个序列的一个更完整的版本是首先检查:我在哪个分支? 为此,您可以使用两个 Git 命令之一:

git rev-parse --abbrev-ref HEAD

要么:

git symbolic-ref --short HEAD

如果您当前在自己的master分支上,这两个都会打印master 它们之间的区别在于它们在完全没有分支的情况下会做什么:例如,在 rebase 的中间,当您处于“分离的 HEAD”state 时。在这种情况下,第二个命令 - git symbolic-ref出错了,而第一个只是打印HEAD

如果您想避免在这样的 state 中执行任何这些操作,请使用第二个命令并检查是否失败。 否则,使用第一个。 我将在这里仅说明第一个:

if test $(git rev-parse --abbrev-rev HEAD) = master; then
    # already on master - use alternative strategy
    git fetch -p && git merge --ff-only refs/remotes/origin/master
else
    # not currently on master: use fancy tricks to update
    git fetch -p &&
        git fetch . refs/remotes/origin/master:refs/heads/master &&
        git checkout master
fi

以上虽然未经测试,但应该适合作为 shell 脚本。 如果你安装了 Git,你就可以运行 shell 脚本——或者你可以把上面的变成一个很长的 Git 别名,使用! 和适当的分号集。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM