There seems to be a difference between the last commit, the HEAD and the state of the file I can see in my directory.
What is HEAD, what can I do with it and what mistake开发者_如何学Python should I avoid?
HEAD is a reference to the last commit in the currently checked-out branch.
There is a small exception to this, which is the detached HEAD. A detached HEAD is the situation you end up in whenever you check out a commit (or tag) instead of a branch. In this case, you have to imagine this as a temporary branch without a name; so instead of having a named branch reference, we only have HEAD. It will still allow you to make commits (which will update HEAD), so the above short definition is still true if you think of a detached HEAD as a temporary branch without a name.
HEAD
is a ref (reference) to the currently checked out commit.
In normal states, it's actually a symbolic ref to the branch you have checked out - if you look at the contents of .git/HEAD you'll see something like "ref: refs/heads/master". The branch itself is a reference to the commit at the tip of the branch. Therefore, in the normal state, HEAD
effectively refers to the commit at the tip of the current branch.
It's also possible to have a "detached HEAD". This happens when you check out something besides a (local) branch, like a remote branch, a specific commit, or a tag. The most common place to see this is during an interactive rebase, when you choose to edit a commit. In detached HEAD state, your HEAD is a direct reference to a commit - the contents of .git/HEAD will be a SHA1 hash.
Generally speaking, HEAD is just a convenient name to mean "what you have checked out" and you don't really have to worry much about it. Just be aware of what you have checked out, and remember that you probably don't want to commit if you're not on a branch (detached HEAD state) unless you know what you're doing (e.g. are in an interactive rebase).
From docs; The role of HEAD
is:
Tree | Role |
---|---|
Header | Last commit snapshot, next [future] parent |
Index | Proposed next commit snapshot |
Working Directory | Sandbox |
HEAD is the pointer to the current branch reference, which is in turn a pointer to the last commit made on that branch.
That means HEAD will be the parent of the next commit that is created. It’s generally simplest to think of HEAD as the snapshot of your last commit on that branch.
I always thought HEAD~5
means go to 5 commits before. But it doesn't carry the GO part of the command. It only carries the reference part of the command.
What you can do with that reference varies by the command you select
In layman terms it's used to answer the question of: WHERE should I go? To which commit?
HEAD
means (the reference to the) current commitHEAD~1
means (the reference to) 1 commit beforeHEAD~
ALSO means (the reference to) 1 commit beforeHEAD~87
means (the reference to) 87 commits beforeHEAD~3..HEAD
means from 3 commits to current commit (in total 3 commits)
Usage:
git checkout HEAD~1
will actually GO/checkout to 1 commit/reference beforegit reset HEAD~3
will uncommit your last 3 commits — without removing the changes, ie you can see all the changes made in the last 3 commits together, remove anything you don't like or add onto it and then commit them all again.git reset --hard HEAD~3
will uncommit your last commit and remove their changes. It will completely remove those changes. For more see here.git diff HEAD~3
to look into the changes of the last 3 commitsgit diff someFile HEAD~3
to look into the last 3 changes of a specific filegit revert --no-commit HEAD~3..HEAD
. Reverts 3 commits, without automatically commiting i.e. you have to dogit commit -m
yourself. For more see heregit rev-parse HEAD~2
outputs the SHA of two commit before.- See all changes between a pull request and main. It's a multi-step process.
git fetch origin/feature22
git checkout feature22
git merge-base feature22 main # will return the SHA of their 050dc022f3a65bdc78d97e2b1ac9b595a924c3f2
git reset 050dc022f3a65bdc78d97e2b1ac9b595a924c3f2
You could just do git reset main
, but that only works if your colleague who created the pull request has the latest changes with main. If they're working on a big feature (and haven't merged with main for a couple days) and you just want to see what additions they have after their last pull from main, then you have to follow the steps above.
Also make sure you see this answer for What is a detached HEAD.
It has some good info on cat .git/HEAD
Out of scope, but super interesting:
Other than HEAD
, there are other kinds of heads. See git revisions:
ORIG_HEAD
ORIG_HEAD
is created by commands that move yourHEAD
in a drastic way, to record the position of theHEAD
before their operation, so that you can easily change the tip of the branch back to the state before you ran them
To undo a git merge
git reset --hard ORIG_HEAD
MERGE_HEAD
I got this error message after I tried to merge again before concluding an existing merge
fatal: You have not concluded your merge (MERGE_HEAD exists). Please, commit your changes before you merge.
To fix this, I had to conclude my merge. Then do another merge.
FETCH_HEAD
records the branch which you fetched from a remote repository with your last git fetch invocation
CHERRY_PICK_HEAD
records the commit which you are cherry-picking when you run
git cherry-pick
.
For more on that see this other answer and docs
HEAD pointer in Git
Git maintains a reference variable called HEAD. And we call this variable a pointer, because its purpose is to reference, or point to, a specific commit in the repository. As we make new commits the pointer is going to change or move to point to a new commit. HEAD always points to the tip of the current branch in our repository. Now, this has to do with our repository, not our staging index, or our working directory.
Another way to think of it is the last state of our repository or what was last checked out, and because it's where the repository left off or the last state, you can also say that the HEAD points to the parent of the next commit or it's where commit writing is going to take place.
I think a good metaphor to think about this is the playback and record head on a cassette tape recorder. As we start recording audio, the tape moves past the head, and it records onto it. when we press Stop the place where that record head is stopped is the place it'll start recording again when we press Record a second time.Now we can move around, we can move the head to different places, but wherever the head is positioned when we hit Record again that's where it's going to start recording.
The HEAD pointer in Git is very similar, it points at the place where we're going to start recording next. It's the place where we left off in our repository for the things that we've committed.
In simple terms, HEAD is a reference to the last commit in the currently check-out branch.
Think of the HEAD as the "current branch". When you switch branches with git checkout, the HEAD revision changes to point to the tip of the new branch.
You can see what HEAD points to by doing:
cat .git/HEAD
It is possible for HEAD to refer to a specific revision that is not associated with a branch name. This situation is called a detached HEAD.
Basically HEAD is a pointer/reference which points to the last commit in the current branch.
You can use these two commands to verify this.
$ git log -1
commit 9883e13257f2e7555eb6e3b14b2c814978c75692 (HEAD -> MyLocalBranch)
Author: vikram <vikramguptavit@gmail.com>
Date: Sun Oct 11 23:32:45 2020 -0400
this is my last commit message
Now use below command to see where HEAD is pointing:
$ git rev-parse HEAD
9883e13257f2e7555eb6e3b14b2c814978c75692
As you can see that these two commit hashes are the same. So HEAD always points to the latest/last commit in the current branch.
精彩评论