It can be done "in place"; I can't say whether you'll consider this approach a hack nonetheless, but it's as direct an approach as I can think of...
First, it sounds like his working copy is not a git repo at all. In that case, you can create the git repo "in place" on his working tree
git init
At this point his working copy will show up as untracked files in this new repo. Now associate the repo with the origin and fetch the history.
git remote add origin <origin-url>
git fetch
where <origin-url>
is the same url you would use to clone.
At this point, you still have an "unborn" master
branch and no other local branches; you still have the local working copy as untracked changes; and you have remote tracking refs for everything on the remote.
The next thing I'd do is something along the lines of
git add .
git diff origin/master
(I'm assuming here that if the local version is a modified copy of the code, it's modified from what's on origin/master
. If not, then you need to at least know what the "correct" parent commit would be, and substitute a reference to that commit. I'll continue assuming origin/master
for now, but feel free to comment if this is wrong and I can try to update accordingly.)
Here we're populating the index and comparing it to the remote's version, because if nothing is different, then you're done. Just wipe the index and work tree and checkout master
(which will create local master
and set it up to track origin/master
).
But it sounds like you don't think that's the case; so if you do see differences, you need to create a new commit. The slightly tricky part is getting git
to understand that this new state is just a child state of the existing origin/master
commit.
There are several ways to do that, and I'm sure opinions will vary on which way is best. A simple approach (but it does use some less-familiar commands) would be
git merge $(git commit-tree -p origin/master -m "Commit Message" $(git write-tree))
...which probably could stand a little explanation.
So first this creates a new TREE
(a snapshot of the project content) based on the index. Because we did a git add .
before doing git diff
, the index reflects the local version. This would print to standard output the ID of the new TREE
object.
We pass that ID to git commit-tree
, which creates a COMMIT
object with the given parent (again I'm assuming origin/master
), commit message (fill in something appropriate after -m
), and TREE
(the one we just created from the index). That would print to standard output the ID of the new COMMIT
object.
Then we merge the new COMMIT
object into the current (unborn) master
branch, which is a slightly weird thing to do but works like a fast-forward onto the specified COMMIT
. So now you have
x -- x -- O <--(origin/master)
\
L <--(master)
where L
will have content equal to the local copy; so it looks just like you had started from O
and made the local changes. You can push
normally at this point.