Reputation: 103
I'm writing a tool which helps with resolving git merge conflicts. When a merge conflict happens via git pull
(or fetch + merge) there will be a special ref called MERGE_HEAD created and I can use it to retrieve the commit message for a particular file:
git log HEAD..MERGE_HEAD somefile
Now, if I previously git stash
ed something and then git stash pop
gives me a merge conflict, were' not merging anything from the git point of view, so there's no MERGE_HEAD. And this is why I'm asking for help:
How to get the changelog of an unmerged file to present to the user and offer them to choose which one to keep?
git ls-files -u
lists the files along with some hashes but they are somewhat weird and I can't make any use of them with any git command?
Upvotes: 3
Views: 167
Reputation: 103
The above answers were helpful to understand git better, however I only needed to get the latest commit message of a file in, this turned out to be pretty easy:
git log -n 1 HEAD file
.
Thank you.
Upvotes: 1
Reputation: 51780
@Rodrigo gave a correct way to list the different blobs (:{1,2,3}:file
), here is some more context on how git stash
works :
git stash
actually does create a commit, and stores this commit in a reference named refs/stash
.
You can view this by inspecting this ref's history :
$ git log --oneline --graph stash
# or equivalently :
$ git log --oneline --graph stash@{0}
* f8ac2b6 (refs/stash) WIP on sidetrack: e330a4e edited on sidetrack
|\
| * e20e1a8 index on sidetrack: e330a4e edited on sidetrack
|/
* e330a4e (HEAD -> sidetrack) edited on sidetrack
* 78db1ef add thefile.txt
...
(side note : if you have several stashes, they are actually listed in the reflog of this refs/stash
reference : git reflog stash
, and you can access older versions of a ref using stash@{1}
, stash@{2}
, etc ... )
Applying a stash is roughly equivalent to running git cherry-pick stash
.
So, if you have a conflict on file that/file.txt
when running git stash pop
or git stash apply
, you will find :
ours
version in HEAD
(as usual) : git show HEAD:that/file.txt
theirs
version in stash
or stash@{0}
: git show stash:that/file.txt
base
version in the parent of stash
: git show stash^:that/file.txt
As you can see above the stash is actually a merge commit, it stores the worktree version of the files (refs/stash
), and the indexed version of the files (its second parent refs/stash^2
), which can be different if you had anything added and not committed yet.
If you apply git stash apply --index
or git stash pop --index
(and git stash tries to restore the content of the index), you have to look closer at what step triggered the conflict : restoring the worktree or the index.
Upvotes: 1
Reputation: 98338
When you have a conflict like this you do not have a commit to refer to, because... well a stash-pop does not create a commit in the first place.
But anyway, when a file is in conflict you can get the different versions of the file quite easily, if you know the right spell. From man gitrevisions
:
:[<n>:]<path>, e.g. :0:README, :README A colon, optionally followed by a stage number (0 to 3) and a colon, followed by a path, names a blob object in the index at the given path. A missing stage number (and the colon that follows it) names a stage 0 entry. During a merge, stage 1 is the common ancestor, stage 2 is the target branch’s version (typically the current branch), and stage 3 is the version from the branch which is being merged.
In the case of a stash-pop conflict, you can get the original version with git show :1:file
, the stashed file is git show :2:file
, and the working dir version is git show :3:file
.
About the hashes you get with git ls-files -u
, they are something like:
100644 a2d3a1c45e24173a1531524034bca8bc29f39dc0 1 file
100644 6a70e21770bce9fbf4440755ff20f8f00534861b 2 file
100644 8749ddd3de43774220449a6033de9c052356788b 3 file
These are the hashes of the different stages of that file, the blob itself, not of any commit, that's why most git commands won't work on it. You can get their contents with git cat-file
:
$ git cat-file -t a2d3a1c45e24173a1531524034bca8bc29f39dc0
blob
$ git cat-file -p a2d3a1c45e24173a1531524034bca8bc29f39dc0
<actual contents of the file>
Upvotes: 6