git checkout to a branch takes long time

…衆ロ難τιáo~ 提交于 2019-12-08 06:15:32

问题


I am on Ubuntu 17.10 and I am using git (version 2.14.1). Whenever I create a branch from master and try to checkout to it (or to the master from it), it takes a whole lot of time, around few minutes, sometimes nearly 10 minutes. True, that I have a few GBs of data, but as far as I understand, the whole data doesn't actually get copied and instead only the changes are saved. What then could be the issue behind this?


回答1:


While Git 2.20 and 2.21 improve git checkout performance (see next section below), since Git 2.23 (August 2019), you are supposed to use git switch instead.

With Git 2.24 (Q4 2019) git switch gets a performance hack back.
And that does have an effect on git checkout -b that the OP uses.

See commit 3136776 (29 Aug 2019) by Derrick Stolee (derrickstolee).
(Merged by Junio C Hamano -- gitster -- in commit 3ff6af7, 30 Sep 2019)

checkout: add simple check for 'git checkout -b'

The 'git switch' command was created to separate half of the behavior of 'git checkout'.

It specifically has the mode to do nothing with the index and working directory if the user only specifies to create a new branch and change HEAD to that branch.
This is also the behavior most users expect from 'git checkout -b', but for historical reasons it also performs an index update by scanning the working directory.
This can be slow for even moderately-sized repos.

A performance fix for 'git checkout -b' was introduced by fa655d8 (checkout: optimize "git checkout -b <new_branch>" 2018-08-16, Git v2.20.0-rc0).
That change includes details about the config setting checkout.optimizeNewBranch when the sparse-checkout feature is required.
The way this change detected if this behavior change is safe was through the skip_merge_working_tree() method.
This method was complex and needed to be updated as new options were introduced.

This behavior was essentially reverted by 65f099b ("switch: no worktree status unless real branch switch happens" 2019-03-29, Git v2.23.0-rc0).
Instead, two members of the checkout_opts struct were used to distinguish between 'git checkout' and 'git switch':

* `switch_branch_doing_nothing_is_ok`
* `only_merge_on_switching_branches`

These settings have opposite values depending on if we start in cmd_checkout or cmd_switch.

The message for 65f099b includes "Users of big repos are encouraged to move to switch."
Making this change while 'git switch' is still experimental is too aggressive.

Create a happy medium between these two options by making 'git checkout -b <branch>' behave just like 'git switch', but only if we read exactly those arguments.
This must be done in cmd_checkout to avoid the arguments being consumed by the option parsing logic.

This differs from the previous change by fa655d8 in that the config option checkout.optimizeNewBranch remains deleted.
This means that 'git checkout -b' will ignore the index merge even if we have a sparse-checkout file.
While this is a behavior change for 'git checkout -b', it matches the behavior of 'git switch -c'.


Git 2.20 (Q4 2018) will improve a git checkout speed:

"git checkout -b newbranch [HEAD]" should not have to do as much as checking out a commit different from HEAD.
An attempt is made to optimize this special case.

See commit fa655d8 (16 Aug 2018) by Ben Peart (benpeart).
(Merged by Junio C Hamano -- gitster -- in commit 0faaf7e, 17 Sep 2018)

checkout: optimize "git checkout -b <new_branch>"

Skip merging the commit, updating the index and working directory if and only if we are creating a new branch via "git checkout -b <new_branch>."
Any other checkout options will still go through the former code path.

If sparse_checkout is on, require the user to manually opt in to this optimized behavior by setting the config setting checkout.optimizeNewBranch to true as we will no longer update the skip-worktree bit in the index, nor add/remove files in the working directory to reflect the current sparse checkout settings.

For comparison, running "git checkout -b <new_branch>" on a large repo takes:

14.6 seconds - without this patch
0.3 seconds - with this patch

Git 2.21 (Q1 2019) further optimizes git checkout, in that git checkout -b <new> [HEAD]" used to create a new branch from the current commit and check it out ought to be a no-op in the index and the working tree in normal cases, but there are corner cases that do require updates to the index and the working tree.

Running it immediately after "git clone --no-checkout" is one of these cases that an earlier optimization kicked in incorrectly, which has been fixed.

See commit 8424bfd, commit 91e3d7c (23 Jan 2019) by Ben Peart (benpeart).
(Merged by Junio C Hamano -- gitster -- in commit 5ad3550, 05 Feb 2019)

checkout: fix regression in checkout -b on intitial checkout

When doing a 'checkout -b', do a full checkout including updating the working tree when doing the initial checkout.
As the new test involves an filesystem access, do it later in the sequence to give chance to other cheaper tests to leave early.
This fixes the regression in behavior caused by fa655d8 (checkout: optimize "git checkout -b <new_branch>", 2018-08-16, Git 2.20).




回答2:


You should running git gc to helps performance.

git gc‘s purpose is twofold: Deleting loose objects and packing objects to use disk space more efficiently.

Runs a number of housekeeping tasks within the current repository, such as compressing file revisions (to reduce disk space and increase performance) and removing unreachable objects which may have been created from prior invocations of git add.

https://git-scm.com/docs/git-gc



来源:https://stackoverflow.com/questions/48823520/git-checkout-to-a-branch-takes-long-time

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!