使用git同步所有分支

30

我从两个主要位置推送代码:我在家里的电脑和我在工作的笔记本电脑。我使用Github来存储我的代码库。

这是情景描述:我在我的PC上对一个我已经在上面工作了一段时间的代码库进行了一些工作(在我的PC和笔记本电脑上都有),最终得到了以下分支:

$ git branch
* master
* v123
* test-b

我已经把它推送到了Github上。目前为止一切顺利。

现在我在我的笔记本电脑上,看到的是这个:在尝试拉取任何内容之前

$ git branch
* master
* v_123

这是我电脑上一个旧版本的代码库(因为我一直在用我的PC),它和最新版本的区别在于:有一个分支(test-b)已经被删除,另一个分支已经被重命名或者说相当于被删除并重新创建了一个新的名称(也就是v_123现在变成了v123),而且所有分支中很可能都发生了很多变化。

我想将所有分支同步到我的电脑上,并正确地跟踪它们。我查看了两个关于克隆/获取分支的最热门问题(如何克隆git中的所有远程分支?; 如何获取git中的所有分支?),但现在我有点迷失方向了。

是否有一些易于使用的git sync-branch --all 命令可以用来将我电脑上的代码库与Github上的最新状态同步?


你不想这样做。这是一个常见的误解。当你“获取”时,你会得到所有的更新,然后你可以在需要使用它时手动更新任何本地分支。 - Andrew C
1
@AndrewC 但这正是我不想做的事情,也就是说:手动逐个更新每个本地分支。我希望通过一个单一的命令使我的存储库完全同步。这不允许吗? - Gabriel
1
当您同步您的仓库时,它完全同步的。如果您使用git branch -r命令,您可以看到所有引用都与远程上的完全相同。git branch命令则只显示本地仓库中的内容。 - Andrew C
1
我何时同步?我什么时候在同步?这正是问题所在。 - Gabriel
1
获取并没有解决太多问题,除了让我看到有什么变化。我不想一个一个地同步分支,这就是问题的重点。 - Gabriel
显示剩余3条评论
5个回答

34

我认为您想要:

git fetch --all -Pp

命令说明:

git fetch:从远程代码库下载对象和引用。

--all:获取所有远程代码库。

-P:删除不存在于远程代码库上的任何跟踪引用。

-p:删除不再存在于远程代码库上的任何本地标签。

更多使用方法请查看 git fetch --help

我们还有一个类似的命令,只执行修剪操作而不下载远程数据:

git remote prune origin

我们也可以设置git客户端在每次获取数据时执行远程修剪操作:

git config --global fetch.prune true

最好将此命令添加到您的bashrc文件中 \ alias gitcleanup='git fetch --all -Pp' - mati kepa
1
git fetch 会更新 git 对远程仓库的本地副本,但不会更改您在任何本地分支中看到的内容。为此,您需要在每个分支中执行 git pull(它首先执行 git fetch)。这可能会报告该分支的本地和远程更改之间的冲突。然后,您需要解决这些冲突。 - Denis Howe
如果您遇到冲突,您需要解决它,或者只需删除本地分支并再次检出以获取远程分支的最新克隆。 - ton

22

不确定,这是否符合您的期望。

git fetch origin
git reset --hard origin/master
git clean -f -d

上述命令将同步远程仓库和本地仓库。执行完上述命令后,你的本地仓库将与远程仓库完全一致。

如果想要保留更改为未提交文件,使用--soft而不是--hard

警告:当你执行git clean -f -d时,所有未跟踪的文件都会消失。

如有任何问题,请告知。


1
感谢@Breen,有几个问题:git fetch origin和简单的git fetch之间有什么区别?git reset --hard origin/master只会同步master分支还是所有其他分支也会同步? - Gabriel
虽然“git fetch”会获取所有分支,但是另外两个命令只影响当前分支,正如问题所问。 - Denis Howe
对于 git fetch 命令,除非当前分支设置了不同的上游分支(这很少见),否则默认仓库为 origin - Denis Howe

11
我遇到了类似的问题:
  • 我想要一次同步所有本地跟踪分支
  • 我希望此操作是安全的。换句话说,如果存在本地修改或分支分歧,请发出警告并不要触及历史记录(也不要篡改未提交的修改)

在寻找简单解决方案时,我最终使用了自己的解决方案(不是很简单),基于一系列 git 别名(代码添加到.gitconfig文件中):https://gist.github.com/arnauldvm/dcec7ee043c25dce30dbae1b576f2102

⚠ 这是新代码,尚未经过严格测试。

用法:git sync


一些解释:

tracking = "!f() { git for-each-ref --format '%(refname:short):%(upstream:short)' 'refs/heads' | egrep -v ':$'; }; f"

