Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GIT: How do I add a file to the first commit (and rewrite history in the process)?

Tags:

git

I'd like to add one file to git repository as if it was there from the start. I only found explanations how to remove a file from entire history, not how to add one.

I tried git filter-branch --tree-filter 'git add LICENSE.txt' but I got error that the file can't be found.

like image 340
minder Avatar asked Jan 25 '14 17:01

minder


People also ask

How do you add files to git commit?

To add and commit files to a Git repository Create your new files or edit existing files in your local project directory. Enter git add --all at the command line prompt in your local project directory to add the files or changes to the repository. Enter git status to see the changes to be committed.

How do I update commit history?

There are many ways to rewrite history with git. Use git commit --amend to change your latest log message. Use git commit --amend to make modifications to the most recent commit. Use git rebase to combine commits and modify history of a branch.

How do I reword initial commit?

To change its message, you want to change the verb in front of it, from pick into reword . Then save the file and exit. Then, another editor will open up with the commit message. Make your changes to the commit message, save, and exit.

Which command do you use to add a new file to a commit?

Add another file, or another part of the changed file: git add CONTRIBUTING.md. Commit the second set of changes: git commit -m "create the contributing guide" (Repeat as necessary) Push the changes to the remote branch: git push -u origin update-readme.


2 Answers

git filter-branch can do this but is probably a lot heavier weight than needed.

How big and branch-y is your history? If it's small and short, the easiest way to do this would be add the new file now, then use git rebase -i --root to move the new commit to the 2nd position and squash it into the root commit.

For instance, let's say you have:

$ git log --oneline --graph --decorate --all
* e8719c9 (HEAD, master) umlaut
* b615ade finish
* e743479 initial

(your SHA-1 values will differ of course) and you want to add LICENSE.txt (already in the work dir) to the tree as part of the root commit. You can just do it now:

$ git add LICENSE.txt && git commit -m 'add LICENSE, for fixup into root'
[master 924ccd9] add LICENSE, for fixup into root
 1 file changed, 1 insertion(+)
 create mode 100644 LICENSE.txt

then run git rebase -i --root. Grab the last line (pick ... add LICENSE, ...) and move it to the second line, changing pick to fixup, and write the rebase-commands file out and exit the editor:

".git/rebase-merge/git-rebase-todo" 22L, 705C written
[detached HEAD 7273593] initial
 2 files changed, 4 insertions(+)
 create mode 100644 LICENSE.txt
 create mode 100644 x.txt
Successfully rebased and updated refs/heads/master.

The (new, completely-rewritten) history now looks more like this:

git log --oneline --graph --decorate --all
* bb71dde (HEAD, master) umlaut
* 7785112 finish
* 7273593 initial

and LICENSE.txt is in all commits.


If you do have a more complicated (branchy) history and want to use git filter-branch to get it all updated, the --tree-filter you need is not:

'git add LICENSE.txt'

but rather:

'cp /somewhere/outside/the/repo/LICENSE.txt LICENSE.txt'

to copy the new file into the tree each time. (A faster method would be to use the --index-filter but this is more complex.)

like image 150
torek Avatar answered Oct 07 '22 01:10

torek


--index-filter provides a simple and fast solution:

git filter-branch --index-filter "cp /abs/path/to/LICENSE.txt . && git add LICENSE.txt" --tag-name-filter cat --prune-empty -- --all

Here is a very simple benchmark against other proposed methods.

The first column (large) shows the timings in seconds for one run of each filter in copies of the Git project repository (45885 commits, checkout of ~30M). The rebase method does not apply since it does not handle merges automatically, even with the -c option.

The second columns (medium) shows median times for three runs of each method in copies of a medium sized repository with a linear history and fairly large trees (2430 commits, checkout of ~80M).

The third column (small) shows median times for three runs of each method in copies of a small repository (554 commits, checkout of ~100K).

              large medium  small
index-filter   1064     38     10
tree-filter    4319     81     15
rebase            -    116     28

Also note that the rebase is not functionally equivalent to the filter-branch variants, as it updates the committer dates.

like image 30
filipos Avatar answered Oct 07 '22 00:10

filipos