git checkout to a branch takes long time

10,524

Solution 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).

Solution 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

Share:
10,524

Related videos on Youtube

Peaceful
Author by

Peaceful

Updated on June 04, 2022

Comments

  • Peaceful
    Peaceful about 2 years

    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?

    • Peaceful
      Peaceful over 6 years
      Why would that content change if I checkout to a newly created branch?
    • TobiSH
      TobiSH over 6 years
      Does there are major changes between master and your branch? Maybe this one is worth reading: stackoverflow.com/questions/15296473/…
    • evolutionxbox
      evolutionxbox over 6 years
      data doesn't actually get copied and instead only the changes are saved --- what do you mean? Commits save snapshots of files, not diffs.
    • Peaceful
      Peaceful over 6 years
      I realized that this is happening only on a particular machine and not on others. On this machine, all git operations are very slow. The machine has I7 processor and 8GB RAM and still this is happening.
    • Marina Liu
      Marina Liu over 6 years
      @Peaceful Does the CPU percentage change a lot (or not) when you switching a branch on that PC? And does the git version is also 2.14.1 on other machines which the switching time is normal?