→ 这将检索所有本地跟踪分支和相应的远程分支,使用冒号分隔。
is-clean-workdir = "!f() { git diff --stat --exit-code || { echo \"Workdir dirty\"; exit 1; }; }; f"
is-clean-index = "!f() { git diff --stat --cached --exit-code || { echo \"Index dirty\"; exit 2; }; }; f"
is-clean = "!f() { git is-clean-workdir && git is-clean-index; }; f"

→ 这将验证工作目录中是否有未决的更改。
co-merge = "!f() { local=\"$1\"; remote=\"$2\"; git checkout \"$local\"; git merge --ff-only \"$remote\"; }; f"

→ 这个命令需要传入两个参数(一个本地分支和一个远程分支),它会切换到本地分支并将其与远程分支合并。它使用--ff-only来避免创建提交合并 ⇒ 如果本地分支与远程分支不一致,它将在标准错误流上发出“fatal: Not possible to fast-forward, aborting.” 的消息。

current-branch = rev-parse --abbrev-ref HEAD

→ 获取当前检出的分支名称。将用于在最后将工作目录恢复到其初始状态。
sync = "!f() { git is-clean || { echo Aborting sync.; exit 1; }; current=$(git current-branch); git fetch --all; git tracking | while IFS=: read local remote; do echo \"Merging $local with $remote\"; git co-merge \"$local\" \"$remote\"; done 3>&1 1>&2 2>&3 | egrep -i --color 'fatal|$' 3>&1 1>&2 2>&3; git checkout \"$current\"; }; f"

→ 这是主要部分。让我们将其分成几个部分:

git is-clean || { echo Aborting sync.; exit 1; }

→→ 如果工作目录中有未完成的任务,则终止该命令。

current=$(git current-branch)

→→ 存储当前检出分支的名称。
git fetch --all

→→ 同步所有远程分支 (--all)。


git tracking | while IFS=: read local remote; do ...

→→ 遍历每个本地跟踪分支。

3>&1 1>&2 2>&3 | egrep -i --color 'fatal|$' 3>&1 1>&2 2>&3

→→ 强调了包含“fatal”关键字的错误。 "3>&1 1>&2 2>&3" 这个神奇的公式可以交换STDOUT和STDERR,必须能够将STDERR管道传输到egrep命令。

git checkout "$current"

→→ 将工作目录恢复到初始状态。


1
已经一个小时了,git 竟然如此愚蠢地拒绝将我的本地分支更新为远程分支,我已经在绝望中爬遍了 SO 的所有答案来解决这个问题。我只是复制粘贴了您的答案,甚至没有试图理解,但是您的 sync 别名完全解决了我的问题。非常好的答案! - calandoa

3
在尝试拉取任何内容之前,您无法看到对远程进行的更改。您必须先从远程获取。这是有原因的。Git是去中心化的。每个仓库都包含其完整副本。这意味着您可以从您的磁盘上的存储库创建完整的克隆。这也意味着,除非您命令它同步,否则您可以完全脱机工作。实际上,Git的工作方式几乎完全强制您离线工作,不计算推送或获取时刻。另一方面,您完全掌控,没有不经过您明确表示就会发生的事情。如何做到?这就是为什么存在git pull。它执行两个操作。首先,它从远程获取所有分支(相当于git fetch)。它们保存为/,默认情况下不列在分支列表中(使用-a覆盖)。然后,它将当前活动分支与其跟踪的分支合并。
现在,如果你想要追踪一个远程分支,那么只需在pull之后checkout它。它将从上次同步的版本创建它,并应该设置好所有内容。如果你想要将未发布的本地分支设置为远程跟踪,请使用带有-u标志的git push。它会将分支的上游设置为推送目标。
编辑:
所以你的目标是用一个命令同时更新所有本地跟踪的分支?不是那些/,而是你的本地分支,而不必在每个分支上都调用pull,现在我明白了?
不幸的是,这在git中是不可能的。但是有一个扩展可以做到这一点。来自项目描述
git-up - 获取并重新设置所有已跟踪的本地远程分支
你可以在这里找到它 http://aanandprasad.com/git-up/ 当你使用它时,使用命令git up,它将存储你当前的更改,获取所有远程分支,然后将所有跟踪的分支重新设置为来自跟踪远程的状态,并取消存储更改。我相信这是你想要的同步方式。

很抱歉,我认为你完全没有理解问题的重点。我从未说过在拉取之前可以看到更改。我是说,在拉取之前所看到的是我的存储库的旧版本或上一个版本。我想找一种简单同步所有分支的方法,就这样。 - Gabriel
@Gabriel 我已经编辑了答案,这是你要找的吗? - Wikiii122

0

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