Search code examples
gitgit-mergegit-rebasegit-log

How is it possible in Git that files silently lost between 2 commits?


Me and coworker encountered this scenario in Git, where files went missing between 2 commits, but we don't see any "delete mode 100644 path/to/file" kind of output. Based on my understanding of Git, I don't see how this is possible.

Here are simplified trace info. Let me know if any further output would help investigation and I will happily append.

We located 2 consecutive commits in one branch:

git log --oneline

That gives:

enter image description here

Note 1423249 and 341c603. I will now check out to each of these commits to show that one example file (there are more) is present in the previous commit 341c603, but missing in the next commit 1423249.

341c603

➜ git checkout 341c603
Note: checking out '341c603'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b <new-branch-name>

HEAD is now at 341c603 v0.1.230
➜ git log  --stat --summary --  app/components/BreadcrumbNav/index.js
commit f88f71e4bec82a004626d2e1326bb1a1544675b3
Author: panguoliang <panguoliang@dae.org>
Date:   Wed May 8 13:31:05 2019 +0800

    ADD fiat module

 app/components/BreadcrumbNav/index.js | 41 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)
 create mode 100644 app/components/BreadcrumbNav/index.js
➜ ls -l  app/components/BreadcrumbNav/index.js
-rw-r--r--  1 wang.boyang  staff  888 May 10 10:10 app/components/BreadcrumbNav/index.js

It's there in 341c603. It was created in an older commit. Now moving to 1423249

1423249

➜ git checkout 1423249
Previous HEAD position was 341c603 v0.1.230
HEAD is now at 1423249 fix websocket, subscribe to current symbol
➜ git log --stat --summary --  ./app/components/BreadcrumbNav/index.js
(empty output)
➜ ls -l  app/components/BreadcrumbNav/index.js
ls: app/components/BreadcrumbNav/index.js: No such file or directory

It's not there! So, what are the changes in 1423249? Was the missing file app/components/BreadcrumbNav/index.js deleted in 1423249?

➜ git show --stat 1423249

commit 1423249134941968692d2094c64369017838d393 (HEAD)
Author: Wang Boyang <boyang@dae.org>
Date:   Thu May 9 12:59:59 2019 +0800

    fix websocket, subscribe to current symbol

 .eslintrc.js                       |   2 ++
 .prettierrc                        |  14 ++++++---
 app/containers/BarBox/actions.js   |  24 ++++++--------
 app/containers/BarBox/constants.js |   8 ++---
 app/containers/BarBox/index.js     |  22 ++++++-------
 app/containers/BarBox/reducer.js   |  18 ++++-------
 app/containers/BarBox/saga.js      |  20 ++++++------
 app/containers/BarBox/selectors.js |   5 ++-
 app/containers/BarBox/styles.js    |   5 ++-
 app/containers/TradePage/index.js  | 116 ++++++++++++++++++++++++++++----------------------------------------
 10 files changed, 102 insertions(+), 132 deletions(-)

There's absolutely no change related to the missing file, app/components/BreadcrumbNav/index.js. So, what's happening?

Edit

Below is a simplified output from git log --graph:

*   commit 47750dc0059d503dcd73de767fe9a1914070b6b9
|\  Merge: d1a0f6e 2115249
| | Author: justinji <justin5562587@gmail.com>
| | Date:   Thu May 9 17:40:01 2019 +0800
| | 
| |     resolve conflicts
| |   
| *   commit 2d8835e30a9a27f9eec687de573e4a77e66ed69a
| |\  Merge: 324857a 341c603
| | | Author: Wang Boyang <boyang@dae.org>
| | | Date:   Thu May 9 13:06:22 2019 +0800
| | | 
| | |     Merge remote-tracking branch 'origin/test' into test
| | | 
| | * commit 341c60334919930ee5f731cae3660c80aefb2ca1
| | | Author: panguoliang <panguoliang@dae.org>
| | | Date:   Thu May 9 12:03:01 2019 +0800
| | | 
| | |     v0.1.230
| | | 
| | |   
| | *   commit 66eaf470248a01b6d7861f1b319335255363195c
| | |\  Merge: 5ec1650 63e528b
| | | | Author: panguoliang <panguoliang@dae.org>
| | | | Date:   Thu May 9 12:00:48 2019 +0800
| | | | 
| | | |     lint
| | | | 
| | * | commit 9f8b93645851d98b1ab08264de8700a0e0dff47c
| | | | Author: panguoliang <panguoliang@dae.org>
| | | | Date:   Thu May 9 11:58:41 2019 +0800
| | | | 
| | | |     ADD Fiat deposit
| | | | 
| | | | 
| * | | commit 1423249134941968692d2094c64369017838d393
| | | | Author: Wang Boyang <boyang@dae.org>
| | | | Date:   Thu May 9 12:59:59 2019 +0800
| | | | 
| | | |     fix websocket, subscribe to current symbol
| | | |   
| * | |   commit 6d2c1073689140b75758d0e008af183340f1842b
| |\ \ \  Merge: f730698 63e528b
| | | |/  Author: Wang Boyang <boyang@dae.org>
| | |/|   Date:   Thu May 9 10:39:23 2019 +0800
| | | |   
| | | |       Merge remote-tracking branch 'origin/test' into test
| | | | 

Findings: in (and after) the merge commit 2d8835e30a9a27f9eec687de573e4a77e66ed69a, the files are lost. cat-file output:

➜ git cat-file commit 2d8835e30a9a27f9eec687de573e4a77e66ed69a
tree a46f997a76ff403d1ec0567913722787d72bf9f6
parent 324857aa9a26852a2c5699650366ac7797a85ac2
parent 341c60334919930ee5f731cae3660c80aefb2ca1
author Wang Boyang <boyang@dae.org> 1557378382 +0800
committer Wang Boyang <boyang@dae.org> 1557378382 +0800

Merge remote-tracking branch 'origin/test' into test

Edit2

The tool difflame gives below output:

➜ ~/Projects/difflame.py 341c603 2d8835e30a9a27f9eec687de573e4a77e66ed69a -- app/components/BreadcrumbNav/index.js
Processing line 48/48
diff --git a/app/components/BreadcrumbNav/index.js b/app/components/BreadcrumbNav/index.js
deleted file mode 100644
index bf18d9d..0000000
--- a/app/components/BreadcrumbNav/index.js
+++ /dev/null
@@ -1,41 +0,0 @@
    341c603: v0.1.230
-341c603 (panguoliang 2019-05-09 12:03:01  1  ) /**
-341c603 (panguoliang 2019-05-09 12:03:01  2  )  *
-341c603 (panguoliang 2019-05-09 12:03:01  3  )  * BreadcrumbNav
-341c603 (panguoliang 2019-05-09 12:03:01  4  )  *
-341c603 (panguoliang 2019-05-09 12:03:01  5  )  */

Is there any way to find out why the merge was done this way (i.e. deleting files), so that it can be avoided in the future?


Solution

  • All comments and answers are tremendously useful. I eventually found out why.

    First of all, like @meagar mentioned, file deletion is simply represented by a file blob not in a commit snapshot. As it turned out, the files disappeared during a merge.

    With any sane mergetool, when faced with 2 parents where one added a file and the other did not, it would hint and likely add the file, or show a conflict like modified in XXXX but deleted in XXX.

    This one didn't. Because I mistake the following 2:

    git merge -s recursive -X ours

    git merge -s ours

    The latter would simply ignore the other parents. So changes from there are gone. There onwards, all doesn't work as expected and file deletions are wrongfully persisted