头图

background

The last article keeps a clean Git submission record. Three enough. 161a41f1593a7e. After you read it, there are private messages saying that this is a very useful function. I suddenly thought of another Git function that I used in my work, which is also quite good. Use, you must tell the whole story

As programmers, we should all have a feeling. Once you enter a project, from development, to release and production, to hotfix, to post-maintenance, you basically have your share. A certain feature is being developed, and the boss suddenly jumped out and said It is more common for you to make hotfixes in production. Faced with this situation, we who use Git usually have two solutions:

  1. Submit unfinished features hastily, and then switch the branch to hotfix
  2. git stash | git stash pop Temporarily store the work content, and then switch to hotfix

The second method is much better than the first one, but in the face of the following scenarios, stash is still not a good solution

The scene we face

  1. Is running a long test on the main branch, switch to hotfix or feature, the test will be interrupted
  2. The project is very large, the index is frequently switched, and the cost is very high
  3. There are old versions released a few years ago, and the settings are different from the current ones. The IDE restructure adaptation switch will also bring a lot of overhead.
  4. To switch branches, you need to reset the corresponding environment variables, such as dev/qa/prod
  5. Need to switch to the code of a colleague to help debug the code to reproduce the problem

Some students thought, git clone multiple repo is not enough? This is a way to solve the above problems, but there are also many problems hidden behind them:

  1. The status of multiple repo is not easy to synchronize, for example, there is no way to quickly cherry-pick, one repo checkout branch, another repo needs to be re-checkout
  2. git history/log is repeated. When the project history is very long, .git folder will take up disk space very much.
  3. The same project, multiple repo, not easy to manage

So what can be done to satisfy these special scenarios without these above-mentioned problems?

git-worktree

In fact, this is a feature that Git has been supporting since 2015, but few people know it. The use of git-worktree is very convenient. Type in the terminal:

git worktree --help

You can quickly see the help document description:

To explain the role of git-worktree in simple words is:

Only need to maintain one repo, and can work on multiple branches at the same time, without affecting each other

There are many red border commands above, and we actually only use the following four:

 git worktree add [-f] [--detach] [--checkout] [--lock] [-b <new-branch>] <path> [<commit-ish>]
 git worktree list [--porcelain]
 git worktree remove [-f] <worktree>
 git worktree prune [-n] [-v] [--expire <expire>]

Before starting the explanation, we need to share with you two Git knowledge points that you may overlook:

  1. By default, the repo initialized by git init or git clone worktree , called main worktree
  2. Use the Git command in a certain directory, the current directory either has a .git folder; or there is a .git file, if there is only a .git file, the content inside must point to the .git folder

The second sentence feels quite convoluted. Let’s use an example to illustrate it. It’s easy to understand.

git worktree add

The current project directory structure is like this ( amend-crash-demo is the root of the repo):

.
└── amend-crash-demo

1 directory

cd amend-crash-demo Run command git worktree add ../feature/feature2

➜  amend-crash-demo git:(main) git worktree add ../feature/feature2
Preparing worktree (new branch 'feature2')
HEAD is now at 82b8711 add main file

Revisit the directory structure

.
├── amend-crash-demo
└── feature
    └── feature2

3 directories

By default, this command will create a branch named feature2 based on the commit-ish where HEAD is located (of course, you can also specify any commit-ish in git log). The branch disk location is shown in the above structure.

cd ../feature/feature2/ .git folder does not exist in this branch, but there is a .git file. Open the file and the content is as follows:

gitdir: /Users/rgyb/Documents/projects/amend-crash-demo/.git/worktrees/feature2

At this point, if you understand the knowledge point 2 above, will it be much clearer?

Next, you can do everything you want on the feature2 branch (add/commit/pull/push), without interfering with the main worktree

In general, the project team has a certain branch naming conventions, such as feature/JIRAID-Title , hotfix/JIRAID-Title , if only New worktree follow the above instructions, branch names / will be handled as a file directory

