What's New for Git 2.7

    Just two months after version 2.6, Git 2.7 came out with new features, fixes, and performance improvements. What interesting has he prepared for us? I’ll talk about a few new things that seemed interesting to the Bitbucket team.

    A complete set of git worktree commands


    The git worktree command appeared in Git 2.5 ; it allows you to upload and simultaneously work with many repository branches in separate folders. For example, if you need to make an urgent revision, but do not want to touch the current working copy, you can simply upload the desired branch to a new folder using the command:
    $ git worktree add -b hotfix/BB-1234 ../hotfix/BB-1234
    Preparing ../hotfix/BB-1234 (identifier BB-1234)
    HEAD is now at 886e0ba Merged in bedwards/BB-13430-api-merge-pr (pull request #7822)
    


    Git 2.7 adds the git worktree list command , which displays a list of working copies of the repository and branches associated with them:
    $ git worktree list
    /Users/kannonboy/src/bitbucket/bitbucket            37732bd [master]
    /Users/kannonboy/src/bitbucket/staging              d5924bc [staging]
    /Users/kannonboy/src/bitbucket/hotfix/BB-1234       37732bd [hotfix/BB-1234]
    

    Improved support for many working copies with the git bisect team . The links used by bisect for “good” and “bad” commits moved from .git / refs / bisect to .git / refs / worktrees / $ worktree_name / refs / bisect , so now bisect can work simultaneously in different working copies of the repository . In addition, starting with Git 2.7, you can use git clone , specifying such a separate working copy as an argument - this will create an independent git repository, and not another working copy of the existing one.



    It is noteworthy that separate working copies can be created not only for branches. Like many other commands, git worktree add can be called with a pointer to a commit, whether its hash or tag:
    $ git worktree add ../git-2.4.7 ca00f80
    Preparing ../git-2.4.7 (identifier git-2.4.7)
    HEAD is now at ca00f80 Git 2.4.7
    $ git worktree add ../git-v2.6.0 v2.6.0
    Preparing ../git-v2.6.0 (identifier git-v2.6.0)
    HEAD is now at be08dee Git 2.6
    $ git worktree add ../git-v2.7.0 v2.7.0
    Preparing ../git-v2.7.0 (identifier git-v2.7.0)
    HEAD is now at 7548842 Git 2.7
    $ git worktree list
    /Users/kannonboy/src/git         7548842 [master]
    /Users/kannonboy/src/git-2.4.7   ca00f80 (detached HEAD)
    /Users/kannonboy/src/git-v2.6.0  be08dee (detached HEAD)
    /Users/kannonboy/src/git-v2.7.0  7548842 (detached HEAD)
    


    Several git stash improvements


    If you are a fan of git rebase , then you are most likely familiar with the --autostash option . It automatically saves all local changes to temporary storage ( stash ) until rebase is executed , and after it is applied, it applies them again.
    $ git rebase master --autostash
    Created autostash: 54f212a
    HEAD is now at 8303dca It's a kludge, but put the tuple from the database in the cache.
    First, rewinding head to replay your work on top of it...
    Applied autostash.
    

    This is convenient because you can rebase on a dirty working copy. For even greater convenience, there is a rebase.autostash parameter that makes the behavior described by default. You can apply it globally using the command:
    $ git config --global rebase.autostash true
    

    This option has existed since Git 1.8.4 , but in Git 2.7 the ability to cancel it using the --no-autostash option has been added . Most likely, this option was added for completeness, since the only thing it gives when trying to rebase on a “dirty” working copy is the corresponding warning:
    $ git rebase master --no-autostash
    Cannot rebase: You have unstaged changes.
    Please commit or stash them.
    

    Speaking of configuration, it is also worth mentioning the stash.showPatch parameter , which also appeared in Git 2.7. With standard settings, the git stash show command displays only brief information about files in temporary storage:
    $ git stash show
    package.json | 2 +-
    1 file changed, 1 insertion(+), 1 deletion(-)
    

    If you additionally specify the -p option , the output will be supplemented by an extended description of file changes:
    diff --git a/package.json b/package.json
    index c876b26..e21eeb3 100644
    --- a/package.json
    +++ b/package.json
    @@ -48,7 +48,7 @@
         "mkdirp": "^0.5.0",
         "byline": "^4.2.1",
         "express": "~3.3.4",
    -    "git-guilt": "^0.1.0",
    +    "git-guilt": "^0.1.1",
         "jsonfile": "^2.0.0",
         "jugglingdb-sqlite3": "0.0.5",
         "jugglingdb-postgres": "~0.1.0",
    

    The stash.showPatch parameter makes this the default behavior. You can apply it globally using a similar command:
    $ git config --global stash.showPatch true
    

    As in the previous case, the included parameter can be canceled and thereby return to the old short output, using the --stat option :
    $ git stash show --stat
    package.json | 2 +-
    1 file changed, 1 insertion(+), 1 deletion(-)
    

    Be careful: the --no-patch option does not result in an error, however, it does not cancel stash.showPatch , as you might expect.

    Git filter-branch acceleration and progress indicator


    git filter-branch is a universal tool for changing repository history. Since each commit has links to parent commits, which means it transitively refers to all the commits that are its ancestors, changing one commit inevitably entails a change in all its descendants. This, in turn, means that the operation of even an elementary change in history can take some time if you need to change a sufficiently old commit.

    Git 2.7 introduced an elegant progress indicator that displays the estimated time until filter-branch completes :


    In addition, if filter-branchdoes not change objects in the index or trees, the index is not read at all when the command is executed, which significantly increases its performance. The --commit-filter option on the animation above only changes the author of each commit and does not affect the tree objects associated with them. Changing the first 1000 Bitbucket Server commits took only 38 seconds when using Git 2.7.0, while a similar operation with Git 2.6.0 required 64 seconds, that is, a speed increase of as much as 40% . The performance tests that appeared in Git 2.7 along with these improvements show even more impressive acceleration - up to 60% .

    Improved negation in .gitignore


    .Gitignore files allow you to exclude from the repository some files that are in the working copy, i.e. they will not be added to the index. Templates support the negation flag with a prefix ! so that it is possible to cancel ignoring a specific file. For example, with such patterns, git will ignore all files with a .json extension , except cat.json :
    # .gitignore
    *.json
    !cat.json
    

    However, in Git 2.6, it was not possible to apply negation to a file located in an already ignored folder.
    # .gitignore
    /animals
    !/animals/cat.json # <-- этот файл игнорируется в Git 2.6 и более ранних версиях
    

    Starting with Git 2.7, the second example works exactly as you would expect: with ! now you can undo ignoring files in folders that would otherwise be ignored.

    But that's not all!


    This is only a small part of the goodies that appeared in Git 2.7. The full list of changes can be found in the release notes , as well as in the comments for commits in the repository of Git itself :
    $ git log v2.6.0..v2.7.0
    



    The author of the original article , Tim Pettersen, participated in the development of JIRA, FishEye / Crucible and Stash. Since the beginning of 2013, he talks about development processes, git, continuous integration and deployment and Atlassian development tools, especially about Bitbucket. Tim regularly posts notes about these and other things on Twitter under the pseudonym @kannonboy .

    Also popular now: