Repositories don't have files. Repositories have commits. The commits then have files, so you might say this is just a semantic quibble, but it's crucial to the answer, because the commits are package deals.
What you can do in this situation—note that I assume you made a commit with your updated file already—is:
- obtain the commits from the other Git repository (
git fetch
);
- use
git merge
to combine entire commits; and then
- make a commit that mostly uses the merge result, but keeps your partciular file intact.
There are a bunch of minor tweaks you can use during this process. In particular, the middle step—use git merge
—can be done with --no-commit
, so that Git does the work of merging, but then stops before making the resulting merge commit. By stopping Git in the middle of the merge like this, you make Git act like it does when it stops due to a failure to perform the merge automatically. You're now in a state in which Git has an unfinished merge, and your job is to finish it. This gives you full control of what goes into the merge as the merge result.
Often, however, it may be better to just allow Git to make this merge as a normal everyday merge, then build a new commit after the merge that restores your one file. This produces a commit that, when checked out, has the same result as a modified merge, but leaves the actual merge in the history. (Remember, Git's commits are the history in the file. Any commit you make is history. A commit that you don't make—that you modify first, and then only make the modified commit—does not leave any traces, because the only history in the Git repository is the set of commits that you can find in the repository.1)
In other words, you can feel safe enough just running:
git fetch
git merge
git checkout <commit-hash> -- path/to/C
git commit
and if you like git pull
you can use git pull
to combine the fetch-and-merge via the convenience git pull
command. (This assumes you have not configured git pull
to run git rebase
as its second command.)
The git checkout hash -- path
command requires that you find some historic commit that contains the file in the form that you want. You can use git log
to find it. If your Git is version 2.23 or later, you can use git restore
instead of git checkout
; the syntax is then:
git restore --staged --worktree --source=<hash> -- <path>
or if you prefer typing fewer characters:
git restore -SW --source=<hash> -- <path>
If you're using the git merge --no-commit
method, you can still use the same kind of git checkout
or git restore
command to replace the file before using git merge --continue
or git commit
to complete the merge. Note that such a merge is called an "evil merge"; see Evil merges in git?.
1There are some technical exceptions to this involving both Git's reflogs, and "dangling" (unreferenced) commits. These aren't found with normal git log
commands, but are findable for a while. But these eventually expire, leaving only the normal commits.