Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Safia Abdalla
Safia Abdalla

Posted on

     

How does Git store working tree state?

Inmy last blog post, I started digging into howgit-status works. I ended up going into a little bit of a rabbit hole. As it turns out, thegit-status command intersects with the Git differ and the way that state about the current working tree is managed. I ended up setting aside two specific questions to answer in my blog post.

  • How does Git execute diffs and how does it manage diffed state?
  • How does Git manage the state of the working tree?

In today’s blog post, I’d like to take a stab at answering the second question more thoroughly. I already figured that Git uses awt_status_state struct (a data structure in C) to store information about whether or not the working tree is in the middle of a merge or a revert or other things. To be more specific, here are the different fields defined in the struct.

structwt_status_state{intmerge_in_progress;intam_in_progress;intam_empty_patch;intrebase_in_progress;intrebase_interactive_in_progress;intcherry_pick_in_progress;intbisect_in_progress;intrevert_in_progress;intdetached_at;char*branch;char*onto;char*detached_from;unsignedchardetached_sha1[20];unsignedcharrevert_head_sha1[20];unsignedcharcherry_pick_head_sha1[20];};

Neat, right? So I poked around the code to try and figure out where this wt_status_state object was populated in the code base. Most of this logic is stored in thewt_status_get_state function. Here’s what the header for that function looks like.

voidwt_status_get_state(structwt_status_state*state,intget_detached_from)

Like most C functions, you give it a pointer to an object that it should populate with information (*state) and some additional information. So how is thewt_status_state struct populated? The first meaningful line of code in the function does this.

if(!stat(git_path_merge_head(),&st)){state->merge_in_progress=1;}

Interesting! So thestat function is a function that returns information about the status of a file. You can read more about ithere. So, whatever thegit_path_merge_head function returns, it must be some sort of file path. I decided to see where and how this function was defined. As it turns out, the function isn’t defined explicitly. Instead, the function is invoked using a macro definition, as below.

#define GIT_PATH_FUNC(func, filename) \    const char *func(void) \    { \        static char *ret; \        if (!ret) \            ret = git_pathdup(filename); \        return ret; \    }

So, basically, whenever we callgit_path_merge_head, what is really invoked is the following snippet of code.

constchar*git_path_merge_head(void){staticchar*ret;if(!ret)ret=git_pathdup("MERGE_HEAD");returnret;}

In this case, thegit_pathdup function returns the location of the.git directory of the repository that we are in (this would be something like~/dev/my-git-repo/.git) concatenated with the defined filename (so the result of invoking the function above on the sample path would be~/dev/my-git-repo/.git/MERGE_HEAD).

OK! Now that we know what thegit_path_merge_head function does, we can go back and look at the code inwt_status_get_state is doing.

if(!stat(git_path_merge_head(),&st)){state->merge_in_progress=1;}

So,stat returns a false-y value if it can’t find the file located at the path returned bygit_path_merge_head. In essence, this snippet of code checks to see if aMERGE_HEAD file exists in the.git directory and sets the state ofmerge_in_progress to a truthy value if that is the case.

The code for checking to see if the user is currently cherry-picking the working tree is the same.

elseif(!stat(git_path_cherry_pick_head(),&st)&&!get_oid("CHERRY_PICK_HEAD",&oid)){state->cherry_pick_in_progress=1;hashcpy(state->cherry_pick_head_sha1,oid.hash);}

And so is the code for checking to see if the working tree is currently being reverted.

if(!stat(git_path_revert_head(),&st)&&!get_oid("REVERT_HEAD",&oid)){state->revert_in_progress=1;hashcpy(state->revert_head_sha1,oid.hash);}

Aha! So under the hood, the state of the working tree is actually stored on the filesystem through a collection of specially named files in the.git directory. There was one condition that was different though.

}elseif(wt_status_check_rebase(NULL,state)){;/* all set */}

Hm. Why does the check for a working tree in the middle of a rebase look like this? As it turns out, in the definition of thewt_status_check_rebase function, Git checks to see if certain rebase-related files (rebase-apply) exist in the working directory. So although the function call for checking if a rebase is in progress looks different, under the hood, it is doing the same thing. It checks to see if specific files exist in the working tree that reflect the state of the repository.

Well! I’m glad I got that answer settled. To be honest, I’ve seen theseMERGE_HEAD andREVERT_HEAD files in my Git repository before. I figured that Git used them to store some information about the merge state, but it’s cool to have a more specific perspective on one way these files are used.

Alright. Catch you next time!

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

I make open source at @nteractio, make software at @Microsoft, and write books and blogs. Dream big and follow through even bigger.
  • Location
    Redmond, WA
  • Education
    Bachelor of Science in Computer Science, Northwestern University
  • Work
    Software Engineer II at Microsoft
  • Joined

More fromSafia Abdalla

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp