tags:

views:

583

answers:

1

I want to make changes to a file in my repo, then force git to believe the file is unmerged and show up in git status like so:

# Unmerged paths:
#   (use "git reset HEAD <file>..." to unstage)
#   (use "git add <file>..." to mark resolution)
#
#       both modified:      lib/delayed/recipes.rb
#

That's the entirety of my question. Read on for an explanation of why, since I know that's the first thing that will be asked.

The purpose here is a bugfix for Piston which today leaves merge conflicts in the index where they are too easily overlooked.

The way piston update works with a Git repo is:

  • Clone the remote repo into a new temporary git repo
  • Checkout that temp repo to the last commit we saw (saved in .piston.yml)
  • Checkout our local repo (in a new branch) to the last commit where .piston.yml was updated
  • Copy our local repo's files into the temp repo
  • Commit all changes in the temp repo (these are our local changes as of the last time we updated this vendored project)
  • Run git merge master in the temp repo to merge our local changes with the remote repo's changes
  • IGNORE MERGE CONFLICTS(!) and copy all the files from the temp repo to our local repo
  • Commit those files (in our new temp branch) to our local repo
  • Checkout local repo back to our original starting point
  • Merge temp branch into local repo (adds any further changes we have made)

I expect to fix this problem by allowing the file with merge conflicts to be committed into the temp branch, but at the very end (after it runs git merge --squash) I want to tell git about the files that had a merge conflict in the temp repo.

+3  A: 

In Git file that has a merge conflicts has (usually) three versions in index, and a version in working area with diff3 -E / rcsmerge conflict markers. The versions in the index are stage 1 from common ancestor, stage 2 for "our" version, and stage 3 for "theirs" version. For unmerged file there is no version in stage 0 (you can use git update-index --unresolve to restore unmerged state by deleting stage 0).

You would need to use git ls-files --stage or git ls-tree <commit> to get sha-1 identifiers of blobs (file versions) you want to put in index, or git hash-object -w <file> if you want to generate version of a file from scratch / from working area version. Then you use git update-index --index-info to put higher order stages into the index file (and git update-index --unresolve after this, or git update-index --force-remove prior to stuffing higher stages to remove stage 0 from index). You can re-generate file with merge markers in working area using git checkout --conflict=merge -- <file>.

HTH (Hope That Helps)


See also: "How to selectively recreate merge state?" thread on Git mailing list.

Jakub Narębski
The two file versions that had the merge conflict are in another repo, and may have had a third version merged in by now. Isn't that a problem? (Though I confess I don't yet understand your response completely.)
ScottJ
I'm beginning to understand better. I think I would have to set it up to appear as an octopus merge, no? Merging common ancestor plus vendor changes plus local changes. This is way more complex than I anticipated and I don't think I'm up for it anymore. Thanks for the answer, though.
ScottJ
No octopus: merges are 3-way merges in Git, therefore three versions needed. I'll try to come up with an example later.
Jakub Narębski