git checkout is not removing files that it should

后端 未结 4 706
忘了有多久
忘了有多久 2021-02-14 07:45

Using a public repo, I want to get my master branch back to a certain commit from the past. I have reviewed the options and the best thing for me looks to be a simple checkout t

4条回答
  •  北海茫月
    2021-02-14 08:11

    TL;DR: remove everything first

    When you used git checkout aaa1 ., you told Git to translate aaa1 to a commit, find that commit (more precisely, its tree), and copy every file in that commit to your index / staging area and work-tree.

    Let's say, just for the sake of argument, that you start with master containing two files, README and hello:

    $ git checkout master
    [output snipped]
    $ ls
    README   hello
    $ cat README
    Yay, you read me!
    $ cat hello
    world
    $ 
    

    Let's say further that commit aaa1 exists and has two files in it, README and addendum. Its README says Thank you for reading. Let's do that checkout:

    $ git checkout aaa1 -- .
    [output snipped]
    $ ls
    README    addendum  hello
    

    (I added the --: it's not actually required here, but it's good practice.) The contents of README are the updated README. The file addendum has also been extracted. The file hello is not removed and remains unchanged from the version found in master. The updated README and hello are staged:

    $ git status --short
    M  README
    A  addendum
    

    but hello is not removed:

    $ git ls-files --stage
    100644 ac6f2cf1acbe1b6f11c7be2288fbae72b982823c 0   README
    100644 7ddf1d71e0209a8512fe4862b4689d6ff542bf99 0   addendum
    100644 cc628ccd10742baea8241c5924df992b5c019f71 0   hello
    

    Using git clean, even with -x, will have no effect: nothing needs cleaning; there are no unstaged files (hello is staged, it's just not modified).


    You specifically wanted to get the work-tree to match commit aaa1, byte for byte. To do that, you must find files that are in the index now, but were not in aaa1, and remove them.

    There is, however, an easier way: just remove everything. Then, use your git checkout aaa1 -- . to extract everything from aaa1. This will fill in the index and work-tree from aaa1: any files that need to be restored to the way they were before removing, are restored (to the way they were in aaa1 which is the same as the way they are in HEAD). Any files that need to be changed to match the way they were in aaa1, are restored (to the way they were in aaa1 which is different).

    $ git rm -rf .
    rm 'README'
    rm 'addendum'
    rm 'hello'
    $ git checkout aaa1 -- .
    $ git ls-files --stage
    100644 ac6f2cf1acbe1b6f11c7be2288fbae72b982823c 0   README
    100644 7ddf1d71e0209a8512fe4862b4689d6ff542bf99 0   addendum
    $ git status --short
    M  README
    A  addendum
    D  hello
    

    You can now commit and you will have a new commit on master that, regardless of what was there before, has exactly the same tree as aaa1.

    (Whether this is a good idea is another thing entirely, but it will get you the desired state.)

提交回复
热议问题