用Git命令切换任何分支并覆盖本地更改

93

有没有一条 Git 命令(或者一系列简短的命令),能够安全可靠地执行以下操作?

  • 取消所有本地修改。
  • 如有必要,从远程获取给定分支。
  • 检出给定分支?

目前我被卡住了:

git fetch -p
git stash
git stash drop
git checkout $branch
git pull

但是我很烦恼,因为我被要求输入两次密码(由 fetchpull)。通常只要密码只需要输入一次,任何解决方案我都会很高兴。

一些说明:

  • 这是一个应用程序的自制部署脚本(代码托管在GitHub上)的一部分。
  • 如果分支已经从原始版本中获取,也不应该有任何区别(即新分支的第一次部署理想情况下不需要任何额外的步骤)。
  • 脚本位于可以被多个人访问的远程机器上,因此不存储凭据,必须输入用户名/密码(但如果可能的话,只需输入一次)。
  • 我不关心任何本地更改;我始终希望得到给定分支的原始副本(部署脚本的后半部分会产生本地更改)。
  • 我无法每次都克隆或导出新的存储库;这需要太长时间。

1
  1. git reset --hard:回退到最新的提交状态
  2. git checkout $branch:切换到指定分支
  3. git pull origin $branch:从远程仓库拉取指定分支的最新代码
- g19fanatic
如果您使用SSH密钥,就不会提示您输入密码。 - Slam
如果你使用的是GitLab,那就不需要担心了。 - Hutch Moore
4个回答

137

你可以按照类似于"如何强制“git pull”覆盖本地文件?"的解决方案进行操作:

git fetch --all
git reset --hard origin/abranch
git checkout abranch 

这只需要一次获取。

使用Git 2.23+,git checkout 在此处被替换为git switch(此处介绍)(仍处于实验阶段)。

git switch -f $branch

(注意到在Jan回答中-f--discard-changes的别名)

即使索引或工作目录与HEAD不同,也可以继续操作。
同时,索引和工作目录都将被恢复以匹配切换的目标。


如果您不想切换分支,而只想从另一个分支中还原文件夹,则git restore是另一条命令,它取代了旧版过时且容易混淆的git checkout
我在这里介绍了git restore

git restore --source=anotherBranch --staged] [--worktree -- aFolder
# or, shorter:
git restore -s anotherBranch -SW -- aFolder

1
我正在使用这个解决方案,但是我在结尾处添加了额外的 git checkout $branch,因为否则 git 返回的当前分支信息是错误的。 - szeryf
1
@VonC,谢谢。这确实已经用分支覆盖了主分支。 - psun
1
@tuxErrante 那你不想切换分支了吗?在这种情况下,git restore 就是为你准备的。在2021年,没有人应该使用 git checkout。它已经过时、废弃且令人困惑。git restore -s experiment -SW -- aFolder:这将从分支 experiment 恢复 aFolder 的内容,包括工作树(W)和索引(S)。 - VonC
1
@tuxErrante 我已经编辑了答案,使得切换分支和恢复内容之间的区别更加清晰。 - VonC
1
@MikeSchinkel 这似乎是一个打字错误。我已经编辑了答案,使用与获取的分支相同的名称。 - VonC
显示剩余4条评论

40

几个要点:

  • 我认为git stash + git stash drop可以被替换为git reset --hard
  • ...或者,更简洁地,将-f添加到checkout命令中:

git checkout -f -b $branch

这将会丢弃所有本地的更改,就像在checkout之前使用git reset --hard一样。

至于主要问题: 与其在最后一步拉取,您可以将适当的分支从远程合并到您的本地分支中:git merge $branch origin/$branch,我相信它不会影响远程。如果是这种情况,这便消除了对凭据的需求,因此解决了您最大的担忧。


5
如果本地分支已经存在,git checkout -f -B $branch会重置该分支。此外,可能需要将 -b 大写。 - xer0x
3
对我来说,只使用“git checkout -B $existing_branch_name”就可以了,而“git checkout -f -b $existing_branch_name”不行——所以像@xer0x所说的那样,我认为答案是不正确的,因为大写字母“-B”是必需的。 - Suan

13

git resetgit clean 在某些情况下可能过于繁琐(并浪费大量时间)。

如果您只是收到以下消息:“以下未跟踪的文件将被覆盖...”,而您希望远程/起源/上游覆盖这些冲突的未跟踪文件,则最佳选择是使用 git checkout -f <分支名>

如果您和我一样,另一个选择是清理并执行 --hard reset,然后重新编译项目。


3
新的git-switch命令(从GIT 2.23开始)还有一个标记--discard-changes,应该对您有所帮助。之后可能需要执行git pull
警告:它仍被视为实验性功能。

好的观点。我过去推广了git switch(https://dev59.com/X2Af5IYBdhLWcg3wsUXT#57066202)。我已经更新了我的2013年答案,包括这个新命令。 - VonC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接