`checkout` = `reset` + `symbolic ref`?

a 夏天 提交于 2019-12-10 16:23:36

问题


Suppose a_branch is an existing branch that points to a different commit than the one HEAD points to (HEAD might point to a commit directly or via some branch).

Are the following commands equivalent?

git checkout a_branch

and

git symbolic-ref HEAD ref/heads/a_branch
git reset --hard a_branch


See also this related post.


回答1:


No, they're not, if you have staged or dirty changes before you run the commands.

If you modify a pre-existing file before running git checkout, the modification will persist after HEAD is moved. This is true whether the changes are staged or dirty.

The same does not hold when running git reset --hard. The modifications, staged or dirty, will be destroyed when you run git reset --hard.




回答2:


I also wondered, what git checkout (and git branch) really means in "plumbing" commands. Therefore, I tried one case, where I created a new branch, as it was only for learning the basics. To make sure, I don't miss anything, I started from scratch:

Create a folder "Test" with one file "test.txt" and write  
"Great content" into that file.

Using chapter 10 from the git book, I investigated the following sequence:

  • git init
  • git add .
  • git commit -m "Init"
  • EITHER porcelain commands:
    • git branch b1
    • git checkout b1
  • OR plumbing commands:
    • git symbolic-ref HEAD
    • git update-ref refs/heads/b1 $(git rev-parse HEAD)

The result: The two coincide!


The details. I will use the following commands to check the status:

Used commands from Git bash:

  • find .git/refs -type f find all files in .git/refs
  • git symbolic-ref HEAD points the symbolic HEAD reference, the same as cat .git/HEAD
  • git rev-parse HEAD get the history (Commits, objects?) reachable by HEAD
  • git rev-list --objects --all View all commit-objects
  • git cat-file -p refs/heads/master View the file content.
    If there were different branches with no common history, one has to use
    git rev-list --objects --no-walk $(git fsck --unreachable | grep '^unreachable commit' | cut -d' ' -f3)
  • git reflog shows one commit and the HEAD history (just one commit) Git porcelain commands
  • git branch -av Show all branches with hash and message (Also displays remotes if there are any!).

In the following, the commands are only shown if they result is something non-empty or it has changed since the last step.

Initialize Git repo

git init # creates empty .git/ folder. HEAD exists but without history.

No objects in .git/objects. Folders /info and /pack are empty.
.git/refs/ is empty

Stage changes

git add .
find .git/refs -type f # One object in c1/ created:
git cat-file -p c15479631b40176f3b09b7bc74ac5e189190e991 # yields "great content"
git cat-file -t c15479631b40176f3b09b7bc74ac5e189190e991 # yields  "blob"

Thus, one object in refs/objects/ was created

Commit changes

git commit -m "Init"
find .git/refs -type f # refs/heads/master created. Not empty. So have a look:
git symbolic-ref HEAD               # refs/heads/master
git cat-file -p refs/heads/master   # The full commit information including tree, author, commiter and commit message
git rev-parse HEAD                  # The hash to which HEAD points
git reflog                          # shows the HEAD history (just one commit)

# View all commit-objects. Everything is reachable by the commit:
git rev-list --objects --all        
git cat-file -p $(git rev-parse HEAD) # Commit Hash changes with time. -t instead of -p yields "commit"
git cat-file -p 69b13879c229e1cc35f270db248910e5a828dc65 # -t yields tree
git cat-file -p c15479631b40176f3b09b7bc74ac5e189190e991 # -t yields blob

git branch -av

master branch with hash from git rev-parse HEAD created

* master 7845459 Init

Create branch

git update-ref refs/heads/b1 $(git rev-parse HEAD)
# refs/heads/master still there. refs/heads/b1 created. So have a look:
find .git/refs -type f
git symbolic-ref HEAD          # Still at ref/heads/master
git cat-file -p refs/heads/b1  # The same result as from "git cat-file -p refs/heads/master"

git branch -av                      

b1 exists but not checked out:

  b1     7845459 Init
* master 7845459 Init

Checkout b1, i.e update HEAD

git symbolic-ref HEAD refs/heads/b1
git symbolic-ref HEAD  # now at refs/heads/b1 => b1 checked out! Cross-check:
git branch -av

b1 checked out:

* b1     7845459 Init
  master 7845459 Init

I hope, this is helpful.



来源:https://stackoverflow.com/questions/43376142/checkout-reset-symbolic-ref

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!