git worktree add ../hotfix/hotfix/JIRA234-fix-naming

After running the command, the file directory structure is like this

.
├── amend-crash-demo
├── feature
│   └── feature2
└── hotfix
    └── hotfix
        └── JIRA234-fix-naming

6 directories

Obviously this is not what we want, then we need the support of the -b parameter, just like git checkout -b

Excuting an order:

git worktree add -b "hotfix/JIRA234-fix-naming" ../hotfix/JIRA234-fix-naming

Let's look at the directory structure again

.
├── amend-crash-demo
├── feature
│   └── feature2
└── hotfix
    ├── JIRA234-fix-naming
    └── hotfix
        └── JIRA234-fix-naming

7 directories

Enter the JIRA234-fix-naming directory, the default is on the hotfix/JIRA234-fix-naming branch

Worktree is easy to set up, without management, the project directory structure is definitely messy, this is what we don’t want to see, so we need to know clearly which worktrees are built in a certain repo

git worktree list

All worktrees share a repo, so in any worktree directory, you can execute the following command to view the worktree list

git worktree list

After executing the command, you can view all the worktree information we created above, main worktree will also be displayed here

/Users/rgyb/Documents/projects/amend-crash-demo                        82b8711 [main]
/Users/rgyb/Documents/projects/chore/chore                                   8782898 (detached HEAD)
/Users/rgyb/Documents/projects/feature/feature2                             82b8711 [feature2]
/Users/rgyb/Documents/projects/hotfix/hotfix/JIRA234-fix-naming     82b8711 [JIRA234-fix-naming]
/Users/rgyb/Documents/projects/hotfix/JIRA234-fix-naming              82b8711 [hotfix/JIRA234-fix-naming]

After the work of worktree is finished, delete it in time, otherwise it will waste a lot of disk space

git worktree remove

This command is very simple. What is the name of the worktree? Just remove it.

git worktree remove hotfix/hotfix/JIRA234-fix-naming

At this time, the hotfix with the wrong branch name is deleted

/Users/rgyb/Documents/projects/amend-crash-demo                        82b8711 [main]
/Users/rgyb/Documents/projects/chore/chore                                   8782898 (detached HEAD)
/Users/rgyb/Documents/projects/feature/feature2                             82b8711 [feature2]
/Users/rgyb/Documents/projects/hotfix/JIRA234-fix-naming              82b8711 [hotfix/JIRA234-fix-naming]

Suppose you create a worktree and make changes in it. Suddenly the worktree is no longer needed. At this moment, you cannot delete it according to the above command. At this time, you need the -f parameter to help.

git worktree remove -f hotfix/JIRA234-fix-naming

Deleted worktree. In fact, there are many administrative files in Git files that are useless. In order to keep clean, we need to clean up further

git worktree prune

This command is a clean pocket operation, which can keep our work tidy all the time

Summarize

At this point, you should understand that the entire process of using git-worktree is the following four commands:

git worktree add
git worktree list
git worktree remove
git worktree prune

You should also understand the difference between git worktree and git clone multiple repo. Maintain only one repo, create multiple worktrees, and flow smoothly between operations

My practice : Usually use git worktree, I will unify the directory structure, for example, store all feature worktrees under the feature directory, and store all hotfix worktrees under the hotfix directory, so that the entire disk directory structure will not change due to the creation of multiple worktrees Get confused

I have some obsessive-compulsive disorder in disk management. Ideally, the worktree of a certain repo should be placed in the file directory of this repo, but this will cause all files under the newly created worktree of Git track, in order to avoid Git track worktree It’s definitely inappropriate to modify the gitignore file back and forth. next section, I will introduce a better way

Soul inquiry

  1. Can the main worktree be deleted? why
  2. Can you understand the changes in the repo/.git/wortree directory after repeated creation and deletion of worktree?

Ri Gong Yibing| Original


日拱一兵
3.4k 声望25.1k 粉丝