Diagnostic TeardownDEVOPS
Git Makes More Sense When a Branch Stops Being a Folder
- Author
- Alex Florian
- Published
- Updated
- Reading time
- 4 min
You create a Git branch, but no new folder appears. Then you switch branches and the files in the same directory change. It can feel as though Git is moving or replacing work unpredictably, especially if you picture each branch as its own folder.
A different picture makes the behavior much easier to follow. Git records connected snapshots of a project, called commits. A branch gives a name to a position in that history. The files open in your editor are the working tree: the version you are currently using and editing. [1][2]
Creating another branch adds a way to identify the history. It doesn't need to create another physical copy of your project beside the first one.
Follow one file through two branches
Consider this hypothetical repository. Commit A contains a file with the line delivery_days = 5. The branch named main points to A. You create another branch called experiment, which initially points to the same commit.
main -------> A delivery_days = 5
experiment -> A the same saved snapshotNothing about creating the second name requires a second folder. Both names currently identify the same saved state.
Now you work on experiment, change the line to delivery_days = 3, and commit it as B:
A -------- B
^ ^
main experiment
5 days 3 daysThe experiment branch has advanced to B; main still identifies A. Switching to main makes the working tree correspond to A, subject to Git's handling of any uncommitted changes. Returning to experiment makes B available again. The saved experimental work hasn't vanished just because the directory now shows main's version. [2]
This is the relationship the folder analogy misses. The branch is a reference into the history; the working directory is where you interact with a selected state.
The next commit isn't always what the editor currently shows
There is one more state to understand before the example becomes dependable: the index, also called the staging area. It contains the content selected for the next commit. Saving a file in an editor and selecting its content for a commit are different operations. [2]
Now rewind to just before creating commit B. You have changed the value from five to three and staged that version. Before committing, you edit it again to two without staging the later edit:
| State in the hypothetical example | Value represented |
|---|---|
| Previously committed snapshot | delivery_days = 5 |
| Staged content for the next commit | delivery_days = 3 |
| Current file in the editor | delivery_days = 2 |
A commit from that state records the staged version, three. It hasn't ignored the later edit; that edit was never included in the proposed snapshot. The working tree can still contain the later value afterward.
Status and diff comparisons help distinguish those states. Before switching, resetting, or integrating work, identify what is staged, what is only in the working tree, and what has already been committed. A recorded commit and uncommitted changes do not have the same protection or recovery route.
Where HEAD fits
HEAD identifies the position currently being used, usually through the checked-out branch. In a detached HEAD state, it refers directly to a commit instead. That is another reason the directory name alone doesn't tell you where new history will be recorded. [1][2]
Likewise, deleting a branch name does not necessarily erase every associated commit immediately. Other references may still reach them. The relevant question is which references preserve the work you need, rather than which folder appears to contain it.
Learning about a colleague's work is another separate operation
A remote is another repository, such as the shared one your team uses. Your remote-tracking references record what you last learned from it; they aren't a permanently live view.
Fetching updates that knowledge and retrieves relevant history. It doesn't automatically combine the remote changes with your current branch. Pull adds an integration step according to the chosen command and configuration. That is why a successful fetch can leave the editor looking unchanged. [2]
Merge and rebase then address how histories join. They have different effects, particularly when commits have already been shared. The separate article on a rejected push follows that decision in detail; understanding a branch doesn't require memorizing every integration option at once.
For now, the important picture is enough: named positions in a connected history, staged content for the next snapshot, and files being edited. Once those states are distinct, Git's operations stop looking like competing ways to synchronize folders. Each changes a particular part of the picture—and you can ask for the operation that matches the change you actually intend.